Njs: Segfault while parsing scripts with empty blocks in the middle.

Created on 20 May 2019  路  2Comments  路  Source: nginx/njs

NJS version

changeset:   965:e0fdef4eb478
tag:         tip
user:        Dmitry Volyntsev <[email protected]>
date:        Thu May 16 15:20:31 2019 +0300
summary:     Fixed uninitialized-memory-access in Object.defineProperties().

JavaScript testcase:

{  // parser->node should include all the below statements.
    function f() {}
    {}  // parser->node is NULL
    f()  // now, parser->node points to this statement.
}

ASAN log:

ASAN:DEADLYSIGNAL
=================================================================
==8437==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000010 (pc 0x56409d6d9c7c bp 0x000000000010 sp 0x7ffd70ea2240 T0)
==8437==The signal is caused by a READ memory access.
==8437==Hint: address points to the zero page.
    #0 0x56409d6d9c7b in njs_vmcode_interpreter njs/njs_vm.c:148
    #1 0x56409d6d4b83 in njs_vm_start njs/njs.c:594
    #2 0x56409d6b7cc3 in njs_process_script njs/njs_shell.c:770
    #3 0x56409d6b0f48 in njs_process_file njs/njs_shell.c:619
    #4 0x56409d6b0f48 in main njs/njs_shell.c:281
    #5 0x7f4735408b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #6 0x56409d6b2ef9 in _start (/home/build/njs/build/njs+0x2aef9)

Found by fluff

bug fluff fuzzer

All 2 comments

@xeioex On it.

It's an issue happened in block_statement.

{
    function f(){}
    {}
}

@xeioex

I checked all the points like below.

    if (parser->node != NULL) {
            /* The statement is not empty block or just semicolon. */

It's OK after a single statement.

But it's wrong after njs_parser_statement_chain, see the codes.

{  // parser->node should include all the below statements.
    function f() {}
    {}  // parser->node is NULL
    f()  // now, parser->node points to this statement.
}

So I think empty block is meaningful.

Here's the patch.

# HG changeset patch
# User hongzhidao <[email protected]>
# Date 1558365269 -28800
# Node ID 1d038720a7611a1a249618e5bace4211519760f1
# Parent  88263426432d8d8cb245b674730f10dc0a5f07f7
Fixed segfault happened in empty block.

diff -r 88263426432d -r 1d038720a761 njs/njs_generator.c
--- a/njs/njs_generator.c   Fri May 17 17:01:10 2019 +0300
+++ b/njs/njs_generator.c   Mon May 20 23:14:29 2019 +0800
@@ -1558,7 +1558,7 @@ njs_generate_block_statement(njs_vm_t *v
         return ret;
     }

-    ret = njs_generate_statement(vm, generator, node->left);
+    ret = njs_generate_statement(vm, generator, node);
     if (nxt_slow_path(ret != NXT_OK)) {
         return ret;
     }
diff -r 88263426432d -r 1d038720a761 njs/njs_parser.c
--- a/njs/njs_parser.c  Fri May 17 17:01:10 2019 +0300
+++ b/njs/njs_parser.c  Mon May 20 23:14:29 2019 +0800
@@ -468,19 +468,15 @@ njs_parser_block_statement(njs_vm_t *vm,
         }
     }

-    if (parser->node != NULL) {
-        /* The statement is not empty block or just semicolon. */
-
-        node = njs_parser_node_new(vm, parser, NJS_TOKEN_BLOCK);
-        if (nxt_slow_path(node == NULL)) {
-            return NJS_TOKEN_ERROR;
-        }
-
-        node->left = parser->node;
-        node->right = NULL;
-        parser->node = node;
+    node = njs_parser_node_new(vm, parser, NJS_TOKEN_BLOCK);
+    if (nxt_slow_path(node == NULL)) {
+        return NJS_TOKEN_ERROR;
     }

+    node->left = parser->node;
+    node->right = NULL;
+    parser->node = node;
+
     njs_parser_scope_end(vm, parser);

     return njs_parser_token(vm, parser);
diff -r 88263426432d -r 1d038720a761 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c  Fri May 17 17:01:10 2019 +0300
+++ b/njs/test/njs_unit_test.c  Mon May 20 23:14:29 2019 +0800
@@ -6016,6 +6016,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("function f() { return 1; } { function f() { return 2; } { function f() { return 3; } }} f()"),
       nxt_string("1") },

+    { nxt_string("{function f() {} {} f() }"),
+      nxt_string("undefined") },
+
     { nxt_string("{ var f; function f() {} }"),
       nxt_string("SyntaxError: \"f\" has already been declared in 1") },

Was this page helpful?
0 / 5 - 0 ratings