From: Dmitry Volyntsev Date: Thu, 3 Sep 2026 15:53:25 +0000 (-0700) Subject: VM: clean up failed module compilation X-Git-Tag: 1.0.2~60 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=fd54d52de557;p=njs.git VM: clean up failed module compilation 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. --- diff --git a/src/njs_generator.c b/src/njs_generator.c index 29def6a1..78db1b94 100644 --- a/src/njs_generator.c +++ b/src/njs_generator.c @@ -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) diff --git a/src/njs_generator.h b/src/njs_generator.h index 689286aa..ae527c4b 100644 --- a/src/njs_generator.h +++ b/src/njs_generator.h @@ -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); diff --git a/src/njs_module.c b/src/njs_module.c index a1613439..6b968884 100644 --- a/src/njs_module.c +++ b/src/njs_module.c @@ -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) diff --git a/src/njs_module.h b/src/njs_module.h index f04fdac0..4fff790f 100644 --- a/src/njs_module.h +++ b/src/njs_module.h @@ -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, diff --git a/src/njs_vm.c b/src/njs_vm.c index bd095269..64f5d8a3 100644 --- a/src/njs_vm.c +++ b/src/njs_vm.c @@ -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; }