-
-
Notifications
You must be signed in to change notification settings - Fork 394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[oxc_semantics] Improper return register when finally
block throws
#2240
Comments
I'd note the result is not implementation defined, per https://tc39.es/ecma262/#sec-try-statement-runtime-semantics-evaluation invoking UpdateEmpty(C, undefined). |
By implementation defined, I meant that the actual |
This was based on my understanding of https://tc39.es/ecma262/#sec-object-internal-methods-and-internal-slots, although I imagine I'm reading it incorrectly. |
@TzviPM I think https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist might be what you are meaning to get to at 10.2.1.10 ? |
Ah, I see: https://tc39.es/ecma262/#sec-ecmascript-function-objects
In https://tc39.es/ecma262/#sec-object-internal-methods-and-internal-slots:
The semantics for a function call are in https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation. The EvaluateCall semantics defers to Call which in turn results in |
@TzviPM correct, though I don't know of an engine that allows for it to do so even with exotic host objects. |
I suspect it is fixed in our new CFG implementation since we don't use registers anymore instead we are creating a simple control flow pointing to appropriate AST nodes. For this code: function not_foo() {
try {
try {
return "foo";
} finally {
throw "foo";
}
} catch (e) {
// do nothing
}
} Now we have this flow: new CFG Visualization Old CFG Visualization And for this: function not_foo() {
try {
return "foo"
} finally {
try {
try {
return "bar";
} finally {
throw "foo";
}
} catch {
// do nothing
}
}
} We get this flow: new CFG Visaulization Old CFG Visualization Both of which seems alright to me, I don't close this issue in case there is another issue I haven't noticed yet. |
@Boshen I think this can be close, Don't you think? |
Consider the following code:
What should the return value of this function be?
According to the ES Spec:
The
try
statement runtime semantics are defined at https://tc39.es/ecma262/#sec-try-statement-runtime-semantics-evaluation:B
:B
:SV
of"foo"
is"foo"
as per https://tc39.es/ecma262/#sec-static-semantics-sv{ [[Type]]: RETURN, [[Value]]: "foo", [[Target]]: EMPTY }
as per https://tc39.es/ecma262/#sec-return-statement-runtime-semantics-evaluationF
:SV
of"foo"
is"foo"
as per https://tc39.es/ecma262/#sec-static-semantics-sv{ [[Type]]: THROW, [[Value]]: "foo", [[Target]]: EMPTY }
as per https://tc39.es/ecma262/#sec-throw-statement-runtime-semantics-evaluationF
is not anormal completion
, do not setF
toB
.F
is athrow completion
, its value is notEMPTY
as per https://tc39.es/ecma262/#sec-updateempty, so returnF
B
is a throw completion, letC
be the result of the catch block withe
bound to"foo"
:EMPTY
as per https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluationreturn EMPTY
is actually an editorial error and should be taken to meanNormalCompletion(EMPTY)
.{ [[Type]]: NORMAL, [[Value]]: EMPTY, [[Target]]: EMPTY }
C
has a value ofEMPTY
, return{ [[Type]]: NORMAL, [[Value]]: undefined, [[Target]]: EMPTY }
as per https://tc39.es/ecma262/#sec-updateemptyWhen calling
foo()
, the result is technically implementation-defined (i.e. not part of the ES spec), but the standard behaviour, sincefoo
results in anormal completion
would be to returnundefined
as per https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist.The problem in our current CFG:
We store return values into a register called
$return
:try-catch
, we set theafter_throw
block to a reservedcatch
block.try
block, we set register to"foo"
.try
block completes, there isNormal
edge going to thefinally
block.after_throw
block (in this case, thecatch
).We see, thus, that the end result of the CFG flow leads to a value of
"foo"
in the$return
register.Solution space
One option is to somehow unset the
return
register when a finally block issues athrow
. The problem with this is:In this code, the throw from the innermost
finally
causes itstry
's"bar"
return value to be unset, but since thecatch
squashes this, the outermostfinally
is a normal completion, and thus this entire statement should still return"foo"
.Another approach would be to ditch the idea of a
$return
register and instead manage completion records more rigorously.The text was updated successfully, but these errors were encountered: