Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: getArgInfo nil dereference #17471

Closed
aclements opened this issue Oct 16, 2016 · 4 comments
Closed

runtime: getArgInfo nil dereference #17471

aclements opened this issue Oct 16, 2016 · 4 comments

Comments

@aclements
Copy link
Member

What version of Go are you using (go version)?

Current master (86b2f29).

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/austin/r/go"
GORACE=""
GOROOT="/home/austin/go.dev"
GOTOOLDIR="/home/austin/go.dev/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build137746302=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"

What did you do?

cd test
go build recover.go
while GOGC=10 ./recover; do; done

What did you expect to see?

Nothing (the test prints nothing when it succeeds).

What did you see instead?

fatal error: unexpected signal during runtime execution                   
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x44162a]

runtime stack:
runtime.throw(0x4bef28, 0x2a)
    /home/austin/go.dev/src/runtime/panic.go:587 +0x95 fp=0xc42006f9c8 sp=0xc42006f9a8
runtime.sigpanic()
    /home/austin/go.dev/src/runtime/signal_unix.go:253 +0x2db fp=0xc42006fa18 sp=0xc42006f9c8
runtime.getArgInfo(0xc42006faa0, 0x50ae28, 0x1, 0xc420119fb0, 0x0)
    /home/austin/go.dev/src/runtime/traceback.go:556 +0xca fp=0xc42006fa68 sp=0xc42006fa18
runtime.tracebackdefers(0xc4200001a0, 0xc42006fc90, 0x0)
    /home/austin/go.dev/src/runtime/traceback.go:110 +0x158 fp=0xc42006fb00 sp=0xc42006fa68
runtime.scanstack(0xc4200001a0, 0xc420028b28)
    /home/austin/go.dev/src/runtime/mgcmark.go:792 +0x28c fp=0xc42006fce0 sp=0xc42006fb00
runtime.scang(0xc4200001a0, 0xc420028b28)
    /home/austin/go.dev/src/runtime/proc.go:830 +0x209 fp=0xc42006fd18 sp=0xc42006fce0
runtime.markroot.func1()
    /home/austin/go.dev/src/runtime/mgcmark.go:250 +0x6d fp=0xc42006fd58 sp=0xc42006fd18
runtime.systemstack(0xc42006fdc0)
    /home/austin/go.dev/src/runtime/asm_amd64.s:314 +0xab fp=0xc42006fd60 sp=0xc42006fd58
runtime.markroot(0xc420028b28, 0xc400000007)
    /home/austin/go.dev/src/runtime/mgcmark.go:255 +0x2ce fp=0xc42006fde8 sp=0xc42006fd60
runtime.gcDrain(0xc420028b28, 0x0)
    /home/austin/go.dev/src/runtime/mgcmark.go:977 +0x8f fp=0xc42006fe18 sp=0xc42006fde8
runtime.gchelper()
    /home/austin/go.dev/src/runtime/mgc.go:1843 +0xe5 fp=0xc42006fe48 sp=0xc42006fe18
runtime.stopm()
    /home/austin/go.dev/src/runtime/proc.go:1599 +0xdd fp=0xc42006fe70 sp=0xc42006fe48
runtime.findrunnable(0xc420025300, 0x0)
    /home/austin/go.dev/src/runtime/proc.go:2023 +0x241 fp=0xc42006ff08 sp=0xc42006fe70
runtime.schedule()
    /home/austin/go.dev/src/runtime/proc.go:2122 +0x14c fp=0xc42006ff48 sp=0xc42006ff08
runtime.park_m(0xc42007a680)
    /home/austin/go.dev/src/runtime/proc.go:2185 +0xa0 fp=0xc42006ff78 sp=0xc42006ff48
runtime.mcall(0x0)
    /home/austin/go.dev/src/runtime/asm_amd64.s:240 +0x5b fp=0xc42006ff88 sp=0xc42006ff78

goroutine 1 [runnable (scan)]:
runtime.convT2E(0x49c1c0, 0xc420117e78, 0x293, 0x49b000)
    /home/austin/go.dev/src/runtime/iface.go:155 +0x9d fp=0xc420117e40 sp=0xc420117e38
main.test14reflect1()
    /home/austin/go.dev/test/recover.go:543 +0x18a fp=0xc420119eb0 sp=0xc420117e40
main.main()
    /home/austin/go.dev/test/recover.go:63 +0xf5 fp=0xc420119ee8 sp=0xc420119eb0
runtime.main()
    /home/austin/go.dev/src/runtime/proc.go:185 +0x20a fp=0xc420119f40 sp=0xc420119ee8
runtime.goexit()
    /home/austin/go.dev/src/runtime/asm_amd64.s:2158 +0x1 fp=0xc420119f48 sp=0xc420119f40

More...

goroutine 2 [force gc (idle)]:
runtime.gopark(0x4c04c8, 0x51dce0, 0x4baa7a, 0xf, 0x4c0314, 0x1)
    /home/austin/go.dev/src/runtime/proc.go:261 +0x13a fp=0xc42002e748 sp=0xc42002e718
runtime.goparkunlock(0x51dce0, 0x4baa7a, 0xf, 0xc420000114, 0x1)
    /home/austin/go.dev/src/runtime/proc.go:267 +0x5e fp=0xc42002e788 sp=0xc42002e748
runtime.forcegchelper()
    /home/austin/go.dev/src/runtime/proc.go:226 +0x9e fp=0xc42002e7c0 sp=0xc42002e788
runtime.goexit()
    /home/austin/go.dev/src/runtime/asm_amd64.s:2158 +0x1 fp=0xc42002e7c8 sp=0xc42002e7c0
created by runtime.init.4
    /home/austin/go.dev/src/runtime/proc.go:215 +0x35

goroutine 3 [GC sweep wait]:
runtime.gopark(0x4c04c8, 0x51de80, 0x4ba6a8, 0xd, 0x41ab14, 0x1)
    /home/austin/go.dev/src/runtime/proc.go:261 +0x13a fp=0xc42002ef38 sp=0xc42002ef08
runtime.goparkunlock(0x51de80, 0x4ba6a8, 0xd, 0x14, 0x1)
    /home/austin/go.dev/src/runtime/proc.go:267 +0x5e fp=0xc42002ef78 sp=0xc42002ef38
runtime.bgsweep(0xc420018070)
    /home/austin/go.dev/src/runtime/mgcsweep.go:63 +0xb6 fp=0xc42002efb8 sp=0xc42002ef78
runtime.goexit()
    /home/austin/go.dev/src/runtime/asm_amd64.s:2158 +0x1 fp=0xc42002efc0 sp=0xc42002efb8
created by runtime.gcenable
    /home/austin/go.dev/src/runtime/mgc.go:213 +0x61

goroutine 17 [finalizer wait]:
runtime.gopark(0x4c04c8, 0x5383a0, 0x4ba8cf, 0xe, 0x14, 0x1)
    /home/austin/go.dev/src/runtime/proc.go:261 +0x13a fp=0xc42002a708 sp=0xc42002a6d8
runtime.goparkunlock(0x5383a0, 0x4ba8cf, 0xe, 0x14, 0x1)
    /home/austin/go.dev/src/runtime/proc.go:267 +0x5e fp=0xc42002a748 sp=0xc42002a708
runtime.runfinq()
    /home/austin/go.dev/src/runtime/mfinal.go:158 +0xaf fp=0xc42002a7c0 sp=0xc42002a748
runtime.goexit()
    /home/austin/go.dev/src/runtime/asm_amd64.s:2158 +0x1 fp=0xc42002a7c8 sp=0xc42002a7c0
created by runtime.createfing
    /home/austin/go.dev/src/runtime/mfinal.go:139 +0x62

goroutine 18 [garbage collection]:
runtime.systemstack_switch()
    /home/austin/go.dev/src/runtime/asm_amd64.s:252 fp=0xc42002ad40 sp=0xc42002ad38
runtime.gcMarkTermination()
    /home/austin/go.dev/src/runtime/mgc.go:1202 +0x141 fp=0xc42002af28 sp=0xc42002ad40
runtime.gcMarkDone()
    /home/austin/go.dev/src/runtime/mgc.go:1166 +0x1db fp=0xc42002af48 sp=0xc42002af28
runtime.gcBgMarkWorker(0xc420024000)
    /home/austin/go.dev/src/runtime/mgc.go:1513 +0x2c6 fp=0xc42002afb8 sp=0xc42002af48
runtime.goexit()
    /home/austin/go.dev/src/runtime/asm_amd64.s:2158 +0x1 fp=0xc42002afc0 sp=0xc42002afb8
created by runtime.gcBgMarkStartWorkers
    /home/austin/go.dev/src/runtime/mgc.go:1357 +0x98

goroutine 19 [GC worker (idle)]:
runtime.gopark(0x4c0368, 0xc4200743a0, 0x4bac08, 0x10, 0x14, 0x0)
    /home/austin/go.dev/src/runtime/proc.go:261 +0x13a fp=0xc42002b748 sp=0xc42002b718
runtime.gcBgMarkWorker(0xc420025300)
    /home/austin/go.dev/src/runtime/mgc.go:1436 +0x108 fp=0xc42002b7b8 sp=0xc42002b748
runtime.goexit()
    /home/austin/go.dev/src/runtime/asm_amd64.s:2158 +0x1 fp=0xc42002b7c0 sp=0xc42002b7b8
created by runtime.gcBgMarkStartWorkers
    /home/austin/go.dev/src/runtime/mgc.go:1357 +0x98

goroutine 20 [GC worker (idle)]:
runtime.gopark(0x4c0368, 0xc4200743b0, 0x4bac08, 0x10, 0x14, 0x0)
    /home/austin/go.dev/src/runtime/proc.go:261 +0x13a fp=0xc42002bf48 sp=0xc42002bf18
runtime.gcBgMarkWorker(0xc420026600)
    /home/austin/go.dev/src/runtime/mgc.go:1436 +0x108 fp=0xc42002bfb8 sp=0xc42002bf48
runtime.goexit()
    /home/austin/go.dev/src/runtime/asm_amd64.s:2158 +0x1 fp=0xc42002bfc0 sp=0xc42002bfb8
created by runtime.gcBgMarkStartWorkers
    /home/austin/go.dev/src/runtime/mgc.go:1357 +0x98

goroutine 21 [GC worker (idle)]:
runtime.gopark(0x4c0368, 0xc4200743c0, 0x4bac08, 0x10, 0x14, 0x0)
    /home/austin/go.dev/src/runtime/proc.go:261 +0x13a fp=0xc42002c748 sp=0xc42002c718
runtime.gcBgMarkWorker(0xc420027900)
    /home/austin/go.dev/src/runtime/mgc.go:1436 +0x108 fp=0xc42002c7b8 sp=0xc42002c748
runtime.goexit()
    /home/austin/go.dev/src/runtime/asm_amd64.s:2158 +0x1 fp=0xc42002c7c0 sp=0xc42002c7b8
created by runtime.gcBgMarkStartWorkers
    /home/austin/go.dev/src/runtime/mgc.go:1357 +0x98
@aclements aclements added this to the Go1.8Maybe milestone Oct 16, 2016
@aclements aclements self-assigned this Oct 16, 2016
@aclements
Copy link
Member Author

aclements commented Oct 16, 2016

We're calling getArgInfo for reflect.methodValueCall:

(gdb) print 'runtime.firstmoduledata'.pclntable.array + f.nameoff
$6 = (uint8 *) 0x50ae60 <runtime.pclntab+263872> "reflect.methodValueCall"
(gdb) print/a *frame
$10 = {fn = 0x50ae28 <runtime.pclntab+263816>, 
  pc = 0x480f00 <reflect.methodValueCall>, continpc = 0x0, lr = 0x0, sp = 0x0, 
  fp = 0x0, varp = 0x0, argp = 0xc420012180, arglen = 0x0, argmap = 0x0}

Of course, the crash is because sp is 0. sp is 0 because getArgInfo's caller, tracebackdefers, never sets frame.sp. So this code probably never worked and we just don't have deferred reflection method calls during a GC very often.

I would expect we could just set frame.sp to deferArgs(d), but gdb is telling me that won't work. I'm not sure why yet.

@aclements
Copy link
Member Author

I would expect we could just set frame.sp to deferArgs(d), but gdb is telling me that won't work. I'm not sure why yet.

Ah, methodValueCall is genuinely a zero argument function (and d.siz is in fact 0, so the defer "frame" is empty). It gets the *methodValue that getArgInfo is looking for from its context register. getArgInfo can find this on the stack not because the caller put it there but because methodValueCall is hand-written to put its context register at 0(SP) (and naturally so, since it's about to pass it as the argument to reflect.callMethod). This means, if we're not actually in a call to methodValueCall, getArgInfo isn't going to find this on the stack.

@gopherbot
Copy link
Contributor

CL https://golang.org/cl/31138 mentions this issue.

@gopherbot
Copy link
Contributor

CL https://golang.org/cl/35638 mentions this issue.

gopherbot pushed a commit that referenced this issue Jan 25, 2017
…n calls

Fixes #18333 (backport)

getArgInfo for reflect.makeFuncStub and reflect.methodValueCall is
necessarily special. These have dynamically determined argument maps
that are stored in their context (that is, their *funcval). These
functions are written to store this context at 0(SP) when called, and
getArgInfo retrieves it from there.

This technique works if getArgInfo is passed an active call frame for
one of these functions. However, getArgInfo is also used in
tracebackdefers, where the "call" is not a true call with an active
stack frame, but a deferred call. In this situation, getArgInfo
currently crashes because tracebackdefers passes a frame with sp set
to 0. However, the entire approach used by getArgInfo is flawed in
this situation because the wrapper has not actually executed, and
hence hasn't saved this metadata to any stack frame.

In the defer case, we know the *funcval from the _defer itself, so we
can fix this by teaching getArgInfo to use the *funcval context
directly when its available, and otherwise get it from the active call
frame.

While we're here, this commit simplifies getArgInfo a bit by making it
play more nicely with the type system. Rather than decoding the
*reflect.methodValue that is the wrapper's context as a *[2]uintptr,
just write out a copy of the reflect.methodValue type in the runtime.

Fixes #16331. Fixes #17471.

Change-Id: I81db4d985179b4a81c68c490cceeccbfc675456a
Reviewed-on: https://go-review.googlesource.com/31138
Run-TryBot: Austin Clements <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Keith Randall <[email protected]>
Reviewed-on: https://go-review.googlesource.com/35638
Run-TryBot: Brad Fitzpatrick <[email protected]>
Reviewed-by: Austin Clements <[email protected]>
@golang golang locked and limited conversation to collaborators Jan 24, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants