Re: catch SIGSEGV in the demangler

Pedro Alves
2013-01-18T15:41:28Z

On 01/18/2013 03:01 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
>
> Pedro> SIGSEGV being a synchronous signal, this makes it so that the
> Pedro> original instruction that triggered the segv is reexecuted, and
> Pedro> the SIGSEGV is raised again. The difference is that this way our
> Pedro> handler is transparent -- the segv's siginfo will be more rich,
> Pedro> including a si_addr that points at the address that caused the
> Pedro> fault, (si_code will still show it was a userspace generated
> Pedro> signal), and "handle_segv" will not appear in the backtrace. Did
> Pedro> you try that and decided against?
>
> I didn't try, because the C standard says this is undefined behavior:
>
> If and when the function returns, if the value of sig is SIGFPE,
> SIGILL, SIGSEGV, or any other implementation-defined value
> corresponding to a computational exception, the behavior is
> undefined; otherwise the program will resume execution at the point
> it was interrupted.
>
> I couldn't find anything in POSIX suggesting otherwise.

Interesting, I'd expect that to be implementation defined.

Catching SIGILL, emulating an unsupported instruction, advancing
the program counter in the passed in context (3rd arg), and returning,
is a not unheard of technique (it's better when the kernel does it,
but still).

>
> It seems to me that the failing spot will still be in the backtrace.
> So, the damage isn't so severe:

You have the failing spot, but lose si_addr, which you can use
to know which address wasn't accessed. True, you can infer that
from the instruction that faulted, but it's not as nice.

>
> (gdb) bt
> #0 0x0000003be3036540 in __sigprocmask (how=2, set=0x2f32850, oset=0x0)
> at ../sysdeps/unix/sysv/linux/ia64/sigprocmask.c:43
> #1 0x0000003be303610b in __libc_siglongjmp (env=0x2f32808, val=-1)
> at longjmp.c:36
> #2 0x0000003be3c0e179 in longjmp (env=<optimized out>, val=<optimized out>)
> at ../nptl/sysdeps/pthread/pt-longjmp.c:27
> #3 0x0000000000722e48 in throw_exception (exception=...)
> at ../../archer/gdb/exceptions.c:234
> #4 0x0000000000802a33 in handle_segv (sig=11)
> at ../../archer/gdb/safe-demangle.c:49
> #5 <signal handler called>
> #6 0x0000003be30e87c8 in __GI___poll (fds=0x2e2cff0, nfds=3,
> timeout=<optimized out>) at ../sysdeps/unix/sysv/linux/poll.c:83
> #7 0x000000000072d1be in gdb_wait_for_event (block=1)
> at ../../archer/gdb/event-loop.c:863
>
>
> Well, ok, the stack trace is weird, since in this scenario we aren't
> actually calling longjmp. I'm not sure what is going on there.

Did you mean to catch the SIGSEGV caused by the raise?
That seems like what you'd get if !in_demangler (you got to
throw_exception)? You got SIGSEGV set to nopass by mistake
perhaps, caught the raise(SIGSEGV), and continued, which
suppressed the signal, and moved along into the throw?

>
> If returning actually works everywhere, I am fine with doing that.

I think it does, but we can always do a raise where it doesn't work.

--
Pedro Alves