From 6549d49630ce5f5ac823fd3ae0c6c8558b8716ae Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Thu, 19 May 2022 16:41:08 -0700 Subject: [PATCH] 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. --- 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(-) diff --git a/src/njs_object.h b/src/njs_object.h index 85d6fde7..219f2f89 100644 --- a/src/njs_object.h +++ b/src/njs_object.h @@ -88,7 +88,9 @@ njs_int_t njs_object_prop_init(njs_vm_t *vm, const njs_object_init_t* init, 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 --git a/src/njs_object_prop.c b/src/njs_object_prop.c index dc1aa215..74e63fc1 100644 --- a/src/njs_object_prop.c +++ b/src/njs_object_prop.c @@ -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 --git a/src/njs_value.c b/src/njs_value.c index 9347d505..f0f3651e 100644 --- a/src/njs_value.c +++ b/src/njs_value.c @@ -942,6 +942,7 @@ njs_external_property_query(njs_vm_t *vm, njs_property_query_t *pq, return NJS_DECLINED; } + pq->temp = 1; prop = &pq->scratch; njs_memzero(prop, sizeof(njs_object_prop_t)); diff --git a/src/njs_value.h b/src/njs_value.h index d654e157..2ebbd0cb 100644 --- a/src/njs_value.h +++ b/src/njs_value.h @@ -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, njs_object_value_t *object_value) (pq)->query = _query; \ (pq)->shared = 0; \ (pq)->own = _own; \ + (pq)->temp = 0; \ } while (0) diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index cb1c6020..502e3fb8 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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("() => () => () => () => () => () => () => () => () => () => () =>" -- 2.47.3