This will crash on Windows but appears to succeed on Linux, however Valgrind reports a use-after-free issue. Windows builds with /fsanitize=address (or -fsanitize) result in a similar report.
On Windows the crash comes from JS_RunGC (either called manually or during JS_FreeRuntime). The top of the call stack is JS_FreeValueRT coming from the finalizer for js_c_function_data_finalizer with a JSCFunctionDataRecord containing js_async_module_execution_fulfilled.
A few things to note:
If the promise is first resolved or rejected, no crash or UAF reported.
If the await is omitted, no issue.
Running with standard qjs.c with this test script does not repro because it will not exit with an unhandled promise.
==29640== Memcheck, a memory error detector
==29640== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==29640== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==29640== Command: ./qjs-debug
==29640==
==29640== Invalid read of size 4
==29640== at 0x116951: JS_FreeValueRT (quickjs.h:661)
==29640== by 0x120984: js_c_function_data_finalizer (quickjs.c:5106)
==29640== by 0x121937: free_object (quickjs.c:5467)
==29640== by 0x121A14: free_gc_object (quickjs.c:5487)
==29640== by 0x1226A1: gc_free_cycles (quickjs.c:5837)
==29640== by 0x1227E8: JS_RunGC (quickjs.c:5868)
==29640== by 0x1185F1: JS_FreeRuntime (quickjs.c:1956)
==29640== by 0x116141: main (qjs.c:581)
==29640== Address 0x4baaa60 is 0 bytes inside a block of size 280 free'd
==29640== at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==29640== by 0x117E8A: js_def_free (quickjs.c:1744)
==29640== by 0x117124: js_free_rt (quickjs.c:1320)
==29640== by 0x1172E9: js_free (quickjs.c:1375)
==29640== by 0x168CBC: js_free_module_def (quickjs.c:27323)
==29640== by 0x118C4C: js_free_modules (quickjs.c:2231)
==29640== by 0x118FAA: JS_FreeContext (quickjs.c:2317)
==29640== by 0x120E31: js_autoinit_free (quickjs.c:5188)
==29640== by 0x120F68: free_property (quickjs.c:5208)
==29640== by 0x12185D: free_object (quickjs.c:5449)
==29640== by 0x121A14: free_gc_object (quickjs.c:5487)
==29640== by 0x1226A1: gc_free_cycles (quickjs.c:5837)
==29640== Block was alloc'd at
==29640== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==29640== by 0x117DDE: js_def_malloc (quickjs.c:1728)
==29640== by 0x1170F2: js_malloc_rt (quickjs.c:1315)
==29640== by 0x1171AC: js_mallocz_rt (quickjs.c:1336)
==29640== by 0x117291: js_mallocz (quickjs.c:1365)
==29640== by 0x168739: js_new_module_def (quickjs.c:27245)
==29640== by 0x17C751: __JS_EvalInternal (quickjs.c:34420)
==29640== by 0x17CC80: JS_EvalInternal (quickjs.c:34504)
==29640== by 0x17CE32: JS_EvalThis (quickjs.c:34535)
==29640== by 0x17CE9A: JS_Eval (quickjs.c:34543)
==29640== by 0x11610A: main (qjs.c:578)
==29640==
==29640== Invalid write of size 4
==29640== at 0x11695A: JS_FreeValueRT (quickjs.h:661)
==29640== by 0x120984: js_c_function_data_finalizer (quickjs.c:5106)
==29640== by 0x121937: free_object (quickjs.c:5467)
==29640== by 0x121A14: free_gc_object (quickjs.c:5487)
==29640== by 0x1226A1: gc_free_cycles (quickjs.c:5837)
==29640== by 0x1227E8: JS_RunGC (quickjs.c:5868)
==29640== by 0x1185F1: JS_FreeRuntime (quickjs.c:1956)
==29640== by 0x116141: main (qjs.c:581)
==29640== Address 0x4baaa60 is 0 bytes inside a block of size 280 free'd
==29640== at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==29640== by 0x117E8A: js_def_free (quickjs.c:1744)
==29640== by 0x117124: js_free_rt (quickjs.c:1320)
==29640== by 0x1172E9: js_free (quickjs.c:1375)
==29640== by 0x168CBC: js_free_module_def (quickjs.c:27323)
==29640== by 0x118C4C: js_free_modules (quickjs.c:2231)
==29640== by 0x118FAA: JS_FreeContext (quickjs.c:2317)
==29640== by 0x120E31: js_autoinit_free (quickjs.c:5188)
==29640== by 0x120F68: free_property (quickjs.c:5208)
==29640== by 0x12185D: free_object (quickjs.c:5449)
==29640== by 0x121A14: free_gc_object (quickjs.c:5487)
==29640== by 0x1226A1: gc_free_cycles (quickjs.c:5837)
==29640== Block was alloc'd at
==29640== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==29640== by 0x117DDE: js_def_malloc (quickjs.c:1728)
==29640== by 0x1170F2: js_malloc_rt (quickjs.c:1315)
==29640== by 0x1171AC: js_mallocz_rt (quickjs.c:1336)
==29640== by 0x117291: js_mallocz (quickjs.c:1365)
==29640== by 0x168739: js_new_module_def (quickjs.c:27245)
==29640== by 0x17C751: __JS_EvalInternal (quickjs.c:34420)
==29640== by 0x17CC80: JS_EvalInternal (quickjs.c:34504)
==29640== by 0x17CE32: JS_EvalThis (quickjs.c:34535)
==29640== by 0x17CE9A: JS_Eval (quickjs.c:34543)
==29640== by 0x11610A: main (qjs.c:578)
==29640==
==29640== Invalid read of size 4
==29640== at 0x116960: JS_FreeValueRT (quickjs.h:661)
==29640== by 0x120984: js_c_function_data_finalizer (quickjs.c:5106)
==29640== by 0x121937: free_object (quickjs.c:5467)
==29640== by 0x121A14: free_gc_object (quickjs.c:5487)
==29640== by 0x1226A1: gc_free_cycles (quickjs.c:5837)
==29640== by 0x1227E8: JS_RunGC (quickjs.c:5868)
==29640== by 0x1185F1: JS_FreeRuntime (quickjs.c:1956)
==29640== by 0x116141: main (qjs.c:581)
==29640== Address 0x4baaa60 is 0 bytes inside a block of size 280 free'd
==29640== at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==29640== by 0x117E8A: js_def_free (quickjs.c:1744)
==29640== by 0x117124: js_free_rt (quickjs.c:1320)
==29640== by 0x1172E9: js_free (quickjs.c:1375)
==29640== by 0x168CBC: js_free_module_def (quickjs.c:27323)
==29640== by 0x118C4C: js_free_modules (quickjs.c:2231)
==29640== by 0x118FAA: JS_FreeContext (quickjs.c:2317)
==29640== by 0x120E31: js_autoinit_free (quickjs.c:5188)
==29640== by 0x120F68: free_property (quickjs.c:5208)
==29640== by 0x12185D: free_object (quickjs.c:5449)
==29640== by 0x121A14: free_gc_object (quickjs.c:5487)
==29640== by 0x1226A1: gc_free_cycles (quickjs.c:5837)
==29640== Block was alloc'd at
==29640== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==29640== by 0x117DDE: js_def_malloc (quickjs.c:1728)
==29640== by 0x1170F2: js_malloc_rt (quickjs.c:1315)
==29640== by 0x1171AC: js_mallocz_rt (quickjs.c:1336)
==29640== by 0x117291: js_mallocz (quickjs.c:1365)
==29640== by 0x168739: js_new_module_def (quickjs.c:27245)
==29640== by 0x17C751: __JS_EvalInternal (quickjs.c:34420)
==29640== by 0x17CC80: JS_EvalInternal (quickjs.c:34504)
==29640== by 0x17CE32: JS_EvalThis (quickjs.c:34535)
==29640== by 0x17CE9A: JS_Eval (quickjs.c:34543)
==29640== by 0x11610A: main (qjs.c:578)
==29640==
==29640==
==29640== HEAP SUMMARY:
==29640== in use at exit: 0 bytes in 0 blocks
==29640== total heap usage: 1,501 allocs, 1,501 frees, 135,153 bytes allocated
==29640==
==29640== All heap blocks were freed -- no leaks are possible
==29640==
==29640== For lists of detected and suppressed errors, rerun with: -s
==29640== ERROR SUMMARY: 6 errors from 3 contexts (suppressed: 0 from 0)
Version 3b45d155c77bbdfe9177b1e03db830d2aff0b2a8
Tested on Windows (vc and clang) and Linux (gcc).
This will crash on Windows but appears to succeed on Linux, however Valgrind reports a use-after-free issue. Windows builds with
/fsanitize=address
(or-fsanitize
) result in a similar report.On Windows the crash comes from
JS_RunGC
(either called manually or duringJS_FreeRuntime
). The top of the call stack isJS_FreeValueRT
coming from the finalizer forjs_c_function_data_finalizer
with aJSCFunctionDataRecord
containingjs_async_module_execution_fulfilled
.A few things to note:
await
is omitted, no issue.Test code
Valgrind output.