Skip to content

Commit e9ca0f8

Browse files
authored
core: Acquire renderer state mutex before calling processLinks (ghostty-org#12463)
Holding the renderer state mutex is a documented precondition of `processLinks`, but `mouseButtonCallback` previously called the function without the mutex. This creates a race with the I/O thread's `processOutput`, which can prune scrollback pages while `processLinks` is reading them, resulting in a use-after-free segfault. See ghostty-org#12409 (Linux: crash while selecting text). https://github.com/ghostty-org/ghostty/blob/57b5e1e2507cd65ab8197d39baa4ce2505185510/src/Surface.zig#L4354-L4355 https://github.com/ghostty-org/ghostty/blob/57b5e1e2507cd65ab8197d39baa4ce2505185510/src/Surface.zig#L3822-L3824 995e4e3 (os: open) changed the body of `processLinks` to be non-trivial and documented the precondition, but the lock was not held at the call site.
2 parents 0e0bcaf + 28f4676 commit e9ca0f8

1 file changed

Lines changed: 2 additions & 0 deletions

File tree

src/Surface.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3821,6 +3821,8 @@ pub fn mouseButtonCallback(
38213821
// clicked link will swallow the event.
38223822
if (self.mouse.over_link) {
38233823
const pos = try self.rt_surface.getCursorPos();
3824+
self.renderer_state.mutex.lock();
3825+
defer self.renderer_state.mutex.unlock();
38243826
if (self.processLinks(pos)) |processed| {
38253827
if (processed) return true;
38263828
} else |err| {

0 commit comments

Comments
 (0)