GNOME Bugzilla – Bug 779692
System.exit() should exit even across main loop iterations
Last modified: 2017-03-08 06:29:58 UTC
Script to reproduce: const GLib = imports.gi.GLib; const System = imports.system; GLib.idle_add(GLib.PRIORITY_LOW, () => { System.exit(42); }); let loop = GLib.MainLoop.new(null, false); loop.run(); Since we switched to implementing System.exit() with an uncatchable exception so that the JSContext could be cleaned up properly, now the exception is dropped when transiting across the FFI boundary, similar to bug 682701.
Created attachment 347441 [details] [review] closure: Fix error when closure debug enabled We don't compile with GJS_VERBOSE_ENABLE_GCLOSURE defined too often, so sometimes errors slip through.
Created attachment 347442 [details] [review] tests: Use bash TAP functions in bash script Previously these tests did nothing because the call to the nonexistent "fail" function simply failed quietly and didn't print any TAP output.
Created attachment 347443 [details] [review] function: Perform dirty exit at FFI boundary If an "uncatchable" (SpiderMonkey term) exception is thrown (that is, return false from a JSAPI call without an exception pending on the JSContext), then we have to deal with the condition when returning back to C code. We use the uncatchable exception mechanism to implement System.exit(), and so gjs_context_eval() checks for this and exits if appropriate. However, when calling System.exit() inside a callback marshalled by FFI, the uncatchable exception propagates up to gjs_callback_closure() and stopes there. There is nothing that can propagate the exception after that point. There may be one or more main loops running, and until they exit, we don't even get back to our JSAPI code that will propagate the exception up to gjs_context_eval(). Therefore, we do a "dirty exit" (our term) if an FFI callback throws an uncatchable exception. This will, unfortunately, trip an assertion if SpiderMonkey is compiled in debug mode, because we haven't cleaned up the JSContext by the time the JSRuntime is destroyed when the thread exits. We can't clean up the JSContext, either, because the caller of gjs_context_eval() is still holding a request on the JSContext so if we did that we would trip a different assertion. This SpiderMonkey limitation is reflected in the added test, whereby the test will still pass if the script exits with any nonzero code, which covers the debug-mode case where we fail the assertion.
Review of attachment 347441 [details] [review]: Looks good.
Review of attachment 347442 [details] [review]: Sure
Review of attachment 347443 [details] [review]: OK
Attachment 347441 [details] pushed as 6f427d1 - closure: Fix error when closure debug enabled Attachment 347442 [details] pushed as 63c9c5c - tests: Use bash TAP functions in bash script Attachment 347443 [details] pushed as c7bdcaa - function: Perform dirty exit at FFI boundary