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: freedefer with d._panic != nil (regression in 1.13) #33841

josharian opened this issue Aug 26, 2019 · 8 comments

runtime: freedefer with d._panic != nil (regression in 1.13) #33841

josharian opened this issue Aug 26, 2019 · 8 comments


Copy link

@josharian josharian commented Aug 26, 2019

This is a regression from 1.12 to 1.13rc1. I'm on darwin/amd64.

main.go (this is just the demo code from

package main

import (


func main() {
	g, err := gocui.NewGui(gocui.OutputNormal, false)
	if err != nil {
	defer g.Close()


	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {

	if err := g.MainLoop(); err != nil && !gocui.IsQuit(err) {

func layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2, 0); err != nil {
		if !gocui.IsUnknownView(err) {
			return err
		fmt.Fprintln(v, "Hello world!")
		if _, err := g.SetCurrentView("hello"); err != nil {
			return err
	return nil

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrQuit


module bug

go 1.13

require v0.5.0

go.sum (just in case): v0.5.0 h1:ri9VZLWHKIH/dq/AfkGe5F8976KWRmKb6ZqcCnyQB/4= v0.5.0/go.mod h1:1QikxFaPhe2frKeKvEwZEIGia3haiOxOUXKinrv17mA= v0.0.0-20190427202837-c0aef3d18bcc h1:wGNpKcHU8Aadr9yOzsT3GEsFLS7HQu8HxQIomnekqf0= v0.0.0-20190427202837-c0aef3d18bcc/go.mod h1:tOy3o5Nf1bA17mnK4W41gD7PS3u4Cv0P0pqFcoWMy8s= v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=

With 1.12, this runs, says "hello world", and exits with ctl-c.

With 1.13rc1, I get:

fatal error: freedefer with d._panic != nil

goroutine 1 [running]:
runtime.throw(0x1124ddf, 0x1e)
	/Users/josh/go/1.13/src/runtime/panic.go:774 +0x72 fp=0xc0000b1ca0 sp=0xc0000b1c70 pc=0x102a192
	/Users/josh/go/1.13/src/runtime/panic.go:480 +0x36 fp=0xc0000b1cc0 sp=0xc0000b1ca0 pc=0x10296b6
	/Users/josh/go/1.13/src/runtime/panic.go:423 +0x205 fp=0xc0000b1d40 sp=0xc0000b1cc0 pc=0x1029665
	/Users/josh/go/1.13/src/runtime/panic.go:530 +0x6f fp=0xc0000b1d88 sp=0xc0000b1d40 pc=0x102976f
runtime: unexpected return pc for*Gui).getTermWindowSize called from 0x11217e2
stack: frame={sp:0xc0000b1d88, fp:0xc0000b1e68} stack=[0xc0000b0000,0xc0000b2000)
000000c0000b1c88:  000000000000001e  000000c0000b1cb0 
000000c0000b1c98:  00000000010296b6 <runtime.freedeferpanic+54>  0000000001124ddf 
000000c0000b1ca8:  000000000000001e  000000c0000b1d30 
000000c0000b1cb8:  0000000001029665 <runtime.freedefer+517>  000000c0000b1ce0 
000000c0000b1cc8:  0000000001128af0  77ec80cc00000002 
000000c0000b1cd8:  000000c0000b1cf0  000000c0000b1d78 
000000c0000b1ce8:  00000000010c7f43 <os/signal.Notify+291>  00000000011ff660 
000000c0000b1cf8:  0000000001140700  000000c0000b1d40 
000000c0000b1d08:  0000000001032e8f <runtime.exitsyscallfast+207>  000000c000024000 
000000c0000b1d18:  000000c0000b1d50  000000000103259c <runtime.reentersyscall+124> 
000000c0000b1d28:  000000c000000180  000000c0000b1d78 
000000c0000b1d38:  000000000102976f <runtime.deferreturn+111>  000000c0000b1dc8 
000000c0000b1d48:  000000c0000b1df8  0000000003980364 
000000c0000b1d58:  000000c000000180  0000000001140700 
000000c0000b1d68:  000000c0000b1dc8  000000c0000b1e58 
000000c0000b1d78:  000000c0000b1e58  00000000010d8619 <*Gui).getTermWindowSize+761> 
000000c0000b1d88: <000000c00000e020  0000000000000001 
000000c0000b1d98:  000000c00008e360  000000c00008e480 
000000c0000b1da8:  000000c00000e020  000000c0000b1dc4 
000000c0000b1db8:  00000000010ff5a0  000000000100bd01 <runtime.largeAlloc+353> 
000000c0000b1dc8:  00000000011432a0  00000000011406f8 
000000c0000b1dd8:  00000000011432a0  0000000000000000 
000000c0000b1de8:  000000c0000b1e98  00000000010d59e8 <> 
000000c0000b1df8:  000000c0000e4090  00000000000001b2 
000000c0000b1e08:  00000000000000b8  0000000000000000 
000000c0000b1e18:  0000000000000000  000000c0000e4090 
000000c0000b1e28:  000000c0000b1f50  00000000010db191 <main.main+65> 
000000c0000b1e38:  0000000000000001  00000000010ff400 
000000c0000b1e48:  000000c000094140  000000c0000b1ef0 
000000c0000b1e58:  00000000010dac73 <> !00000000011217e2 
000000c0000b1e68: >000000000000000c  0000000001142ea0 
000000c0000b1e78:  000000c000094140  000000c0000b1f20 
000000c0000b1e88:  0000000001037bca <runtime.doInit+138>  00000000011e6380 
000000c0000b1e98:  000000c000044750  000000c0000b1f50 
000000c0000b1ea8:  000000000100535f <runtime.closechan+479>  000000c000072058 
000000c0000b1eb8:  0000000000000000  0000000000000000 
000000c0000b1ec8:  0000000000000000  00000000010f0320 
000000c0000b1ed8:  000000c000072058  000000c0000b1fd0 
000000c0000b1ee8:  000000000102bb1e <runtime.main+542>  000000c000072000 
000000c0000b1ef8:  0000000000000000  000000c000072000 
000000c0000b1f08:  0000000000000000  0000000000000000 
000000c0000b1f18:  0000000000000000  0000000000000008 
000000c0000b1f28:  000000c0000b1f60  000000000102ba04 <runtime.main+260> 
000000c0000b1f38:  0000000001128880  0000000000000000 
000000c0000b1f48:  0000000000000000  000000c0000b1f87 
000000c0000b1f58:  000000c000000180  0000000000000000*Gui).getTermWindowSize(0xc, 0x1142ea0, 0xc000094140, 0xc0000b1f20, 0x1037bca)
	/Users/josh/pkg/mod/ +0x2f9 fp=0xc0000b1e68 sp=0xc0000b1d88 pc=0x10d8619

goroutine 18 [syscall]:
	/Users/josh/go/1.13/src/runtime/sigqueue.go:144 +0x96
	/Users/josh/go/1.13/src/os/signal/signal_unix.go:23 +0x22
created by os/signal.init.0
	/Users/josh/go/1.13/src/os/signal/signal_unix.go:29 +0x41

goroutine 20 [select]:
	/Users/josh/pkg/mod/ +0x32f
created by
	/Users/josh/pkg/mod/ +0x6c5
exit status 2

Note that this will shred your terminal window, so don't reproduce this in a window in which you have history you care about.

Tentatively marking as release blocker. I don't plan to investigate further at the moment, unless others cannot reproduce.

cc @randall77 @aclements @ianlancetaylor

Copy link

@randall77 randall77 commented Aug 26, 2019

I can't reproduce that error. Instead I get a different one:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x494547]

goroutine 1 [running]:
os.(*File).Close(0x10, 0x6, 0x5413)
	/usr/local/google/home/khr/Downloads/go1.13rc1/src/os/file_unix.go:233 +0x27*Gui).getTermWindowSize(0xc0000fa000, 0x78, 0x30, 0x0, 0x0)
	/usr/local/google/home/khr/gopath/pkg/mod/ +0x2f4, 0x4fd000, 0xc000010310, 0xc000059ef0, 0x4d8153)
	/usr/local/google/home/khr/gopath/pkg/mod/ +0x108
	/usr/local/google/home/khr/gowork/issue33841/main.go:11 +0x41
Copy link
Contributor Author

@josharian josharian commented Aug 26, 2019

Does it function correctly for you with 1.12.x?

Copy link

@randall77 randall77 commented Aug 26, 2019


Copy link
Contributor Author

@josharian josharian commented Aug 26, 2019

Excellent; glad you can at least reproduce something. :) Let me know if/how I can be of help.

Copy link

@randall77 randall77 commented Aug 26, 2019

I have a theory. The code does this:

	var sz struct {
		rows uint16
                cols uint16
        defer out.Close()
            	_, _, _ = syscall.Syscall(syscall.SYS_IOCTL,
			out.Fd(), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&sz)))

The sz variable gets allocated on the stack just before the on-stack defer record.
The defer gets queued first, and then the syscall happens. This syscall actually writes more data than just the 4 bytes of the sz variable, overwriting the defer record.

The ioctl manpage says this is the structure:

 struct winsize {
               unsigned short ws_row;
               unsigned short ws_col;
               unsigned short ws_xpixel;   /* unused */
               unsigned short ws_ypixel;   /* unused */

I think it's writing something to those two additional fields.

Adding 4 bytes of padding to the end of that structure fixes the bug.

Copy link

@ianlancetaylor ianlancetaylor commented Aug 26, 2019

CC @mattn

Copy link

@randall77 randall77 commented Aug 26, 2019

I'm going to close this as not a bug in Go.
I've commented on the gocui bug: awesome-gocui/gocui#33

@randall77 randall77 closed this Aug 26, 2019
Copy link
Contributor Author

@josharian josharian commented Aug 26, 2019

Thanks, Keith, and sorry for the fire drill.

@golang golang locked and limited conversation to collaborators Aug 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.