处理SIGSEGV与恢复?

Kyl*_*ndt 7 go

所述信号包的状态:

同步信号是由程序执行中的错误触发的信号:SIGBUS,SIGFPE和SIGSEGV.这些仅在程序执行时被认为是同步的,而不是在使用os.Process.Kill或kill程序或类似机制发送时.通常,除了下面讨论的,Go程序将同步信号转换为运行时恐慌.

然而,似乎recover()没有抓住这一点.

程序:

package main

import (
    "fmt"
    "unsafe"

    "log"
)

func seeAnotherDay() {
    defer func() {
        if p := recover(); p != nil {
            err := fmt.Errorf("recover panic: panic call")
            log.Println(err)
            return
        }
    }()
    panic("oops")
}

func notSoMuch() {
    defer func() {
        if p := recover(); p != nil {
            err := fmt.Errorf("recover panic: sigseg")
            log.Println(err)
            return
        }
    }()
    b := make([]byte, 1)
    log.Println("access some memory")
    foo := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(9999999999999999)))
    fmt.Print(*foo + 1)
}

func main() {
    seeAnotherDay()
    notSoMuch()
}
Run Code Online (Sandbox Code Playgroud)

输出:

2017/04/04 12:13:16 recover panic: panic call
2017/04/04 12:13:16 access some memory
unexpected fault address 0xb01dfacedebac1e
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0xb01dfacedebac1e pc=0x108aa8a]

goroutine 1 [running]:
runtime.throw(0x10b5807, 0x5)
        /usr/local/go/src/runtime/panic.go:596 +0x95 fp=0xc420043ea8 sp=0xc420043e88
runtime.sigpanic()
        /usr/local/go/src/runtime/signal_unix.go:297 +0x28c fp=0xc420043ef8 sp=0xc420043ea8
main.notSoMuch()
        /Users/kbrandt/src/sigseg/main.go:32 +0xca fp=0xc420043f78 sp=0xc420043ef8
main.main()
        /Users/kbrandt/src/sigseg/main.go:37 +0x25 fp=0xc420043f88 sp=0xc420043f78
runtime.main()
        /usr/local/go/src/runtime/proc.go:185 +0x20a fp=0xc420043fe0 sp=0xc420043f88
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2197 +0x1 fp=0xc420043fe8 sp=0xc420043fe0
exit status 2
Run Code Online (Sandbox Code Playgroud)

有没有办法以局部方式处理代码的某些部分来处理SIGSEGV?

小智 5

是的,您将需要使用debug.SetPanicOnFault将意外(非零)地址处的故障转换为可以从中恢复的恐慌。从文档:

SetPanicOnFault 控制程序在意外(非零)地址出现故障时运行时的行为。此类故障通常是由运行时内存损坏等错误引起的,因此默认响应是使程序崩溃。在不太严重的情况下,使用内存映射文件或不安全的内存操作的程序可能会导致非空地址的错误;SetPanicOnFault 允许此类程序请求运行时仅触发恐慌,而不是崩溃。SetPanicOnFault 仅适用于当前 goroutine。它返回之前的设置。

对于影响的本地化,请注意 SetPanicOnFault 是在 goroutine 级别设置的,因此单个 goroutine 可以处理已知的不安全访问。