diff --git a/doc/api/errors.md b/doc/api/errors.md
index 84a21b581d1cc0..134f52265e0f6d 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1271,6 +1271,18 @@ While using `N-API`, `Constructor.prototype` was not an object.
While calling `napi_create_dataview()`, a given `offset` was outside the bounds
of the dataview or `offset + length` was larger than a length of given `buffer`.
+
+### ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT
+
+While calling `napi_create_typedarray()`, the provided `offset` was not a
+multiple of the element size.
+
+
+### ERR_NAPI_INVALID_TYPEDARRAY_LENGTH
+
+While calling `napi_create_typedarray()`, `(length * size_of_element) +
+byte_offset` was larger than the length of given `buffer`.
+
### ERR_NO_CRYPTO
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index 2e959acea4ab05..70569fd8439611 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -319,6 +319,9 @@ E('ERR_NAPI_CONS_PROTOTYPE_OBJECT', 'Constructor.prototype must be an object');
E('ERR_NAPI_INVALID_DATAVIEW_ARGS',
'byte_offset + byte_length should be less than or eqaul to the size in ' +
'bytes of the array passed in');
+E('ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT', 'start offset of %s should be a ' +
+ 'multiple of %s');
+E('ERR_NAPI_INVALID_TYPEDARRAY_LENGTH', 'Invalid typed array length');
E('ERR_NO_CRYPTO', 'Node.js is not compiled with OpenSSL crypto support');
E('ERR_NO_ICU', '%s is not supported on Node.js compiled without ICU');
E('ERR_NO_LONGER_SUPPORTED', '%s is no longer supported');
diff --git a/src/node_api.cc b/src/node_api.cc
index 2101fcba020d95..27ab6707de7a6f 100644
--- a/src/node_api.cc
+++ b/src/node_api.cc
@@ -142,6 +142,30 @@ struct napi_env__ {
(!try_catch.HasCaught() ? napi_ok \
: napi_set_last_error((env), napi_pending_exception))
+#define THROW_RANGE_ERROR_IF_FALSE(env, condition, error, message) \
+ do { \
+ if (!(condition)) { \
+ napi_throw_range_error((env), (error), (message)); \
+ return napi_set_last_error((env), napi_generic_failure); \
+ } \
+ } while (0)
+
+#define CREATE_TYPED_ARRAY( \
+ env, type, size_of_element, buffer, byte_offset, length, out) \
+ do { \
+ if ((size_of_element) > 1) { \
+ THROW_RANGE_ERROR_IF_FALSE( \
+ (env), (byte_offset) % (size_of_element) == 0, \
+ "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT", \
+ "start offset of "#type" should be a multiple of "#size_of_element); \
+ } \
+ THROW_RANGE_ERROR_IF_FALSE((env), (length) * (size_of_element) + \
+ (byte_offset) <= buffer->ByteLength(), \
+ "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH", \
+ "Invalid typed array length"); \
+ (out) = v8::type::New((buffer), (byte_offset), (length)); \
+ } while (0)
+
namespace {
namespace v8impl {
@@ -3063,31 +3087,40 @@ napi_status napi_create_typedarray(napi_env env,
switch (type) {
case napi_int8_array:
- typedArray = v8::Int8Array::New(buffer, byte_offset, length);
+ CREATE_TYPED_ARRAY(
+ env, Int8Array, 1, buffer, byte_offset, length, typedArray);
break;
case napi_uint8_array:
- typedArray = v8::Uint8Array::New(buffer, byte_offset, length);
+ CREATE_TYPED_ARRAY(
+ env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
break;
case napi_uint8_clamped_array:
- typedArray = v8::Uint8ClampedArray::New(buffer, byte_offset, length);
+ CREATE_TYPED_ARRAY(
+ env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
break;
case napi_int16_array:
- typedArray = v8::Int16Array::New(buffer, byte_offset, length);
+ CREATE_TYPED_ARRAY(
+ env, Int16Array, 2, buffer, byte_offset, length, typedArray);
break;
case napi_uint16_array:
- typedArray = v8::Uint16Array::New(buffer, byte_offset, length);
+ CREATE_TYPED_ARRAY(
+ env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
break;
case napi_int32_array:
- typedArray = v8::Int32Array::New(buffer, byte_offset, length);
+ CREATE_TYPED_ARRAY(
+ env, Int32Array, 4, buffer, byte_offset, length, typedArray);
break;
case napi_uint32_array:
- typedArray = v8::Uint32Array::New(buffer, byte_offset, length);
+ CREATE_TYPED_ARRAY(
+ env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
break;
case napi_float32_array:
- typedArray = v8::Float32Array::New(buffer, byte_offset, length);
+ CREATE_TYPED_ARRAY(
+ env, Float32Array, 4, buffer, byte_offset, length, typedArray);
break;
case napi_float64_array:
- typedArray = v8::Float64Array::New(buffer, byte_offset, length);
+ CREATE_TYPED_ARRAY(
+ env, Float64Array, 8, buffer, byte_offset, length, typedArray);
break;
default:
return napi_set_last_error(env, napi_invalid_arg);
diff --git a/test/addons-napi/test_typedarray/test.js b/test/addons-napi/test_typedarray/test.js
index 27ef054fe4635e..4a4e79ebe7bcdb 100644
--- a/test/addons-napi/test_typedarray/test.js
+++ b/test/addons-napi/test_typedarray/test.js
@@ -55,3 +55,21 @@ arrayTypes.forEach((currentType) => {
assert.notStrictEqual(theArray, template);
assert.strictEqual(theArray.buffer, buffer);
});
+
+arrayTypes.forEach((currentType) => {
+ const template = Reflect.construct(currentType, buffer);
+ assert.throws(() => {
+ test_typedarray.CreateTypedArray(template, buffer, 0, 136);
+ }, /Invalid typed array length/);
+});
+
+const nonByteArrayTypes = [ Int16Array, Uint16Array, Int32Array, Uint32Array,
+ Float32Array, Float64Array ];
+nonByteArrayTypes.forEach((currentType) => {
+ const template = Reflect.construct(currentType, buffer);
+ assert.throws(() => {
+ test_typedarray.CreateTypedArray(template, buffer,
+ currentType.BYTES_PER_ELEMENT + 1, 1);
+ console.log(`start of offset ${currentType}`);
+ }, /start offset of/);
+});
diff --git a/test/addons-napi/test_typedarray/test_typedarray.c b/test/addons-napi/test_typedarray/test_typedarray.c
index 0325faedd09f8e..82c7a5bf361d30 100644
--- a/test/addons-napi/test_typedarray/test_typedarray.c
+++ b/test/addons-napi/test_typedarray/test_typedarray.c
@@ -97,11 +97,11 @@ napi_value External(napi_env env, napi_callback_info info) {
}
napi_value CreateTypedArray(napi_env env, napi_callback_info info) {
- size_t argc = 2;
- napi_value args[2];
+ size_t argc = 4;
+ napi_value args[4];
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
- NAPI_ASSERT(env, argc == 2, "Wrong number of arguments");
+ NAPI_ASSERT(env, argc == 2 || argc == 4, "Wrong number of arguments");
napi_value input_array = args[0];
napi_valuetype valuetype0;
@@ -136,6 +136,28 @@ napi_value CreateTypedArray(napi_env env, napi_callback_info info) {
NAPI_CALL(env, napi_get_typedarray_info(
env, input_array, &type, &length, NULL, &in_array_buffer, &byte_offset));
+ if (argc == 4) {
+ napi_valuetype valuetype2;
+ NAPI_CALL(env, napi_typeof(env, args[2], &valuetype2));
+
+ NAPI_ASSERT(env, valuetype2 == napi_number,
+ "Wrong type of arguments. Expects a number as third argument.");
+
+ uint32_t uint32_length;
+ NAPI_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
+ length = uint32_length;
+
+ napi_valuetype valuetype3;
+ NAPI_CALL(env, napi_typeof(env, args[3], &valuetype3));
+
+ NAPI_ASSERT(env, valuetype3 == napi_number,
+ "Wrong type of arguments. Expects a number as third argument.");
+
+ uint32_t uint32_byte_offset;
+ NAPI_CALL(env, napi_get_value_uint32(env, args[3], &uint32_byte_offset));
+ byte_offset = uint32_byte_offset;
+ }
+
napi_value output_array;
NAPI_CALL(env, napi_create_typedarray(
env, type, length, input_buffer, byte_offset, &output_array));