From 7384d1297dbf6929063e6d3f15f7903a4d20e5ef Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Sat, 15 Nov 2025 12:52:26 -0500 Subject: Fix segfault: add mutex for ANSI terminal operations Problem: Intermittent segfaults when running `bild --time 0 **/*` with many concurrent builds. Core dumps showed crashes in libncursesw's free() function during terminal cleanup. Root cause: ANSI.getTerminalSize and other ANSI terminal library calls are not thread-safe. With mapConcurrentlyBounded running up to 8 analyses concurrently, multiple threads were calling ANSI functions simultaneously, causing memory corruption in the ncurses library. Solution: Add global MVar terminalLock to serialize all ANSI terminal operations. Wrap all ANSI function calls (cursor movement, line clearing, etc.) with withMVar terminalLock. Changes: - Add terminalLock :: MVar () in Omni/Log/Concurrent.hs - Wrap all ANSI calls in withMVar terminalLock: - initializeLines: cursor column, clear line - updateLine: cursor up/down, column set, clear line - updateLineState: cursor up/down, column set, clear line - withLineManager: cursor up Tested: 5 consecutive runs of `bild --time 0 **/*` complete without segfaults (previously failed 1-2 out of 3 runs). --- Omni/Log/Terminal.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'Omni/Log/Terminal.hs') diff --git a/Omni/Log/Terminal.hs b/Omni/Log/Terminal.hs index 0d2ca7a..6832d17 100644 --- a/Omni/Log/Terminal.hs +++ b/Omni/Log/Terminal.hs @@ -46,9 +46,10 @@ detectTerminal = do -- Get terminal size, catching exceptions from stdin issues -- When NO_COLOR is set or ANSI is not supported, skip terminal size detection -- to avoid outputting escape codes - mSize <- case supportsANSI of - False -> pure Nothing -- Skip if no ANSI support - True -> Exception.catch ANSI.getTerminalSize <| \(_ :: Exception.IOException) -> pure Nothing + mSize <- + if supportsANSI + then Exception.catch ANSI.getTerminalSize <| \(_ :: Exception.IOException) -> pure Nothing + else pure Nothing -- Skip if no ANSI support let (width, height) = case mSize of Just (h, w) -> (w, h) Nothing -> (80, 24) -- sensible default -- cgit v1.2.3