Skip to content

Commit 9edf023

Browse files
romandevevanlucas
authored andcommitted
n-api: throw RangeError napi_create_typedarray()
According to the ECMA spec, we should throw a RangeError in the following cases: - `(length * elementSize) + offset` > the size of the array passed in - `offset % elementSize` != `0` In the current implementation, this check was omitted. So, the following code will cause a crash. ``` napi_create_typedarray(env, napi_uint16_array, 2 /* length */, buffer, 1 /* byte_offset */, &output_array); ``` This change fixes the problem and write some related tests. Refs: https://tc39.github.io/ecma262/#sec-typedarray-buffer-byteoffset-length PR-URL: #18037 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
1 parent b05f09a commit 9edf023

File tree

5 files changed

+100
-12
lines changed

5 files changed

+100
-12
lines changed

doc/api/errors.md

+12
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,18 @@ While using `N-API`, `Constructor.prototype` was not an object.
12711271
While calling `napi_create_dataview()`, a given `offset` was outside the bounds
12721272
of the dataview or `offset + length` was larger than a length of given `buffer`.
12731273

1274+
<a id="ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT"></a>
1275+
### ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT
1276+
1277+
While calling `napi_create_typedarray()`, the provided `offset` was not a
1278+
multiple of the element size.
1279+
1280+
<a id="ERR_NAPI_INVALID_TYPEDARRAY_LENGTH"></a>
1281+
### ERR_NAPI_INVALID_TYPEDARRAY_LENGTH
1282+
1283+
While calling `napi_create_typedarray()`, `(length * size_of_element) +
1284+
byte_offset` was larger than the length of given `buffer`.
1285+
12741286
<a id="ERR_NO_CRYPTO"></a>
12751287
### ERR_NO_CRYPTO
12761288

lib/internal/errors.js

+3
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,9 @@ E('ERR_NAPI_CONS_PROTOTYPE_OBJECT', 'Constructor.prototype must be an object');
319319
E('ERR_NAPI_INVALID_DATAVIEW_ARGS',
320320
'byte_offset + byte_length should be less than or eqaul to the size in ' +
321321
'bytes of the array passed in');
322+
E('ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT', 'start offset of %s should be a ' +
323+
'multiple of %s');
324+
E('ERR_NAPI_INVALID_TYPEDARRAY_LENGTH', 'Invalid typed array length');
322325
E('ERR_NO_CRYPTO', 'Node.js is not compiled with OpenSSL crypto support');
323326
E('ERR_NO_ICU', '%s is not supported on Node.js compiled without ICU');
324327
E('ERR_NO_LONGER_SUPPORTED', '%s is no longer supported');

src/node_api.cc

+42-9
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,30 @@ struct napi_env__ {
142142
(!try_catch.HasCaught() ? napi_ok \
143143
: napi_set_last_error((env), napi_pending_exception))
144144

145+
#define THROW_RANGE_ERROR_IF_FALSE(env, condition, error, message) \
146+
do { \
147+
if (!(condition)) { \
148+
napi_throw_range_error((env), (error), (message)); \
149+
return napi_set_last_error((env), napi_generic_failure); \
150+
} \
151+
} while (0)
152+
153+
#define CREATE_TYPED_ARRAY( \
154+
env, type, size_of_element, buffer, byte_offset, length, out) \
155+
do { \
156+
if ((size_of_element) > 1) { \
157+
THROW_RANGE_ERROR_IF_FALSE( \
158+
(env), (byte_offset) % (size_of_element) == 0, \
159+
"ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT", \
160+
"start offset of "#type" should be a multiple of "#size_of_element); \
161+
} \
162+
THROW_RANGE_ERROR_IF_FALSE((env), (length) * (size_of_element) + \
163+
(byte_offset) <= buffer->ByteLength(), \
164+
"ERR_NAPI_INVALID_TYPEDARRAY_LENGTH", \
165+
"Invalid typed array length"); \
166+
(out) = v8::type::New((buffer), (byte_offset), (length)); \
167+
} while (0)
168+
145169
namespace {
146170
namespace v8impl {
147171

@@ -3063,31 +3087,40 @@ napi_status napi_create_typedarray(napi_env env,
30633087

30643088
switch (type) {
30653089
case napi_int8_array:
3066-
typedArray = v8::Int8Array::New(buffer, byte_offset, length);
3090+
CREATE_TYPED_ARRAY(
3091+
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
30673092
break;
30683093
case napi_uint8_array:
3069-
typedArray = v8::Uint8Array::New(buffer, byte_offset, length);
3094+
CREATE_TYPED_ARRAY(
3095+
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
30703096
break;
30713097
case napi_uint8_clamped_array:
3072-
typedArray = v8::Uint8ClampedArray::New(buffer, byte_offset, length);
3098+
CREATE_TYPED_ARRAY(
3099+
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
30733100
break;
30743101
case napi_int16_array:
3075-
typedArray = v8::Int16Array::New(buffer, byte_offset, length);
3102+
CREATE_TYPED_ARRAY(
3103+
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
30763104
break;
30773105
case napi_uint16_array:
3078-
typedArray = v8::Uint16Array::New(buffer, byte_offset, length);
3106+
CREATE_TYPED_ARRAY(
3107+
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
30793108
break;
30803109
case napi_int32_array:
3081-
typedArray = v8::Int32Array::New(buffer, byte_offset, length);
3110+
CREATE_TYPED_ARRAY(
3111+
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
30823112
break;
30833113
case napi_uint32_array:
3084-
typedArray = v8::Uint32Array::New(buffer, byte_offset, length);
3114+
CREATE_TYPED_ARRAY(
3115+
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
30853116
break;
30863117
case napi_float32_array:
3087-
typedArray = v8::Float32Array::New(buffer, byte_offset, length);
3118+
CREATE_TYPED_ARRAY(
3119+
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
30883120
break;
30893121
case napi_float64_array:
3090-
typedArray = v8::Float64Array::New(buffer, byte_offset, length);
3122+
CREATE_TYPED_ARRAY(
3123+
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
30913124
break;
30923125
default:
30933126
return napi_set_last_error(env, napi_invalid_arg);

test/addons-napi/test_typedarray/test.js

+18
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,21 @@ arrayTypes.forEach((currentType) => {
5555
assert.notStrictEqual(theArray, template);
5656
assert.strictEqual(theArray.buffer, buffer);
5757
});
58+
59+
arrayTypes.forEach((currentType) => {
60+
const template = Reflect.construct(currentType, buffer);
61+
assert.throws(() => {
62+
test_typedarray.CreateTypedArray(template, buffer, 0, 136);
63+
}, /Invalid typed array length/);
64+
});
65+
66+
const nonByteArrayTypes = [ Int16Array, Uint16Array, Int32Array, Uint32Array,
67+
Float32Array, Float64Array ];
68+
nonByteArrayTypes.forEach((currentType) => {
69+
const template = Reflect.construct(currentType, buffer);
70+
assert.throws(() => {
71+
test_typedarray.CreateTypedArray(template, buffer,
72+
currentType.BYTES_PER_ELEMENT + 1, 1);
73+
console.log(`start of offset ${currentType}`);
74+
}, /start offset of/);
75+
});

test/addons-napi/test_typedarray/test_typedarray.c

+25-3
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ napi_value External(napi_env env, napi_callback_info info) {
9797
}
9898

9999
napi_value CreateTypedArray(napi_env env, napi_callback_info info) {
100-
size_t argc = 2;
101-
napi_value args[2];
100+
size_t argc = 4;
101+
napi_value args[4];
102102
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
103103

104-
NAPI_ASSERT(env, argc == 2, "Wrong number of arguments");
104+
NAPI_ASSERT(env, argc == 2 || argc == 4, "Wrong number of arguments");
105105

106106
napi_value input_array = args[0];
107107
napi_valuetype valuetype0;
@@ -136,6 +136,28 @@ napi_value CreateTypedArray(napi_env env, napi_callback_info info) {
136136
NAPI_CALL(env, napi_get_typedarray_info(
137137
env, input_array, &type, &length, NULL, &in_array_buffer, &byte_offset));
138138

139+
if (argc == 4) {
140+
napi_valuetype valuetype2;
141+
NAPI_CALL(env, napi_typeof(env, args[2], &valuetype2));
142+
143+
NAPI_ASSERT(env, valuetype2 == napi_number,
144+
"Wrong type of arguments. Expects a number as third argument.");
145+
146+
uint32_t uint32_length;
147+
NAPI_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
148+
length = uint32_length;
149+
150+
napi_valuetype valuetype3;
151+
NAPI_CALL(env, napi_typeof(env, args[3], &valuetype3));
152+
153+
NAPI_ASSERT(env, valuetype3 == napi_number,
154+
"Wrong type of arguments. Expects a number as third argument.");
155+
156+
uint32_t uint32_byte_offset;
157+
NAPI_CALL(env, napi_get_value_uint32(env, args[3], &uint32_byte_offset));
158+
byte_offset = uint32_byte_offset;
159+
}
160+
139161
napi_value output_array;
140162
NAPI_CALL(env, napi_create_typedarray(
141163
env, type, length, input_buffer, byte_offset, &output_array));

0 commit comments

Comments
 (0)