Skip to content
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

[runtime] Setup stack trace for use in exception filters too #8241

Merged
merged 1 commit into from Apr 24, 2018

Conversation

radical
Copy link
Member

@radical radical commented Apr 13, 2018

If we have
catch (Exception e) when (SomeMethod (e))

.. then the exception object received in SomeMethod has an empty
trace. This is because in handle_exception_first_pass we populate the
trace in MonoException object only at the "end":

- filter returns TRUE
- exception caught
- unhandled exception

But if we have a filter then the trace at that point needs to be
accessible. And if the filter fails then as we unwind more frames, the
earlier frames (trace_ips) need to be retained to get the correct full
trace.

dynamic_methods needs to be handled similarly and in
setup_stack_trace we need to add to the existing dynamic_methods in
the MonoException object.

Fixes #7649 .

@radical
Copy link
Member Author

radical commented Apr 13, 2018

I don't know how to have a test case for the mono_ex->dynamic_methods change (combine the new dynamic_methods with the existing one in the MonoException object). It isn't being used anywhere else or being surfaced. But the change makes sense to me. And I did try it with a test case where I had two dynamic methods and without this, at the end we have reference to only one dynamic method.

@radical
Copy link
Member Author

radical commented Apr 13, 2018

Also, reading handle_exception_first_pass, https://github.com/mono/mono/blob/master/mono/mini/mini-exceptions.c#L1654 suggests that this function can be called with a MonoException object which already has traces (and hence possibly dynamic_methods?). I tried to get to this case by : catching an exception which had 2 dynamic methods in it's trace. And then throwing that same exception object in a different callstack but I found that this time the object had no trace_ips, but it still had the two dynamic_methods! So, somebody is clearing trace_ips for the rethrow but forgot to clean up dynamic_methods too?

I'm not very familiar with the code, so I might be making sense only in my head :)

@radical
Copy link
Member Author

radical commented Apr 13, 2018

Linux x64 - all the tests passed but the build failed at csprojdiff step.

@luhenry
Copy link
Contributor

luhenry commented Apr 15, 2018

@alexanderkyte @vargaz could you please review?

// Single frame
// Filter returns false
try {
throw e;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you reuse the exception here? Also, you should mark Throw () with [MethodImpl(MethodImplOptions.NoInlining)], otherwise the framecount is 1 too very likely.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question. This was based on exception19.cs where the exception was being reused too. I think maybe we can enhance this to test that the trace was indeed reset when the filter invoked. Currently, trace from both the original exception and the new trace here would have 1 frame, but if we change Throw to instead have two frames then we will be checking if the filter got a new trace or not. How does that sound?

+		} catch (Exception ex) when (CheckTrace (ex, 2, true)) {
+			CheckTrace (ex, 2);
+		}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good 👍

Copy link
Contributor

@lewurm lewurm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, good job! I'm not 100% sure about the dynamic_methods stuff. It looks like it makes sense, and also doesn't break any tests.

If we have
	`catch (Exception e) when (SomeMethod (e))`

.. then the exception object received in `SomeMethod` has an empty
trace. This is because in `handle_exception_first_pass` we populate the
trace in `MonoException` object only at the "end":

	- filter returns TRUE
	- exception caught
	- unhandled exception

But if we have a filter then the trace at that point needs to be
accessible. And if the filter fails then as we unwind more frames, the
earlier frames (`trace_ips`) need to be retained to get the correct full
trace.

`dynamic_methods` needs to be handled similarly and in
`setup_stack_trace` we need to add to the existing `dynamic_methods` in
the MonoException object.

Fixes mono#7649 .
@radical
Copy link
Member Author

radical commented Apr 21, 2018

@radical
Copy link
Member Author

radical commented Apr 21, 2018

The runtime crashed while running some System/System.Xml tests. Looking at the trace I don't think my patch caused it but I don't know what made it crash.

https://gist.github.com/radical/0996979b5fdd2dce6f1b0a460a0d6e27

.. for Linux AArch64

@lewurm
Copy link
Contributor

lewurm commented Apr 22, 2018

@monojenkins build Linux ARMv7

@lewurm
Copy link
Contributor

lewurm commented Apr 22, 2018

@monojenkins build Linux ARMv5

@lewurm
Copy link
Contributor

lewurm commented Apr 22, 2018

@monojenkins build Linux AArch64

@luhenry
Copy link
Contributor

luhenry commented Apr 23, 2018

@monojenkins build Linux ARMv7

@luhenry
Copy link
Contributor

luhenry commented Apr 23, 2018

@monojenkins build Linux AArch64

@lewurm
Copy link
Contributor

lewurm commented Apr 23, 2018

@monojenkins rebase

@luhenry luhenry merged commit 963f944 into mono:master Apr 24, 2018
@radical radical deleted the fix-filter-trace branch April 25, 2018 03:22
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…no#8241)

If we have
	`catch (Exception e) when (SomeMethod (e))`

.. then the exception object received in `SomeMethod` has an empty
trace. This is because in `handle_exception_first_pass` we populate the
trace in `MonoException` object only at the "end":

	- filter returns TRUE
	- exception caught
	- unhandled exception

But if we have a filter then the trace at that point needs to be
accessible. And if the filter fails then as we unwind more frames, the
earlier frames (`trace_ips`) need to be retained to get the correct full
trace.

`dynamic_methods` needs to be handled similarly and in
`setup_stack_trace` we need to add to the existing `dynamic_methods` in
the MonoException object.

Fixes mono/mono#7649 .

Commit migrated from mono/mono@963f944
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Exception stacktrace is null when task delegate is created from local function
3 participants