[njs] Fixed break instruction in a try-catch block.
Dmitry Volyntsev
xeioex at nginx.com
Wed Jun 29 06:05:44 UTC 2022
details: https://hg.nginx.org/njs/rev/b7c4e0f714a9
branches:
changeset: 1902:b7c4e0f714a9
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Tue Jun 28 23:04:00 2022 -0700
description:
Fixed break instruction in a try-catch block.
Previously, JUMP offset for a break instruction inside a try-catch
block was not set to a correct offset during code generation
when a return instruction was present in inner try-catch block.
The fix is to update the JUMP offset appropriately.
This closes #553 issue on Github.
diffstat:
src/njs_generator.c | 41 +++++++++++++++++++++++++++++++++-
src/test/njs_unit_test.c | 56 +++++++++++++++++++++++++++++++++++++----------
2 files changed, 83 insertions(+), 14 deletions(-)
diffs (140 lines):
diff -r 116b09a57817 -r b7c4e0f714a9 src/njs_generator.c
--- a/src/njs_generator.c Tue Jun 28 22:36:38 2022 -0700
+++ b/src/njs_generator.c Tue Jun 28 23:04:00 2022 -0700
@@ -4495,6 +4495,11 @@ njs_generate_try_catch(njs_vm_t *vm, njs
NJS_GENERATOR_ALL,
&ctx->try_exit_label);
+ /*
+ * block can be NULL when &ctx->try_exit_label is "@return"
+ * for outermost try-catch block.
+ */
+
if (block != NULL) {
patch = njs_generate_make_exit_patch(vm, block,
&ctx->try_exit_label,
@@ -4503,6 +4508,26 @@ njs_generate_try_catch(njs_vm_t *vm, njs
if (njs_slow_path(patch == NULL)) {
return NJS_ERROR;
}
+
+ } else {
+
+ /*
+ * when block == NULL, we still want to patch the "finally"
+ * instruction break_offset.
+ */
+
+ block = njs_generate_find_block(vm, generator->block,
+ NJS_GENERATOR_ALL,
+ &no_label);
+
+ if (block != NULL) {
+ patch = njs_generate_make_exit_patch(vm, block, &no_label,
+ njs_code_offset(generator, finally)
+ + offsetof(njs_vmcode_finally_t, break_offset));
+ if (njs_slow_path(patch == NULL)) {
+ return NJS_ERROR;
+ }
+ }
}
}
}
@@ -4669,8 +4694,7 @@ njs_generate_try_end(njs_vm_t *vm, njs_g
* outermost try-catch block.
*/
block = njs_generate_find_block(vm, generator->block,
- NJS_GENERATOR_ALL
- | NJS_GENERATOR_TRY, dest_label);
+ NJS_GENERATOR_ALL, dest_label);
if (block != NULL) {
patch = njs_generate_make_exit_patch(vm, block, dest_label,
njs_code_offset(generator, finally)
@@ -4678,6 +4702,19 @@ njs_generate_try_end(njs_vm_t *vm, njs_g
if (njs_slow_path(patch == NULL)) {
return NJS_ERROR;
}
+
+ } else {
+
+ block = njs_generate_find_block(vm, generator->block,
+ NJS_GENERATOR_ALL, &no_label);
+ if (block != NULL) {
+ patch = njs_generate_make_exit_patch(vm, block, &no_label,
+ njs_code_offset(generator, finally)
+ + offsetof(njs_vmcode_finally_t, break_offset));
+ if (njs_slow_path(patch == NULL)) {
+ return NJS_ERROR;
+ }
+ }
}
}
diff -r 116b09a57817 -r b7c4e0f714a9 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Tue Jun 28 22:36:38 2022 -0700
+++ b/src/test/njs_unit_test.c Tue Jun 28 23:04:00 2022 -0700
@@ -3411,20 +3411,52 @@ static njs_unit_test_t njs_test[] =
njs_str("a,2") },
{ njs_str("function f(n) { "
- " var r1 = 0, r2 = 0, r3 = 0;"
- " a:{ try { try { "
- " if (n == 0) { break a; } "
- " if (n == 1) { throw 'a'; } "
- " } "
- " catch (e) { break a; } finally { r1++; } } "
- " catch (e) {} "
- " finally { r2++; } "
- " r3++; "
- " }; "
- "return [r1, r2, r3]"
- "}; njs.dump([f(0), f(1), f(3)])"),
+ " var r1 = 0, r2 = 0, r3 = 0;"
+ " a:{ try { try { "
+ " if (n == 0) { break a; } "
+ " if (n == 1) { throw 'a'; } "
+ " } "
+ " catch (e) { break a; } finally { r1++; } } "
+ " catch (e) {} "
+ " finally { r2++; } "
+ " r3++; "
+ " }; "
+ "return [r1, r2, r3]"
+ "}; njs.dump([f(0), f(1), f(3)])"),
njs_str("[[1,1,0],[1,1,0],[1,1,1]]") },
+
+ { njs_str("function f(n) {"
+ " while (1)"
+ " try {"
+ " if (n == 0) { break; }"
+ " if (n == 1) { throw 'a'; }"
+ ""
+ " try { return 42; }"
+ " catch (a) {}"
+ ""
+ " } catch (b) { return b; }"
+ "};"
+ "njs.dump([f(0), f(1), f(2)])"),
+ njs_str("[undefined,'a',42]") },
+
+ { njs_str("function f(n, r) {"
+ " while (1)"
+ " try {"
+ " if (n == 0) { break; }"
+ " if (n == 1) { throw 'a'; }"
+ ""
+ " try { return 42; }"
+ " catch (a) {}"
+ " finally { r.push('in');}"
+ ""
+ " } catch (b) { return b; }"
+ " finally { r.push('out'); }"
+ "};"
+ "function g(n) { var r = []; return [f(n, r), r]}"
+ "njs.dump([g(0), g(1), g(2)])"),
+ njs_str("[[undefined,['out']],['a',['out']],[42,['in','out']]]") },
+
/**/
{ njs_str("function f() { Object.prototype.toString = 1; };"
More information about the nginx-devel
mailing list