-
Notifications
You must be signed in to change notification settings - Fork 54
Trap Result #151
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
Trap Result #151
Conversation
…lt<T>`, `ResultWithBacktrace<T>`) which provide a better method for trap handling than exceptions. function wrappers accept these types instead of the actual return type and then, if a trap happens, it is returned in this result struct instead of as an exception. - `Result` represents a function with no return value, which does not capture the trap backtrace. - `ResultWithBacktrace` represents a function with no return value, which captures the trap backtrace. - `Result<T>` represents a function which returns `T`, which does not capture the trap backtrace. - `ResultWithBacktrace<T>` represents a function which returns `T`, which captures the trap backtrace. Also some associated to the `TrapException`: - Added a `TrapCode Type` property, which was an obvious omission from traps - Modified `FunctionOffset` and `ModuleOffset` of the `TrapFrame` to use `nuint` instead of `int` (which could cause an arithmetic overflow)
I'm not sure what the macos failure is caused by, it looks like something wrong with the CI process itself? |
That error looks an awful lot like the crashes I would see when testing throwing exceptions in WasmerSharp and Wasmtime to compare. It happened locally on mac but not windows. Frustrating to discover. I only mention it to caution against assuming the CI itself is at fault. |
Unfortunately I don't have access to a mac to test on. Any hints on what fixed the problem for you that I could try? |
I can try pulling your fork and see what happens for me later tonight or tomorrow. My solution was to stop using WasmerSharp. Useful, right? Ha. It just feels too much of a coincidence, given you are working with the traps, and I was testing how the two runtimes handled exceptions. |
I can confirm |
Thanks for the testing, that at least confirms it isn't just a flakey CI problem. |
If possible could you share the log from the test on your Mac? Hopefully that will contain more useful information than the CI log. |
I have worked around the CI failure on MacOS by replacing the stackoverflow errors with integer div zero errors. I think the problem with MacOS+Stackoverflow is a bug in wasmtime-dotnet, independent of the changes in this PR. I've pushed up #152 which includes a test that I expect to fail on MacOS to help identify the issue. |
Hi @martindevans! I'll review this today and dig into the stack overflow trap crashing the test host. |
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.
This looks great and I love the opt-in nature of it!
Just a few comments; almost all of them are minor nits.
tests/TrapTests.cs
Outdated
var result = run(); | ||
|
||
result.Type.Should().Be(ResultType.Trap); | ||
result.Trap.Should().Be(TrapCode.IntegerDivisionByZero); |
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.
Should we be asserting here (and in ItReturnsATrapCodeGenericResult
) that the frames are empty?
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.
Unless I'm misunderstanding what you're asking for I don't think that's possible in those two cases. They're both Result
types (not ResultWithBacktrace
) so the only thing available is the TrapCode
, the backtrace is not available.
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.
Oh right, the name Trap
threw me off here. It should probably be, at the minimum, TrapCode
so it doesn't seem like the whole trap exception is being stored.
Stepping back, though, should we not store a TrapException
for the non-backtrace capturing Result
types too, just without Frames
populated?
I think it'd be useful to get the message in addition to the code, just without the backtrace.
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.
Good point on the naming, I'll change that now 👍
Regarding the TrapException
/message
my intention was to have the Result
be as lightweight as possible, avoiding allocating a TrapException
and the message string. Personally I would prefer to keep it that way.
Maybe the problem here is naming - Result
(the simpler name) is the opt-in to a lighter weight version with no useful debugging information. Perhaps instead they should be named Result
(with a backtrace) and ResultWithoutAnyUsefulInformation
(pending a better name). That way it's probably more obvious that the version with the backtrace is the one you "should" use?
Having said all that, I'm wondering if another possible way to do this is instead of having some special "blessed types" which can interact with traps we should instead detect if the return type implements a special interface and then do things through that. That way we can ship a single Result
type with backtraces/messages etc, but there's a door to hook into the trap system (in a safe way of course) and get just what you need. If you don't mind holding off on this PR for a while I'll experiment with that approach to see if it's feasible.
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.
Sounds good, I'll hold off on the PR to see what you come up with.
I'm also good with landing this PR if that's what you decide is best.
I've pushed up a commit that should address all feedback, except that last point. Thanks for the excellent review, as usual 👍 |
I've pushed up #153 which further develops this idea with a system for custom result types. Although the details of how it works are more complex I think it offers a better user experience for the 99% of users who can just use |
Closing this as superseded with #153. |
Added in 4 new
Result
types (Result
,ResultWithBacktrace
,Result<T>
,ResultWithBacktrace<T>
) which provide a better method for trap handling than exceptions. This entire new system is opt-in, the function wrappers accept these types instead of the actual return type and then, if a trap happens, it is returned in this result struct instead of as an exception.Result
represents a function with no return value, which does not capture the trap backtrace.ResultWithBacktrace
represents a function with no return value, which captures the trap backtrace.Result<T>
represents a function which returnsT
, which does not capture the trap backtrace.ResultWithBacktrace<T>
represents a function which returnsT
, which captures the trap backtrace.Also some associated to the
TrapException
:TrapCode Type
property, which was an obvious omission from trapsFunctionOffset
andModuleOffset
of theTrapFrame
to usenuint
instead ofint
(which could cause an arithmetic overflow) (see Overflow Exception In Trap Handling #150)