Skip to content

runtime: panicmem should expose the address it's panicking about. #37023

@seebs

Description

@seebs

What version of Go are you using (go version)?

1.13

Does this issue reproduce with the latest release?

probably

What operating system and processor architecture are you using (go env)?

AMD64

What did you do?

I don't know, but it resulted in a segfault. :) But then I started experimenting with panic and recover, and discovered (somewhat to my surprise) that I can catch a SEGV's panic.

What did you expect to see?

A runtime error/exception/something that has comparable information to what I'd get if I didn't recover().

What did you see instead?

The string "invalid memory address or nil pointer dereference"

So, contrast:

unexpected fault address 0x7f84e68d6112
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0x7f84e68d6112 pc=0x5f17cb]

goroutine 992352 [running]:
runtime.throw(0xfab924, 0x5)
        /usr/local/Cellar/go/1.13/libexec/src/runtime/panic.go:774 +0x72 fp=0xd5b852e7f8 sp=0xd5b852e7c8 pc=0x42f3b2
runtime.sigpanic()
        /usr/local/Cellar/go/1.13/libexec/src/runtime/signal_unix.go:401 +0x3de fp=0xd5b852e828 sp=0xd5b852e7f8 pc=0x444a3e
[...]

If I look at [runtime/]debug.StackTrace(), I can get some of this information, but I can't necessarily get the actual address of the unexpected fault. It looks to me like runtime has this information at the time when the panic is generated (or would be, if I turned on SetPanicOnFault):

        case _SIGSEGV:
                if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 {
                        panicmem()
                }
                // Support runtime/debug.SetPanicOnFault.
                if g.paniconfault {
                        panicmem()
                }
                print("unexpected fault address ", hex(g.sigcode1), "\n")
                throw("fault")

But it looks like panicmem doesn't expose these values. Possibly it should. I can't think of a reasonable approach immediately -- obviously I'd just like the siginfo_t exposed, except that this is unportable even by memory fault handling standards and won't be compatible between implementations. But it seems like exposing the affected address (g.sigcode1) and possibly the kind-of-error (SEGV_MAPERR or SEGV_ACCERR?)

But as a simple baseline that I think is probably supportable on current systems, if panicmem took a uintptr, and the resulting panic were an error type that could be queried for the uintptr, or displayed it by default, that might make life easier.

Because on the one hand, I want to catch the panics and prevent them from breaking things, but on the other hand, diagnosing them sort of benefits from having the address be available.

(On the third hand, it might be that changing the exact panic result in these cases would break the Compatibility Promise, without some hypothetical new debug.SetFancyPanicOnFault() that would not have been used in the existing code.)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions