]> git.kaiwu.me - njs.git/commitdiff
VM: clean up failed module compilation
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 3 Sep 2026 15:53:25 +0000 (08:53 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Thu, 10 Sep 2026 03:11:04 +0000 (20:11 -0700)
Module compilation publishes a provisional module before parsing to support
recursive loading.  Remove that module on failure and release code records,
line maps, and code buffers produced after the compilation checkpoint so a
failed load does not poison subsequent lookups.

src/njs_generator.c
src/njs_generator.h
src/njs_module.c
src/njs_module.h
src/njs_vm.c

index 29def6a175d921453d8926c42150633b187f2fd9..78db1b948abbc700b92be464fc72edc78354f902 100644 (file)
@@ -4981,6 +4981,8 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
         return NULL;
     }
 
+    code->start = NULL;
+    code->end = NULL;
     code->lines = NULL;
 
     if (vm->options.backtrace) {
@@ -5077,6 +5079,29 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
 }
 
 
+void
+njs_generator_cleanup(njs_vm_t *vm, njs_uint_t code_index)
+{
+    njs_vm_code_t  *code;
+
+    if (vm->codes == NULL) {
+        return;
+    }
+
+    while (vm->codes->items > code_index) {
+        code = njs_arr_remove_last(vm->codes);
+
+        if (code->start != NULL) {
+            njs_mp_free(vm->mem_pool, code->start);
+        }
+
+        if (code->lines != NULL) {
+            njs_arr_destroy(code->lines);
+        }
+    }
+}
+
+
 static njs_int_t
 njs_generate_scope_end(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
index 689286aadb940d427c50608b1103d6669997cf38..ae527c4b296ac6a7a5db72cbba917b9858c0545c 100644 (file)
@@ -46,6 +46,7 @@ njs_int_t njs_generator_init(njs_generator_t *generator, njs_mp_t *mem_pool,
     njs_str_t *file, njs_int_t depth, njs_bool_t runtime);
 njs_vm_code_t *njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_scope_t *scope, const njs_str_t *name);
+void njs_generator_cleanup(njs_vm_t *vm, njs_uint_t code_index);
 njs_vm_code_t *njs_lookup_code(njs_vm_t *vm, u_char *pc);
 uint32_t njs_lookup_line(njs_arr_t *lines, uint32_t offset);
 
index a16134390dbb982df8bb1e1c5c5e1811323837ba..6b968884da3cf20d09ef4a4860e86a4ec2c900b2 100644 (file)
@@ -139,6 +139,23 @@ njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_value_t *value)
 }
 
 
+void
+njs_module_remove(njs_vm_t *vm, njs_mod_t *module)
+{
+    njs_flathsh_query_t  fhq;
+
+    fhq.key = module->name;
+    fhq.key_hash = njs_djb_hash(module->name.start, module->name.length);
+    fhq.pool = vm->mem_pool;
+    fhq.proto = &njs_modules_hash_proto;
+
+    (void) njs_flathsh_delete(&vm->shared->modules_hash, &fhq);
+
+    njs_mp_free(vm->mem_pool, module->name.start);
+    njs_mp_free(vm->mem_pool, module);
+}
+
+
 njs_int_t
 njs_module_require(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused, njs_value_t *retval)
index f04fdac03a2450d2f72d561264f63e93b593c939..4fff790fde88333ce6e096cf5b2cb440aa489754 100644 (file)
@@ -16,6 +16,7 @@ struct njs_mod_s {
 
 
 njs_mod_t *njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_value_t *value);
+void njs_module_remove(njs_vm_t *vm, njs_mod_t *module);
 njs_mod_t *njs_module_find(njs_vm_t *vm, njs_str_t *name,
     njs_bool_t shared);
 njs_int_t njs_module_require(njs_vm_t *vm, njs_value_t *args,
index bd095269464d23949bf573f62c62fac0a90510c7..64f5d8a37c2a85dd3825dc8952d51621331daf03 100644 (file)
@@ -326,6 +326,7 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start,
     u_char *end)
 {
     njs_int_t              ret;
+    njs_uint_t             code_index;
     njs_mod_t              *module;
     njs_parser_t           parser;
     njs_vm_code_t          *code;
@@ -333,6 +334,10 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start,
     njs_parser_scope_t     *scope;
     njs_function_lambda_t  *lambda;
 
+    parser.mem_pool = NULL;
+    lambda = NULL;
+    code_index = (vm->codes != NULL) ? vm->codes->items : 0;
+
     module = njs_module_find(vm, name, 1);
     if (module != NULL) {
         return module;
@@ -345,15 +350,14 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start,
 
     ret = njs_parser_init(vm, &parser, NULL, 0, &module->name, *start, end);
     if (njs_slow_path(ret != NJS_OK)) {
-        return NULL;
+        goto failed;
     }
 
     parser.module = 1;
 
     ret = njs_parser(vm, &parser);
     if (njs_slow_path(ret != NJS_OK)) {
-        njs_parser_destroy(&parser);
-        return NULL;
+        goto failed;
     }
 
     *start = parser.lexer->start;
@@ -361,23 +365,20 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start,
     ret = njs_generator_init(&generator, parser.mem_pool, &module->name, 0, 0);
     if (njs_slow_path(ret != NJS_OK)) {
         njs_internal_error(vm, "njs_generator_init() failed");
-        njs_parser_destroy(&parser);
-        return NULL;
+        goto failed;
     }
 
     code = njs_generate_scope(vm, &generator, parser.scope, &njs_entry_module);
     if (njs_slow_path(code == NULL)) {
         njs_internal_error(vm, "njs_generate_scope() failed");
 
-        njs_parser_destroy(&parser);
-        return NULL;
+        goto failed;
     }
 
     lambda = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t));
     if (njs_fast_path(lambda == NULL)) {
         njs_memory_error(vm);
-        njs_parser_destroy(&parser);
-        return NULL;
+        goto failed;
     }
 
     scope = parser.scope;
@@ -390,6 +391,21 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start,
     njs_parser_destroy(&parser);
 
     return module;
+
+failed:
+
+    if (parser.mem_pool != NULL) {
+        njs_parser_destroy(&parser);
+    }
+
+    if (lambda != NULL) {
+        njs_mp_free(vm->mem_pool, lambda);
+    }
+
+    njs_generator_cleanup(vm, code_index);
+    njs_module_remove(vm, module);
+
+    return NULL;
 }