doulan3966 2019-03-29 11:09
浏览 297
已采纳

为什么在src / runtime / proc.go的主要功能中似乎没有用的无限for循环?

Today I came across a post asking about this question. At the end of the main function in src/runtime/proc.go there is a seemingly useless infinite for loop. Why is it there?

source code link

    if atomic.Load(&panicking) != 0 {
        gopark(nil, nil, waitReasonPanicWait, traceEvGoStop, 1)
    }

    exit(0)
    for {
        var x *int32
        *x = 0
    }
  • 写回答

1条回答 默认 最新

  • dsbo44836129 2019-03-29 14:19
    关注

    Assigning 0 to a protected memory region e.g. *(*int)(nil) = 0 and *x = 0 in systems with memory protection unit causes segmentation fault and stops the programme,
    And in systems without memory protection unit, just writes 0 to the memory address at zero and nothing happens so they added a for loop to stop the programme (CPU) there.

    1. Normally it is (should be) unreachable code.

    2. File: ~/go/src/runtime/proc.go at the end of func main():

        exit(0)
        for {
            var x *int32
            *x = 0
        }
    

    ref:

    The runtime is a special case in many ways, and this is among the more special parts. This loop exists to catch problems while testing new ports. If that loop is ever reached, something has gone badly wrong: the exit call should have caused the program to exit. We can't assume that panic is working. We can't really assume that anything is working. What we want to do is stop the program. Since exit failed, it's possible that a nil dereference will succeed. If that fails too, we still have to do something, so we just loop. We can't return because this is the main function that started the program; there is nothing to return to.


    1. Also Calling panic("err msg") here inside /usr/local/go/src/runtime/panic.go at the end of func fatalpanic(msgs *_panic) has unreachable code:
        systemstack(func() {
            exit(2)
        })
    
        *(*int)(nil) = 0 // not reached
    }
    

    1. Here var x *int: x is a nil pointer, so *x = 0 is a panic: runtime error: invalid memory address or nil pointer dereference and causes segmentation violation:
    package main
    
    func main() {
        var x *int
        *x = 0
    }
    

    Output:

    panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x44f972]
    

    1. Here for test propose to generated a panic and recover:
      File ~/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")
    }
    

    1. File ~/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
        }
    }
    
    1. File ~/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
        }
    }
    

    Which is called here ~/go/src/cmd/compile/internal/gc/subr.go at the end of:

    
    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()
    }
    

    1. Following code panics here inside /usr/local/go/src/runtime/panic.go at the end of func fatalpanic(msgs *_panic):
        systemstack(func() {
            exit(2)
        })
    
        *(*int)(nil) = 0 // not reached
    }
    

    Code to panic! (similar to Calling panic("err msg"):

    package main
    
    import (
        "fmt"
        "math/rand"
    )
    
    func main() {
        r := rand.Rand{}
        i := r.Int()
        fmt.Println(i)
    }
    

    Output:

    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
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 随机森林与房贷信用风险模型
  • ¥50 buildozer打包kivy app失败
  • ¥30 在vs2022里运行python代码
  • ¥15 不同尺寸货物如何寻找合适的包装箱型谱
  • ¥15 求解 yolo算法问题
  • ¥15 虚拟机打包apk出现错误
  • ¥15 用visual studi code完成html页面
  • ¥15 聚类分析或者python进行数据分析
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备