问题描述
今天我看到一个帖子,问这个问题。在src/runtime/proc.go
中的main函数的末尾有一个看似无用的无限for循环。为什么会在那里?
source code link
if atomic.Load(&panicking) != 0 {
gopark(nil, nil, waitReasonPanicWait, traceEvGoStop, 1)
}
exit(0)
for {
var x *int32
*x = 0
}
推荐答案
将0
分配给受保护的内存区域,例如*(*int)(nil) = 0
和*x = 0
在memory protection unit的系统中会导致segmentation fault并停止程序,
在没有内存保护单元的系统中,只需将0
写入内存地址为零,什么也不会发生,因此他们添加了一个for循环在那里停止程序(CPU)。
通常是(应该)无法访问的代码。
文件:~/go/src/runtime/proc.go
结尾func main()
:
exit(0)
for {
var x *int32
*x = 0
}
ref:
运行库在许多方面都是一个特例,这是其中之一 特殊零件。存在此循环是为了在测试新的 港口。如果达到了那个循环,那么一定出了严重的问题: Exit调用应该已导致程序退出。我们不能假设 这种恐慌正在奏效。我们不能真的假设任何事情 在工作。我们想要做的是停止这个程序。由于退出失败, 零引用可能会成功。如果这也失败了, 我们仍然需要做些什么,所以我们只需循环。我们不能回去了 因为这是启动程序的主要函数;有 没有什么可以回去的。 还在func fatalpanic(msgs *_panic)
末尾的/usr/local/go/src/runtime/panic.go
内部调用panic("err msg")
具有无法访问的代码:
systemstack(func() {
exit(2)
})
*(*int)(nil) = 0 // not reached
}
此处var x *int
:x
是nil
指针,因此*x = 0
是死机:运行时错误:内存地址无效或无指针取消引用并导致分段冲突:
package main
func main() {
var x *int
*x = 0
}
输出:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x44f972]
此处针对测试建议生成死机并恢复:
文件~/go/src/internal/x/crypto/cryptobyte/cryptobyte_test.go
func TestGeneratedPanic(t *testing.T) {
defer func() {
recover()
}()
var b Builder
b.AddUint8LengthPrefixed(func(b *Builder) {
var p *byte
*p = 0
})
t.Error("Builder did not panic")
}
文件~/go/src/cmd/compile/internal/gc/subr.go
:
func hcrash() {
if Debug['h'] != 0 {
flusherrors()
if outfile != "" {
os.Remove(outfile)
}
var x *int
*x = 0
}
}
文件~/go/pkg/bootstrap/src/bootstrap/cmd/compile/internal/gc/subr.go
:
func hcrash() {
if Debug['h'] != 0 {
flusherrors()
if outfile != "" {
os.Remove(outfile)
}
var x *int
*x = 0
}
}
此处在~/go/src/cmd/compile/internal/gc/subr.go
的末尾调用:
func Fatalf(fmt_ string, args ...interface{}) {
flusherrors()
if Debug_panic != 0 || nsavederrors+nerrors == 0 {
fmt.Printf("%v: internal compiler error: ", linestr(lineno))
fmt.Printf(fmt_, args...)
fmt.Printf("
")
// If this is a released compiler version, ask for a bug report.
if strings.HasPrefix(objabi.Version, "go") {
fmt.Printf("
")
fmt.Printf("Please file a bug report including a short program that triggers the error.
")
fmt.Printf("https://golang.org/issue/new
")
} else {
// Not a release; dump a stack trace, too.
fmt.Println()
os.Stdout.Write(debug.Stack())
fmt.Println()
}
}
hcrash()
errorexit()
}
以下代码在func fatalpanic(msgs *_panic)
末尾的/usr/local/go/src/runtime/panic.go
中死机:
systemstack(func() {
exit(2)
})
*(*int)(nil) = 0 // not reached
}
Code to panic!(类似于调用panic("err msg")
:
package main
import (
"fmt"
"math/rand"
)
func main() {
r := rand.Rand{}
i := r.Int()
fmt.Println(i)
}
输出:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xd8276]
goroutine 1 [running]:
math/rand.(*Rand).Int63(...)
/usr/local/go/src/math/rand/rand.go:85
math/rand.(*Rand).Int(...)
/usr/local/go/src/math/rand/rand.go:103
main.main()
/tmp/sandbox449835614/main.go:10 +0x36