From fadbf135d0b251387fd785083df79e27d1025cac Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 24 Apr 2026 20:32:17 +0300 Subject: fix task 38: plug profiling fd leak on setup failure paths runTraceWithContext and runHeadlessParquet opened cpu/mem/exec-trace profile files via setupProfiling, then relied on the shutdown watcher goroutine (registered later) to close them. If any intervening step (newEventLoop, recorder.Start) returned an error, the watcher was never registered and the profile fds leaked until process exit. Add a defer profiling.stop(logln) immediately after setupProfiling so the fds are released on every return path. profiling.stop is idempotent via sync.Once so the watcher and defer can both run harmlessly. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/ior.go | 5 +++++ internal/ior_parquet_sink.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/internal/ior.go b/internal/ior.go index ab52299..e6e7233 100644 --- a/internal/ior.go +++ b/internal/ior.go @@ -400,6 +400,11 @@ func runTraceWithContext(parentCtx context.Context, cfg flags.Config, started ch if err != nil { return err } + // Guarantee the profiling file descriptors (cpu/mem/exec-trace profiles) are + // closed even if a later setup step fails before the shutdown watcher is + // registered. profiling.stop is idempotent via sync.Once, so double-calling + // it from the watcher goroutine and from this defer is safe. + defer profiling.stop(logln) signalTraceStarted(started) diff --git a/internal/ior_parquet_sink.go b/internal/ior_parquet_sink.go index eb187e8..83ca769 100644 --- a/internal/ior_parquet_sink.go +++ b/internal/ior_parquet_sink.go @@ -119,6 +119,11 @@ func runHeadlessParquet(cfg flags.Config) error { if err != nil { return err } + // Guarantee the profiling file descriptors (cpu/mem/exec-trace profiles) are + // closed even if a later setup step fails before the shutdown watcher is + // registered. profiling.stop is idempotent via sync.Once, so double-calling + // it from the watcher goroutine and from this defer is safe. + defer profiling.stop(logln) el, err := newEventLoop(newEventLoopConfig(cfg)) if err != nil { -- cgit v1.2.3