[njs] Fixed Error() instance dumping when "name" prop is not primitive.

Dmitry Volyntsev xeioex at nginx.com
Tue Feb 28 06:15:41 UTC 2023


details:   https://hg.nginx.org/njs/rev/1aa137411b09
branches:  
changeset: 2053:1aa137411b09
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Mon Feb 27 22:14:34 2023 -0800
description:
Fixed Error() instance dumping when "name" prop is not primitive.

Previously, njs_error_to_string2() might be invoked with error argument
pointing to vm->retval.  When "name" prop was not primitive vm->retval
might be overwritten.  As a result error pointer might be referencing a
primitive value.  In turn the second call of njs_object_property()
received an invalid object pointer because it expects only object value
types.

The fix is to ensure that error object pointer is never overwritten.

This closes #615 issue on Github.

diffstat:

 src/njs_array.c          |   5 +++--
 src/njs_date.c           |   5 +++--
 src/njs_error.c          |  14 ++++++++++++--
 src/njs_json.c           |  18 +++++++++++-------
 src/njs_object.h         |   2 +-
 src/njs_object_prop.c    |  26 ++++++++++++++------------
 src/njs_value.c          |   2 +-
 src/test/njs_unit_test.c |   3 +++
 8 files changed, 48 insertions(+), 27 deletions(-)

diffs (254 lines):

diff -r e92881f2b395 -r 1aa137411b09 src/njs_array.c
--- a/src/njs_array.c	Mon Feb 27 19:05:03 2023 -0800
+++ b/src/njs_array.c	Mon Feb 27 22:14:34 2023 -0800
@@ -1404,10 +1404,11 @@ njs_array_prototype_to_string(njs_vm_t *
 
     static const njs_value_t  join_string = njs_string("join");
 
-    if (njs_is_object(&args[0])) {
+    if (njs_is_object(njs_argument(args, 0))) {
         njs_object_property_init(&lhq, &join_string, NJS_JOIN_HASH);
 
-        ret = njs_object_property(vm, &args[0], &lhq, &value);
+        ret = njs_object_property(vm, njs_object(njs_argument(args, 0)), &lhq,
+                                  &value);
 
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
diff -r e92881f2b395 -r 1aa137411b09 src/njs_date.c
--- a/src/njs_date.c	Mon Feb 27 19:05:03 2023 -0800
+++ b/src/njs_date.c	Mon Feb 27 22:14:34 2023 -0800
@@ -1385,10 +1385,11 @@ njs_date_prototype_to_json(njs_vm_t *vm,
 
     static const njs_value_t  to_iso_string = njs_string("toISOString");
 
-    if (njs_is_object(&args[0])) {
+    if (njs_is_object(njs_argument(args, 0))) {
         njs_object_property_init(&lhq, &to_iso_string, NJS_TO_ISO_STRING_HASH);
 
-        ret = njs_object_property(vm, &args[0], &lhq, &value);
+        ret = njs_object_property(vm, njs_object(njs_argument(args, 0)), &lhq,
+                                  &value);
 
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
diff -r e92881f2b395 -r 1aa137411b09 src/njs_error.c
--- a/src/njs_error.c	Mon Feb 27 19:05:03 2023 -0800
+++ b/src/njs_error.c	Mon Feb 27 22:14:34 2023 -0800
@@ -574,6 +574,7 @@ njs_error_to_string2(njs_vm_t *vm, njs_v
     size_t              length;
     u_char              *p;
     njs_int_t           ret;
+    njs_object_t        *error_object;
     njs_value_t         value1, value2;
     njs_value_t         *name_value, *message_value;
     njs_string_prop_t   name, message;
@@ -581,6 +582,8 @@ njs_error_to_string2(njs_vm_t *vm, njs_v
 
     static const njs_value_t  default_name = njs_string("Error");
 
+    njs_assert(njs_is_object(error));
+
     if (want_stack) {
         ret = njs_error_stack(vm, njs_value_arg(error), retval);
         if (njs_slow_path(ret == NJS_ERROR)) {
@@ -592,9 +595,11 @@ njs_error_to_string2(njs_vm_t *vm, njs_v
         }
     }
 
+    error_object = njs_object(error);
+
     njs_object_property_init(&lhq, &njs_string_name, NJS_NAME_HASH);
 
-    ret = njs_object_property(vm, error, &lhq, &value1);
+    ret = njs_object_property(vm, error_object, &lhq, &value1);
 
     if (njs_slow_path(ret == NJS_ERROR)) {
         return ret;
@@ -616,7 +621,7 @@ njs_error_to_string2(njs_vm_t *vm, njs_v
     lhq.key_hash = NJS_MESSAGE_HASH;
     lhq.key = njs_str_value("message");
 
-    ret = njs_object_property(vm, error, &lhq, &value2);
+    ret = njs_object_property(vm, error_object, &lhq, &value2);
 
     if (njs_slow_path(ret == NJS_ERROR)) {
         return ret;
@@ -686,6 +691,11 @@ njs_error_prototype_to_string(njs_vm_t *
 njs_int_t
 njs_error_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *error)
 {
+    if (njs_slow_path(!njs_is_object(error))) {
+        njs_type_error(vm, "\"error\" is not an object");
+        return NJS_ERROR;
+    }
+
     return njs_error_to_string2(vm, retval, error, 1);
 }
 
diff -r e92881f2b395 -r 1aa137411b09 src/njs_json.c
--- a/src/njs_json.c	Mon Feb 27 19:05:03 2023 -0800
+++ b/src/njs_json.c	Mon Feb 27 22:14:34 2023 -0800
@@ -1252,15 +1252,19 @@ njs_object_to_json_function(njs_vm_t *vm
 
     static const njs_value_t  to_json_string = njs_string("toJSON");
 
-    njs_object_property_init(&lhq, &to_json_string, NJS_TO_JSON_HASH);
-
-    ret = njs_object_property(vm, value, &lhq, &retval);
-
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
+    if (njs_is_object(value)) {
+        njs_object_property_init(&lhq, &to_json_string, NJS_TO_JSON_HASH);
+
+        ret = njs_object_property(vm, njs_object(value), &lhq, &retval);
+
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return NULL;
+        }
+
+        return njs_is_function(&retval) ? njs_function(&retval) : NULL;
     }
 
-    return njs_is_function(&retval) ? njs_function(&retval) : NULL;
+    return NULL;
 }
 
 
diff -r e92881f2b395 -r 1aa137411b09 src/njs_object.h
--- a/src/njs_object.h	Mon Feb 27 19:05:03 2023 -0800
+++ b/src/njs_object.h	Mon Feb 27 22:14:34 2023 -0800
@@ -98,7 +98,7 @@ njs_int_t njs_prop_private_copy(njs_vm_t
     njs_object_t *proto);
 njs_object_prop_t *njs_object_prop_alloc(njs_vm_t *vm, const njs_value_t *name,
     const njs_value_t *value, uint8_t attributes);
-njs_int_t njs_object_property(njs_vm_t *vm, const njs_value_t *value,
+njs_int_t njs_object_property(njs_vm_t *vm, njs_object_t *object,
     njs_lvlhsh_query_t *lhq, njs_value_t *retval);
 njs_object_prop_t *njs_object_property_add(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *key, njs_bool_t replace);
diff -r e92881f2b395 -r 1aa137411b09 src/njs_object_prop.c
--- a/src/njs_object_prop.c	Mon Feb 27 19:05:03 2023 -0800
+++ b/src/njs_object_prop.c	Mon Feb 27 22:14:34 2023 -0800
@@ -91,15 +91,13 @@ njs_object_prop_alloc2(njs_vm_t *vm, con
 
 
 njs_int_t
-njs_object_property(njs_vm_t *vm, const njs_value_t *value,
-    njs_lvlhsh_query_t *lhq, njs_value_t *retval)
+njs_object_property(njs_vm_t *vm, njs_object_t *object, njs_lvlhsh_query_t *lhq,
+    njs_value_t *retval)
 {
     njs_int_t          ret;
-    njs_object_t       *object;
+    njs_value_t        value;
     njs_object_prop_t  *prop;
 
-    object = njs_object(value);
-
     do {
         ret = njs_lvlhsh_find(&object->hash, lhq);
 
@@ -135,7 +133,9 @@ found:
         return NJS_OK;
     }
 
-    return njs_function_apply(vm, njs_prop_getter(prop), value, 1, retval);
+    njs_set_object(&value, object);
+
+    return njs_function_apply(vm, njs_prop_getter(prop), &value, 1, retval);
 }
 
 
@@ -720,6 +720,7 @@ njs_descriptor_prop(njs_vm_t *vm, const 
     njs_int_t           ret;
     njs_bool_t          data, accessor;
     njs_value_t         value;
+    njs_object_t        *desc_object;
     njs_function_t      *getter, *setter;
     njs_object_prop_t   *prop;
     njs_lvlhsh_query_t  lhq;
@@ -741,10 +742,11 @@ njs_descriptor_prop(njs_vm_t *vm, const 
     accessor = 0;
     getter = NJS_PROP_PTR_UNSET;
     setter = NJS_PROP_PTR_UNSET;
+    desc_object = njs_object(desc);
 
     njs_object_property_init(&lhq, &get_string, NJS_GET_HASH);
 
-    ret = njs_object_property(vm, desc, &lhq, &value);
+    ret = njs_object_property(vm, desc_object, &lhq, &value);
     if (njs_slow_path(ret == NJS_ERROR)) {
         return NULL;
     }
@@ -762,7 +764,7 @@ njs_descriptor_prop(njs_vm_t *vm, const 
     lhq.key = njs_str_value("set");
     lhq.key_hash = NJS_SET_HASH;
 
-    ret = njs_object_property(vm, desc, &lhq, &value);
+    ret = njs_object_property(vm, desc_object, &lhq, &value);
     if (njs_slow_path(ret == NJS_ERROR)) {
         return NULL;
     }
@@ -780,7 +782,7 @@ njs_descriptor_prop(njs_vm_t *vm, const 
     lhq.key = njs_str_value("value");
     lhq.key_hash = NJS_VALUE_HASH;
 
-    ret = njs_object_property(vm, desc, &lhq, &value);
+    ret = njs_object_property(vm, desc_object, &lhq, &value);
     if (njs_slow_path(ret == NJS_ERROR)) {
         return NULL;
     }
@@ -793,7 +795,7 @@ njs_descriptor_prop(njs_vm_t *vm, const 
     lhq.key = njs_str_value("writable");
     lhq.key_hash = NJS_WRITABABLE_HASH;
 
-    ret = njs_object_property(vm, desc, &lhq, &value);
+    ret = njs_object_property(vm, desc_object, &lhq, &value);
     if (njs_slow_path(ret == NJS_ERROR)) {
         return NULL;
     }
@@ -812,7 +814,7 @@ njs_descriptor_prop(njs_vm_t *vm, const 
     lhq.key = njs_str_value("enumerable");
     lhq.key_hash = NJS_ENUMERABLE_HASH;
 
-    ret = njs_object_property(vm, desc, &lhq, &value);
+    ret = njs_object_property(vm, desc_object, &lhq, &value);
     if (njs_slow_path(ret == NJS_ERROR)) {
         return NULL;
     }
@@ -824,7 +826,7 @@ njs_descriptor_prop(njs_vm_t *vm, const 
     lhq.key = njs_str_value("configurable");
     lhq.key_hash = NJS_CONFIGURABLE_HASH;
 
-    ret = njs_object_property(vm, desc, &lhq, &value);
+    ret = njs_object_property(vm, desc_object, &lhq, &value);
     if (njs_slow_path(ret == NJS_ERROR)) {
         return NULL;
     }
diff -r e92881f2b395 -r 1aa137411b09 src/njs_value.c
--- a/src/njs_value.c	Mon Feb 27 19:05:03 2023 -0800
+++ b/src/njs_value.c	Mon Feb 27 22:14:34 2023 -0800
@@ -157,7 +157,7 @@ njs_value_to_primitive(njs_vm_t *vm, njs
             lhq.key_hash = hashes[hint];
             lhq.key = names[hint];
 
-            ret = njs_object_property(vm, value, &lhq, &method);
+            ret = njs_object_property(vm, njs_object(value), &lhq, &method);
 
             if (njs_slow_path(ret == NJS_ERROR)) {
                 return ret;
diff -r e92881f2b395 -r 1aa137411b09 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Mon Feb 27 19:05:03 2023 -0800
+++ b/src/test/njs_unit_test.c	Mon Feb 27 22:14:34 2023 -0800
@@ -22849,6 +22849,9 @@ static njs_unit_test_t  njs_shell_test[]
                "sq(function () { return 3 })" ENTER),
       njs_str("9") },
 
+    { njs_str("var e = Error(); e.name = {}; e" ENTER),
+      njs_str("[object Object]") },
+
     /* Temporary indexes */
 
     { njs_str("var a = [1,2,3], i; for (i in a) {Object.seal({});}" ENTER),


More information about the nginx-devel mailing list