2014-08-18 14:26:28 -06:00
|
|
|
// Copyright 2014 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package runtime
|
|
|
|
|
2015-11-02 12:09:24 -07:00
|
|
|
import (
|
|
|
|
"runtime/internal/atomic"
|
2016-09-22 15:08:37 -06:00
|
|
|
"runtime/internal/sys"
|
2015-11-02 12:09:24 -07:00
|
|
|
"unsafe"
|
|
|
|
)
|
2014-09-03 09:49:43 -06:00
|
|
|
|
2016-03-04 12:29:55 -07:00
|
|
|
// Calling panic with one of the errors below will call errorString.Error
|
|
|
|
// which will call mallocgc to concatenate strings. That will fail if
|
|
|
|
// malloc is locked, causing a confusing error message. Throw a better
|
|
|
|
// error message instead.
|
|
|
|
func panicCheckMalloc(err error) {
|
|
|
|
gp := getg()
|
|
|
|
if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
|
|
|
|
throw(string(err.(errorString)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-30 12:18:41 -06:00
|
|
|
var indexError = error(errorString("index out of range"))
|
|
|
|
|
2014-08-18 14:26:28 -06:00
|
|
|
func panicindex() {
|
2016-03-04 12:29:55 -07:00
|
|
|
panicCheckMalloc(indexError)
|
2014-08-30 12:18:41 -06:00
|
|
|
panic(indexError)
|
2014-08-18 14:26:28 -06:00
|
|
|
}
|
|
|
|
|
2014-08-30 12:18:41 -06:00
|
|
|
var sliceError = error(errorString("slice bounds out of range"))
|
|
|
|
|
2014-08-18 14:26:28 -06:00
|
|
|
func panicslice() {
|
2016-03-04 12:29:55 -07:00
|
|
|
panicCheckMalloc(sliceError)
|
2014-08-30 12:18:41 -06:00
|
|
|
panic(sliceError)
|
2014-08-18 14:26:28 -06:00
|
|
|
}
|
2014-09-03 09:49:43 -06:00
|
|
|
|
|
|
|
var divideError = error(errorString("integer divide by zero"))
|
|
|
|
|
|
|
|
func panicdivide() {
|
2016-03-04 12:29:55 -07:00
|
|
|
panicCheckMalloc(divideError)
|
2014-09-03 09:49:43 -06:00
|
|
|
panic(divideError)
|
|
|
|
}
|
|
|
|
|
liblink, runtime: diagnose and fix C code running on Go stack
This CL contains compiler+runtime changes that detect C code
running on Go (not g0, not gsignal) stacks, and it contains
corrections for what it detected.
The detection works by changing the C prologue to use a different
stack guard word in the G than Go prologue does. On the g0 and
gsignal stacks, that stack guard word is set to the usual
stack guard value. But on ordinary Go stacks, that stack
guard word is set to ^0, which will make any stack split
check fail. The C prologue then calls morestackc instead
of morestack, and morestackc aborts the program with
a message about running C code on a Go stack.
This check catches all C code running on the Go stack
except NOSPLIT code. The NOSPLIT code is allowed,
so the check is complete. Since it is a dynamic check,
the code must execute to be caught. But unlike the static
checks we've been using in cmd/ld, the dynamic check
works with function pointers and other indirect calls.
For example it caught sigpanic being pushed onto Go
stacks in the signal handlers.
Fixes #8667.
LGTM=khr, iant
R=golang-codereviews, khr, iant
CC=golang-codereviews, r
https://golang.org/cl/133700043
2014-09-08 12:05:23 -06:00
|
|
|
var overflowError = error(errorString("integer overflow"))
|
|
|
|
|
|
|
|
func panicoverflow() {
|
2016-03-04 12:29:55 -07:00
|
|
|
panicCheckMalloc(overflowError)
|
liblink, runtime: diagnose and fix C code running on Go stack
This CL contains compiler+runtime changes that detect C code
running on Go (not g0, not gsignal) stacks, and it contains
corrections for what it detected.
The detection works by changing the C prologue to use a different
stack guard word in the G than Go prologue does. On the g0 and
gsignal stacks, that stack guard word is set to the usual
stack guard value. But on ordinary Go stacks, that stack
guard word is set to ^0, which will make any stack split
check fail. The C prologue then calls morestackc instead
of morestack, and morestackc aborts the program with
a message about running C code on a Go stack.
This check catches all C code running on the Go stack
except NOSPLIT code. The NOSPLIT code is allowed,
so the check is complete. Since it is a dynamic check,
the code must execute to be caught. But unlike the static
checks we've been using in cmd/ld, the dynamic check
works with function pointers and other indirect calls.
For example it caught sigpanic being pushed onto Go
stacks in the signal handlers.
Fixes #8667.
LGTM=khr, iant
R=golang-codereviews, khr, iant
CC=golang-codereviews, r
https://golang.org/cl/133700043
2014-09-08 12:05:23 -06:00
|
|
|
panic(overflowError)
|
|
|
|
}
|
|
|
|
|
|
|
|
var floatError = error(errorString("floating point error"))
|
|
|
|
|
|
|
|
func panicfloat() {
|
2016-03-04 12:29:55 -07:00
|
|
|
panicCheckMalloc(floatError)
|
liblink, runtime: diagnose and fix C code running on Go stack
This CL contains compiler+runtime changes that detect C code
running on Go (not g0, not gsignal) stacks, and it contains
corrections for what it detected.
The detection works by changing the C prologue to use a different
stack guard word in the G than Go prologue does. On the g0 and
gsignal stacks, that stack guard word is set to the usual
stack guard value. But on ordinary Go stacks, that stack
guard word is set to ^0, which will make any stack split
check fail. The C prologue then calls morestackc instead
of morestack, and morestackc aborts the program with
a message about running C code on a Go stack.
This check catches all C code running on the Go stack
except NOSPLIT code. The NOSPLIT code is allowed,
so the check is complete. Since it is a dynamic check,
the code must execute to be caught. But unlike the static
checks we've been using in cmd/ld, the dynamic check
works with function pointers and other indirect calls.
For example it caught sigpanic being pushed onto Go
stacks in the signal handlers.
Fixes #8667.
LGTM=khr, iant
R=golang-codereviews, khr, iant
CC=golang-codereviews, r
https://golang.org/cl/133700043
2014-09-08 12:05:23 -06:00
|
|
|
panic(floatError)
|
|
|
|
}
|
|
|
|
|
|
|
|
var memoryError = error(errorString("invalid memory address or nil pointer dereference"))
|
|
|
|
|
|
|
|
func panicmem() {
|
2016-03-04 12:29:55 -07:00
|
|
|
panicCheckMalloc(memoryError)
|
liblink, runtime: diagnose and fix C code running on Go stack
This CL contains compiler+runtime changes that detect C code
running on Go (not g0, not gsignal) stacks, and it contains
corrections for what it detected.
The detection works by changing the C prologue to use a different
stack guard word in the G than Go prologue does. On the g0 and
gsignal stacks, that stack guard word is set to the usual
stack guard value. But on ordinary Go stacks, that stack
guard word is set to ^0, which will make any stack split
check fail. The C prologue then calls morestackc instead
of morestack, and morestackc aborts the program with
a message about running C code on a Go stack.
This check catches all C code running on the Go stack
except NOSPLIT code. The NOSPLIT code is allowed,
so the check is complete. Since it is a dynamic check,
the code must execute to be caught. But unlike the static
checks we've been using in cmd/ld, the dynamic check
works with function pointers and other indirect calls.
For example it caught sigpanic being pushed onto Go
stacks in the signal handlers.
Fixes #8667.
LGTM=khr, iant
R=golang-codereviews, khr, iant
CC=golang-codereviews, r
https://golang.org/cl/133700043
2014-09-08 12:05:23 -06:00
|
|
|
panic(memoryError)
|
|
|
|
}
|
|
|
|
|
2014-09-03 09:49:43 -06:00
|
|
|
func throwinit() {
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("recursive call during initialization - linker skew")
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new deferred function fn with siz bytes of arguments.
|
|
|
|
// The compiler turns a defer statement into a call to this.
|
|
|
|
//go:nosplit
|
|
|
|
func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
|
2014-11-11 15:04:34 -07:00
|
|
|
if getg().m.curg != getg() {
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
// go code on the system stack can't defer
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("defer on system stack")
|
2014-11-11 15:04:34 -07:00
|
|
|
}
|
|
|
|
|
2016-03-01 16:21:55 -07:00
|
|
|
// the arguments of fn are in a perilous state. The stack map
|
|
|
|
// for deferproc does not describe them. So we can't let garbage
|
2014-09-03 09:49:43 -06:00
|
|
|
// collection or stack copying trigger until we've copied them out
|
2016-03-01 16:21:55 -07:00
|
|
|
// to somewhere safe. The memmove below does that.
|
2014-12-08 15:18:58 -07:00
|
|
|
// Until the copy completes, we can only call nosplit routines.
|
|
|
|
sp := getcallersp(unsafe.Pointer(&siz))
|
|
|
|
argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn)
|
2014-11-11 15:04:34 -07:00
|
|
|
callerpc := getcallerpc(unsafe.Pointer(&siz))
|
2014-09-03 09:49:43 -06:00
|
|
|
|
2016-09-22 15:08:37 -06:00
|
|
|
d := newdefer(siz)
|
|
|
|
if d._panic != nil {
|
|
|
|
throw("deferproc: d.panic != nil after newdefer")
|
|
|
|
}
|
|
|
|
d.fn = fn
|
|
|
|
d.pc = callerpc
|
|
|
|
d.sp = sp
|
|
|
|
switch siz {
|
|
|
|
case 0:
|
|
|
|
// Do nothing.
|
|
|
|
case sys.PtrSize:
|
|
|
|
*(*uintptr)(deferArgs(d)) = *(*uintptr)(unsafe.Pointer(argp))
|
|
|
|
default:
|
|
|
|
memmove(deferArgs(d), unsafe.Pointer(argp), uintptr(siz))
|
|
|
|
}
|
2014-09-03 09:49:43 -06:00
|
|
|
|
|
|
|
// deferproc returns 0 normally.
|
|
|
|
// a deferred func that stops a panic
|
|
|
|
// makes the deferproc return 1.
|
|
|
|
// the code the compiler generates always
|
|
|
|
// checks the return value and jumps to the
|
|
|
|
// end of the function if deferproc returns != 0.
|
|
|
|
return0()
|
|
|
|
// No code can go here - the C return register has
|
|
|
|
// been set and must not be clobbered.
|
|
|
|
}
|
|
|
|
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
// Small malloc size classes >= 16 are the multiples of 16: 16, 32, 48, 64, 80, 96, 112, 128, 144, ...
|
|
|
|
// Each P holds a pool for defers with small arg sizes.
|
|
|
|
// Assign defer allocations to pools by rounding to 16, to match malloc size classes.
|
|
|
|
|
|
|
|
const (
|
|
|
|
deferHeaderSize = unsafe.Sizeof(_defer{})
|
|
|
|
minDeferAlloc = (deferHeaderSize + 15) &^ 15
|
|
|
|
minDeferArgs = minDeferAlloc - deferHeaderSize
|
|
|
|
)
|
2014-09-03 09:49:43 -06:00
|
|
|
|
|
|
|
// defer size class for arg size sz
|
2014-09-08 15:37:49 -06:00
|
|
|
//go:nosplit
|
2014-09-03 09:49:43 -06:00
|
|
|
func deferclass(siz uintptr) uintptr {
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
if siz <= minDeferArgs {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return (siz - minDeferArgs + 15) / 16
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// total size of memory block for defer with arg size sz
|
|
|
|
func totaldefersize(siz uintptr) uintptr {
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
if siz <= minDeferArgs {
|
|
|
|
return minDeferAlloc
|
|
|
|
}
|
|
|
|
return deferHeaderSize + siz
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that defer arg sizes that map to the same defer size class
|
|
|
|
// also map to the same malloc size class.
|
|
|
|
func testdefersizes() {
|
|
|
|
var m [len(p{}.deferpool)]int32
|
|
|
|
|
|
|
|
for i := range m {
|
|
|
|
m[i] = -1
|
|
|
|
}
|
|
|
|
for i := uintptr(0); ; i++ {
|
|
|
|
defersc := deferclass(i)
|
|
|
|
if defersc >= uintptr(len(m)) {
|
|
|
|
break
|
|
|
|
}
|
2014-12-29 00:16:32 -07:00
|
|
|
siz := roundupsize(totaldefersize(i))
|
2014-09-03 09:49:43 -06:00
|
|
|
if m[defersc] < 0 {
|
|
|
|
m[defersc] = int32(siz)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if m[defersc] != int32(siz) {
|
|
|
|
print("bad defer size class: i=", i, " siz=", siz, " defersc=", defersc, "\n")
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("bad defer size class")
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
// The arguments associated with a deferred call are stored
|
|
|
|
// immediately after the _defer header in memory.
|
|
|
|
//go:nosplit
|
|
|
|
func deferArgs(d *_defer) unsafe.Pointer {
|
runtime: fix call* signatures and deferArgs with siz=0
This commit fixes two bizarrely related bugs:
1. The signatures for the call* functions were wrong, indicating that
they had only two pointer arguments instead of three. We didn't notice
because the call* functions are defined by a macro expansion, which go
vet doesn't see.
2. deferArgs on a defer object with a zero-sized frame returned a
pointer just past the end of the allocated object, which is illegal in
Go (and can cause the "sweep increased allocation count" crashes).
In a fascinating twist, these two bugs canceled each other out, which
is why I'm fixing them together. The pointer returned by deferArgs is
used in only two ways: as an argument to memmove and as an argument to
reflectcall. memmove is NOSPLIT, so the argument was unobservable.
reflectcall immediately tail calls one of the call* functions, which
are not NOSPLIT, but the deferArgs pointer just happened to be the
third argument that was accidentally marked as a scalar. Hence, when
the garbage collector scanned the stack, it didn't see the bad
pointer as a pointer.
I believe this was all ultimately benign. In principle, stack growth
during the reflectcall could fail to update the args pointer, but it
never points to the stack, so it never needs to be updated. Also in
principle, the garbage collector could fail to mark the args object
because of the incorrect call* signatures, but in all calls to
reflectcall (including the ones spelled "call" in the reflect package)
the args object is kept live by the calling stack.
Change-Id: Ic932c79d5f4382be23118fdd9dba9688e9169e28
Reviewed-on: https://go-review.googlesource.com/31654
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2016-10-20 20:27:39 -06:00
|
|
|
if d.siz == 0 {
|
|
|
|
// Avoid pointer past the defer allocation.
|
|
|
|
return nil
|
|
|
|
}
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
return add(unsafe.Pointer(d), unsafe.Sizeof(*d))
|
|
|
|
}
|
|
|
|
|
|
|
|
var deferType *_type // type of _defer struct
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
var x interface{}
|
|
|
|
x = (*_defer)(nil)
|
|
|
|
deferType = (*(**ptrtype)(unsafe.Pointer(&x))).elem
|
|
|
|
}
|
|
|
|
|
2014-09-03 09:49:43 -06:00
|
|
|
// Allocate a Defer, usually using per-P pool.
|
|
|
|
// Each defer must be released with freedefer.
|
2016-09-22 15:08:37 -06:00
|
|
|
//
|
|
|
|
// This must not grow the stack because there may be a frame without
|
|
|
|
// stack map information when this is called.
|
|
|
|
//
|
|
|
|
//go:nosplit
|
2014-09-03 09:49:43 -06:00
|
|
|
func newdefer(siz int32) *_defer {
|
|
|
|
var d *_defer
|
|
|
|
sc := deferclass(uintptr(siz))
|
2016-09-22 15:08:37 -06:00
|
|
|
gp := getg()
|
2014-09-03 09:49:43 -06:00
|
|
|
if sc < uintptr(len(p{}.deferpool)) {
|
2016-09-22 15:08:37 -06:00
|
|
|
pp := gp.m.p.ptr()
|
2015-02-05 06:35:41 -07:00
|
|
|
if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil {
|
2016-09-22 15:08:37 -06:00
|
|
|
// Take the slow path on the system stack so
|
|
|
|
// we don't grow newdefer's stack.
|
|
|
|
systemstack(func() {
|
|
|
|
lock(&sched.deferlock)
|
|
|
|
for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
|
|
|
|
d := sched.deferpool[sc]
|
|
|
|
sched.deferpool[sc] = d.link
|
|
|
|
d.link = nil
|
|
|
|
pp.deferpool[sc] = append(pp.deferpool[sc], d)
|
|
|
|
}
|
|
|
|
unlock(&sched.deferlock)
|
|
|
|
})
|
2015-02-05 06:35:41 -07:00
|
|
|
}
|
2015-03-05 07:52:41 -07:00
|
|
|
if n := len(pp.deferpool[sc]); n > 0 {
|
|
|
|
d = pp.deferpool[sc][n-1]
|
|
|
|
pp.deferpool[sc][n-1] = nil
|
|
|
|
pp.deferpool[sc] = pp.deferpool[sc][:n-1]
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if d == nil {
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
// Allocate new defer+args.
|
2016-09-22 15:08:37 -06:00
|
|
|
systemstack(func() {
|
|
|
|
total := roundupsize(totaldefersize(uintptr(siz)))
|
|
|
|
d = (*_defer)(mallocgc(total, deferType, true))
|
|
|
|
})
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
|
|
|
d.siz = siz
|
|
|
|
d.link = gp._defer
|
|
|
|
gp._defer = d
|
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free the given defer.
|
|
|
|
// The defer cannot be used after this call.
|
2016-09-22 15:08:37 -06:00
|
|
|
//
|
|
|
|
// This must not grow the stack because there may be a frame without a
|
|
|
|
// stack map when this is called.
|
|
|
|
//
|
|
|
|
//go:nosplit
|
2014-09-03 09:49:43 -06:00
|
|
|
func freedefer(d *_defer) {
|
2014-10-07 21:17:31 -06:00
|
|
|
if d._panic != nil {
|
2014-10-07 21:39:00 -06:00
|
|
|
freedeferpanic()
|
2014-10-07 21:17:31 -06:00
|
|
|
}
|
2014-10-07 22:03:50 -06:00
|
|
|
if d.fn != nil {
|
|
|
|
freedeferfn()
|
|
|
|
}
|
2014-09-03 09:49:43 -06:00
|
|
|
sc := deferclass(uintptr(d.siz))
|
2017-08-17 08:51:35 -06:00
|
|
|
if sc >= uintptr(len(p{}.deferpool)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
pp := getg().m.p.ptr()
|
|
|
|
if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) {
|
|
|
|
// Transfer half of local cache to the central cache.
|
|
|
|
//
|
|
|
|
// Take this slow path on the system stack so
|
|
|
|
// we don't grow freedefer's stack.
|
|
|
|
systemstack(func() {
|
|
|
|
var first, last *_defer
|
|
|
|
for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 {
|
|
|
|
n := len(pp.deferpool[sc])
|
|
|
|
d := pp.deferpool[sc][n-1]
|
|
|
|
pp.deferpool[sc][n-1] = nil
|
|
|
|
pp.deferpool[sc] = pp.deferpool[sc][:n-1]
|
|
|
|
if first == nil {
|
|
|
|
first = d
|
|
|
|
} else {
|
|
|
|
last.link = d
|
2015-02-05 06:35:41 -07:00
|
|
|
}
|
2017-08-17 08:51:35 -06:00
|
|
|
last = d
|
|
|
|
}
|
|
|
|
lock(&sched.deferlock)
|
|
|
|
last.link = sched.deferpool[sc]
|
|
|
|
sched.deferpool[sc] = first
|
|
|
|
unlock(&sched.deferlock)
|
|
|
|
})
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
2017-09-13 16:53:47 -06:00
|
|
|
|
|
|
|
// These lines used to be simply `*d = _defer{}` but that
|
|
|
|
// started causing a nosplit stack overflow via typedmemmove.
|
|
|
|
d.siz = 0
|
|
|
|
d.started = false
|
|
|
|
d.sp = 0
|
|
|
|
d.pc = 0
|
|
|
|
d.fn = nil
|
|
|
|
d._panic = nil
|
|
|
|
d.link = nil
|
|
|
|
|
2017-08-17 08:51:35 -06:00
|
|
|
pp.deferpool[sc] = append(pp.deferpool[sc], d)
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
|
|
|
|
2014-10-07 21:39:00 -06:00
|
|
|
// Separate function so that it can split stack.
|
|
|
|
// Windows otherwise runs out of stack space.
|
|
|
|
func freedeferpanic() {
|
|
|
|
// _panic must be cleared before d is unlinked from gp.
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("freedefer with d._panic != nil")
|
2014-10-07 21:39:00 -06:00
|
|
|
}
|
|
|
|
|
2014-10-07 22:03:50 -06:00
|
|
|
func freedeferfn() {
|
|
|
|
// fn must be cleared before d is unlinked from gp.
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("freedefer with d.fn != nil")
|
2014-10-07 22:03:50 -06:00
|
|
|
}
|
|
|
|
|
2014-09-03 09:49:43 -06:00
|
|
|
// Run a deferred function if there is one.
|
|
|
|
// The compiler inserts a call to this at the end of any
|
|
|
|
// function which calls defer.
|
|
|
|
// If there is a deferred function, this will call runtime·jmpdefer,
|
|
|
|
// which will jump to the deferred function such that it appears
|
|
|
|
// to have been called by the caller of deferreturn at the point
|
2016-03-01 16:21:55 -07:00
|
|
|
// just before deferreturn was called. The effect is that deferreturn
|
2014-09-03 09:49:43 -06:00
|
|
|
// is called again and again until there are no more deferred functions.
|
|
|
|
// Cannot split the stack because we reuse the caller's frame to
|
|
|
|
// call the deferred function.
|
|
|
|
|
|
|
|
// The single argument isn't actually used - it just has its address
|
|
|
|
// taken so it can be matched against pending defers.
|
|
|
|
//go:nosplit
|
|
|
|
func deferreturn(arg0 uintptr) {
|
|
|
|
gp := getg()
|
|
|
|
d := gp._defer
|
|
|
|
if d == nil {
|
|
|
|
return
|
|
|
|
}
|
2014-12-08 15:18:58 -07:00
|
|
|
sp := getcallersp(unsafe.Pointer(&arg0))
|
|
|
|
if d.sp != sp {
|
2014-09-03 09:49:43 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Moving arguments around.
|
2016-09-22 15:08:37 -06:00
|
|
|
//
|
|
|
|
// Everything called after this point must be recursively
|
|
|
|
// nosplit because the garbage collector won't know the form
|
|
|
|
// of the arguments until the jmpdefer can flip the PC over to
|
|
|
|
// fn.
|
|
|
|
switch d.siz {
|
|
|
|
case 0:
|
|
|
|
// Do nothing.
|
|
|
|
case sys.PtrSize:
|
|
|
|
*(*uintptr)(unsafe.Pointer(&arg0)) = *(*uintptr)(deferArgs(d))
|
|
|
|
default:
|
|
|
|
memmove(unsafe.Pointer(&arg0), deferArgs(d), uintptr(d.siz))
|
|
|
|
}
|
2014-09-03 09:49:43 -06:00
|
|
|
fn := d.fn
|
2014-10-07 22:03:50 -06:00
|
|
|
d.fn = nil
|
2014-09-03 09:49:43 -06:00
|
|
|
gp._defer = d.link
|
2016-09-22 15:08:37 -06:00
|
|
|
freedefer(d)
|
2014-12-08 15:18:58 -07:00
|
|
|
jmpdefer(fn, uintptr(unsafe.Pointer(&arg0)))
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
|
|
|
|
2016-03-01 16:21:55 -07:00
|
|
|
// Goexit terminates the goroutine that calls it. No other goroutine is affected.
|
|
|
|
// Goexit runs all deferred calls before terminating the goroutine. Because Goexit
|
2014-09-16 13:50:05 -06:00
|
|
|
// is not panic, however, any recover calls in those deferred functions will return nil.
|
2014-09-03 09:49:43 -06:00
|
|
|
//
|
|
|
|
// Calling Goexit from the main goroutine terminates that goroutine
|
|
|
|
// without func main returning. Since func main has not returned,
|
|
|
|
// the program continues execution of other goroutines.
|
|
|
|
// If all other goroutines exit, the program crashes.
|
|
|
|
func Goexit() {
|
|
|
|
// Run all deferred functions for the current goroutine.
|
2014-09-19 17:33:14 -06:00
|
|
|
// This code is similar to gopanic, see that implementation
|
|
|
|
// for detailed comments.
|
2014-09-03 09:49:43 -06:00
|
|
|
gp := getg()
|
2014-09-19 17:33:14 -06:00
|
|
|
for {
|
2014-09-03 09:49:43 -06:00
|
|
|
d := gp._defer
|
2014-09-19 17:33:14 -06:00
|
|
|
if d == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if d.started {
|
|
|
|
if d._panic != nil {
|
|
|
|
d._panic.aborted = true
|
2014-10-07 21:17:31 -06:00
|
|
|
d._panic = nil
|
2014-09-19 17:33:14 -06:00
|
|
|
}
|
2014-10-07 22:03:50 -06:00
|
|
|
d.fn = nil
|
2014-09-19 17:33:14 -06:00
|
|
|
gp._defer = d.link
|
|
|
|
freedefer(d)
|
|
|
|
continue
|
|
|
|
}
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
d.started = true
|
2014-12-30 11:59:55 -07:00
|
|
|
reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
|
2014-09-19 17:33:14 -06:00
|
|
|
if gp._defer != d {
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("bad defer entry in Goexit")
|
2014-09-19 17:33:14 -06:00
|
|
|
}
|
2014-10-07 21:17:31 -06:00
|
|
|
d._panic = nil
|
2014-10-07 22:03:50 -06:00
|
|
|
d.fn = nil
|
2014-09-03 09:49:43 -06:00
|
|
|
gp._defer = d.link
|
|
|
|
freedefer(d)
|
|
|
|
// Note: we ignore recovers here because Goexit isn't a panic
|
|
|
|
}
|
runtime: call goexit1 instead of goexit
Currently, runtime.Goexit() calls goexit()—the goroutine exit stub—to
terminate the goroutine. This *mostly* works, but can cause a
"leftover stack barriers" panic if the following happens:
1. Goroutine A has a reasonably large stack.
2. The garbage collector scan phase runs and installs stack barriers
in A's stack. The top-most stack barrier happens to fall at address X.
3. Goroutine A unwinds the stack far enough to be a candidate for
stack shrinking, but not past X.
4. Goroutine A calls runtime.Goexit(), which calls goexit(), which
calls goexit1().
5. The garbage collector enters mark termination.
6. Goroutine A is preempted right at the prologue of goexit1() and
performs a stack shrink, which calls gentraceback.
gentraceback stops as soon as it sees goexit on the stack, which is
only two frames up at this point, even though there may really be many
frames above it. More to the point, the stack barrier at X is above
the goexit frame, so gentraceback never sees that stack barrier. At
the end of gentraceback, it checks that it saw all of the stack
barriers and panics because it didn't see the one at X.
The fix is simple: call goexit1, which actually implements the process
of exiting a goroutine, rather than goexit, the exit stub.
To make sure this doesn't happen again in the future, we also add an
argument to the stub prototype of goexit so you really, really have to
want to call it in order to call it. We were able to reliably
reproduce the above sequence with a fair amount of awful code inserted
at the right places in the runtime, but chose to change the goexit
prototype to ensure this wouldn't happen again rather than pollute the
runtime with ugly testing code.
Change-Id: Ifb6fb53087e09a252baddadc36eebf954468f2a8
Reviewed-on: https://go-review.googlesource.com/13323
Reviewed-by: Russ Cox <rsc@golang.org>
2015-08-06 13:36:50 -06:00
|
|
|
goexit1()
|
2014-09-03 09:49:43 -06:00
|
|
|
}
|
liblink, runtime: diagnose and fix C code running on Go stack
This CL contains compiler+runtime changes that detect C code
running on Go (not g0, not gsignal) stacks, and it contains
corrections for what it detected.
The detection works by changing the C prologue to use a different
stack guard word in the G than Go prologue does. On the g0 and
gsignal stacks, that stack guard word is set to the usual
stack guard value. But on ordinary Go stacks, that stack
guard word is set to ^0, which will make any stack split
check fail. The C prologue then calls morestackc instead
of morestack, and morestackc aborts the program with
a message about running C code on a Go stack.
This check catches all C code running on the Go stack
except NOSPLIT code. The NOSPLIT code is allowed,
so the check is complete. Since it is a dynamic check,
the code must execute to be caught. But unlike the static
checks we've been using in cmd/ld, the dynamic check
works with function pointers and other indirect calls.
For example it caught sigpanic being pushed onto Go
stacks in the signal handlers.
Fixes #8667.
LGTM=khr, iant
R=golang-codereviews, khr, iant
CC=golang-codereviews, r
https://golang.org/cl/133700043
2014-09-08 12:05:23 -06:00
|
|
|
|
2016-02-21 11:56:08 -07:00
|
|
|
// Call all Error and String methods before freezing the world.
|
|
|
|
// Used when crashing with panicking.
|
|
|
|
// This must match types handled by printany.
|
|
|
|
func preprintpanics(p *_panic) {
|
2016-10-04 22:15:42 -06:00
|
|
|
defer func() {
|
|
|
|
if recover() != nil {
|
|
|
|
throw("panic while printing panic value")
|
|
|
|
}
|
|
|
|
}()
|
2016-02-21 11:56:08 -07:00
|
|
|
for p != nil {
|
|
|
|
switch v := p.arg.(type) {
|
|
|
|
case error:
|
|
|
|
p.arg = v.Error()
|
|
|
|
case stringer:
|
|
|
|
p.arg = v.String()
|
|
|
|
}
|
|
|
|
p = p.link
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-01 16:21:55 -07:00
|
|
|
// Print all currently active panics. Used when crashing.
|
2014-09-08 13:33:08 -06:00
|
|
|
func printpanics(p *_panic) {
|
|
|
|
if p.link != nil {
|
|
|
|
printpanics(p.link)
|
|
|
|
print("\t")
|
|
|
|
}
|
|
|
|
print("panic: ")
|
|
|
|
printany(p.arg)
|
|
|
|
if p.recovered {
|
|
|
|
print(" [recovered]")
|
|
|
|
}
|
|
|
|
print("\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
// The implementation of the predeclared function panic.
|
|
|
|
func gopanic(e interface{}) {
|
|
|
|
gp := getg()
|
|
|
|
if gp.m.curg != gp {
|
2014-11-11 15:04:34 -07:00
|
|
|
print("panic: ")
|
|
|
|
printany(e)
|
|
|
|
print("\n")
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("panic on system stack")
|
2014-09-08 13:33:08 -06:00
|
|
|
}
|
runtime: delete panicstring; move its checks into gopanic
In Go 1.3 the runtime called panicstring to report errors like
divide by zero or memory faults. Now we call panic (gopanic)
with pre-allocated error values. That new path is missing the
checking that panicstring did, so add it there.
The only call to panicstring left is in cnew, which is problematic
because if it fails, probably the heap is corrupt. In that case,
calling panicstring creates a new errorCString (no allocation there),
but then panic tries to print it, invoking errorCString.Error, which
does a string concatenation (allocating), which then dies.
Replace that one panicstring with a throw: cnew is for allocating
runtime data structures and should never ask for an inappropriate
amount of memory.
With panicstring gone, delete newErrorCString, errorCString.
While we're here, delete newErrorString, not called by anyone.
(It can't be: that would be C code calling Go code that might
block or grow the stack.)
Found while debugging a malloc corruption.
This resulted in 'panic during panic' instead of a more useful message.
LGTM=khr
R=khr
CC=golang-codereviews
https://golang.org/cl/138290045
2014-09-18 12:49:24 -06:00
|
|
|
|
|
|
|
// m.softfloat is set during software floating point.
|
|
|
|
// It increments m.locks to avoid preemption.
|
|
|
|
// We moved the memory loads out, so there shouldn't be
|
|
|
|
// any reason for it to panic anymore.
|
|
|
|
if gp.m.softfloat != 0 {
|
|
|
|
gp.m.locks--
|
|
|
|
gp.m.softfloat = 0
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("panic during softfloat")
|
runtime: delete panicstring; move its checks into gopanic
In Go 1.3 the runtime called panicstring to report errors like
divide by zero or memory faults. Now we call panic (gopanic)
with pre-allocated error values. That new path is missing the
checking that panicstring did, so add it there.
The only call to panicstring left is in cnew, which is problematic
because if it fails, probably the heap is corrupt. In that case,
calling panicstring creates a new errorCString (no allocation there),
but then panic tries to print it, invoking errorCString.Error, which
does a string concatenation (allocating), which then dies.
Replace that one panicstring with a throw: cnew is for allocating
runtime data structures and should never ask for an inappropriate
amount of memory.
With panicstring gone, delete newErrorCString, errorCString.
While we're here, delete newErrorString, not called by anyone.
(It can't be: that would be C code calling Go code that might
block or grow the stack.)
Found while debugging a malloc corruption.
This resulted in 'panic during panic' instead of a more useful message.
LGTM=khr
R=khr
CC=golang-codereviews
https://golang.org/cl/138290045
2014-09-18 12:49:24 -06:00
|
|
|
}
|
|
|
|
if gp.m.mallocing != 0 {
|
|
|
|
print("panic: ")
|
|
|
|
printany(e)
|
|
|
|
print("\n")
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("panic during malloc")
|
runtime: delete panicstring; move its checks into gopanic
In Go 1.3 the runtime called panicstring to report errors like
divide by zero or memory faults. Now we call panic (gopanic)
with pre-allocated error values. That new path is missing the
checking that panicstring did, so add it there.
The only call to panicstring left is in cnew, which is problematic
because if it fails, probably the heap is corrupt. In that case,
calling panicstring creates a new errorCString (no allocation there),
but then panic tries to print it, invoking errorCString.Error, which
does a string concatenation (allocating), which then dies.
Replace that one panicstring with a throw: cnew is for allocating
runtime data structures and should never ask for an inappropriate
amount of memory.
With panicstring gone, delete newErrorCString, errorCString.
While we're here, delete newErrorString, not called by anyone.
(It can't be: that would be C code calling Go code that might
block or grow the stack.)
Found while debugging a malloc corruption.
This resulted in 'panic during panic' instead of a more useful message.
LGTM=khr
R=khr
CC=golang-codereviews
https://golang.org/cl/138290045
2014-09-18 12:49:24 -06:00
|
|
|
}
|
2015-01-30 13:30:41 -07:00
|
|
|
if gp.m.preemptoff != "" {
|
runtime: delete panicstring; move its checks into gopanic
In Go 1.3 the runtime called panicstring to report errors like
divide by zero or memory faults. Now we call panic (gopanic)
with pre-allocated error values. That new path is missing the
checking that panicstring did, so add it there.
The only call to panicstring left is in cnew, which is problematic
because if it fails, probably the heap is corrupt. In that case,
calling panicstring creates a new errorCString (no allocation there),
but then panic tries to print it, invoking errorCString.Error, which
does a string concatenation (allocating), which then dies.
Replace that one panicstring with a throw: cnew is for allocating
runtime data structures and should never ask for an inappropriate
amount of memory.
With panicstring gone, delete newErrorCString, errorCString.
While we're here, delete newErrorString, not called by anyone.
(It can't be: that would be C code calling Go code that might
block or grow the stack.)
Found while debugging a malloc corruption.
This resulted in 'panic during panic' instead of a more useful message.
LGTM=khr
R=khr
CC=golang-codereviews
https://golang.org/cl/138290045
2014-09-18 12:49:24 -06:00
|
|
|
print("panic: ")
|
|
|
|
printany(e)
|
|
|
|
print("\n")
|
2015-01-30 13:30:41 -07:00
|
|
|
print("preempt off reason: ")
|
|
|
|
print(gp.m.preemptoff)
|
|
|
|
print("\n")
|
|
|
|
throw("panic during preemptoff")
|
runtime: delete panicstring; move its checks into gopanic
In Go 1.3 the runtime called panicstring to report errors like
divide by zero or memory faults. Now we call panic (gopanic)
with pre-allocated error values. That new path is missing the
checking that panicstring did, so add it there.
The only call to panicstring left is in cnew, which is problematic
because if it fails, probably the heap is corrupt. In that case,
calling panicstring creates a new errorCString (no allocation there),
but then panic tries to print it, invoking errorCString.Error, which
does a string concatenation (allocating), which then dies.
Replace that one panicstring with a throw: cnew is for allocating
runtime data structures and should never ask for an inappropriate
amount of memory.
With panicstring gone, delete newErrorCString, errorCString.
While we're here, delete newErrorString, not called by anyone.
(It can't be: that would be C code calling Go code that might
block or grow the stack.)
Found while debugging a malloc corruption.
This resulted in 'panic during panic' instead of a more useful message.
LGTM=khr
R=khr
CC=golang-codereviews
https://golang.org/cl/138290045
2014-09-18 12:49:24 -06:00
|
|
|
}
|
|
|
|
if gp.m.locks != 0 {
|
|
|
|
print("panic: ")
|
|
|
|
printany(e)
|
|
|
|
print("\n")
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("panic holding locks")
|
runtime: delete panicstring; move its checks into gopanic
In Go 1.3 the runtime called panicstring to report errors like
divide by zero or memory faults. Now we call panic (gopanic)
with pre-allocated error values. That new path is missing the
checking that panicstring did, so add it there.
The only call to panicstring left is in cnew, which is problematic
because if it fails, probably the heap is corrupt. In that case,
calling panicstring creates a new errorCString (no allocation there),
but then panic tries to print it, invoking errorCString.Error, which
does a string concatenation (allocating), which then dies.
Replace that one panicstring with a throw: cnew is for allocating
runtime data structures and should never ask for an inappropriate
amount of memory.
With panicstring gone, delete newErrorCString, errorCString.
While we're here, delete newErrorString, not called by anyone.
(It can't be: that would be C code calling Go code that might
block or grow the stack.)
Found while debugging a malloc corruption.
This resulted in 'panic during panic' instead of a more useful message.
LGTM=khr
R=khr
CC=golang-codereviews
https://golang.org/cl/138290045
2014-09-18 12:49:24 -06:00
|
|
|
}
|
|
|
|
|
2014-09-08 13:33:08 -06:00
|
|
|
var p _panic
|
|
|
|
p.arg = e
|
|
|
|
p.link = gp._panic
|
|
|
|
gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
|
|
|
|
|
2017-04-19 08:32:34 -06:00
|
|
|
atomic.Xadd(&runningPanicDefers, 1)
|
|
|
|
|
2014-09-08 13:33:08 -06:00
|
|
|
for {
|
|
|
|
d := gp._defer
|
|
|
|
if d == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
// If defer was started by earlier panic or Goexit (and, since we're back here, that triggered a new panic),
|
|
|
|
// take defer off list. The earlier panic or Goexit will not continue running.
|
|
|
|
if d.started {
|
|
|
|
if d._panic != nil {
|
|
|
|
d._panic.aborted = true
|
|
|
|
}
|
2014-10-07 21:17:31 -06:00
|
|
|
d._panic = nil
|
2014-10-07 22:03:50 -06:00
|
|
|
d.fn = nil
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
gp._defer = d.link
|
|
|
|
freedefer(d)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark defer as started, but keep on list, so that traceback
|
|
|
|
// can find and update the defer's argument frame if stack growth
|
2015-06-11 07:49:38 -06:00
|
|
|
// or a garbage collection happens before reflectcall starts executing d.fn.
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
d.started = true
|
|
|
|
|
|
|
|
// Record the panic that is running the defer.
|
|
|
|
// If there is a new panic during the deferred call, that panic
|
|
|
|
// will find d in the list and will mark d._panic (this panic) aborted.
|
2015-10-15 15:33:50 -06:00
|
|
|
d._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
|
2014-09-08 13:33:08 -06:00
|
|
|
|
2014-09-08 19:02:36 -06:00
|
|
|
p.argp = unsafe.Pointer(getargp(0))
|
2014-12-30 11:59:55 -07:00
|
|
|
reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
|
2014-09-08 19:02:36 -06:00
|
|
|
p.argp = nil
|
2014-09-08 13:33:08 -06:00
|
|
|
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
// reflectcall did not panic. Remove d.
|
|
|
|
if gp._defer != d {
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("bad defer entry in panic")
|
2014-09-08 13:33:08 -06:00
|
|
|
}
|
2014-10-07 21:17:31 -06:00
|
|
|
d._panic = nil
|
2014-10-07 22:03:50 -06:00
|
|
|
d.fn = nil
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
gp._defer = d.link
|
2014-09-08 13:33:08 -06:00
|
|
|
|
2016-03-01 16:21:55 -07:00
|
|
|
// trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic
|
2014-09-08 13:33:08 -06:00
|
|
|
//GC()
|
|
|
|
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
pc := d.pc
|
2014-12-08 15:18:58 -07:00
|
|
|
sp := unsafe.Pointer(d.sp) // must be pointer so it gets adjusted during stack copy
|
2014-09-08 13:33:08 -06:00
|
|
|
freedefer(d)
|
|
|
|
if p.recovered {
|
2017-04-19 08:32:34 -06:00
|
|
|
atomic.Xadd(&runningPanicDefers, -1)
|
|
|
|
|
2014-09-08 13:33:08 -06:00
|
|
|
gp._panic = p.link
|
|
|
|
// Aborted panics are marked but remain on the g.panic list.
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
// Remove them from the list.
|
2014-09-08 13:33:08 -06:00
|
|
|
for gp._panic != nil && gp._panic.aborted {
|
|
|
|
gp._panic = gp._panic.link
|
|
|
|
}
|
|
|
|
if gp._panic == nil { // must be done with signal
|
|
|
|
gp.sig = 0
|
|
|
|
}
|
|
|
|
// Pass information about recovering frame to recovery.
|
2014-12-08 15:18:58 -07:00
|
|
|
gp.sigcode0 = uintptr(sp)
|
2014-09-08 13:33:08 -06:00
|
|
|
gp.sigcode1 = pc
|
2014-11-11 15:04:34 -07:00
|
|
|
mcall(recovery)
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("recovery failed") // mcall should not return
|
2014-09-08 13:33:08 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ran out of deferred calls - old-school panic now
|
2016-02-21 11:56:08 -07:00
|
|
|
// Because it is unsafe to call arbitrary user code after freezing
|
|
|
|
// the world, we call preprintpanics to invoke all necessary Error
|
|
|
|
// and String methods to prepare the panic strings before startpanic.
|
|
|
|
preprintpanics(gp._panic)
|
2014-09-08 13:33:08 -06:00
|
|
|
startpanic()
|
2017-04-19 08:32:34 -06:00
|
|
|
|
|
|
|
// startpanic set panicking, which will block main from exiting,
|
|
|
|
// so now OK to decrement runningPanicDefers.
|
|
|
|
atomic.Xadd(&runningPanicDefers, -1)
|
|
|
|
|
2014-09-08 13:33:08 -06:00
|
|
|
printpanics(gp._panic)
|
|
|
|
dopanic(0) // should not return
|
|
|
|
*(*int)(nil) = 0 // not reached
|
|
|
|
}
|
|
|
|
|
|
|
|
// getargp returns the location where the caller
|
|
|
|
// writes outgoing function call arguments.
|
|
|
|
//go:nosplit
|
2016-09-08 10:49:31 -06:00
|
|
|
//go:noinline
|
2014-09-08 13:33:08 -06:00
|
|
|
func getargp(x int) uintptr {
|
|
|
|
// x is an argument mainly so that we can return its address.
|
|
|
|
return uintptr(noescape(unsafe.Pointer(&x)))
|
|
|
|
}
|
|
|
|
|
|
|
|
// The implementation of the predeclared function recover.
|
|
|
|
// Cannot split the stack because it needs to reliably
|
|
|
|
// find the stack segment of its caller.
|
|
|
|
//
|
|
|
|
// TODO(rsc): Once we commit to CopyStackAlways,
|
|
|
|
// this doesn't need to be nosplit.
|
|
|
|
//go:nosplit
|
|
|
|
func gorecover(argp uintptr) interface{} {
|
|
|
|
// Must be in a function running as part of a deferred call during the panic.
|
|
|
|
// Must be called from the topmost function of the call
|
|
|
|
// (the function used in the defer statement).
|
|
|
|
// p.argp is the argument pointer of that topmost deferred function call.
|
|
|
|
// Compare against argp reported by caller.
|
|
|
|
// If they match, the caller is the one who can recover.
|
|
|
|
gp := getg()
|
|
|
|
p := gp._panic
|
2014-09-08 19:02:36 -06:00
|
|
|
if p != nil && !p.recovered && argp == uintptr(p.argp) {
|
2014-09-08 13:33:08 -06:00
|
|
|
p.recovered = true
|
|
|
|
return p.arg
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//go:nosplit
|
|
|
|
func startpanic() {
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(startpanic_m)
|
2014-09-08 13:33:08 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//go:nosplit
|
|
|
|
func dopanic(unused int) {
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
pc := getcallerpc(unsafe.Pointer(&unused))
|
|
|
|
sp := getcallersp(unsafe.Pointer(&unused))
|
2014-09-08 13:33:08 -06:00
|
|
|
gp := getg()
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(func() {
|
|
|
|
dopanic_m(gp, pc, sp) // should never return
|
|
|
|
})
|
2014-09-08 13:33:08 -06:00
|
|
|
*(*int)(nil) = 0
|
|
|
|
}
|
|
|
|
|
2016-10-18 08:26:07 -06:00
|
|
|
//go:linkname sync_throw sync.throw
|
|
|
|
func sync_throw(s string) {
|
|
|
|
throw(s)
|
|
|
|
}
|
|
|
|
|
2014-09-08 13:33:08 -06:00
|
|
|
//go:nosplit
|
2014-12-27 21:58:00 -07:00
|
|
|
func throw(s string) {
|
2014-10-22 13:51:54 -06:00
|
|
|
print("fatal error: ", s, "\n")
|
2014-09-08 13:33:08 -06:00
|
|
|
gp := getg()
|
|
|
|
if gp.m.throwing == 0 {
|
|
|
|
gp.m.throwing = 1
|
|
|
|
}
|
|
|
|
startpanic()
|
|
|
|
dopanic(0)
|
|
|
|
*(*int)(nil) = 0 // not reached
|
|
|
|
}
|
2015-10-15 20:00:12 -06:00
|
|
|
|
2017-04-19 08:32:34 -06:00
|
|
|
// runningPanicDefers is non-zero while running deferred functions for panic.
|
|
|
|
// runningPanicDefers is incremented and decremented atomically.
|
|
|
|
// This is used to try hard to get a panic stack trace out when exiting.
|
|
|
|
var runningPanicDefers uint32
|
|
|
|
|
|
|
|
// panicking is non-zero when crashing the program for an unrecovered panic.
|
|
|
|
// panicking is incremented and decremented atomically.
|
|
|
|
var panicking uint32
|
|
|
|
|
|
|
|
// paniclk is held while printing the panic information and stack trace,
|
|
|
|
// so that two concurrent panics don't overlap their output.
|
2015-10-15 20:00:12 -06:00
|
|
|
var paniclk mutex
|
|
|
|
|
|
|
|
// Unwind the stack after a deferred function calls recover
|
2016-03-01 16:21:55 -07:00
|
|
|
// after a panic. Then arrange to continue running as though
|
2015-10-15 20:00:12 -06:00
|
|
|
// the caller of the deferred function returned normally.
|
|
|
|
func recovery(gp *g) {
|
|
|
|
// Info about defer passed in G struct.
|
|
|
|
sp := gp.sigcode0
|
|
|
|
pc := gp.sigcode1
|
|
|
|
|
|
|
|
// d's arguments need to be in the stack.
|
|
|
|
if sp != 0 && (sp < gp.stack.lo || gp.stack.hi < sp) {
|
|
|
|
print("recover: ", hex(sp), " not in [", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n")
|
|
|
|
throw("bad recovery")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make the deferproc for this d return again,
|
|
|
|
// this time returning 1. The calling function will
|
|
|
|
// jump to the standard return epilogue.
|
|
|
|
gp.sched.sp = sp
|
|
|
|
gp.sched.pc = pc
|
|
|
|
gp.sched.lr = 0
|
|
|
|
gp.sched.ret = 1
|
|
|
|
gogo(&gp.sched)
|
|
|
|
}
|
|
|
|
|
|
|
|
func startpanic_m() {
|
|
|
|
_g_ := getg()
|
|
|
|
if mheap_.cachealloc.size == 0 { // very early
|
|
|
|
print("runtime: panic before malloc heap initialized\n")
|
|
|
|
_g_.m.mallocing = 1 // tell rest of panic not to try to malloc
|
|
|
|
} else if _g_.m.mcache == nil { // can happen if called from signal handler or throw
|
|
|
|
_g_.m.mcache = allocmcache()
|
|
|
|
}
|
|
|
|
|
|
|
|
switch _g_.m.dying {
|
|
|
|
case 0:
|
|
|
|
_g_.m.dying = 1
|
2015-10-19 03:52:55 -06:00
|
|
|
_g_.writebuf = nil
|
2015-11-02 12:09:24 -07:00
|
|
|
atomic.Xadd(&panicking, 1)
|
2015-10-15 20:00:12 -06:00
|
|
|
lock(&paniclk)
|
|
|
|
if debug.schedtrace > 0 || debug.scheddetail > 0 {
|
|
|
|
schedtrace(true)
|
|
|
|
}
|
|
|
|
freezetheworld()
|
|
|
|
return
|
|
|
|
case 1:
|
2016-12-08 15:15:40 -07:00
|
|
|
// Something failed while panicking, probably the print of the
|
2015-10-15 20:00:12 -06:00
|
|
|
// argument to panic(). Just print a stack trace and exit.
|
|
|
|
_g_.m.dying = 2
|
|
|
|
print("panic during panic\n")
|
|
|
|
dopanic(0)
|
|
|
|
exit(3)
|
|
|
|
fallthrough
|
|
|
|
case 2:
|
|
|
|
// This is a genuine bug in the runtime, we couldn't even
|
|
|
|
// print the stack trace successfully.
|
|
|
|
_g_.m.dying = 3
|
|
|
|
print("stack trace unavailable\n")
|
|
|
|
exit(4)
|
|
|
|
fallthrough
|
|
|
|
default:
|
2017-08-19 14:33:51 -06:00
|
|
|
// Can't even print! Just exit.
|
2015-10-15 20:00:12 -06:00
|
|
|
exit(5)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var didothers bool
|
|
|
|
var deadlock mutex
|
|
|
|
|
|
|
|
func dopanic_m(gp *g, pc, sp uintptr) {
|
|
|
|
if gp.sig != 0 {
|
2016-05-04 01:42:13 -06:00
|
|
|
signame := signame(gp.sig)
|
|
|
|
if signame != "" {
|
|
|
|
print("[signal ", signame)
|
|
|
|
} else {
|
|
|
|
print("[signal ", hex(gp.sig))
|
|
|
|
}
|
|
|
|
print(" code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n")
|
2015-10-15 20:00:12 -06:00
|
|
|
}
|
|
|
|
|
2015-10-30 09:03:02 -06:00
|
|
|
level, all, docrash := gotraceback()
|
2015-10-15 20:00:12 -06:00
|
|
|
_g_ := getg()
|
2015-10-30 09:03:02 -06:00
|
|
|
if level > 0 {
|
|
|
|
if gp != gp.m.curg {
|
|
|
|
all = true
|
|
|
|
}
|
2015-10-15 20:00:12 -06:00
|
|
|
if gp != gp.m.g0 {
|
|
|
|
print("\n")
|
|
|
|
goroutineheader(gp)
|
|
|
|
traceback(pc, sp, 0, gp)
|
2015-10-30 09:03:02 -06:00
|
|
|
} else if level >= 2 || _g_.m.throwing > 0 {
|
2015-10-15 20:00:12 -06:00
|
|
|
print("\nruntime stack:\n")
|
|
|
|
traceback(pc, sp, 0, gp)
|
|
|
|
}
|
2015-10-30 09:03:02 -06:00
|
|
|
if !didothers && all {
|
2015-10-15 20:00:12 -06:00
|
|
|
didothers = true
|
|
|
|
tracebackothers(gp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unlock(&paniclk)
|
|
|
|
|
2015-11-02 12:09:24 -07:00
|
|
|
if atomic.Xadd(&panicking, -1) != 0 {
|
2015-10-15 20:00:12 -06:00
|
|
|
// Some other m is panicking too.
|
|
|
|
// Let it print what it needs to print.
|
|
|
|
// Wait forever without chewing up cpu.
|
|
|
|
// It will exit when it's done.
|
|
|
|
lock(&deadlock)
|
|
|
|
lock(&deadlock)
|
|
|
|
}
|
|
|
|
|
|
|
|
if docrash {
|
|
|
|
crash()
|
|
|
|
}
|
|
|
|
|
|
|
|
exit(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
//go:nosplit
|
|
|
|
func canpanic(gp *g) bool {
|
|
|
|
// Note that g is m->gsignal, different from gp.
|
|
|
|
// Note also that g->m can change at preemption, so m can go stale
|
|
|
|
// if this function ever makes a function call.
|
|
|
|
_g_ := getg()
|
|
|
|
_m_ := _g_.m
|
|
|
|
|
|
|
|
// Is it okay for gp to panic instead of crashing the program?
|
|
|
|
// Yes, as long as it is running Go code, not runtime code,
|
|
|
|
// and not stuck in a system call.
|
|
|
|
if gp == nil || gp != _m_.curg {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
status := readgstatus(gp)
|
|
|
|
if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if GOOS == "windows" && _m_.libcallsp != 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|