[njs] Added support for detached-buffers.

Dmitry Volyntsev xeioex at nginx.com
Mon Sep 21 12:11:19 UTC 2020


details:   https://hg.nginx.org/njs/rev/f7f7994b69b5
branches:  
changeset: 1525:f7f7994b69b5
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Fri Sep 18 18:00:32 2020 +0000
description:
Added support for detached-buffers.

diffstat:

 auto/cc                  |    4 +
 auto/help                |    6 +-
 auto/options             |    4 +-
 src/njs_array_buffer.c   |    4 +
 src/njs_buffer.c         |   90 ++++++++++++++++---
 src/njs_builtin.c        |   69 +++++++++++++++
 src/njs_object_hash.h    |    8 +
 src/njs_typed_array.c    |  209 ++++++++++++++++++++++++++++++++++++++--------
 src/njs_value.c          |   10 ++
 src/njs_value.h          |    4 +
 src/njs_vm.h             |    5 +-
 src/test/njs_unit_test.c |    4 +
 12 files changed, 360 insertions(+), 57 deletions(-)

diffs (905 lines):

diff -r 0cfc928cc1e4 -r f7f7994b69b5 auto/cc
--- a/auto/cc	Thu Sep 17 13:10:51 2020 +0300
+++ b/auto/cc	Fri Sep 18 18:00:32 2020 +0000
@@ -177,5 +177,9 @@ if [ "$NJS_DEBUG_MEMORY" = "YES" ]; then
         njs_define=NJS_DEBUG_MEMORY . auto/define
 fi
 
+if [ "$NJS_TEST262" = "YES" ]; then
+        njs_define=NJS_TEST262 . auto/define
+fi
+
 # Stop on error exit status again.
 set -e
diff -r 0cfc928cc1e4 -r f7f7994b69b5 auto/help
--- a/auto/help	Thu Sep 17 13:10:51 2020 +0300
+++ b/auto/help	Fri Sep 18 18:00:32 2020 +0000
@@ -14,10 +14,12 @@ default: "$NJS_CC_OPT"
 default: "$NJS_LD_OPT"
   --ar=FILE                 set static linking program, default: "$AR"
 
+  --address-sanitizer=YES   enables build with address sanitizer, \
+default: "$NJS_ADDRESS_SANITIZER"
   --debug=YES               enables additional runtime checks, \
 default: "$NJS_DEBUG"
   --debug-memory=YES        enables memory alloc debug, \
 default: "$NJS_DEBUG_MEMORY"
-  --address-sanitizer=YES   enables build with address sanitizer, \
-default: "$NJS_ADDRESS_SANITIZER"
+  --test262=YES             enables test262 extentions, \
+default: "$NJS_TEST262"
 END
diff -r 0cfc928cc1e4 -r f7f7994b69b5 auto/options
--- a/auto/options	Thu Sep 17 13:10:51 2020 +0300
+++ b/auto/options	Fri Sep 18 18:00:32 2020 +0000
@@ -9,6 +9,7 @@ NJS_LD_OPT=${NJS_CC_OPT:--O}
 NJS_DEBUG=NO
 NJS_DEBUG_MEMORY=NO
 NJS_ADDRESS_SANITIZER=NO
+NJS_TEST262=YES
 
 NJS_CONFIGURE_OPTIONS=
 
@@ -25,9 +26,10 @@ do
         --ld-opt=*)                      NJS_LD_OPT="$value"                 ;;
         --ar=*)                          AR="$value"                         ;;
 
+        --address-sanitizer=*)           NJS_ADDRESS_SANITIZER="$value"      ;;
         --debug=*)                       NJS_DEBUG="$value"                  ;;
         --debug-memory=*)                NJS_DEBUG_MEMORY="$value"           ;;
-        --address-sanitizer=*)           NJS_ADDRESS_SANITIZER="$value"      ;;
+        --test262=*)                     NJS_TEST262="$value"                ;;
 
         --help)
             . auto/help
diff -r 0cfc928cc1e4 -r f7f7994b69b5 src/njs_array_buffer.c
--- a/src/njs_array_buffer.c	Thu Sep 17 13:10:51 2020 +0300
+++ b/src/njs_array_buffer.c	Fri Sep 18 18:00:32 2020 +0000
@@ -204,6 +204,10 @@ njs_array_buffer_prototype_byte_length(n
     }
 
     array = njs_array_buffer(value);
+    if (njs_slow_path(njs_is_detached_buffer(array))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
 
     njs_set_number(&vm->retval, array->size);
 
diff -r 0cfc928cc1e4 -r f7f7994b69b5 src/njs_buffer.c
--- a/src/njs_buffer.c	Thu Sep 17 13:10:51 2020 +0300
+++ b/src/njs_buffer.c	Fri Sep 18 18:00:32 2020 +0000
@@ -441,6 +441,11 @@ njs_buffer_from_typed_array(njs_vm_t *vm
     njs_typed_array_t  *buffer, *array;
 
     array = njs_typed_array(value);
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     length = njs_typed_array_length(array);
 
     buffer = njs_buffer_alloc_array(vm, length, 0);
@@ -597,9 +602,9 @@ njs_buffer_array_range(njs_vm_t *vm, njs
     const njs_value_t *start, const njs_value_t *end, const char *name,
     uint8_t **out_start, uint8_t **out_end)
 {
-    uint8_t    *u8;
-    uint64_t   num_start, num_end;
-    njs_int_t  ret;
+    uint64_t            num_start, num_end;
+    njs_int_t           ret;
+    njs_array_buffer_t  *buffer;
 
     num_start = 0;
 
@@ -633,9 +638,14 @@ njs_buffer_array_range(njs_vm_t *vm, njs
         num_end = num_start;
     }
 
-    u8 = njs_typed_array_buffer(array)->u.u8;
-    *out_start = &u8[array->offset + num_start];
-    *out_end = &u8[array->offset + num_end];
+    buffer = njs_typed_array_buffer(array);
+    if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
+    *out_start = &buffer->u.u8[array->offset + num_start];
+    *out_end = &buffer->u.u8[array->offset + num_end];
 
     return NJS_OK;
 }
@@ -746,6 +756,10 @@ njs_buffer_concat(njs_vm_t *vm, njs_valu
             }
 
             arr = njs_typed_array(value);
+            if (njs_slow_path(njs_is_detached_buffer(arr->buffer))) {
+                njs_type_error(vm, "detached buffer");
+                return NJS_ERROR;
+            }
 
             if (njs_slow_path((SIZE_MAX - len) < arr->byte_length)) {
                 njs_type_error(vm, "Invalid length");
@@ -770,6 +784,10 @@ njs_buffer_concat(njs_vm_t *vm, njs_valu
             }
 
             arr = njs_typed_array(&retval);
+            if (njs_slow_path(njs_is_detached_buffer(arr->buffer))) {
+                njs_type_error(vm, "detached buffer");
+                return NJS_ERROR;
+            }
 
             if (njs_slow_path((SIZE_MAX - len) < arr->byte_length)) {
                 njs_type_error(vm, "Invalid length");
@@ -947,6 +965,11 @@ njs_buffer_prototype_read_int(njs_vm_t *
 #endif
 
     buffer = array->buffer;
+    if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     u8 = &buffer->u.u8[index + array->offset];
 
     switch (size) {
@@ -1127,6 +1150,11 @@ njs_buffer_prototype_read_float(njs_vm_t
 #endif
 
     buffer = array->buffer;
+    if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     u8 = &buffer->u.u8[index + array->offset];
 
     switch (size) {
@@ -1657,6 +1685,11 @@ njs_buffer_fill(njs_vm_t *vm, njs_typed_
             return ret;
         }
 
+        if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+            njs_type_error(vm, "detached buffer");
+            return NJS_ERROR;
+        }
+
         memset(start, njs_number_to_uint32(num) & 0xff, end - offset);
     }
 
@@ -1783,6 +1816,11 @@ njs_buffer_prototype_to_string(njs_vm_t 
         end = njs_min(end, array->byte_length);
     }
 
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     str.start = &njs_typed_array_buffer(array)->u.u8[array->offset + start];
     str.length = end - start;
 
@@ -1890,12 +1928,14 @@ static njs_int_t
 njs_buffer_prototype_index_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t last)
 {
-    uint8_t                      *u8, byte;
+    uint8_t                      byte;
     int64_t                      from, to, increment, length, offset, index, i;
     njs_int_t                    ret;
     njs_str_t                    str;
     njs_value_t                  *this, *value, *value_from, *enc, dst;
+    const uint8_t                *u8;
     njs_typed_array_t            *array, *src;
+    njs_array_buffer_t           *buffer;
     const njs_buffer_encoding_t  *encoding;
 
     encoding = njs_buffer_utf8_encoding();
@@ -1977,7 +2017,13 @@ njs_buffer_prototype_index_of(njs_vm_t *
         }
     }
 
-    u8 = &njs_typed_array_buffer(array)->u.u8[0];
+    buffer = njs_typed_array_buffer(array);
+    if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
+    u8 = &buffer->u.u8[0];
     offset = array->offset;
 
     switch (value->type) {
@@ -1997,6 +2043,11 @@ njs_buffer_prototype_index_of(njs_vm_t *
                 goto fail;
             }
 
+            if (njs_slow_path(njs_is_detached_buffer(src->buffer))) {
+                njs_type_error(vm, "detached buffer");
+                return NJS_ERROR;
+            }
+
             str.start = &src->buffer->u.u8[src->offset];
             str.length = src->byte_length;
         }
@@ -2152,13 +2203,14 @@ static njs_int_t
 njs_buffer_prototype_to_json(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    u_char             *p, *end;
-    njs_int_t          ret;
-    njs_value_t        *value;
-    njs_value_t        object, array;
-    njs_array_t        *arr;
-    njs_object_t       *obj;
-    njs_typed_array_t  *ta;
+    u_char              *p, *end;
+    njs_int_t           ret;
+    njs_value_t         *value;
+    njs_value_t         object, array;
+    njs_array_t         *arr;
+    njs_object_t        *obj;
+    njs_typed_array_t   *ta;
+    njs_array_buffer_t  *buffer;
 
     static const njs_value_t  string_buffer = njs_string("Buffer");
 
@@ -2185,7 +2237,13 @@ njs_buffer_prototype_to_json(njs_vm_t *v
         return NJS_ERROR;
     }
 
-    p = &njs_typed_array_buffer(ta)->u.u8[ta->offset];
+    buffer = njs_typed_array_buffer(ta);
+    if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
+    p = &buffer->u.u8[ta->offset];
     end = p + ta->byte_length;
     value = arr->start;
 
diff -r 0cfc928cc1e4 -r f7f7994b69b5 src/njs_builtin.c
--- a/src/njs_builtin.c	Thu Sep 17 13:10:51 2020 +0300
+++ b/src/njs_builtin.c	Fri Sep 18 18:00:32 2020 +0000
@@ -35,6 +35,9 @@ static njs_int_t njs_env_hash_init(njs_v
 static const njs_object_init_t  njs_global_this_init;
 static const njs_object_init_t  njs_njs_object_init;
 static const njs_object_init_t  njs_process_object_init;
+#ifdef NJS_TEST262
+static const njs_object_init_t  njs_262_object_init;
+#endif
 
 
 static const njs_object_init_t  *njs_object_init[] = {
@@ -43,6 +46,9 @@ static const njs_object_init_t  *njs_obj
     &njs_process_object_init,
     &njs_math_object_init,
     &njs_json_object_init,
+#ifdef NJS_TEST262
+    &njs_262_object_init,
+#endif
     NULL
 };
 
@@ -1259,6 +1265,18 @@ static const njs_object_prop_t  njs_glob
         .configurable = 1,
     },
 
+#ifdef NJS_TEST262
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("$262"),
+        .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_262,
+                                  NJS_262_HASH),
+        .writable = 1,
+        .enumerable = 1,
+        .configurable = 1,
+    },
+#endif
+
     /* Global constructors. */
 
     {
@@ -1831,3 +1849,54 @@ static const njs_object_init_t  njs_proc
     njs_process_object_properties,
     njs_nitems(njs_process_object_properties),
 };
+
+
+#if (NJS_TEST262)
+
+static njs_int_t
+njs_262_detach_array_buffer(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    njs_value_t         *value;
+    njs_array_buffer_t  *buffer;
+
+    value = njs_arg(args, nargs, 1);
+    if (njs_slow_path(!njs_is_array_buffer(value))) {
+        njs_type_error(vm, "\"this\" is not an ArrayBuffer");
+        return NJS_ERROR;
+    }
+
+    buffer = njs_array_buffer(value);
+    buffer->u.data = NULL;
+    buffer->size = 0;
+
+    njs_set_null(&vm->retval);
+
+    return NJS_OK;
+}
+
+static const njs_object_prop_t  njs_262_object_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG),
+        .value = njs_string("$262"),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_long_string("detachArrayBuffer"),
+        .value = njs_native_function(njs_262_detach_array_buffer, 2),
+        .writable = 1,
+        .configurable = 1,
+    },
+};
+
+
+static const njs_object_init_t  njs_262_object_init = {
+    njs_262_object_properties,
+    njs_nitems(njs_262_object_properties),
+};
+
+#endif
diff -r 0cfc928cc1e4 -r f7f7994b69b5 src/njs_object_hash.h
--- a/src/njs_object_hash.h	Thu Sep 17 13:10:51 2020 +0300
+++ b/src/njs_object_hash.h	Fri Sep 18 18:00:32 2020 +0000
@@ -301,6 +301,14 @@
         'n'), 'j'), 's')
 
 
+#define NJS_262_HASH                                                          \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(NJS_DJB_HASH_INIT,                                       \
+        '$'), '2'), '6'), '2')
+
+
 #define NJS_NUMBER_HASH                                                       \
     njs_djb_hash_add(                                                         \
     njs_djb_hash_add(                                                         \
diff -r 0cfc928cc1e4 -r f7f7994b69b5 src/njs_typed_array.c
--- a/src/njs_typed_array.c	Thu Sep 17 13:10:51 2020 +0300
+++ b/src/njs_typed_array.c	Fri Sep 18 18:00:32 2020 +0000
@@ -64,7 +64,19 @@ njs_typed_array_alloc(njs_vm_t *vm, njs_
             return NULL;
         }
 
-        if (!njs_is_undefined(njs_arg(args, nargs, 2))) {
+        if (njs_is_defined(njs_arg(args, nargs, 2))) {
+            ret = njs_value_to_index(vm, njs_argument(args, 2), &size);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NULL;
+            }
+        }
+
+        if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+            njs_type_error(vm, "detached buffer");
+            return NULL;
+        }
+
+        if (njs_is_defined(njs_arg(args, nargs, 2))) {
             ret = njs_value_to_index(vm, njs_argument(args, 2), &size);
             if (njs_slow_path(ret != NJS_OK)) {
                 return NULL;
@@ -95,6 +107,11 @@ njs_typed_array_alloc(njs_vm_t *vm, njs_
 
     } else if (njs_is_typed_array(value)) {
         src_tarray = njs_typed_array(value);
+        if (njs_slow_path(njs_is_detached_buffer(src_tarray->buffer))) {
+            njs_type_error(vm, "detached buffer");
+            return NULL;
+        }
+
         size = (uint64_t) njs_typed_array_length(src_tarray) * element_size;
 
     } else if (njs_is_object(value)) {
@@ -224,9 +241,10 @@ static njs_int_t
 njs_typed_array_create(njs_vm_t *vm, njs_value_t *constructor,
     njs_value_t *args, njs_uint_t nargs, njs_value_t *retval)
 {
-    njs_int_t     ret;
-    njs_value_t   this;
-    njs_object_t  *object;
+    njs_int_t          ret;
+    njs_value_t        this;
+    njs_object_t       *object;
+    njs_typed_array_t  *array;
 
     object = njs_function_new_object(vm, constructor);
     if (njs_slow_path(object == NULL)) {
@@ -247,8 +265,14 @@ njs_typed_array_create(njs_vm_t *vm, njs
         return NJS_ERROR;
     }
 
+    array = njs_typed_array(retval);
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     if (njs_slow_path(nargs == 1 && njs_is_number(&args[0])
-                      && njs_typed_array_length(njs_typed_array(retval))
+                      && njs_typed_array_length(array)
                          < njs_number(&args[0])))
     {
         njs_type_error(vm, "Derived TypedArray constructor "
@@ -425,6 +449,10 @@ njs_typed_array_writable(njs_vm_t *vm, n
     njs_array_buffer_t  *buffer;
 
     buffer = array->buffer;
+    if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NULL;
+    }
 
     ret = njs_array_buffer_writable(vm, buffer);
     if (njs_slow_path(ret != NJS_OK)) {
@@ -485,6 +513,7 @@ static njs_int_t
 njs_typed_array_prototype_length(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused)
 {
+    uint32_t           length;
     njs_value_t        *this;
     njs_typed_array_t  *array;
 
@@ -496,8 +525,13 @@ njs_typed_array_prototype_length(njs_vm_
     }
 
     array = njs_typed_array(this);
-
-    njs_set_number(&vm->retval, njs_typed_array_length(array));
+    length = njs_typed_array_length(array);
+
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        length = 0;
+    }
+
+    njs_set_number(&vm->retval, length);
 
     return NJS_OK;
 }
@@ -529,6 +563,7 @@ static njs_int_t
 njs_typed_array_prototype_byte_length(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused)
 {
+    size_t             byte_length;
     njs_value_t        *this;
     njs_typed_array_t  *array;
 
@@ -540,8 +575,18 @@ njs_typed_array_prototype_byte_length(nj
     }
 
     array = njs_typed_array(this);
-
-    njs_set_number(&vm->retval, array->byte_length);
+    byte_length = array->byte_length;
+
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        if (njs_is_data_view(this)) {
+            njs_type_error(vm, "detached buffer");
+            return NJS_ERROR;
+        }
+
+        byte_length = 0;
+    }
+
+    njs_set_number(&vm->retval, byte_length);
 
     return NJS_OK;
 }
@@ -551,6 +596,7 @@ static njs_int_t
 njs_typed_array_prototype_byte_offset(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused)
 {
+    size_t             byte_offset;
     njs_value_t        *this;
     njs_typed_array_t  *array;
 
@@ -562,8 +608,18 @@ njs_typed_array_prototype_byte_offset(nj
     }
 
     array = njs_typed_array(this);
-
-    njs_set_number(&vm->retval, njs_typed_array_offset(array));
+    byte_offset = njs_typed_array_offset(array);
+
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        if (njs_is_data_view(this)) {
+            njs_type_error(vm, "detached buffer");
+            return NJS_ERROR;
+        }
+
+        byte_offset = 0;
+    }
+
+    njs_set_number(&vm->retval, byte_offset);
 
     return NJS_OK;
 }
@@ -693,6 +749,11 @@ njs_typed_array_prototype_set(njs_vm_t *
 
     if (njs_is_typed_array(src)) {
         src_tarray = njs_typed_array(src);
+        if (njs_slow_path(njs_is_detached_buffer(src_tarray->buffer))) {
+            njs_type_error(vm, "detached buffer");
+            return NJS_ERROR;
+        }
+
         src_length = njs_typed_array_length(src_tarray);
 
         if (njs_slow_path((src_length > length)
@@ -767,6 +828,11 @@ njs_typed_array_prototype_set(njs_vm_t *
                 }
             }
 
+            if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+                njs_type_error(vm, "detached buffer");
+                return NJS_ERROR;
+            }
+
             njs_typed_array_prop_set(vm, self, offset + i, num);
         }
     }
@@ -803,6 +869,11 @@ njs_typed_array_prototype_fill(njs_vm_t 
     }
 
     array = njs_typed_array(this);
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     length = njs_typed_array_length(array);
 
     setval = njs_lvalue_arg(&lvalue, args, nargs, 1);
@@ -929,6 +1000,10 @@ njs_typed_array_prototype_slice(njs_vm_t
     array = njs_typed_array(this);
     length = njs_typed_array_length(array);
     buffer = njs_typed_array_buffer(array);
+    if (njs_slow_path(copy && njs_is_detached_buffer(buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
 
     ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &start);
     if (njs_slow_path(ret != NJS_OK)) {
@@ -966,13 +1041,16 @@ njs_typed_array_prototype_slice(njs_vm_t
             return ret;
         }
 
-        new_array = njs_typed_array(&vm->retval);
-        if (njs_typed_array_length(new_array) < count) {
-            njs_type_error(vm, "Derived TypedArray constructor is "
-                           "too small array");
+        if (count == 0) {
+            return NJS_OK;
+        }
+
+        if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+            njs_type_error(vm, "detached buffer");
             return NJS_ERROR;
         }
 
+        new_array = njs_typed_array(&vm->retval);
         new_buffer = njs_typed_array_buffer(new_array);
         element_size = njs_typed_array_element_size(array->type);
 
@@ -1022,6 +1100,11 @@ njs_typed_array_prototype_copy_within(nj
     }
 
     array = njs_typed_array(this);
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     length = njs_typed_array_length(array);
 
     value = njs_arg(args, nargs, 1);
@@ -1044,10 +1127,9 @@ njs_typed_array_prototype_copy_within(nj
 
     value = njs_arg(args, nargs, 3);
 
-    if (njs_is_undefined(value)) {
-        final = length;
-
-    } else {
+    final = length;
+
+    if (njs_is_defined(value)) {
         ret = njs_value_to_integer(vm, value, &final);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
@@ -1085,14 +1167,15 @@ static njs_int_t
 njs_typed_array_prototype_iterator(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t type)
 {
-    double             val;
-    int64_t            i, length;
-    njs_int_t          ret;
-    njs_arr_t          results;
-    njs_value_t        *this, *this_arg, *r;
-    njs_value_t        arguments[4], retval;
-    njs_function_t     *function;
-    njs_typed_array_t  *array, *dst;
+    double              val;
+    int64_t             i, length;
+    njs_int_t           ret;
+    njs_arr_t           results;
+    njs_value_t         *this, *this_arg, *r;
+    njs_value_t         arguments[4], retval;
+    njs_function_t      *function;
+    njs_typed_array_t   *array, *dst;
+    njs_array_buffer_t  *buffer;
 
     this = njs_argument(args, 0);
     if (njs_slow_path(!njs_is_typed_array(this))) {
@@ -1112,6 +1195,7 @@ njs_typed_array_prototype_iterator(njs_v
     function = njs_function(njs_argument(args, 1));
     this_arg = njs_arg(args, nargs, 2);
 
+    buffer = array->buffer;
     results.separate = 0;
     results.pointer = 0;
 
@@ -1136,6 +1220,11 @@ njs_typed_array_prototype_iterator(njs_v
     }
 
     for (i = 0; i < length; i++) {
+        if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+            njs_type_error(vm, "detached buffer");
+            return NJS_ERROR;
+        }
+
         val = njs_typed_array_prop(array, i);
 
         arguments[0] = *this_arg;
@@ -1349,6 +1438,11 @@ njs_typed_array_prototype_index_of(njs_v
         }
     }
 
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     v = njs_number(njs_argument(args, 1));
 
     i64 = v;
@@ -1491,12 +1585,13 @@ static njs_int_t
 njs_typed_array_prototype_reduce(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t right)
 {
-    int64_t            i, from, to, increment, length;
-    njs_int_t          ret;
-    njs_value_t        *this, accumulator;
-    njs_value_t        arguments[5];
-    njs_function_t     *function;
-    njs_typed_array_t  *array;
+    int64_t             i, from, to, increment, length;
+    njs_int_t           ret;
+    njs_value_t         *this, accumulator;
+    njs_value_t         arguments[5];
+    njs_function_t      *function;
+    njs_typed_array_t   *array;
+    njs_array_buffer_t  *buffer;
 
     this = njs_argument(args, 0);
     if (njs_slow_path(!njs_is_typed_array(this))) {
@@ -1530,15 +1625,27 @@ njs_typed_array_prototype_reduce(njs_vm_
         increment = 1;
     }
 
+    buffer = array->buffer;
+
     if (nargs > 2) {
         accumulator = *njs_argument(args, 2);
 
     } else {
+        if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+            njs_type_error(vm, "detached buffer");
+            return NJS_ERROR;
+        }
+
         njs_set_number(&accumulator, njs_typed_array_prop(array, from));
         from += increment;
     }
 
     for (i = from; i != to; i += increment) {
+        if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+            njs_type_error(vm, "detached buffer");
+            return NJS_ERROR;
+        }
+
         njs_set_undefined(&arguments[0]);
         arguments[1] = accumulator;
         njs_set_number(&arguments[2], njs_typed_array_prop(array, i));
@@ -1785,6 +1892,7 @@ njs_typed_array_get_f64(const void *a)
 
 typedef struct {
     njs_vm_t               *vm;
+    njs_array_buffer_t     *buffer;
     njs_function_t         *function;
     njs_bool_t             exception;
     double                 (*get)(const void *v);
@@ -1821,6 +1929,11 @@ njs_typed_array_generic_compare(const vo
         goto exception;
     }
 
+    if (njs_slow_path(njs_is_detached_buffer(ctx->buffer))) {
+        njs_type_error(ctx->vm, "detached buffer");
+        goto exception;
+    }
+
     if (njs_slow_path(isnan(num))) {
         return 0;
     }
@@ -1858,7 +1971,14 @@ njs_typed_array_prototype_sort(njs_vm_t 
         return NJS_ERROR;
     }
 
+    array = njs_typed_array(this);
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     ctx.vm = vm;
+    ctx.buffer = array->buffer;
     ctx.exception = 0;
 
     comparefn = njs_arg(args, nargs, 1);
@@ -1875,8 +1995,6 @@ njs_typed_array_prototype_sort(njs_vm_t 
         ctx.function = NULL;
     }
 
-    array = njs_typed_array(this);
-
     switch (array->type) {
     case NJS_OBJ_TYPE_UINT8_ARRAY:
     case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY:
@@ -2022,6 +2140,11 @@ njs_typed_array_prototype_join(njs_vm_t 
     }
 
     array = njs_typed_array(this);
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     arr_length = njs_typed_array_length(array);
 
     separator = njs_arg(args, nargs, 1);
@@ -2406,13 +2529,17 @@ njs_data_view_constructor(njs_vm_t *vm, 
     size = 0;
     offset = 0;
 
-    buffer = njs_array_buffer(njs_argument(args, 1));
-
     ret = njs_value_to_index(vm, njs_arg(args, nargs, 2), &offset);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
+    buffer = njs_array_buffer(njs_argument(args, 1));
+    if (njs_slow_path(njs_is_detached_buffer(buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     if (!njs_is_undefined(njs_arg(args, nargs, 3))) {
         ret = njs_value_to_index(vm, njs_argument(args, 3), &size);
         if (njs_slow_path(ret != NJS_OK)) {
@@ -2526,6 +2653,10 @@ njs_data_view_prototype_get(njs_vm_t *vm
 #endif
 
     view = njs_data_view(this);
+    if (njs_slow_path(njs_is_detached_buffer(view->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
 
     if (njs_typed_array_element_size(type) + index > view->byte_length) {
         njs_range_error(vm, "index %uL is outside the bound of the buffer",
@@ -2647,6 +2778,10 @@ njs_data_view_prototype_set(njs_vm_t *vm
 #endif
 
     view = njs_data_view(this);
+    if (njs_slow_path(njs_is_detached_buffer(view->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
 
     if (njs_typed_array_element_size(type) + index > view->byte_length) {
         njs_range_error(vm, "index %uL is outside the bound of the buffer",
diff -r 0cfc928cc1e4 -r f7f7994b69b5 src/njs_value.c
--- a/src/njs_value.c	Thu Sep 17 13:10:51 2020 +0300
+++ b/src/njs_value.c	Fri Sep 18 18:00:32 2020 +0000
@@ -807,6 +807,11 @@ njs_typed_array_property_query(njs_vm_t 
 {
     njs_object_prop_t  *prop;
 
+    if (njs_slow_path(njs_is_detached_buffer(array->buffer))) {
+        njs_type_error(vm, "detached buffer");
+        return NJS_ERROR;
+    }
+
     if (index >= njs_typed_array_length(array)) {
         return NJS_DECLINED;
     }
@@ -959,6 +964,11 @@ njs_value_property(njs_vm_t *vm, njs_val
         if (njs_is_typed_array(value)) {
             tarray = njs_typed_array(value);
 
+            if (njs_slow_path(njs_is_detached_buffer(tarray->buffer))) {
+                njs_type_error(vm, "detached buffer");
+                return NJS_ERROR;
+            }
+
             if (njs_slow_path(index >= njs_typed_array_length(tarray))) {
                 goto slow_path;
             }
diff -r 0cfc928cc1e4 -r f7f7994b69b5 src/njs_value.h
--- a/src/njs_value.h	Thu Sep 17 13:10:51 2020 +0300
+++ b/src/njs_value.h	Fri Sep 18 18:00:32 2020 +0000
@@ -659,6 +659,10 @@ typedef struct {
     ((value)->type == NJS_TYPED_ARRAY)
 
 
+#define njs_is_detached_buffer(buffer)                                        \
+    ((buffer)->u.data == NULL)
+
+
 #define njs_is_data_view(value)                                               \
     ((value)->type == NJS_DATA_VIEW)
 
diff -r 0cfc928cc1e4 -r f7f7994b69b5 src/njs_vm.h
--- a/src/njs_vm.h	Thu Sep 17 13:10:51 2020 +0300
+++ b/src/njs_vm.h	Fri Sep 18 18:00:32 2020 +0000
@@ -140,7 +140,10 @@ enum njs_object_e {
     NJS_OBJECT_PROCESS,
     NJS_OBJECT_MATH,
     NJS_OBJECT_JSON,
-#define NJS_OBJECT_MAX         (NJS_OBJECT_JSON + 1)
+#ifdef NJS_TEST262
+    NJS_OBJECT_262,
+#endif
+    NJS_OBJECT_MAX
 };
 
 
diff -r 0cfc928cc1e4 -r f7f7994b69b5 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Thu Sep 17 13:10:51 2020 +0300
+++ b/src/test/njs_unit_test.c	Fri Sep 18 18:00:32 2020 +0000
@@ -19578,7 +19578,11 @@ static njs_unit_test_t  njs_externals_te
       njs_str("true") },
 
     { njs_str("Object.keys(this).sort()"),
+#if (NJS_TEST262)
+      njs_str("$262,$r,$r2,$r3,$shared,global,njs,process") },
+#else
       njs_str("$r,$r2,$r3,$shared,global,njs,process") },
+#endif
 
     { njs_str("Object.getOwnPropertySymbols($r2)[0] == Symbol.toStringTag"),
       njs_str("true") },


More information about the nginx-devel mailing list