Open fatcerberus opened 6 years ago
I've found that if I enable first-chance exceptions, I will get called back for a throw after an await but in that case uncaught
is set to false, i.e. the Chakra debugger erroneously considers the error to be handled. I'm trying to look into the cause of this but I haven't turned up any leads yet.
Nevermind, I was wrong - the error after the await doesn't generate a first-chance exception either.
@fatcerberus the throw new Error("*munch*");
will not be executed unless you call the .then(...
on ch.exe you see the first chance exception will be generated when you do
/**exception(all):stack();**/
async function f()
{
await null;
throw new Error("*munch*");
}
f().then( function (result) {
console.log('here 1 ' + result);
},
function (error) {
console.log('here 2 ' + error);
});
same is true if you debug in the Edge using F12.
@akroshg That doesn’t seem right: #4608 implements uncaught rejection notifications and if what you say is true that means we won’t get a rejected promise notification for this code. But my own experience has proven the opposite.
I am not sure about #4608, but what I meant was it generates the first chance exception. Is that not what you see?
You say the throw won’t be executed until someone adds a .then() to the promise, which doesn’t make sense since in that case #4608 wouldn’t work (it does).
hmm, I must be mistaken then.
Comparing this with HostPromiseRejectionTracker (#4608) is a bit of a misnomer. The detection mechanisms are totally different.
With HostPromiseRejectionTracker the trigger is whenever a promise is rejected to check if it's got a handler or not - to be honest I have no idea what the trigger the debugger uses is.
The above case:
async function f()
{
await null;
throw new Error("*munch*");
}
f();
Roughly de-sugars to:
function f()
{
var p = Promise.Resolve(null);
var prom;
p.then(()=>{
try{
throw new Error("*munch*");//
}
catch(e){
prom = Promise.Reject(e);//-> rejected promise with no handler
// -> triggers HostPromiseRejectionTracker
}
}
return prom;
}
f();
(I note that there should be 1 more try catch block and at least one more throwaway promise to write that fully but it just gets unnecessarily messy)
The throw definitely fires - but the debugger does not flag for it - you can catch and log the error if wanted of course.
@rhuanjl Right, I know they’re different mechanisms. I was just referring specifically to akroshg’s assertion that the throw is not executed at all, which clearly isn’t the case or else rejection tracking would be pointless.
This seems to be the culprit: https://github.com/Microsoft/ChakraCore/blob/002e9be2aa8c8ea29ce37a605c7f6c6baa2890bd/lib/Runtime/Debug/ProbeContainer.cpp#L1026-L1029
In the case of the following code:
async function f() {
await null;
throw new Error();
}
f();
When deciding whether to pass this exception onto the debugger, ChakraCore considers the thrown exception to both:
While 1) is true, 2) most definitely isn't as there is no catch
in the async function. The exception is caught directly by the runtime in order to reject a promise.
I've taken a quick look at this, and I believe that the issue is not Async functions at all but rather the way Promise reactions are implemented
An alternative repro of this issue would be:
Promise.resolve().then(()=>{throw new Error("hunger increases");});
No break point is seen in the debugger for this code.
In JavascriptPromise.cpp the following function call occurs in 2 different methods that handle promise reactions:
Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
I believe from looking over the code that this turns off debugger break points until it's disabled again I assume there is a purpose for this - but I'll be honest I don't really understand some parts of this code at the moment, could the fix perhaps be to only set that if the promise IsHandled?
See PR #5328 for a fix here a fix for exceptions in promises w/out handlers hooked up.
While debugging is enabled, if one throws an error inside of an async function:
Normally, such an error would be intercepted and trigger a breakpoint (
JsDiagDebugEventRuntimeException
):However, if one were to uncomment the
await
in the code above, no breakpoint will be triggered and the promise is just silently rejected:Update (6/26/2018): There are multiple work items here & I wanted to break them out independently. Will leave this open to track getting this to work w/ async/await. The other issues are:
RE async/await, it looks like we'll need to do some work to update byte-code-generation & possibly jit code so that we understand syntactic constructs that result in a "handled" async functions.