-
Notifications
You must be signed in to change notification settings - Fork 39
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
forbid hook routines raising exceptions #1236
forbid hook routines raising exceptions #1236
Conversation
The beginning of a language specification test category dedicated to hooks is added. At the moment, only the exception-effect-related behaviour is covered.
The procedure symbol is also marked with the `sfNeverRaises` flag, so that defects are prevented from escaping at run-time (they're not tracked at compile-time). A new report is added: `rsemHooksCannotRaise`.
Lifting/synthesizing hooks no longer needs to track whether an exception is possible.
They're guaranteed to not require exception propagation, so a normal `mnkCall` can always be used. The comment detailing the now-resolved problem with hooks that raise is also removed.
If a procedure is flagged with `sfNeverRaises`, the body is wrapped in a catch-all exception handler, where the new `nimUnhandledException` runtime procedure is invoked from the handler. If the handler is not actually used, `cgirgen`'s unreachable code elimination automatically eliminates it again. Implementing this in `mirgen` ensures consistent behaviour across all backends.
For the VM, it's not as simple as for the other two, so the implementation is still missing.
The trace hooks were considered to be able to raise exceptions and have effects, but this is no longer the case, so the pointer can be safely cast to procedural values without.
The callback is only used internally, so this does not constitute a breaking change of the `Task` API.
Three individual tests need to be adjusted to the language change: * `tnew` and `gctest use `debugEcho` instead of `write` (the former has no effects) * `tarcmisc` has to cast away the raise effects of `Stream.close` for now
Hooks not being considered as potentially raising is visible in the pretty-printed MIR output.
Reporting of unhandled exceptions doesn't include a trailing ':' in the displayed message if there's no exception message. A message is now set on the raised defect, which, besides resulting in consistent output, also helps makes sure that the correct defect is reported.
The procedure is implemented as a syscall (`vmops`), which raises the existing `vmEvtUnhandledException` VM event, thus terminating the VM right away. Since syscall implementations are currently unable to create a stack- trace, no stack-trace is passed along, which `compilerbridge.buildError` now accounts for (by creating the stack- trace itself). This is somewhat hack-y.
While not possible directly with JavaScript, node.js provides `process.exit`, which allows terminating in case of an unhandled exception.
For user-defined effects (tags) the same reasoning applies, meaning that |
In line with what @saem started for the specification test cleanup, I've used a |
The quoted bullet point below is incomplete, want write sure what you meant to write:
|
Oh, indeed. I've completed the sentence now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very cool, there is the bit in the PR body, but this is good to merge afterwards.
/merge |
Merge requested by: @saem Contents after the first section break of the PR description has been removed and preserved below:
|
Summary
This is enforced as follows:
error is reported
Exception effects of hooks side-steps effect tracking for
procedures, and if a hook does raise at run-time, behaviour was
previously undefined. Disallowing hooks to raise exceptions resolves
both issues.
Performance of the produced executables also improves significantly
(depending on the code), as destroy hooks not being able to raise
results in better code generation.
Details
The implementation is made up of three parts:
sempass2
)mirgen
/liftdestructors
)Static Detection
sfOverriden
flag,sempass2
tests against an empty.raises
specification, ensuringthat no (tracked) exceptions can be raised
.raises: []
was explicitly specified, togive precedence to the
can raise unlisted exception
error.sfNeverRaises
, to enforce atrun-time that no exceptions (defects) leave the routine
The meaning of
sfNeverRaises
is changed from being a hint/guaranteeto being a request.
Enforcement
mirgen
wraps the body ofsfNeverRaises
procedure in atry: ... except: nimUnhandledException()
cgirgen
removes theexcept
ifit's not used in practice
liftdestructors
) are flagged withsfNeverRaises
; thecanRaise
tracking is removedRuntimes
nimUnhandledException
displays the exception and quitsthe process
nimUnhandledException
displays the exceptionand quits the process
nimUnhandledException
re-raises theexception (there's currently no way to terminate the program)
nimUnhandledException
is avmop
that raises avmEvtUnhandledException
event, which aborts executionStandard Library and Tests
Task
=destroy
hook being inferred to raise exceptionsGC_fullCollect
being inferred to raise exceptionsTests
Three individual tests need to be adjusted to the language change:
tnew
andgctest
usedebugEcho
instead ofwrite
(the formerhas no effects)
tarcmisc
has to cast away the raise effects ofStream.close
fornow
Specification
The beginnings of a specification test category for hook routines is
added. At the moment, it only covers the exception behaviour.