mirror of https://github.com/nodejs/node.git
src: migrate string_bytes.cc to throw errors with code
PR-URL: https://github.com/nodejs/node/pull/19739 Fixes: https://github.com/nodejs/node/issues/3175 Fixes: https://github.com/nodejs/node/issues/9489 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>pull/19739/merge
parent
289d152ce0
commit
63eb267c34
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "base64.h"
|
||||
#include "node_internals.h"
|
||||
#include "node_errors.h"
|
||||
#include "node_buffer.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
@ -36,20 +37,6 @@
|
|||
// use external string resources.
|
||||
#define EXTERN_APEX 0xFBEE9
|
||||
|
||||
// TODO(addaleax): These should all have better error messages. In particular,
|
||||
// they should mention what the actual limits are.
|
||||
#define SB_MALLOC_FAILED_ERROR \
|
||||
v8::Exception::Error(OneByteString(isolate, "\"toString()\" failed"))
|
||||
|
||||
#define SB_STRING_TOO_LONG_ERROR \
|
||||
v8::Exception::Error(OneByteString(isolate, "\"toString()\" failed"))
|
||||
|
||||
#define SB_BUFFER_CREATION_ERROR \
|
||||
v8::Exception::Error(OneByteString(isolate, "\"toString()\" failed"))
|
||||
|
||||
#define SB_BUFFER_SIZE_EXCEEDED_ERROR \
|
||||
v8::Exception::Error(OneByteString(isolate, "\"toString()\" failed"))
|
||||
|
||||
namespace node {
|
||||
|
||||
using v8::HandleScope;
|
||||
|
@ -93,7 +80,7 @@ class ExternString: public ResourceType {
|
|||
|
||||
TypeName* new_data = node::UncheckedMalloc<TypeName>(length);
|
||||
if (new_data == nullptr) {
|
||||
*error = SB_MALLOC_FAILED_ERROR;
|
||||
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
memcpy(new_data, data, length * sizeof(*new_data));
|
||||
|
@ -126,7 +113,7 @@ class ExternString: public ResourceType {
|
|||
|
||||
if (str.IsEmpty()) {
|
||||
delete h_str;
|
||||
*error = SB_STRING_TOO_LONG_ERROR;
|
||||
*error = node::ERR_STRING_TOO_LARGE(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
|
||||
|
@ -183,7 +170,7 @@ MaybeLocal<Value> ExternOneByteString::NewSimpleFromCopy(Isolate* isolate,
|
|||
v8::NewStringType::kNormal,
|
||||
length);
|
||||
if (str.IsEmpty()) {
|
||||
*error = SB_STRING_TOO_LONG_ERROR;
|
||||
*error = node::ERR_STRING_TOO_LARGE(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
return str.ToLocalChecked();
|
||||
|
@ -201,7 +188,7 @@ MaybeLocal<Value> ExternTwoByteString::NewSimpleFromCopy(Isolate* isolate,
|
|||
v8::NewStringType::kNormal,
|
||||
length);
|
||||
if (str.IsEmpty()) {
|
||||
*error = SB_STRING_TOO_LONG_ERROR;
|
||||
*error = node::ERR_STRING_TOO_LARGE(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
return str.ToLocalChecked();
|
||||
|
@ -616,7 +603,7 @@ static size_t hex_encode(const char* src, size_t slen, char* dst, size_t dlen) {
|
|||
#define CHECK_BUFLEN_IN_RANGE(len) \
|
||||
do { \
|
||||
if ((len) > Buffer::kMaxLength) { \
|
||||
*error = SB_BUFFER_SIZE_EXCEEDED_ERROR; \
|
||||
*error = node::ERR_BUFFER_TOO_LARGE(isolate); \
|
||||
return MaybeLocal<Value>(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -639,9 +626,13 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
|
|||
switch (encoding) {
|
||||
case BUFFER:
|
||||
{
|
||||
if (buflen > node::Buffer::kMaxLength) {
|
||||
*error = node::ERR_BUFFER_TOO_LARGE(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
auto maybe_buf = Buffer::Copy(isolate, buf, buflen);
|
||||
if (maybe_buf.IsEmpty()) {
|
||||
*error = SB_BUFFER_CREATION_ERROR;
|
||||
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
return maybe_buf.ToLocalChecked();
|
||||
|
@ -651,7 +642,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
|
|||
if (contains_non_ascii(buf, buflen)) {
|
||||
char* out = node::UncheckedMalloc(buflen);
|
||||
if (out == nullptr) {
|
||||
*error = SB_MALLOC_FAILED_ERROR;
|
||||
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
force_ascii(buf, out, buflen);
|
||||
|
@ -666,7 +657,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
|
|||
v8::NewStringType::kNormal,
|
||||
buflen);
|
||||
if (val.IsEmpty()) {
|
||||
*error = SB_STRING_TOO_LONG_ERROR;
|
||||
*error = node::ERR_STRING_TOO_LARGE(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
return val.ToLocalChecked();
|
||||
|
@ -678,7 +669,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
|
|||
size_t dlen = base64_encoded_size(buflen);
|
||||
char* dst = node::UncheckedMalloc(dlen);
|
||||
if (dst == nullptr) {
|
||||
*error = SB_MALLOC_FAILED_ERROR;
|
||||
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
|
||||
|
@ -692,7 +683,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
|
|||
size_t dlen = buflen * 2;
|
||||
char* dst = node::UncheckedMalloc(dlen);
|
||||
if (dst == nullptr) {
|
||||
*error = SB_MALLOC_FAILED_ERROR;
|
||||
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
size_t written = hex_encode(buf, buflen, dst, dlen);
|
||||
|
@ -723,7 +714,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
|
|||
if (IsBigEndian()) {
|
||||
uint16_t* dst = node::UncheckedMalloc<uint16_t>(buflen);
|
||||
if (dst == nullptr) {
|
||||
*error = SB_MALLOC_FAILED_ERROR;
|
||||
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
size_t nbytes = buflen * sizeof(uint16_t);
|
||||
|
|
|
@ -6,7 +6,6 @@ if (!common.enoughTestMem)
|
|||
common.skip(skipMessage);
|
||||
|
||||
const binding = require(`./build/${common.buildType}/binding`);
|
||||
const assert = require('assert');
|
||||
|
||||
// v8 fails silently if string length > v8::String::kMaxLength
|
||||
// v8::String::kMaxLength defined in v8.h
|
||||
|
@ -25,6 +24,11 @@ try {
|
|||
if (!binding.ensureAllocation(2 * kStringMaxLength))
|
||||
common.skip(skipMessage);
|
||||
|
||||
assert.throws(function() {
|
||||
const stringLengthHex = kStringMaxLength.toString(16);
|
||||
common.expectsError(function() {
|
||||
buf.toString('ascii');
|
||||
}, /"toString\(\)" failed/);
|
||||
}, {
|
||||
message: `Cannot create a string larger than 0x${stringLengthHex} bytes`,
|
||||
code: 'ERR_STRING_TOO_LARGE',
|
||||
type: Error
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@ if (!common.enoughTestMem)
|
|||
common.skip(skipMessage);
|
||||
|
||||
const binding = require(`./build/${common.buildType}/binding`);
|
||||
const assert = require('assert');
|
||||
|
||||
// v8 fails silently if string length > v8::String::kMaxLength
|
||||
// v8::String::kMaxLength defined in v8.h
|
||||
|
@ -25,6 +24,11 @@ try {
|
|||
if (!binding.ensureAllocation(2 * kStringMaxLength))
|
||||
common.skip(skipMessage);
|
||||
|
||||
assert.throws(function() {
|
||||
const stringLengthHex = kStringMaxLength.toString(16);
|
||||
common.expectsError(function() {
|
||||
buf.toString('base64');
|
||||
}, /"toString\(\)" failed/);
|
||||
}, {
|
||||
message: `Cannot create a string larger than 0x${stringLengthHex} bytes`,
|
||||
code: 'ERR_STRING_TOO_LARGE',
|
||||
type: Error
|
||||
});
|
||||
|
|
|
@ -25,9 +25,14 @@ try {
|
|||
if (!binding.ensureAllocation(2 * kStringMaxLength))
|
||||
common.skip(skipMessage);
|
||||
|
||||
assert.throws(function() {
|
||||
const stringLengthHex = kStringMaxLength.toString(16);
|
||||
common.expectsError(function() {
|
||||
buf.toString('latin1');
|
||||
}, /"toString\(\)" failed/);
|
||||
}, {
|
||||
message: `Cannot create a string larger than 0x${stringLengthHex} bytes`,
|
||||
code: 'ERR_STRING_TOO_LARGE',
|
||||
type: Error
|
||||
});
|
||||
|
||||
let maxString = buf.toString('latin1', 1);
|
||||
assert.strictEqual(maxString.length, kStringMaxLength);
|
||||
|
|
|
@ -6,7 +6,6 @@ if (!common.enoughTestMem)
|
|||
common.skip(skipMessage);
|
||||
|
||||
const binding = require(`./build/${common.buildType}/binding`);
|
||||
const assert = require('assert');
|
||||
|
||||
// v8 fails silently if string length > v8::String::kMaxLength
|
||||
// v8::String::kMaxLength defined in v8.h
|
||||
|
@ -25,6 +24,11 @@ try {
|
|||
if (!binding.ensureAllocation(2 * kStringMaxLength))
|
||||
common.skip(skipMessage);
|
||||
|
||||
assert.throws(function() {
|
||||
const stringLengthHex = kStringMaxLength.toString(16);
|
||||
common.expectsError(function() {
|
||||
buf.toString('hex');
|
||||
}, /"toString\(\)" failed/);
|
||||
}, {
|
||||
message: `Cannot create a string larger than 0x${stringLengthHex} bytes`,
|
||||
code: 'ERR_STRING_TOO_LARGE',
|
||||
type: Error
|
||||
});
|
||||
|
|
|
@ -25,10 +25,27 @@ try {
|
|||
if (!binding.ensureAllocation(2 * kStringMaxLength))
|
||||
common.skip(skipMessage);
|
||||
|
||||
assert.throws(function() {
|
||||
buf.toString();
|
||||
}, /"toString\(\)" failed|Array buffer allocation failed/);
|
||||
const stringLengthHex = kStringMaxLength.toString(16);
|
||||
|
||||
assert.throws(function() {
|
||||
buf.toString();
|
||||
}, function(e) {
|
||||
if (e.message !== 'Array buffer allocation failed') {
|
||||
common.expectsError({
|
||||
message: `Cannot create a string larger than 0x${stringLengthHex} bytes`,
|
||||
code: 'ERR_STRING_TOO_LARGE',
|
||||
type: Error
|
||||
})(e);
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
common.expectsError(function() {
|
||||
buf.toString('utf8');
|
||||
}, /"toString\(\)" failed/);
|
||||
}, {
|
||||
message: `Cannot create a string larger than 0x${stringLengthHex} bytes`,
|
||||
code: 'ERR_STRING_TOO_LARGE',
|
||||
type: Error
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@ if (!common.enoughTestMem)
|
|||
common.skip(skipMessage);
|
||||
|
||||
const binding = require(`./build/${common.buildType}/binding`);
|
||||
const assert = require('assert');
|
||||
|
||||
// v8 fails silently if string length > v8::String::kMaxLength
|
||||
// v8::String::kMaxLength defined in v8.h
|
||||
|
@ -25,6 +24,12 @@ try {
|
|||
if (!binding.ensureAllocation(2 * kStringMaxLength))
|
||||
common.skip(skipMessage);
|
||||
|
||||
assert.throws(function() {
|
||||
const stringLengthHex = kStringMaxLength.toString(16);
|
||||
|
||||
common.expectsError(function() {
|
||||
buf.toString('utf16le');
|
||||
}, /"toString\(\)" failed/);
|
||||
}, {
|
||||
message: `Cannot create a string larger than 0x${stringLengthHex} bytes`,
|
||||
code: 'ERR_STRING_TOO_LARGE',
|
||||
type: Error
|
||||
});
|
||||
|
|
|
@ -32,8 +32,15 @@ stream.end();
|
|||
stream.on('finish', common.mustCall(function() {
|
||||
fs.readFile(file, 'utf8', common.mustCall(function(err, buf) {
|
||||
assert.ok(err instanceof Error);
|
||||
assert.ok(/^(Array buffer allocation failed|"toString\(\)" failed)$/
|
||||
.test(err.message));
|
||||
if (err.message !== 'Array buffer allocation failed') {
|
||||
const stringLengthHex = kStringMaxLength.toString(16);
|
||||
common.expectsError({
|
||||
message: 'Cannot create a string larger than ' +
|
||||
`0x${stringLengthHex} bytes`,
|
||||
code: 'ERR_STRING_TOO_LARGE',
|
||||
type: Error
|
||||
})(err);
|
||||
}
|
||||
assert.strictEqual(buf, undefined);
|
||||
}));
|
||||
}));
|
||||
|
|
Loading…
Reference in New Issue