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.
Normally it is (should be) unreachable code.
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.
- 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
}
- 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]
- 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")
}
- 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
}
}
- 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()
}
- 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