2017-04-04 128 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. 分隔成一個管理進程和「不可信/不安全」的子進程,而監督者拿起從子進程不當的退出條件,並適當地作出報告。