Repository: nginx/njs (c)

Issue:
njs_process_script_fuzzer: ASAN error in njs_vsprintf
### Describe the bug

We found a crashing test case when running the njs_process_script_fuzzer with ASAN.

- [x] The bug is reproducible with the latest version of njs.
- [x] I minimized the code to the smallest possible to reproduce the issue.

### To reproduce

Steps to reproduce the behavior:

- JS script
```js
var sym = Symbol();
obj[sym];
var obj = { [sym]: "" };
```

### Expected behavior

Should not trigger ASAN error.

### Actual behavior

```
=================================================================
==3557937==ERROR: AddressSanitizer: unknown-crash on address 0x000100000000 at pc 0x0000004a39c1 bp 0x7ffd8a654230 sp 0x7ffd8a653a00
READ of size 2027 at 0x000100000000 thread T0
    #0 0x4a39c0 in __asan_memcpy /src/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3
    #1 0x51cb37 in njs_vsprintf /src/njs/src/njs_sprintf.c:430:19
    #2 0x64d603 in njs_throw_error_va /src/njs/src/njs_error.c:60:9
    #3 0x64d603 in njs_throw_error /src/njs/src/njs_error.c:72:5
    #4 0x523766 in njs_property_query /src/njs/src/njs_value.c:614:13
    #5 0x520c69 in njs_value_property /src/njs/src/njs_value.c:1070:11
    #6 0x54561b in njs_vmcode_interpreter /src/njs/src/njs_vmcode.c:308:15
    #7 0x52e4f2 in njs_vm_start /src/njs/src/njs_vm.c:698:11
    #8 0x512615 in njs_engine_njs_eval /src/njs/external/njs_shell.c:1387:16
    #9 0x512165 in njs_process_script /src/njs/external/njs_shell.c:3340:11
    #10 0x510eed in njs_main /src/njs/external/njs_shell.c:454:15
    #11 0x510eed in LLVMFuzzerTestOneInput /src/njs/external/njs_shell.c:869:12
    #12 0x4efe6c in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /tmp/libfuzzer/./FuzzerLoop.cpp:532:15
    #13 0x4e1dc5 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /tmp/libfuzzer/./FuzzerDriver.cpp:284:6
    #14 0x4e6a71 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /tmp/libfuzzer/./FuzzerDriver.cpp:713:9
    #15 0x4e1a92 in main /tmp/libfuzzer/./FuzzerMain.cpp:19:10
```



Discussion:

Patch:
diff --git a/src/njs_generator.c b/src/njs_generator.c
--- a/src/njs_generator.c
+++ b/src/njs_generator.c
@@ -5491,7 +5491,7 @@ njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator,
 
     ref_err->type = NJS_OBJ_TYPE_REF_ERROR;
 
-    njs_lexer_entry(vm, node->u.reference.atom_id, &entry);
+    njs_atom_string_get(vm, node->u.reference.atom_id, &entry);
 
     return njs_name_copy(vm, &ref_err->u.name, &entry);
 }
diff --git a/src/njs_lexer.h b/src/njs_lexer.h
--- a/src/njs_lexer.h
+++ b/src/njs_lexer.h
@@ -288,16 +288,6 @@ const njs_lexer_keyword_entry_t *njs_lexer_keyword(const u_char *key,
 njs_int_t njs_lexer_keywords(njs_arr_t *array);
 
 
-njs_inline void
-njs_lexer_entry(njs_vm_t *vm, uintptr_t atom_id, njs_str_t *entry)
-{
-    njs_value_t  value;
-
-    njs_atom_to_value(vm, &value, atom_id);
-    njs_string_get(vm, &value, entry);
-}
-
-
 njs_inline njs_bool_t
 njs_lexer_token_is_keyword(njs_lexer_token_t *token)
 {
diff --git a/src/njs_object.h b/src/njs_object.h
--- a/src/njs_object.h
+++ b/src/njs_object.h
@@ -241,18 +241,17 @@ njs_key_string_get(njs_vm_t *vm, njs_value_t *key, njs_str_t *str)
 }
 
 
-njs_inline njs_int_t
+njs_inline void
 njs_atom_string_get(njs_vm_t *vm, uint32_t atom_id, njs_str_t *str)
 {
     njs_value_t  value;
 
     if (njs_atom_to_value(vm, &value, atom_id) != NJS_OK) {
-        return NJS_ERROR;
+        str->start = (u_char *) "unknown";
+        str->length = njs_length("unknown");
     }
 
     njs_key_string_get(vm, &value, str);
-
-    return NJS_OK;
 }
 
 
diff --git a/src/njs_parser.c b/src/njs_parser.c
--- a/src/njs_parser.c
+++ b/src/njs_parser.c
@@ -6702,7 +6702,6 @@ njs_parser_labelled_statement_after(njs_parser_t *parser,
     njs_int_t          ret;
     njs_str_t          str;
     uintptr_t          atom_id;
-    njs_value_t        entry;
     njs_parser_node_t  *node;
 
     node = parser->node;
@@ -6719,8 +6718,7 @@ njs_parser_labelled_statement_after(njs_parser_t *parser,
 
     atom_id = (uint32_t) (uintptr_t) parser->target;
 
-    njs_atom_to_value(parser->vm, &entry, atom_id);
-    njs_string_get(parser->vm, &entry, &str);
+    njs_atom_string_get(parser->vm, atom_id, &str);
 
     ret = njs_name_copy(parser->vm, &parser->node->name, &str);
     if (ret != NJS_OK) {
diff --git a/src/njs_value.c b/src/njs_value.c
--- a/src/njs_value.c
+++ b/src/njs_value.c
@@ -560,7 +560,6 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *value,
 {
     uint32_t        index;
     njs_int_t       ret;
-    njs_value_t     key;
     njs_object_t    *obj;
     njs_function_t  *function;
 
@@ -607,19 +606,9 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *value,
     case NJS_UNDEFINED:
     case NJS_NULL:
     default:
-        ret = njs_atom_to_value(vm, &key, atom_id);
-
-        if (njs_fast_path(ret == NJS_OK)) {
-            njs_string_get(vm, &key, &pq->lhq.key);
-            njs_type_error(vm, "cannot get property \"%V\" of %s",
-                           &pq->lhq.key, njs_is_null(value) ? "null"
-                                                            : "undefined");
-            return NJS_ERROR;
-        }
-
-        njs_type_error(vm, "cannot get property \"unknown\" of %s",
-                       njs_is_null(value) ? "null" : "undefined");
-
+        njs_atom_string_get(vm, atom_id, &pq->lhq.key);
+        njs_type_error(vm, "cannot get property \"%V\" of %s", &pq->lhq.key,
+                       njs_type_string(value->type));
         return NJS_ERROR;
     }
 
diff --git a/src/njs_variable.c b/src/njs_variable.c
--- a/src/njs_variable.c
+++ b/src/njs_variable.c
@@ -239,7 +239,7 @@ njs_variable_scope_find(njs_parser_t *parser, njs_parser_scope_t *scope,
 
 failed:
 
-    njs_lexer_entry(parser->vm, atom_id, &entry);
+    njs_atom_string_get(parser->vm, atom_id, &entry);
 
     njs_parser_syntax_error(parser, "\"%V\" has already been declared", &entry);
     return NULL;


Test patch:
diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c
+++ b/src/test/njs_unit_test.c
@@ -3923,6 +3923,9 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("delete this !== true"),
       njs_str("false") },
 
+    { njs_str("undefined[Symbol()]"),
+      njs_str("TypeError: cannot get property \"Symbol()\" of undefined") },
+
     /* Object shorthand methods. */
 
     { njs_str("var o = {m(){}}; new o.m();"),