terminal: fix race when closing a terminal

Fix race when closing a terminal. The race appears as a nil pointer
dereference panic in pty.StartWithAttrs when trying to access the
provided term.cmd variable.

Before calling pty.StartwithAttrs in the Terminal.Draw function,
term.cmd is checked for nil. Terminal.Close must be called concurrently
right after this check and before/while entering pty.StartWithAttrs.
This can be avoided with a mutex.

Link: https://github.com/creack/pty/issues/146
Link: https://lists.sr.ht/~rjarry/aerc-devel/%3CCJ2I45HMOTGD.2J1QMEJ4T1E3N%40t450.arielp.com%3E#%3CCJ3D069RCTXL.3VEZ7JIGFHOHK@Archetype%3E
Fixes: https://todo.sr.ht/~rjarry/aerc/38
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Koni Marti 2022-05-23 22:16:13 +02:00 committed by Robin Jarry
parent f4d4e2b4e1
commit 1bac87e804

View file

@ -108,6 +108,7 @@ type Terminal struct {
damageMutex sync.Mutex damageMutex sync.Mutex
writeMutex sync.Mutex writeMutex sync.Mutex
readMutex sync.Mutex readMutex sync.Mutex
closeMutex sync.Mutex
OnClose func(err error) OnClose func(err error)
OnEvent func(event tcell.Event) bool OnEvent func(event tcell.Event) bool
@ -178,6 +179,9 @@ func (term *Terminal) flushTerminal() {
} }
func (term *Terminal) Close(err error) { func (term *Terminal) Close(err error) {
term.closeMutex.Lock()
defer term.closeMutex.Unlock()
if term.closed { if term.closed {
return return
} }
@ -199,6 +203,9 @@ func (term *Terminal) Close(err error) {
} }
func (term *Terminal) Destroy() { func (term *Terminal) Destroy() {
term.closeMutex.Lock()
defer term.closeMutex.Unlock()
if term.destroyed { if term.destroyed {
return return
} }
@ -228,6 +235,9 @@ func (term *Terminal) invalidate() {
} }
func (term *Terminal) Draw(ctx *ui.Context) { func (term *Terminal) Draw(ctx *ui.Context) {
term.closeMutex.Lock()
defer term.closeMutex.Unlock()
if term.destroyed { if term.destroyed {
return return
} }