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

OSv freezes when exception is thrown out of main #64

Closed
tgrabiec opened this issue Oct 21, 2013 · 4 comments
Closed

OSv freezes when exception is thrown out of main #64

tgrabiec opened this issue Oct 21, 2013 · 4 comments
Assignees

Comments

@tgrabiec
Copy link
Member

OSv freezes when running the following program:

  int main(int argc, char const *argv[])
  {
    throw 1;
  }
  (gdb) where
  #0  0x000000000046de20 in uw_frame_state_for ()
  #1  0x000000000046fa93 in _Unwind_RaiseException ()
  #2  0x000000000039e062 in __cxa_throw ()
  #3  0x0000100000000780 in ?? ()
  #4  0x00002000001fff20 in ?? ()
  #5  0x0000000000203024 in run_main (prog=<optimized out>, args=<optimized out>)
      at ../../loader.cc:214

Result on Linux:
terminate called after throwing an instance of 'int'
Aborted (core dumped)

@nyh
Copy link
Contributor

nyh commented Oct 21, 2013

On Mon, Oct 21, 2013 at 3:10 PM, Tomasz Grabiec [email protected]:

OSv freezes when running the following program:

int main(int argc, char const *argv[])
{
throw 1;
}

(gdb) where
#0 0x000000000046de20 in uw_frame_state_for ()
#1 #1 0x000000000046fa93 in
_Unwind_RaiseException ()
#2 #2 0x000000000039e062 in
__cxa_throw ()
#3 #3 0x0000100000000780 in
?? ()
#4 #4 0x00002000001fff20
in ?? ()
#5 #5 0x0000000000203024
in run_main (prog=, args=)
at ../../loader.cc:214

Interesting, a regression?

Can you please check tests/tst-except.so?
It also checks "throw 1".

It used to not work correctly, but then I a bug in dl_iterate_phdr and it
worked. If it doesn't now we have a regression and we can bisect it.

Result on Linux:
terminate called after throwing an instance of 'int'
Aborted (core dumped)


Reply to this email directly or view it on GitHubhttps://github.com//issues/64
.

Nadav Har'El
[email protected]

@tgrabiec
Copy link
Member Author

tst-except passes, probably because exception does not go out of main

2013/10/21 nyh [email protected]

On Mon, Oct 21, 2013 at 3:10 PM, Tomasz Grabiec [email protected]:

OSv freezes when running the following program:

int main(int argc, char const *argv[])
{
throw 1;
}

(gdb) where
#0 0x000000000046de20 in uw_frame_state_for ()
#1 #1 0x000000000046fa93
in
_Unwind_RaiseException ()
#2 #2 0x000000000039e062
in
__cxa_throw ()
#3 #3 0x0000100000000780
in
?? ()
#4 #4
0x00002000001fff20
in ?? ()
#5 #5
0x0000000000203024
in run_main (prog=, args=)
at ../../loader.cc:214

Interesting, a regression?

Can you please check tests/tst-except.so?
It also checks "throw 1".

It used to not work correctly, but then I a bug in dl_iterate_phdr and it
worked. If it doesn't now we have a regression and we can bisect it.

Result on Linux:
terminate called after throwing an instance of 'int'
Aborted (core dumped)


Reply to this email directly or view it on GitHub<
https://github.com/cloudius-systems/osv/issues/64>
.

Nadav Har'El
[email protected]


Reply to this email directly or view it on GitHubhttps://github.com//issues/64#issuecomment-26712536
.

@nyh
Copy link
Contributor

nyh commented Oct 21, 2013

On Mon, Oct 21, 2013 at 3:28 PM, Tomasz Grabiec [email protected]:

tst-except passes, probably because exception does not go out of main

I see... Good (it's obviously much more serious to have a general bug with
exceptions than just having a bug with unhandled exceptions).

Probably the simplest solution is just to add a "try" in loader.cc's
run_main() around the call to main(), and if caught an exception, print a
message (or better yet, follow C++'s normal unhandled exception behavior:
see http://www.cplusplus.com/reference/exception/terminate/ or
http://msdn.microsoft.com/en-us/library/ac9f67ah.aspx.

If you are not planning on doing this (or otherwise solving this bug), I
can.

Nadav Har'El
[email protected]

@tgrabiec
Copy link
Member Author

2013/10/21 nyh [email protected]

On Mon, Oct 21, 2013 at 3:28 PM, Tomasz Grabiec <[email protected]

wrote:

tst-except passes, probably because exception does not go out of main

I see... Good (it's obviously much more serious to have a general bug with
exceptions than just having a bug with unhandled exceptions).

Probably the simplest solution is just to add a "try" in loader.cc's
run_main() around the call to main(), and if caught an exception, print a
message (or better yet, follow C++'s normal unhandled exception behavior:
see http://www.cplusplus.com/reference/exception/terminate/ or
http://msdn.microsoft.com/en-us/library/ac9f67ah.aspx.

If you are not planning on doing this (or otherwise solving this bug), I
can.

I wasn't going to work on this now, so please go ahead.

Nadav Har'El
[email protected]


Reply to this email directly or view it on GitHubhttps://github.com//issues/64#issuecomment-26713086
.

@ghost ghost assigned nyh Oct 21, 2013
nyh added a commit that referenced this issue Oct 23, 2013
As noticed by Tomek in issue #64, unhandled C++ exceptions cause OSv to
silently hang, in an endless loop inside the unwinding code.

So this patch fixes the wrong CFI (DWARF Call Frame Information) which
caused the unwinder to loop. We just had a single line of assembly missing:
The topmost frame - the thread's main function - needs to undefine the
saved %rip to prevent going further back. If we don't do that, gdb will
end every "bt" output with a warning "Frame did not save its PC" (but hey,
nobody complained... ;-)), and the unwinding library, will, unfortunately,
go into an endless loop as seen in issue #64.

With this one-line patch, unhandled exceptions now work as expected -
they abort with a message like:

	terminate called after throwing an instance of 'int'
	Aborted

And attaching a debugger you can see exactly where the offending throw came
from (i.e., the stack does *not* unnecessarily unwind when there's nobody
waiting to catch the exception).

This works for uncaught exceptions anywhere - including inside main()
and from constructors when loading the object (before running main()).

"bt" in gdb also no longer ends each stack trace with an error message.
The last frame it shows is "thread_main()".

Signed-off-by: Nadav Har'El <[email protected]>
@nyh nyh closed this as completed Oct 23, 2013
nyh added a commit that referenced this issue Oct 27, 2013
Commit 7fc023e fixed issue #64, and
made unhandled exceptions work correctly.

This patch adds a test to tst-except.cc to test this - that an unhandled
exception really does call the custom termination handler that the C++
standard allows to set (before the above commit, this test would hang).

Unfortunately, gcc's libsupc++ tries very hard to ensure that the
terminination handler really does abort - if the handler returns, or
throws an exception, the library nevertheless aborts. So we need to
trick it with an ugly longjmp to make this test be able to complete
without aborting the system.

Signed-off-by: Nadav Har'El <[email protected]>
wkozaczuk pushed a commit that referenced this issue Mar 17, 2021
d8-d15 are callee-saved registers [1], and since q8-q15 are listed in the
clobber list in the inline asm, the compiler added instructions to save and
restore d8-d15 from the stack.

To be exact, fpu_state_load() was surrounded by callee-register-saving snippets
like this, for example:

stp     d8, d9, [sp, #48]
stp     d10, d11, [sp, #64]
stp     d12, d13, [sp, #80]
stp     d14, d15, [sp, #96]

... our inline asm here ...

ldp     d8, d9, [sp, #48]
ldp     d10, d11, [sp, #64]
ldp     d12, d13, [sp, #80]
ldp     d14, d15, [sp, #96]

This was effectively zeroing out the upper 64 bits of q8-q15 during interrupts
and pre-emptive context switches.

Two possible ways to work around this issue would be to remove q8-q15 from the
clobber list, or to move the implementation to a real assembly file.

I chose to move fpu_state_save/load to assembly (entry.S) to guarantee that the
compiler won't potentially add any unwanted instructions. This also takes out
any guesswork of how the syntax of inline assembly works.

[1] https://developer.arm.com/documentation/ihi0055/latest/
    See section "SIMD and Floating-Point Registers"

[2] d8-d15 is the 64-bit name for v8-v15
    q8-q15 is the 128-bit name for v8-v15

Signed-off-by: Stewart Hildebrand <[email protected]>
Message-Id: <[email protected]>
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

No branches or pull requests

2 participants