为什么在src/time/pro.go的main函数中有一个看似无用的无限for循环?

人气:341 发布:2022-10-16 标签: runtime go

问题描述

今天我看到一个帖子,问这个问题。在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 *intxnil指针,因此*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

851