This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Problems with _Unwind_Backtrace() vs signal handlers
- From: Andrew Haley <aph at redhat dot com>
- To: Bryce McKinlay <mckinlay at redhat dot com>
- Cc: gcc at gcc dot gnu dot org
- Date: Mon, 2 Aug 2004 12:14:38 +0100
- Subject: Problems with _Unwind_Backtrace() vs signal handlers
- References: <410C33B6.1030903@redhat.com>
Bryce McKinlay writes:
> libjava wants to use _Unwind_Backtrace() and friends to print diagnostic
> stack traces for exceptions (as well as examine the stack for security
> checks, etc). There appears to be a problem when trying to
> _Unwind_Backtrace through signal handler frames.
>
> For a normal call, the IP returned by _Unwind_GetIP() is the return
> address for the frame above it - that is, the instruction following the
> "call" instruction. When unwinding through a signal handler, however,
> _Unwind_GetIP() returns a pointer to the faulting instruction. This
> inconsistency makes it difficult for libjava to print the correct source
> line number for NullPointerExceptions, and I suspect it also has
> something to do with the next problem:
>
> The test case below is a simplification of what libjava is doing when it
> tries to print a stack trace for a NullPointerException. When compiled
> with no optimization, it works ok, but when compiled with -O2, the
> _Unwind_Backtrace() either misses/skips over some frames, or terminates
> prematurely. I tried this test on i686, x86-64, and ppc-32, and it seems
> more or less consistently broken on each of those platforms.
>
> Note that the unwinder seems to work fine through the signal frame to
> find an exception handler, it is just _Unwind_Backtrace() that fails.
We've been around this one a bunch of times before. The problem is
that some signal handlers point the return address at the faulting
instruction, and some at the following instruction. Various ports of
libgcj do various things to cope.
See:
http://gcc.gnu.org/ml/gcc-patches/2004-06/msg02631.html
When a signal handler is called in libgcj, we call MAKE_THROW_FRAME,
and this fixes the frame on the stack so that _Unwind_GetIP() returns
a pointer to the following instruction.
I see that the signal handlers in libgcj create the exception before
calling MAKE_THROW_FRAME: that's a bug. In the past this wasn't a bug
because we didn't use the unwinder to generate the stack trace.
We shouldn't see an incorrect return address unless we're calling
_Unwind_Backtrace before MAKE_THROW_FRAME, and there's no reason to do
that.
I suggest you try something like
SIGNAL_HANDLER (catch_segv)
{
unblock_signal (SIGSEGV);
MAKE_THROW_FRAME (nullp);
java::lang::NullPointerException *nullp
= new java::lang::NullPointerException;
throw nullp;
}
Andrew.