Skip to content

Commit 5b60d83

Browse files
committed
buffer: make buflen in integer range
1 parent 0951e7b commit 5b60d83

File tree

2 files changed

+71
-12
lines changed

2 files changed

+71
-12
lines changed

src/string_bytes.cc

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,13 @@ static inline unsigned unhex(uint8_t x) {
244244
return unhex_table[x];
245245
}
246246

247+
static size_t keep_buflen_in_range(size_t len) {
248+
if (len > static_cast<size_t>(std::numeric_limits<int>::max())) {
249+
return static_cast<size_t>(std::numeric_limits<int>::max());
250+
}
251+
return len;
252+
}
253+
247254
template <typename TypeName>
248255
static size_t hex_decode(char* buf,
249256
size_t len,
@@ -306,7 +313,7 @@ size_t StringBytes::Write(Isolate* isolate,
306313
enum encoding encoding) {
307314
HandleScope scope(isolate);
308315
size_t nbytes;
309-
316+
buflen = keep_buflen_in_range(buflen);
310317
CHECK(val->IsString() == true);
311318
Local<String> str = val.As<String>();
312319

@@ -579,6 +586,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
579586
}
580587

581588
case ASCII:
589+
buflen = keep_buflen_in_range(buflen);
582590
if (simdutf::validate_ascii_with_errors(buf, buflen).error) {
583591
// The input contains non-ASCII bytes.
584592
char* out = node::UncheckedMalloc(buflen);
@@ -592,23 +600,23 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
592600
return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
593601
}
594602

595-
case UTF8:
596-
{
597-
val = String::NewFromUtf8(isolate,
598-
buf,
599-
v8::NewStringType::kNormal,
600-
buflen);
601-
Local<String> str;
602-
if (!val.ToLocal(&str)) {
603-
*error = node::ERR_STRING_TOO_LONG(isolate);
604-
}
605-
return str;
603+
case UTF8: {
604+
buflen = keep_buflen_in_range(buflen);
605+
val =
606+
String::NewFromUtf8(isolate, buf, v8::NewStringType::kNormal, buflen);
607+
Local<String> str;
608+
if (!val.ToLocal(&str)) {
609+
*error = node::ERR_STRING_TOO_LONG(isolate);
606610
}
611+
return str;
612+
}
607613

608614
case LATIN1:
615+
buflen = keep_buflen_in_range(buflen);
609616
return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
610617

611618
case BASE64: {
619+
buflen = keep_buflen_in_range(buflen);
612620
size_t dlen = base64_encoded_size(buflen);
613621
char* dst = node::UncheckedMalloc(dlen);
614622
if (dst == nullptr) {
@@ -623,6 +631,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
623631
}
624632

625633
case BASE64URL: {
634+
buflen = keep_buflen_in_range(buflen);
626635
size_t dlen = base64_encoded_size(buflen, Base64Mode::URL);
627636
char* dst = node::UncheckedMalloc(dlen);
628637
if (dst == nullptr) {
@@ -637,6 +646,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
637646
}
638647

639648
case HEX: {
649+
buflen = keep_buflen_in_range(buflen);
640650
size_t dlen = buflen * 2;
641651
char* dst = node::UncheckedMalloc(dlen);
642652
if (dst == nullptr) {
@@ -650,6 +660,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
650660
}
651661

652662
case UCS2: {
663+
buflen = keep_buflen_in_range(buflen);
653664
size_t str_len = buflen / 2;
654665
if (IsBigEndian()) {
655666
uint16_t* dst = node::UncheckedMalloc<uint16_t>(str_len);

test/pummel/test-buffer-large-size.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
// Test Buffer size larger than integer range
5+
const assert = require('assert');
6+
const {
7+
SlowBuffer,
8+
} = require('buffer');
9+
const kStringMaxLength = require('buffer').constants.MAX_STRING_LENGTH;
10+
11+
const stringTooLongError = {
12+
message: `Cannot create a string longer than 0x${kStringMaxLength.toString(16)}` +
13+
' characters',
14+
code: 'ERR_STRING_TOO_LONG',
15+
name: 'Error',
16+
};
17+
18+
const size = 2 ** 32;
19+
20+
// Test Buffer.toString
21+
{
22+
try {
23+
assert.throws(() => Buffer(size).toString('utf8'), stringTooLongError);
24+
assert.throws(() => SlowBuffer(size).toString('utf8'), stringTooLongError);
25+
assert.throws(() => Buffer.alloc(size).toString('utf8'), stringTooLongError);
26+
assert.throws(() => Buffer.allocUnsafe(size).toString('utf8'), stringTooLongError);
27+
assert.throws(() => Buffer.allocUnsafeSlow(size).toString('utf8'), stringTooLongError);
28+
} catch (e) {
29+
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
30+
throw e;
31+
}
32+
common.skip('insufficient space for Buffer.alloc');
33+
}
34+
}
35+
36+
// Test Buffer.write
37+
{
38+
try {
39+
const buf = Buffer.alloc(size);
40+
assert.strictEqual(buf.write('a', 2, kStringMaxLength), 1);
41+
assert.strictEqual(buf.write('a', 2, size), 1);
42+
} catch (e) {
43+
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
44+
throw e;
45+
}
46+
common.skip('insufficient space for Buffer.alloc');
47+
}
48+
}

0 commit comments

Comments
 (0)