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
This commit is contained in:
parent
fa7b922e7a
commit
71c00c200f
2
go.mod
2
go.mod
|
@ -68,7 +68,7 @@ require (
|
||||||
github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c // indirect
|
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/simplexml v0.0.0-20190410153822-31eea3082786 // indirect
|
||||||
github.com/masterzen/winrm v0.0.0-20180224160350-7e40f93ae939
|
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/miekg/dns v1.1.1 // indirect
|
||||||
github.com/mitchellh/cli v1.0.0
|
github.com/mitchellh/cli v1.0.0
|
||||||
github.com/mitchellh/go-fs v0.0.0-20180402234041-7b48fa161ea7
|
github.com/mitchellh/go-fs v0.0.0-20180402234041-7b48fa161ea7
|
||||||
|
|
4
go.sum
4
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-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 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
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-20190424173100-523744f04859 h1:smQbSzmT3EHl4EUwtFwFGmGIpiYgIiiPeVv1uguIQEE=
|
||||||
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/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
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/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
|
|
|
@ -38,6 +38,10 @@ func (tty *TTY) Size() (int, int, error) {
|
||||||
return tty.size()
|
return tty.size()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tty *TTY) SizePixel() (int, int, int, int, error) {
|
||||||
|
return tty.sizePixel()
|
||||||
|
}
|
||||||
|
|
||||||
func (tty *TTY) Input() *os.File {
|
func (tty *TTY) Input() *os.File {
|
||||||
return tty.input()
|
return tty.input()
|
||||||
}
|
}
|
||||||
|
@ -115,6 +119,6 @@ type WINSIZE struct {
|
||||||
H int
|
H int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tty *TTY) SIGWINCH() chan WINSIZE {
|
func (tty *TTY) SIGWINCH() <-chan WINSIZE {
|
||||||
return tty.sigwinch()
|
return tty.sigwinch()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TTY struct {
|
type TTY struct {
|
||||||
|
@ -54,6 +55,11 @@ func (tty *TTY) size() (int, int, error) {
|
||||||
return 80, 24, nil
|
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 {
|
func (tty *TTY) input() *os.File {
|
||||||
return tty.in
|
return tty.in
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ type TTY struct {
|
||||||
bin *bufio.Reader
|
bin *bufio.Reader
|
||||||
out *os.File
|
out *os.File
|
||||||
termios syscall.Termios
|
termios syscall.Termios
|
||||||
ws chan WINSIZE
|
|
||||||
ss chan os.Signal
|
ss chan os.Signal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,24 +47,8 @@ func open() (*TTY, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tty.ws = make(chan WINSIZE)
|
|
||||||
tty.ss = make(chan os.Signal, 1)
|
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
|
return tty, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,11 +69,16 @@ func (tty *TTY) close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tty *TTY) size() (int, int, 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
|
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 {
|
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 {
|
func (tty *TTY) input() *os.File {
|
||||||
|
@ -127,6 +115,28 @@ func (tty *TTY) raw() (func() error, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tty *TTY) sigwinch() chan WINSIZE {
|
func (tty *TTY) sigwinch() <-chan WINSIZE {
|
||||||
return tty.ws
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
package tty
|
package tty
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
"errors"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
@ -122,11 +124,13 @@ type charInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TTY struct {
|
type TTY struct {
|
||||||
in *os.File
|
in *os.File
|
||||||
out *os.File
|
out *os.File
|
||||||
st uint32
|
st uint32
|
||||||
rs []rune
|
rs []rune
|
||||||
ws chan WINSIZE
|
ws chan WINSIZE
|
||||||
|
sigwinchCtx context.Context
|
||||||
|
sigwinchCtxCancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func readConsoleInput(fd uintptr, record *inputRecord) (err error) {
|
func readConsoleInput(fd uintptr, record *inputRecord) (err error) {
|
||||||
|
@ -183,6 +187,7 @@ func open() (*TTY, error) {
|
||||||
procSetConsoleMode.Call(h, uintptr(st))
|
procSetConsoleMode.Call(h, uintptr(st))
|
||||||
|
|
||||||
tty.ws = make(chan WINSIZE)
|
tty.ws = make(chan WINSIZE)
|
||||||
|
tty.sigwinchCtx, tty.sigwinchCtxCancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
return tty, nil
|
return tty, nil
|
||||||
}
|
}
|
||||||
|
@ -206,10 +211,24 @@ func (tty *TTY) readRune() (rune, error) {
|
||||||
switch ir.eventType {
|
switch ir.eventType {
|
||||||
case windowBufferSizeEvent:
|
case windowBufferSizeEvent:
|
||||||
wr := (*windowBufferSizeRecord)(unsafe.Pointer(&ir.event))
|
wr := (*windowBufferSizeRecord)(unsafe.Pointer(&ir.event))
|
||||||
tty.ws <- WINSIZE{
|
ws := WINSIZE{
|
||||||
W: int(wr.size.x),
|
W: int(wr.size.x),
|
||||||
H: int(wr.size.y),
|
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:
|
case keyEvent:
|
||||||
kr := (*keyEventRecord)(unsafe.Pointer(&ir.event))
|
kr := (*keyEventRecord)(unsafe.Pointer(&ir.event))
|
||||||
if kr.keyDown != 0 {
|
if kr.keyDown != 0 {
|
||||||
|
@ -307,8 +326,9 @@ func (tty *TTY) readRune() (rune, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tty *TTY) close() error {
|
func (tty *TTY) close() error {
|
||||||
close(tty.ws)
|
|
||||||
procSetConsoleMode.Call(tty.in.Fd(), uintptr(tty.st))
|
procSetConsoleMode.Call(tty.in.Fd(), uintptr(tty.st))
|
||||||
|
tty.sigwinchCtxCancel()
|
||||||
|
close(tty.ws)
|
||||||
return nil
|
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
|
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 {
|
func (tty *TTY) input() *os.File {
|
||||||
return tty.in
|
return tty.in
|
||||||
}
|
}
|
||||||
|
@ -349,6 +378,6 @@ func (tty *TTY) raw() (func() error, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tty *TTY) sigwinch() chan WINSIZE {
|
func (tty *TTY) sigwinch() <-chan WINSIZE {
|
||||||
return tty.ws
|
return tty.ws
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,7 +299,7 @@ github.com/mattn/go-colorable
|
||||||
github.com/mattn/go-isatty
|
github.com/mattn/go-isatty
|
||||||
# github.com/mattn/go-runewidth v0.0.4
|
# github.com/mattn/go-runewidth v0.0.4
|
||||||
github.com/mattn/go-runewidth
|
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/mattn/go-tty
|
||||||
# github.com/mitchellh/cli v1.0.0
|
# github.com/mitchellh/cli v1.0.0
|
||||||
github.com/mitchellh/cli
|
github.com/mitchellh/cli
|
||||||
|
|
Loading…
Reference in New Issue