Skip to content

Commit e42c01b

Browse files
kylo5abyRafaelGSS
authored andcommitted
buffer: make buflen in integer range
PR-URL: #51821 Fixes: #51817 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 11781e8 commit e42c01b

File tree

2 files changed

+74
-12
lines changed

2 files changed

+74
-12
lines changed

src/string_bytes.cc

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,13 @@ MaybeLocal<Value> ExternTwoByteString::NewSimpleFromCopy(Isolate* isolate,
198198

199199
} // anonymous namespace
200200

201+
static size_t keep_buflen_in_range(size_t len) {
202+
if (len > static_cast<size_t>(std::numeric_limits<int>::max())) {
203+
return static_cast<size_t>(std::numeric_limits<int>::max());
204+
}
205+
return len;
206+
}
207+
201208
size_t StringBytes::WriteUCS2(
202209
Isolate* isolate, char* buf, size_t buflen, Local<String> str, int flags) {
203210
uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
@@ -243,7 +250,7 @@ size_t StringBytes::Write(Isolate* isolate,
243250
enum encoding encoding) {
244251
HandleScope scope(isolate);
245252
size_t nbytes;
246-
253+
buflen = keep_buflen_in_range(buflen);
247254
CHECK(val->IsString() == true);
248255
Local<String> str = val.As<String>();
249256
String::ValueView input_view(isolate, str);
@@ -516,6 +523,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
516523
}
517524

518525
case ASCII:
526+
buflen = keep_buflen_in_range(buflen);
519527
if (simdutf::validate_ascii_with_errors(buf, buflen).error) {
520528
// The input contains non-ASCII bytes.
521529
char* out = node::UncheckedMalloc(buflen);
@@ -529,23 +537,23 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
529537
return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
530538
}
531539

532-
case UTF8:
533-
{
534-
val = String::NewFromUtf8(isolate,
535-
buf,
536-
v8::NewStringType::kNormal,
537-
buflen);
538-
Local<String> str;
539-
if (!val.ToLocal(&str)) {
540-
*error = node::ERR_STRING_TOO_LONG(isolate);
541-
}
542-
return str;
540+
case UTF8: {
541+
buflen = keep_buflen_in_range(buflen);
542+
val =
543+
String::NewFromUtf8(isolate, buf, v8::NewStringType::kNormal, buflen);
544+
Local<String> str;
545+
if (!val.ToLocal(&str)) {
546+
*error = node::ERR_STRING_TOO_LONG(isolate);
543547
}
548+
return str;
549+
}
544550

545551
case LATIN1:
552+
buflen = keep_buflen_in_range(buflen);
546553
return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
547554

548555
case BASE64: {
556+
buflen = keep_buflen_in_range(buflen);
549557
size_t dlen = simdutf::base64_length_from_binary(buflen);
550558
char* dst = node::UncheckedMalloc(dlen);
551559
if (dst == nullptr) {
@@ -560,6 +568,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
560568
}
561569

562570
case BASE64URL: {
571+
buflen = keep_buflen_in_range(buflen);
563572
size_t dlen =
564573
simdutf::base64_length_from_binary(buflen, simdutf::base64_url);
565574
char* dst = node::UncheckedMalloc(dlen);
@@ -576,6 +585,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
576585
}
577586

578587
case HEX: {
588+
buflen = keep_buflen_in_range(buflen);
579589
size_t dlen = buflen * 2;
580590
char* dst = node::UncheckedMalloc(dlen);
581591
if (dst == nullptr) {
@@ -589,6 +599,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
589599
}
590600

591601
case UCS2: {
602+
buflen = keep_buflen_in_range(buflen);
592603
size_t str_len = buflen / 2;
593604
if constexpr (IsBigEndian()) {
594605
uint16_t* dst = node::UncheckedMalloc<uint16_t>(str_len);

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

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

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy