[njs] Fixed redefinition of special props in Object.defineProperty().

Dmitry Volyntsev xeioex at nginx.com
Thu May 19 23:50:26 UTC 2022


details:   https://hg.nginx.org/njs/rev/beb180165976
branches:  
changeset: 1860:beb180165976
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu May 19 16:41:08 2022 -0700
description:
Fixed redefinition of special props in Object.defineProperty().

Previously, when NJS_PROPERTY_HANDLER property was updated it might be
left in inconsistent state.  Namely, prop->type was left unchanged, but
prop->value did not have an expected property handler.  As a result
consecutive reference to the property may result in a segment violation.

The fix is to update the prop->type during redefinition.

This closes #504 issue on Github.

diffstat:

 src/njs_object.h         |   4 +++-
 src/njs_object_prop.c    |  11 ++++++++++-
 src/njs_value.c          |   1 +
 src/njs_value.h          |   2 ++
 src/test/njs_unit_test.c |   6 ++++++
 5 files changed, 22 insertions(+), 2 deletions(-)

diffs (88 lines):

diff -r aa27056f4bc9 -r beb180165976 src/njs_object.h
--- a/src/njs_object.h	Wed May 18 00:01:05 2022 -0700
+++ b/src/njs_object.h	Thu May 19 16:41:08 2022 -0700
@@ -88,7 +88,9 @@ njs_int_t njs_object_prop_init(njs_vm_t 
 njs_inline njs_bool_t
 njs_is_data_descriptor(njs_object_prop_t *prop)
 {
-    return prop->writable != NJS_ATTRIBUTE_UNSET || njs_is_valid(&prop->value);
+    return njs_is_valid(&prop->value) ||
+           prop->writable != NJS_ATTRIBUTE_UNSET ||
+           prop->type == NJS_PROPERTY_HANDLER;
 }
 
 
diff -r aa27056f4bc9 -r beb180165976 src/njs_object_prop.c
--- a/src/njs_object_prop.c	Wed May 18 00:01:05 2022 -0700
+++ b/src/njs_object_prop.c	Thu May 19 16:41:08 2022 -0700
@@ -364,6 +364,15 @@ set_prop:
          * the property's attributes to their default values.
          */
 
+        if (pq.temp) {
+            pq.lhq.value = NULL;
+            prop->configurable = prev->configurable;
+            prop->enumerable = prev->enumerable;
+            goto set_prop;
+        }
+
+        prev->type = prop->type;
+
         if (njs_is_data_descriptor(prev)) {
             njs_set_undefined(&prev->getter);
             njs_set_undefined(&prev->setter);
@@ -414,7 +423,7 @@ set_prop:
 
 done:
 
-    if (njs_is_valid(&prop->value) || njs_is_accessor_descriptor(prop)) {
+    if (njs_is_valid(&prop->value)) {
         if (prev->type == NJS_PROPERTY_HANDLER) {
             if (prev->writable) {
                 ret = prev->value.data.u.prop_handler(vm, prev, object,
diff -r aa27056f4bc9 -r beb180165976 src/njs_value.c
--- a/src/njs_value.c	Wed May 18 00:01:05 2022 -0700
+++ b/src/njs_value.c	Thu May 19 16:41:08 2022 -0700
@@ -942,6 +942,7 @@ njs_external_property_query(njs_vm_t *vm
         return NJS_DECLINED;
     }
 
+    pq->temp = 1;
     prop = &pq->scratch;
 
     njs_memzero(prop, sizeof(njs_object_prop_t));
diff -r aa27056f4bc9 -r beb180165976 src/njs_value.h
--- a/src/njs_value.h	Wed May 18 00:01:05 2022 -0700
+++ b/src/njs_value.h	Thu May 19 16:41:08 2022 -0700
@@ -374,6 +374,7 @@ typedef struct {
     njs_object_prop_t           *own_whiteout;
     uint8_t                     query;
     uint8_t                     shared;
+    uint8_t                     temp;
     uint8_t                     own;
 } njs_property_query_t;
 
@@ -1030,6 +1031,7 @@ njs_set_object_value(njs_value_t *value,
         (pq)->query = _query;                                                 \
         (pq)->shared = 0;                                                     \
         (pq)->own = _own;                                                     \
+        (pq)->temp = 0;                                                       \
     } while (0)
 
 
diff -r aa27056f4bc9 -r beb180165976 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Wed May 18 00:01:05 2022 -0700
+++ b/src/test/njs_unit_test.c	Thu May 19 16:41:08 2022 -0700
@@ -9681,6 +9681,12 @@ static njs_unit_test_t  njs_test[] =
               "fn(1); arr"),
       njs_str("1,2,3,4,5,6") },
 
+    { njs_str("function f(){};"
+              "Object.defineProperty(f, 'length', {set: () => {}});"
+              "Object.defineProperty(f, 'length', {value: 42});"
+              "f.length"),
+      njs_str("42") },
+
     /* Function nesting depth. */
 
     { njs_str("() => () => () => () => () => () => () => () => () => () => () =>"



More information about the nginx-devel mailing list