Почему в основной функции в src / runtime / proc.go существует кажущийся бесполезным бесконечный цикл for?

#go #runtime

#Вперед #время выполнения

Вопрос:

Сегодня я наткнулся на сообщение, в котором задается этот вопрос. В конце основной функции в src/runtime/proc.go есть, казалось бы, бесполезный бесконечный цикл for . Почему это там?

ссылка на исходный код

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

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

Комментарии:

1. groups.google.com/forum/m /#!topic/golang-nuts/FnF3oZeJ7aY

2. Связать группы с мобильных устройств невероятно сложно, вот подходящая ссылка: groups.google.com/d/msg/golang-nuts/FnF3oZeJ7aY/sLz0G3oDAgAJ

Ответ №1:

Назначение 0 защищенной области памяти, например, *(*int)(nil) = 0 и *x = 0 в системах с модулем защиты памяти вызывает ошибку сегментации и останавливает программу,
а в системах без модуля защиты памяти просто записывается 0 в нулевой адрес памяти, и ничего не происходит, поэтому они добавили цикл for для остановки программы (CPU) там.

  1. Обычно это (должен быть) недоступный код.

  2. Файл: ~/go/src/runtime/proc.go в конце func main() :

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

ссылка:

Среда выполнения — это особый случай во многих отношениях, и это одна из наиболее особых частей. Этот цикл существует для выявления проблем при тестировании новых портов. Если этот цикл когда-либо достигнут, что-то пошло не так: вызов exit должен был привести к завершению программы. Мы не можем предположить, что panic работает. На самом деле мы не можем предположить, что что-то работает. Что мы хотим сделать, так это остановить программу. Поскольку не удалось завершить, возможно, что нулевое разыменование завершится успешно. Если это тоже не удается, нам все равно нужно что-то делать, поэтому мы просто выполняем цикл. Мы не можем вернуться, потому что это основная функция, которая запустила программу; возвращаться не к чему.


  1. Также вызов panic("err msg") здесь внутри /usr/local/go/src/runtime/panic.go в конце func fatalpanic(msgs *_panic) имеет недоступный код:
     systemstack(func() {
        exit(2)
    })

    *(*int)(nil) = 0 // not reached
}
  

  1. Здесь 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]
  

  1. Здесь для теста предлагается сгенерировать панику и восстановить:
    Файл ~/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. Файл ~/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. Файл ~/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("n")

        // If this is a released compiler version, ask for a bug report.
        if strings.HasPrefix(objabi.Version, "go") {
            fmt.Printf("n")
            fmt.Printf("Please file a bug report including a short program that triggers the error.n")
            fmt.Printf("https://golang.org/issue/newn")
        } else {
            // Not a release; dump a stack trace, too.
            fmt.Println()
            os.Stdout.Write(debug.Stack())
            fmt.Println()
        }
    }

    hcrash()
    errorexit()
}
  

  1. Следующий код паникует здесь внутри /usr/local/go/src/runtime/panic.go в конце func fatalpanic(msgs *_panic) :
     systemstack(func() {
        exit(2)
    })

    *(*int)(nil) = 0 // not reached
}
  

Код для паники! (аналогично вызову 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