This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Problems with _Unwind_Backtrace() vs signal handlers


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.

Bryce

/* Compile with -fnon-call-exceptions */

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

#include <unwind.h>

extern void segv_handler(int sig);
extern int foo() __attribute__ ((noinline));
extern int bar(char *z) __attribute__ ((noinline));

int main(int argc, char *argv)
{
  /* Set up SEGV handler.  */
  struct sigaction action;
  action.sa_handler = segv_handler;
  action.sa_flags = 0;
  sigaction (SIGSEGV, &action, NULL);
  
  /* Cause a segfault. */
  printf ("%i\n", foo());
}

int bar(char *ptr)
{
  return ptr[10];  /* segfault */
}

int foo()
{
  return bar(NULL);
}

_Unwind_Reason_Code
unwind_trace_fn (struct _Unwind_Context *context, void *p)
{
  _Unwind_Ptr ip = _Unwind_GetIP (context);
  void *fn = _Unwind_FindEnclosingFunction((void *) ip);

  if (fn == main)
    printf ("main()\n");
  if (fn == foo)
    printf ("foo()\n");  
  if (fn == bar)
    printf ("bar()\n");
  return _URC_NO_REASON;
}

void segv_handler(int sig)
{
  _Unwind_Backtrace (unwind_trace_fn, NULL);
  exit(1);
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]