Skip to content

Commit f2c4e6f

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

File tree

3 files changed

+74
-12
lines changed

3 files changed

+74
-12
lines changed

src/string_bytes.cc

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ size_t StringBytes::Write(Isolate* isolate,
306306
enum encoding encoding) {
307307
HandleScope scope(isolate);
308308
size_t nbytes;
309-
309+
buflen = StringBytes::keep_buflen_in_range(buflen);
310310
CHECK(val->IsString() == true);
311311
Local<String> str = val.As<String>();
312312

@@ -545,6 +545,13 @@ std::string StringBytes::hex_encode(const char* src, size_t slen) {
545545
return dst;
546546
}
547547

548+
size_t StringBytes::keep_buflen_in_range(size_t len) {
549+
if (len > static_cast<int>(std::numeric_limits<int>::max())) {
550+
return static_cast<int>(std::numeric_limits<int>::max());
551+
}
552+
return len;
553+
}
554+
548555
#define CHECK_BUFLEN_IN_RANGE(len) \
549556
do { \
550557
if ((len) > Buffer::kMaxLength) { \
@@ -579,6 +586,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
579586
}
580587

581588
case ASCII:
589+
buflen = StringBytes::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,24 +600,24 @@ 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 = StringBytes::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 = StringBytes::keep_buflen_in_range(buflen);
609616
return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
610617

611618
case BASE64: {
612619
size_t dlen = base64_encoded_size(buflen);
620+
dlen = StringBytes::keep_buflen_in_range(dlen);
613621
char* dst = node::UncheckedMalloc(dlen);
614622
if (dst == nullptr) {
615623
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
@@ -624,6 +632,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
624632

625633
case BASE64URL: {
626634
size_t dlen = base64_encoded_size(buflen, Base64Mode::URL);
635+
dlen = StringBytes::keep_buflen_in_range(dlen);
627636
char* dst = node::UncheckedMalloc(dlen);
628637
if (dst == nullptr) {
629638
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
@@ -638,6 +647,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
638647

639648
case HEX: {
640649
size_t dlen = buflen * 2;
650+
dlen = StringBytes::keep_buflen_in_range(dlen);
641651
char* dst = node::UncheckedMalloc(dlen);
642652
if (dst == nullptr) {
643653
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
@@ -651,6 +661,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
651661

652662
case UCS2: {
653663
size_t str_len = buflen / 2;
664+
str_len = StringBytes::keep_buflen_in_range(str_len);
654665
if (IsBigEndian()) {
655666
uint16_t* dst = node::UncheckedMalloc<uint16_t>(str_len);
656667
if (str_len != 0 && dst == nullptr) {

src/string_bytes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ class StringBytes {
105105

106106
static std::string hex_encode(const char* src, size_t slen);
107107

108+
static size_t keep_buflen_in_range(size_t len);
109+
108110
private:
109111
static size_t WriteUCS2(v8::Isolate* isolate,
110112
char* buf,

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

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

0 commit comments

Comments
 (0)