#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) там.
-
Обычно это (должен быть) недоступный код.
-
Файл:
~/go/src/runtime/proc.go
в концеfunc main()
:
exit(0)
for {
var x *int32
*x = 0
}
Среда выполнения — это особый случай во многих отношениях, и это одна из наиболее особых частей. Этот цикл существует для выявления проблем при тестировании новых портов. Если этот цикл когда-либо достигнут, что-то пошло не так: вызов exit должен был привести к завершению программы. Мы не можем предположить, что panic работает. На самом деле мы не можем предположить, что что-то работает. Что мы хотим сделать, так это остановить программу. Поскольку не удалось завершить, возможно, что нулевое разыменование завершится успешно. Если это тоже не удается, нам все равно нужно что-то делать, поэтому мы просто выполняем цикл. Мы не можем вернуться, потому что это основная функция, которая запустила программу; возвращаться не к чему.
- Также вызов
panic("err msg")
здесь внутри/usr/local/go/src/runtime/panic.go
в концеfunc fatalpanic(msgs *_panic)
имеет недоступный код:
systemstack(func() {
exit(2)
})
*(*int)(nil) = 0 // not reached
}
- Здесь
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]
- Здесь для теста предлагается сгенерировать панику и восстановить:
Файл~/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("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()
}
- Следующий код паникует здесь внутри
/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