From 71c00c200ff5098d8b6e68d2ca1f6d7c08ae0ac8 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 18 Apr 2019 13:20:41 +0200 Subject: [PATCH] fix panic: send on closed channel on windows: if the term is resized when ReadString is being called and no one is reading form ws, we get a panic: send on closed channel. It could make sense to poll getconsolescreenbufferinfo calls instead of this: something started from the sigwinch() func on unix: same story, sigwinch was listened upon by default but if the signals (chan sends) were not handled, this could cause a crash fix #7434 --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/mattn/go-tty/tty.go | 6 ++- vendor/github.com/mattn/go-tty/tty_plan9.go | 6 +++ vendor/github.com/mattn/go-tty/tty_unix.go | 54 +++++++++++-------- vendor/github.com/mattn/go-tty/tty_windows.go | 45 +++++++++++++--- vendor/modules.txt | 2 +- 7 files changed, 84 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index 6ac5d5901..077d6b896 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c // indirect github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect github.com/masterzen/winrm v0.0.0-20180224160350-7e40f93ae939 - github.com/mattn/go-tty v0.0.0-20190407112021-83fae09cc007 + github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859 github.com/miekg/dns v1.1.1 // indirect github.com/mitchellh/cli v1.0.0 github.com/mitchellh/go-fs v0.0.0-20180402234041-7b48fa161ea7 diff --git a/go.sum b/go.sum index 21ebcb7d6..d2c4a9aa4 100644 --- a/go.sum +++ b/go.sum @@ -231,8 +231,8 @@ github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-tty v0.0.0-20190407112021-83fae09cc007 h1:xjZxmVDmDZoEsl2gV0qD0pyBH+wXmJIZd27wsNFphJk= -github.com/mattn/go-tty v0.0.0-20190407112021-83fae09cc007/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859 h1:smQbSzmT3EHl4EUwtFwFGmGIpiYgIiiPeVv1uguIQEE= +github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= diff --git a/vendor/github.com/mattn/go-tty/tty.go b/vendor/github.com/mattn/go-tty/tty.go index 8747638b3..f8e33626e 100644 --- a/vendor/github.com/mattn/go-tty/tty.go +++ b/vendor/github.com/mattn/go-tty/tty.go @@ -38,6 +38,10 @@ func (tty *TTY) Size() (int, int, error) { return tty.size() } +func (tty *TTY) SizePixel() (int, int, int, int, error) { + return tty.sizePixel() +} + func (tty *TTY) Input() *os.File { return tty.input() } @@ -115,6 +119,6 @@ type WINSIZE struct { H int } -func (tty *TTY) SIGWINCH() chan WINSIZE { +func (tty *TTY) SIGWINCH() <-chan WINSIZE { return tty.sigwinch() } diff --git a/vendor/github.com/mattn/go-tty/tty_plan9.go b/vendor/github.com/mattn/go-tty/tty_plan9.go index e880e5147..8aed66806 100644 --- a/vendor/github.com/mattn/go-tty/tty_plan9.go +++ b/vendor/github.com/mattn/go-tty/tty_plan9.go @@ -4,6 +4,7 @@ import ( "bufio" "os" "syscall" + "errors" ) type TTY struct { @@ -54,6 +55,11 @@ func (tty *TTY) size() (int, int, error) { return 80, 24, nil } +func (tty *TTY) sizePixel() (int, int, int, int, error) { + x, y, _ := tty.size() + return x, y, -1, -1, errors.New("no implemented method for querying size in pixels on Plan 9") +} + func (tty *TTY) input() *os.File { return tty.in } diff --git a/vendor/github.com/mattn/go-tty/tty_unix.go b/vendor/github.com/mattn/go-tty/tty_unix.go index 2a4350cca..15a16329a 100644 --- a/vendor/github.com/mattn/go-tty/tty_unix.go +++ b/vendor/github.com/mattn/go-tty/tty_unix.go @@ -18,7 +18,6 @@ type TTY struct { bin *bufio.Reader out *os.File termios syscall.Termios - ws chan WINSIZE ss chan os.Signal } @@ -48,24 +47,8 @@ func open() (*TTY, error) { return nil, err } - tty.ws = make(chan WINSIZE) tty.ss = make(chan os.Signal, 1) - signal.Notify(tty.ss, syscall.SIGWINCH) - go func() { - defer close(tty.ws) - for sig := range tty.ss { - switch sig { - case syscall.SIGWINCH: - if w, h, err := tty.size(); err == nil { - tty.ws <- WINSIZE{ - W: w, - H: h, - } - } - default: - } - } - }() + return tty, nil } @@ -86,11 +69,16 @@ func (tty *TTY) close() error { } func (tty *TTY) size() (int, int, error) { + x, y, _, _, err := tty.sizePixel() + return x, y, err +} + +func (tty *TTY) sizePixel() (int, int, int, int, error) { var dim [4]uint16 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(tty.out.Fd()), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dim)), 0, 0, 0); err != 0 { - return -1, -1, err + return -1, -1, -1, -1, err } - return int(dim[1]), int(dim[0]), nil + return int(dim[1]), int(dim[0]), int(dim[2]), int(dim[3]), nil } func (tty *TTY) input() *os.File { @@ -127,6 +115,28 @@ func (tty *TTY) raw() (func() error, error) { }, nil } -func (tty *TTY) sigwinch() chan WINSIZE { - return tty.ws +func (tty *TTY) sigwinch() <-chan WINSIZE { + signal.Notify(tty.ss, syscall.SIGWINCH) + + ws := make(chan WINSIZE) + go func() { + defer close(ws) + for sig := range tty.ss { + if sig != syscall.SIGWINCH { + continue + } + + w, h, err := tty.size() + if err != nil { + continue + } + // send but do not block for it + select { + case ws <- WINSIZE{W: w, H: h}: + default: + } + + } + }() + return ws } diff --git a/vendor/github.com/mattn/go-tty/tty_windows.go b/vendor/github.com/mattn/go-tty/tty_windows.go index cab27987f..eb3e248d1 100644 --- a/vendor/github.com/mattn/go-tty/tty_windows.go +++ b/vendor/github.com/mattn/go-tty/tty_windows.go @@ -3,7 +3,9 @@ package tty import ( + "context" "os" + "errors" "syscall" "unsafe" @@ -122,11 +124,13 @@ type charInfo struct { } type TTY struct { - in *os.File - out *os.File - st uint32 - rs []rune - ws chan WINSIZE + in *os.File + out *os.File + st uint32 + rs []rune + ws chan WINSIZE + sigwinchCtx context.Context + sigwinchCtxCancel context.CancelFunc } func readConsoleInput(fd uintptr, record *inputRecord) (err error) { @@ -183,6 +187,7 @@ func open() (*TTY, error) { procSetConsoleMode.Call(h, uintptr(st)) tty.ws = make(chan WINSIZE) + tty.sigwinchCtx, tty.sigwinchCtxCancel = context.WithCancel(context.Background()) return tty, nil } @@ -206,10 +211,24 @@ func (tty *TTY) readRune() (rune, error) { switch ir.eventType { case windowBufferSizeEvent: wr := (*windowBufferSizeRecord)(unsafe.Pointer(&ir.event)) - tty.ws <- WINSIZE{ + ws := WINSIZE{ W: int(wr.size.x), H: int(wr.size.y), } + + if err := tty.sigwinchCtx.Err(); err != nil { + // closing + // the following select might panic without this guard close + return 0, err + } + + select { + case tty.ws <- ws: + case <-tty.sigwinchCtx.Done(): + return 0, tty.sigwinchCtx.Err() + default: + return 0, nil // no one is currently trying to read + } case keyEvent: kr := (*keyEventRecord)(unsafe.Pointer(&ir.event)) if kr.keyDown != 0 { @@ -307,8 +326,9 @@ func (tty *TTY) readRune() (rune, error) { } func (tty *TTY) close() error { - close(tty.ws) procSetConsoleMode.Call(tty.in.Fd(), uintptr(tty.st)) + tty.sigwinchCtxCancel() + close(tty.ws) return nil } @@ -321,6 +341,15 @@ func (tty *TTY) size() (int, int, error) { return int(csbi.window.right - csbi.window.left + 1), int(csbi.window.bottom - csbi.window.top + 1), nil } +func (tty *TTY) sizePixel() (int, int, int, int, error) { + x, y, err := tty.size() + if err != nil { + x = -1 + y = -1 + } + return x, y, -1, -1, errors.New("no implemented method for querying size in pixels on Windows") +} + func (tty *TTY) input() *os.File { return tty.in } @@ -349,6 +378,6 @@ func (tty *TTY) raw() (func() error, error) { }, nil } -func (tty *TTY) sigwinch() chan WINSIZE { +func (tty *TTY) sigwinch() <-chan WINSIZE { return tty.ws } diff --git a/vendor/modules.txt b/vendor/modules.txt index 206dc7eea..2ad0ea20c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -299,7 +299,7 @@ github.com/mattn/go-colorable github.com/mattn/go-isatty # github.com/mattn/go-runewidth v0.0.4 github.com/mattn/go-runewidth -# github.com/mattn/go-tty v0.0.0-20190407112021-83fae09cc007 +# github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859 github.com/mattn/go-tty # github.com/mitchellh/cli v1.0.0 github.com/mitchellh/cli