From d66df1f567c08bb1005b639250abc4d79c248fc6 Mon Sep 17 00:00:00 2001 From: re2zero Date: Wed, 3 Jun 2026 16:33:32 +0800 Subject: [PATCH] Show error message when trace feature fails on fork When TraceScreen_forkTracer() fails (e.g. OOM, PID quota exceeded, seccomp/AppArmor restrictions), the TraceScreen was not displayed and users received no feedback. The UI appeared unresponsive. - Show error message in TraceScreen when forkTracer fails - Preserve errno across cleanup in error path for accurate reporting - Use plain snprintf (not xSnprintf) to avoid fail() on truncation - Guard NULL strace before fileno() to prevent crash - Guard all fd_strace usage with fd_strace >= 0 checks Fixes #1991 Assisted-by: Claude (Anthropic) --- Action.c | 9 +++++++-- TraceScreen.c | 18 ++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Action.c b/Action.c index d630cb80d..2af597562 100644 --- a/Action.c +++ b/Action.c @@ -10,6 +10,7 @@ in the source distribution for its full text. #include "Action.h" #include +#include #include #include #include @@ -675,9 +676,13 @@ static Htop_Reaction actionStrace(State* st) { TraceScreen* ts = TraceScreen_new(p); bool ok = TraceScreen_forkTracer(ts); - if (ok) { - InfoScreen_run((InfoScreen*)ts); + if (!ok) { + char errmsg[256]; + int saved_errno = errno; + snprintf(errmsg, sizeof(errmsg), "Failed to start tracer: %s", strerror(saved_errno)); + InfoScreen_addLine(&ts->super, errmsg); } + InfoScreen_run((InfoScreen*)ts); TraceScreen_delete((Object*)ts); clear(); CRT_enableDelay(); diff --git a/TraceScreen.c b/TraceScreen.c index f87700f2b..e18892f33 100644 --- a/TraceScreen.c +++ b/TraceScreen.c @@ -127,21 +127,27 @@ bool TraceScreen_forkTracer(TraceScreen* this) { return true; err: - close(fdpair[1]); - close(fdpair[0]); + { + int saved_errno = errno; + close(fdpair[1]); + close(fdpair[0]); + errno = saved_errno; + } return false; } static void TraceScreen_updateTrace(InfoScreen* super) { TraceScreen* this = (TraceScreen*) super; - int fd_strace = fileno(this->strace); + int fd_strace = -1; + if (this->strace) { + fd_strace = fileno(this->strace); + } fd_set fds; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); - if (this->strace_alive) { - assert(fd_strace != -1); + if (this->strace_alive && fd_strace >= 0) { FD_SET(fd_strace, &fds); } @@ -150,7 +156,7 @@ static void TraceScreen_updateTrace(InfoScreen* super) { char buffer[1025]; size_t nread = 0; - if (ready > 0 && FD_ISSET(fd_strace, &fds)) + if (fd_strace >= 0 && ready > 0 && FD_ISSET(fd_strace, &fds)) nread = fread(buffer, 1, sizeof(buffer) - 1, this->strace); if (nread && this->tracing) {