Skip to content

Commit

Permalink
buffer: make buflen in integer range
Browse files Browse the repository at this point in the history
  • Loading branch information
kylo5aby committed Feb 23, 2024
1 parent 0951e7b commit 2e93994
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 12 deletions.
35 changes: 23 additions & 12 deletions src/string_bytes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ size_t StringBytes::Write(Isolate* isolate,
enum encoding encoding) {
HandleScope scope(isolate);
size_t nbytes;

buflen = StringBytes::keep_buflen_in_range(buflen);
CHECK(val->IsString() == true);
Local<String> str = val.As<String>();

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

size_t StringBytes::keep_buflen_in_range(size_t len) {
if (len > static_cast<size_t>(std::numeric_limits<int>::max())) {
return static_cast<size_t>(std::numeric_limits<int>::max());
}
return len;
}

#define CHECK_BUFLEN_IN_RANGE(len) \
do { \
if ((len) > Buffer::kMaxLength) { \
Expand Down Expand Up @@ -579,6 +586,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
}

case ASCII:
buflen = StringBytes::keep_buflen_in_range(buflen);
if (simdutf::validate_ascii_with_errors(buf, buflen).error) {
// The input contains non-ASCII bytes.
char* out = node::UncheckedMalloc(buflen);
Expand All @@ -592,24 +600,24 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
}

case UTF8:
{
val = String::NewFromUtf8(isolate,
buf,
v8::NewStringType::kNormal,
buflen);
Local<String> str;
if (!val.ToLocal(&str)) {
*error = node::ERR_STRING_TOO_LONG(isolate);
}
return str;
case UTF8: {
buflen = StringBytes::keep_buflen_in_range(buflen);
val =
String::NewFromUtf8(isolate, buf, v8::NewStringType::kNormal, buflen);
Local<String> str;
if (!val.ToLocal(&str)) {
*error = node::ERR_STRING_TOO_LONG(isolate);
}
return str;
}

case LATIN1:
buflen = StringBytes::keep_buflen_in_range(buflen);
return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);

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

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

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

case UCS2: {
size_t str_len = buflen / 2;
str_len = StringBytes::keep_buflen_in_range(str_len);
if (IsBigEndian()) {
uint16_t* dst = node::UncheckedMalloc<uint16_t>(str_len);
if (str_len != 0 && dst == nullptr) {
Expand Down
2 changes: 2 additions & 0 deletions src/string_bytes.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ class StringBytes {

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

static size_t keep_buflen_in_range(size_t len);

private:
static size_t WriteUCS2(v8::Isolate* isolate,
char* buf,
Expand Down
48 changes: 48 additions & 0 deletions test/pummel/test-buffer-large-size.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict';
const common = require('../common');

// Test Buffer size larger than integer range
const assert = require('assert');
const {
SlowBuffer,
} = require('buffer');
const kStringMaxLength = require('buffer').constants.MAX_STRING_LENGTH;

const stringTooLongError = {
message: `Cannot create a string longer than 0x${kStringMaxLength.toString(16)}` +
' characters',
code: 'ERR_STRING_TOO_LONG',
name: 'Error',
};

const size = 2 ** 32;

// Test Buffer.toString
{
try {
assert.throws(() => Buffer(size).toString('utf8'), stringTooLongError);
assert.throws(() => SlowBuffer(size).toString('utf8'), stringTooLongError);
assert.throws(() => Buffer.alloc(size).toString('utf8'), stringTooLongError);
assert.throws(() => Buffer.allocUnsafe(size).toString('utf8'), stringTooLongError);
assert.throws(() => Buffer.allocUnsafeSlow(size).toString('utf8'), stringTooLongError);
} catch (e) {
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
throw e;
}
common.skip('insufficient space for Buffer.alloc');
}
}

// Test Buffer.write
{
try {
const buf = Buffer.alloc(size);
assert.strictEqual(buf.write('a', 2, kStringMaxLength), 1);
assert.strictEqual(buf.write('a', 2, size), 1);
} catch (e) {
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
throw e;
}
common.skip('insufficient space for Buffer.alloc');
}
}

0 comments on commit 2e93994

Please sign in to comment.