[njs] Shell: unified normal mode and LLVMFuzzerTestOneInput().

Dmitry Volyntsev xeioex at nginx.com
Thu Nov 9 19:59:30 UTC 2023


details:   https://hg.nginx.org/njs/rev/9a886a575f61
branches:  
changeset: 2230:9a886a575f61
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Nov 09 11:11:19 2023 -0800
description:
Shell: unified normal mode and LLVMFuzzerTestOneInput().

Now both main() and LLVMFuzzerTestOneInput() use njs_main()
as a main routine.

diffstat:

 external/njs_shell.c |  510 ++++++++++++++++++++++++--------------------------
 1 files changed, 245 insertions(+), 265 deletions(-)

diffs (615 lines):

diff -r d0f7f3c071ad -r 9a886a575f61 external/njs_shell.c
--- a/external/njs_shell.c	Tue Nov 07 15:35:35 2023 -0800
+++ b/external/njs_shell.c	Thu Nov 09 11:11:19 2023 -0800
@@ -30,10 +30,6 @@
 #endif
 
 
-typedef void (*njs_console_output_pt)(njs_vm_t *vm, njs_value_t *value,
-    njs_int_t ret);
-
-
 typedef struct {
     uint8_t                 disassemble;
     uint8_t                 denormals;
@@ -51,7 +47,7 @@ typedef struct {
     int                     stack_size;
 
     char                    *file;
-    char                    *command;
+    njs_str_t               command;
     size_t                  n_paths;
     char                    **paths;
     char                    **argv;
@@ -94,16 +90,20 @@ typedef struct {
 
     njs_queue_t             labels;
 
+    njs_bool_t              suppress_stdout;
+
     njs_completion_t        completion;
 } njs_console_t;
 
 
+static njs_int_t njs_main(njs_opts_t *opts);
 static njs_int_t njs_console_init(njs_vm_t *vm, njs_console_t *console);
 static void njs_console_output(njs_vm_t *vm, njs_value_t *value,
     njs_int_t ret);
 static njs_int_t njs_externals_init(njs_vm_t *vm);
 static njs_vm_t *njs_create_vm(njs_opts_t *opts, njs_vm_opt_t *vm_options);
 static void njs_process_output(njs_vm_t *vm, njs_value_t *value, njs_int_t ret);
+static njs_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options);
 static njs_int_t njs_process_script(njs_vm_t *vm, void *runtime,
     const njs_str_t *script);
 
@@ -111,7 +111,6 @@ static njs_int_t njs_process_script(njs_
 
 static njs_int_t njs_options_parse(njs_opts_t *opts, int argc, char **argv);
 static void njs_options_free(njs_opts_t *opts);
-static njs_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options);
 
 #ifdef NJS_HAVE_READLINE
 static njs_int_t njs_interactive_shell(njs_opts_t *opts,
@@ -301,25 +300,97 @@ static njs_int_t      njs_console_proto_
 static njs_console_t  njs_console;
 
 
+static njs_int_t
+njs_main(njs_opts_t *opts)
+{
+    njs_vm_t      *vm;
+    njs_int_t     ret;
+    njs_vm_opt_t  vm_options;
+
+    njs_mm_denormals(opts.denormals);
+
+    njs_vm_opt_init(&vm_options);
+
+    if (opts->file == NULL) {
+        if (opts->command.length != 0) {
+            opts->file = (char *) "string";
+        }
+
+#ifdef NJS_HAVE_READLINE
+        else if (opts->interactive) {
+            opts->file = (char *) "shell";
+        }
+#endif
+
+        if (opts->file == NULL) {
+            njs_stderror("file name is required in non-interactive mode\n");
+            return NJS_ERROR;
+        }
+    }
+
+    vm_options.file.start = (u_char *) opts->file;
+    vm_options.file.length = njs_strlen(opts->file);
+
+    vm_options.init = 1;
+    vm_options.interactive = opts->interactive;
+    vm_options.disassemble = opts->disassemble;
+    vm_options.backtrace = 1;
+    vm_options.quiet = opts->quiet;
+    vm_options.sandbox = opts->sandbox;
+    vm_options.unsafe = !opts->safe;
+    vm_options.module = opts->module;
+#ifdef NJS_DEBUG_GENERATOR
+    vm_options.generator_debug = opts->generator_debug;
+#endif
+#ifdef NJS_DEBUG_OPCODE
+    vm_options.opcode_debug = opts->opcode_debug;
+#endif
+
+    vm_options.ops = &njs_console_ops;
+    vm_options.addons = njs_console_addon_modules;
+    vm_options.external = &njs_console;
+    vm_options.argv = opts->argv;
+    vm_options.argc = opts->argc;
+    vm_options.ast = opts->ast;
+    vm_options.unhandled_rejection = opts->unhandled_rejection;
+
+    if (opts->stack_size != 0) {
+        vm_options.max_stack_size = opts->stack_size;
+    }
+
+#if (!defined NJS_FUZZER_TARGET && defined NJS_HAVE_READLINE)
+
+    if (opts->interactive) {
+        ret = njs_interactive_shell(opts, &vm_options);
+
+    } else
+
+#endif
+
+    if (opts->command.length != 0) {
+        vm = njs_create_vm(opts, &vm_options);
+        if (vm == NULL) {
+            return NJS_ERROR;
+        }
+
+        ret = njs_process_script(vm, njs_vm_external_ptr(vm), &opts->command);
+        njs_vm_destroy(vm);
+
+    } else {
+        ret = njs_process_file(opts, &vm_options);
+    }
+
+    return ret;
+}
+
+
 #ifndef NJS_FUZZER_TARGET
 
 int
 main(int argc, char **argv)
 {
-    njs_vm_t      *vm;
-    njs_int_t     ret;
-    njs_opts_t    opts;
-    njs_str_t     command;
-    njs_vm_opt_t  vm_options;
-
-    static uintptr_t uptr[] = {
-        (uintptr_t) njs_console_output,
-    };
-
-    static njs_vm_meta_t metas = {
-        .size = njs_nitems(uptr),
-        .values = uptr
-    };
+    njs_int_t   ret;
+    njs_opts_t  opts;
 
     njs_memzero(&opts, sizeof(njs_opts_t));
     opts.interactive = 1;
@@ -336,79 +407,7 @@ main(int argc, char **argv)
         goto done;
     }
 
-    njs_mm_denormals(opts.denormals);
-
-    njs_vm_opt_init(&vm_options);
-
-    if (opts.file == NULL) {
-        if (opts.command != NULL) {
-            opts.file = (char *) "string";
-        }
-
-#ifdef NJS_HAVE_READLINE
-        else if (opts.interactive) {
-            opts.file = (char *) "shell";
-        }
-#endif
-
-        if (opts.file == NULL) {
-            njs_stderror("file name is required in non-interactive mode\n");
-            goto done;
-        }
-    }
-
-    vm_options.file.start = (u_char *) opts.file;
-    vm_options.file.length = njs_strlen(opts.file);
-
-    vm_options.init = 1;
-    vm_options.interactive = opts.interactive;
-    vm_options.disassemble = opts.disassemble;
-    vm_options.backtrace = 1;
-    vm_options.quiet = opts.quiet;
-    vm_options.sandbox = opts.sandbox;
-    vm_options.unsafe = !opts.safe;
-    vm_options.module = opts.module;
-#ifdef NJS_DEBUG_GENERATOR
-    vm_options.generator_debug = opts.generator_debug;
-#endif
-#ifdef NJS_DEBUG_OPCODE
-    vm_options.opcode_debug = opts.opcode_debug;
-#endif
-
-    vm_options.ops = &njs_console_ops;
-    vm_options.addons = njs_console_addon_modules;
-    vm_options.metas = &metas;
-    vm_options.external = &njs_console;
-    vm_options.argv = opts.argv;
-    vm_options.argc = opts.argc;
-    vm_options.ast = opts.ast;
-    vm_options.unhandled_rejection = opts.unhandled_rejection;
-
-    if (opts.stack_size != 0) {
-        vm_options.max_stack_size = opts.stack_size;
-    }
-
-#ifdef NJS_HAVE_READLINE
-
-    if (opts.interactive) {
-        ret = njs_interactive_shell(&opts, &vm_options);
-
-    } else
-
-#endif
-
-    if (opts.command) {
-        vm = njs_create_vm(&opts, &vm_options);
-        if (vm != NULL) {
-            command.start = (u_char *) opts.command;
-            command.length = njs_strlen(opts.command);
-            ret = njs_process_script(vm, njs_vm_external_ptr(vm), &command);
-            njs_vm_destroy(vm);
-        }
-
-    } else {
-        ret = njs_process_file(&opts, &vm_options);
-    }
+    ret = njs_main(&opts);
 
 done:
 
@@ -494,7 +493,8 @@ njs_options_parse(njs_opts_t *opts, int 
             opts->interactive = 0;
 
             if (++i < argc) {
-                opts->command = argv[i];
+                opts->command.start = (u_char *) argv[i];
+                opts->command.length = njs_strlen(argv[i]);
                 goto done;
             }
 
@@ -638,163 +638,12 @@ njs_options_free(njs_opts_t *opts)
 }
 
 
-static njs_int_t
-njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options)
-{
-    int          fd;
-    char         *file;
-    u_char       *p, *end, *start;
-    size_t       size;
-    ssize_t      n;
-    njs_vm_t     *vm;
-    njs_int_t    ret;
-    njs_str_t    source, script;
-    struct stat  sb;
-    u_char       buf[4096];
-
-    file = opts->file;
-
-    if (file[0] == '-' && file[1] == '\0') {
-        fd = STDIN_FILENO;
-
-    } else {
-        fd = open(file, O_RDONLY);
-        if (fd == -1) {
-            njs_stderror("failed to open file: '%s' (%s)\n",
-                         file, strerror(errno));
-            return NJS_ERROR;
-        }
-    }
-
-    if (fstat(fd, &sb) == -1) {
-        njs_stderror("fstat(%d) failed while reading '%s' (%s)\n",
-                     fd, file, strerror(errno));
-        ret = NJS_ERROR;
-        goto close_fd;
-    }
-
-    size = sizeof(buf);
-
-    if (S_ISREG(sb.st_mode) && sb.st_size) {
-        size = sb.st_size;
-    }
-
-    vm = NULL;
-
-    source.length = 0;
-    source.start = realloc(NULL, size);
-    if (source.start == NULL) {
-        njs_stderror("alloc failed while reading '%s'\n", file);
-        ret = NJS_ERROR;
-        goto done;
-    }
-
-    p = source.start;
-    end = p + size;
-
-    for ( ;; ) {
-        n = read(fd, buf, sizeof(buf));
-
-        if (n == 0) {
-            break;
-        }
-
-        if (n < 0) {
-            njs_stderror("failed to read file: '%s' (%s)\n",
-                      file, strerror(errno));
-            ret = NJS_ERROR;
-            goto done;
-        }
-
-        if (p + n > end) {
-            size *= 2;
-
-            start = realloc(source.start, size);
-            if (start == NULL) {
-                njs_stderror("alloc failed while reading '%s'\n", file);
-                ret = NJS_ERROR;
-                goto done;
-            }
-
-            source.start = start;
-
-            p = source.start + source.length;
-            end = source.start + size;
-        }
-
-        memcpy(p, buf, n);
-
-        p += n;
-        source.length += n;
-    }
-
-    vm = njs_create_vm(opts, vm_options);
-    if (vm == NULL) {
-        ret = NJS_ERROR;
-        goto done;
-    }
-
-    script = source;
-
-    /* shebang */
-
-    if (script.length > 2 && memcmp(script.start, "#!", 2) == 0) {
-        p = njs_strlchr(script.start, script.start + script.length, '\n');
-
-        if (p != NULL) {
-            script.length -= (p + 1 - script.start);
-            script.start = p + 1;
-
-        } else {
-            script.length = 0;
-        }
-    }
-
-    ret = njs_process_script(vm, vm_options->external, &script);
-    if (ret != NJS_OK) {
-        ret = NJS_ERROR;
-        goto done;
-    }
-
-    ret = NJS_OK;
-
-done:
-
-    if (vm != NULL) {
-        njs_vm_destroy(vm);
-    }
-
-    if (source.start != NULL) {
-        free(source.start);
-    }
-
-close_fd:
-
-    if (fd != STDIN_FILENO) {
-        (void) close(fd);
-    }
-
-    return ret;
-}
-
 #else
 
 int
 LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
 {
-    njs_vm_t      *vm;
-    njs_opts_t    opts;
-    njs_str_t     script;
-    njs_vm_opt_t  vm_options;
-
-    static uintptr_t uptr[] = {
-        (uintptr_t) NULL,
-    };
-
-    static njs_vm_meta_t metas = {
-        .size = njs_nitems(uptr),
-        .values = uptr
-    };
+    njs_opts_t  opts;
 
     if (size == 0) {
         return 0;
@@ -802,24 +651,15 @@ LLVMFuzzerTestOneInput(const uint8_t* da
 
     njs_memzero(&opts, sizeof(njs_opts_t));
 
-    njs_vm_opt_init(&vm_options);
-
-    vm_options.init = 1;
-    vm_options.backtrace = 0;
-    vm_options.metas = &metas;
-    vm_options.ops = &njs_console_ops;
-
-    vm = njs_create_vm(&opts, &vm_options);
+    opts.file = (char *) "fuzzer";
+    opts.command.start = (u_char *) data;
+    opts.command.length = size;
 
-    if (njs_fast_path(vm != NULL)) {
-        script.length = size;
-        script.start = (u_char *) data;
+    njs_memzero(&njs_console, sizeof(njs_console_t));
 
-        (void) njs_process_script(vm, NULL, &script);
-        njs_vm_destroy(vm);
-    }
+    njs_console.suppress_stdout = 1;
 
-    return 0;
+    return njs_main(&opts);
 }
 
 #endif
@@ -1025,6 +865,146 @@ njs_process_events(void *runtime)
 
 
 static njs_int_t
+njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options)
+{
+    int          fd;
+    char         *file;
+    u_char       *p, *end, *start;
+    size_t       size;
+    ssize_t      n;
+    njs_vm_t     *vm;
+    njs_int_t    ret;
+    njs_str_t    source, script;
+    struct stat  sb;
+    u_char       buf[4096];
+
+    file = opts->file;
+
+    if (file[0] == '-' && file[1] == '\0') {
+        fd = STDIN_FILENO;
+
+    } else {
+        fd = open(file, O_RDONLY);
+        if (fd == -1) {
+            njs_stderror("failed to open file: '%s' (%s)\n",
+                         file, strerror(errno));
+            return NJS_ERROR;
+        }
+    }
+
+    if (fstat(fd, &sb) == -1) {
+        njs_stderror("fstat(%d) failed while reading '%s' (%s)\n",
+                     fd, file, strerror(errno));
+        ret = NJS_ERROR;
+        goto close_fd;
+    }
+
+    size = sizeof(buf);
+
+    if (S_ISREG(sb.st_mode) && sb.st_size) {
+        size = sb.st_size;
+    }
+
+    vm = NULL;
+
+    source.length = 0;
+    source.start = realloc(NULL, size);
+    if (source.start == NULL) {
+        njs_stderror("alloc failed while reading '%s'\n", file);
+        ret = NJS_ERROR;
+        goto done;
+    }
+
+    p = source.start;
+    end = p + size;
+
+    for ( ;; ) {
+        n = read(fd, buf, sizeof(buf));
+
+        if (n == 0) {
+            break;
+        }
+
+        if (n < 0) {
+            njs_stderror("failed to read file: '%s' (%s)\n",
+                      file, strerror(errno));
+            ret = NJS_ERROR;
+            goto done;
+        }
+
+        if (p + n > end) {
+            size *= 2;
+
+            start = realloc(source.start, size);
+            if (start == NULL) {
+                njs_stderror("alloc failed while reading '%s'\n", file);
+                ret = NJS_ERROR;
+                goto done;
+            }
+
+            source.start = start;
+
+            p = source.start + source.length;
+            end = source.start + size;
+        }
+
+        memcpy(p, buf, n);
+
+        p += n;
+        source.length += n;
+    }
+
+    vm = njs_create_vm(opts, vm_options);
+    if (vm == NULL) {
+        ret = NJS_ERROR;
+        goto done;
+    }
+
+    script = source;
+
+    /* shebang */
+
+    if (script.length > 2 && memcmp(script.start, "#!", 2) == 0) {
+        p = njs_strlchr(script.start, script.start + script.length, '\n');
+
+        if (p != NULL) {
+            script.length -= (p + 1 - script.start);
+            script.start = p + 1;
+
+        } else {
+            script.length = 0;
+        }
+    }
+
+    ret = njs_process_script(vm, vm_options->external, &script);
+    if (ret != NJS_OK) {
+        ret = NJS_ERROR;
+        goto done;
+    }
+
+    ret = NJS_OK;
+
+done:
+
+    if (vm != NULL) {
+        njs_vm_destroy(vm);
+    }
+
+    if (source.start != NULL) {
+        free(source.start);
+    }
+
+close_fd:
+
+    if (fd != STDIN_FILENO) {
+        (void) close(fd);
+    }
+
+    return ret;
+}
+
+
+static njs_int_t
 njs_process_script(njs_vm_t *vm, void *runtime, const njs_str_t *script)
 {
     u_char              *start, *end;
@@ -1091,12 +1071,12 @@ njs_process_script(njs_vm_t *vm, void *r
 static void
 njs_process_output(njs_vm_t *vm, njs_value_t *value, njs_int_t ret)
 {
-    njs_console_output_pt  pt;
+    njs_console_t  *console;
 
-    pt = (njs_console_output_pt) njs_vm_meta(vm, 0);
+    console = njs_vm_external_ptr(vm);
 
-    if (pt != NULL) {
-        pt(vm, value, ret);
+    if (!console->suppress_stdout) {
+        njs_console_output(vm, value, ret);
     }
 }
 


More information about the nginx-devel mailing list