]> git.kaiwu.me - njs.git/commitdiff
Fix indexed fast paths for exotic objects
authorDmitry Volyntsev <xeioex@nginx.com>
Fri, 4 Sep 2026 01:47:58 +0000 (18:47 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Fri, 4 Sep 2026 21:53:08 +0000 (14:53 -0700)
Previously, Object.values() and Object.entries() erased the concrete type of
an exotic receiver, while indexed property fast paths accepted any object
with the fast_array bit.  Typed arrays could consequently be interpreted as
njs_array_t objects, causing invalid memory reads and writes.

The fix is to preserve the receiver type during enumeration and to use
njs_is_fast_array() for both indexed get and set fast paths.

The issue was introduced in 69072164 (0.8.6); the overbroad fast path dates
to 912ab387 (0.3.8).

This closes #1098 issue on GitHub.

src/njs_object.c
src/njs_value.c
src/test/njs_unit_test.c

index fbaf2208c6c5ac4f51fffa395f6ad6a6d3c0675b..65964070aa19d3e44f80b6e72ec2a0528900c5c4 100644 (file)
@@ -1140,7 +1140,7 @@ njs_object_own_enumerate_object(njs_vm_t *vm, const njs_object_t *object,
         }
 
         entry = NULL;
-        njs_set_object(&value, (njs_object_t *) object);
+        njs_set_type_object(&value, (njs_object_t *) object, object->type);
 
         for (i = 0; i< items_sorted->length; i++) {
             ret = njs_value_property_val(vm, &value, &items_sorted->start[i],
index 2a7f7fd574818ff49b280d8cbe79d18a23359542..7d77e341551f15ea4dc58e3b0cc585fda06c6c2d 100644 (file)
@@ -1075,9 +1075,7 @@ njs_value_property(njs_vm_t *vm, njs_value_t *value, uint32_t atom_id,
             return NJS_OK;
         }
 
-        if (njs_slow_path(!(njs_is_object(value)
-                            && njs_object(value)->fast_array)))
-        {
+        if (njs_slow_path(!njs_is_fast_array(value))) {
             goto slow_path;
         }
 
@@ -1194,9 +1192,7 @@ njs_value_property_set(njs_vm_t *vm, njs_value_t *value, uint32_t atom_id,
             return NJS_OK;
         }
 
-        if (njs_slow_path(!(njs_is_object(value)
-                            && njs_object(value)->fast_array)))
-        {
+        if (njs_slow_path(!njs_is_fast_array(value))) {
             goto slow_path;
         }
 
index baa4cd58d76ea13fd9586e0b4e46d4bcd0168ef5..8ce6c53f28b87ff7b2e89de75a19ab4a29331300 100644 (file)
@@ -6996,6 +6996,24 @@ static njs_unit_test_t  njs_test[] =
               "           try {a.set(init,Infinity)} catch (e) {return e.name == 'RangeError'};})"),
       njs_str("true") },
 
+    { njs_str("var a = new Uint8Array([1]);"
+              "Object.defineProperty(a, 'x', {enumerable: true,"
+              "  get() { return this === a && this[0]; }});"
+              "Object.values(a)"),
+      njs_str("1,1") },
+
+    { njs_str("var a = new Uint8Array([1]);"
+              "Object.defineProperty(a, 'x', {enumerable: true,"
+              "  get() { this[0] = 2; return this[0]; }});"
+              "Object.values(a); a[0]"),
+      njs_str("2") },
+
+    { njs_str("var a = Buffer.from([1]);"
+              "Object.defineProperty(a, 'x', {enumerable: true,"
+              "  get() { return this === a && this[0]; }});"
+              "Object.values(a)"),
+      njs_str("1,1") },
+
     { njs_str(NJS_INT_TYPED_ARRAY_LIST
               ".map(v=>{try { var a = new v(1); $262.detachArrayBuffer(a.buffer); Object.entries(a)} "
               "catch (e) {return e.name}}).every(v=>v === 'TypeError')"),