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

报告相同问题?

悬赏问题

  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料