2017-04-04 127 views
5

signal package状态:处理与恢复SIGSEGV?

同步信号是由错误的程序 执行触发信号:SIGBUS,SIGFPE和SIGSEGV。使用 os.Process.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() 
} 

输出:

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 

有什么办法,我可以在本地化的代码的某些部分的方式处理SIGSEGV?

+0

在“为什么你要做到这一点,这似乎nutso”条款是在我的系统用户可以创建模板。我想保护主运行时免受渲染模板时生成的任何错误。真实世界的问题在github上[这里](https://github.com/bosun-monitor/bosun/issues/2054)。 –

+2

与Gopher中的人闲聊的想法似乎是sigsegv将程序置于未定义状态,无法从安全中恢复。 –

+1

您无法从“致命错误”中恢复,这不是“恐慌” – JimB

回答

1

当你遇到一个SIGSEGV,你在所有的赌注,是断带关于程序状态的情况真的很。唯一通常安全的做法是停止一切,并可能让系统将您的内存转储文件进行调试,这就是Go所做的。在这种情况下,没有任何方法可以“保护主运行时”。

如果您有运行代码,不可信或不安全运行时,你真的应该把它隔离到一个单独的进程来代替。如果你运行从用户(而不是用户自己)接收到的代码的人,这个过程中最应该被沙盒。

所以我的建议是,请执行下列操作:

  1. 让它崩溃,并让用户从那里处理它。用户在Go中编写导致sigsegv的代码通常需要或多或少主动地尝试向人们的方向进行拍摄,因此它应该是罕见的,并且可以根据自己承担的风险进行归档。
  2. 分隔成一个管理进程和“不可信/不安全”的子进程,而监督者拿起从子进程不当的退出条件,并适当地作出报告。