[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