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 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题