PTYSession use-after-free via TmuxGateway delegate
Thanks for filing an issue! Please answer the questions below so I can help you.
- iTerm2 version: iTerm2-3_5_20230719-nightly
- OS version: 13.4.1 (22F82)
- Hardware: MacBook Pro (16-inch, 2021), M1 Max; also reproduced on an M1 MacBook Air
- com.googlecode.iterm2.plist
- crashlog.txt
Detailed steps to reproduce the problem:
There is some nondeterminism involved apparently due to to the use of timers, so it doesn't work every time. I'm not 100% sure of the factors involved.
Before starting, create a new profile. Under General, set Command to 'tmux -CC new' (with a suitable path to tmux if necessary). Under Session, set the undo timer to 0 seconds.
Then:
- Run iTerm with:
NSZombieEnabled=YES /path/to/iTerm.app/Contents/MacOS/iTerm2
- Close all windows.
- Create a new window with the new profile, which should automatically open a second window with the tmux session.
- Run:
killall -STOP tmux; sleep 2; killall -9 tmux
While this is running, type into the session and also attempt to scroll.
If it works, iTerm will crash with a message like:
*** -[PTYSession tmuxWriteString:]: message sent to deallocated instance 0x13d0dcc00
(If it fails, the tmux windows will close but iTerm won't crash.)
The crash happens when a PTYTab
is deallocated, which in turn deallocates the iTermTmuxOptionMonitor
set as _tmuxTitleMonitor
, whose dealloc
method calls -[TmuxGateway unsubscribe]
, which eventually calls tmuxWriteString
on delegate_
. delegate_
points to a PTYSession
, but nothing keeps delegate_
alive or nils it out when it dies.
As a secondary issue, if the tmux process just ends without printing an exit message, -[TmuxGateway hostDisconnected]
is never called. Among other consequences, the object may be leaked, because there may be unacknowledged commands in commandQueue_
which have the TmuxGateway
itself as target, creating a retain cycle. Without this leak, the crash is semi-concidentally prevented, because the TmuxGateway
is deallocated before the PTYTab
; the reference from iTermTmuxOptionMonitor
to TmuxGateway
is weak and so the unsubscribe
call in -[iTermTmuxOptionMonitor dealloc]
just does nothing.
If the undo timer is not 0 seconds, it's difficult to reproduce this because the PTYSession
will normally still be alive when the PTYTab
is deallocated. However, when I originally ran into this issue, I had the undo timer set to the default 5 seconds. The crashes I experienced always happened right after command-tabbing to a previously inactive iTerm, so I suspect this has something to do with App Nap.