]> git.kaiwu.me - njs.git/commitdiff
Fixed frame allocation from an awaited frame.
authorDmitry Volyntsev <xeioex@nginx.com>
Mon, 21 Feb 2022 16:52:59 +0000 (16:52 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Mon, 21 Feb 2022 16:52:59 +0000 (16:52 +0000)
njs_function_frame_save() is used to save the awaited frame when "await"
instruction is encountered. The saving was done as a memcpy() of
existing runtime frame.

njs_function_frame_alloc() is used to alloc a new function frame, this
function tries to use a spare preallocated memory from the previous
frame first.  Previously, this function might result in "use-after-free"
when invoked from a restored frame saved with njs_function_frame_save().
Because njs_function_frame_save() left pointers to the spare memory of
the original frame which may be already free when saved frame is
restored.

The fix is to erase fields for the spare memory from the saved frame.

This closes #469 issue on Github.

src/njs_function.c
test/js/async_recursive_large.t.js [new file with mode: 0644]
test/js/async_recursive_mid.t.js

index c9d4d9732fd262af1636cb63fcaa3b4327caaa6a..78857e01e50fa93dd7194ca326e56b8d0c1c6e89 100644 (file)
@@ -811,9 +811,13 @@ njs_function_frame_save(njs_vm_t *vm, njs_frame_t *frame, u_char *pc)
     njs_native_frame_t  *active, *native;
 
     *frame = *vm->active_frame;
+
     frame->previous_active_frame = NULL;
 
     native = &frame->native;
+    native->size = 0;
+    native->free = NULL;
+    native->free_size = 0;
 
     active = &vm->active_frame->native;
     value_count = njs_function_frame_value_count(active);
diff --git a/test/js/async_recursive_large.t.js b/test/js/async_recursive_large.t.js
new file mode 100644 (file)
index 0000000..423e8d0
--- /dev/null
@@ -0,0 +1,26 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+async function f(v) {
+    if (v == 1000) {
+        return;
+    }
+
+    stages.push(`f>${v}`);
+
+    await "X";
+
+    await f(v + 1);
+
+    stages.push(`f<${v}`);
+}
+
+f(0)
+.then(v => {
+    assert.sameValue(stages.length, 2000);
+})
+.then($DONE, $DONE);
index 4d3a9fd197d632f1a2d20f6ff21f2d15f8b51cea..6b67796298d6dca81fca1c58ed472fa7e4c3f36a 100644 (file)
@@ -6,7 +6,7 @@ flags: [async]
 let stages = [];
 
 async function f(v) {
-    if (v == 3) {
+    if (v == 1000) {
         return;
     }