From 39ff87324a6654a86b675690bd2dbbc49c272fc6 Mon Sep 17 00:00:00 2001 From: dengzhongyuan Date: Wed, 1 Jul 2026 14:44:13 +0800 Subject: [PATCH 1/2] trace: show error message when fork fails in TraceScreen When TraceScreen_forkTracer() fails (e.g. out of memory, PID quota exceeded), the trace screen now displays the system error message instead of silently doing nothing. Fixes #1991 --- Action.c | 6 ++---- TraceScreen.c | 11 +++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Action.c b/Action.c index d630cb80d..88a7ce521 100644 --- a/Action.c +++ b/Action.c @@ -674,10 +674,8 @@ static Htop_Reaction actionStrace(State* st) { assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); TraceScreen* ts = TraceScreen_new(p); - bool ok = TraceScreen_forkTracer(ts); - if (ok) { - InfoScreen_run((InfoScreen*)ts); - } + TraceScreen_forkTracer(ts); + InfoScreen_run((InfoScreen*)ts); TraceScreen_delete((Object*)ts); clear(); CRT_enableDelay(); diff --git a/TraceScreen.c b/TraceScreen.c index 42d5ee016..5b0ec661b 100644 --- a/TraceScreen.c +++ b/TraceScreen.c @@ -60,6 +60,16 @@ void TraceScreen_delete(Object* cast) { free(InfoScreen_done((InfoScreen*)this)); } +static void TraceScreen_scan(InfoScreen* super) { + TraceScreen* this = (TraceScreen*) super; + if (!this->strace_alive) { + char* err = NULL; + xAsprintf(&err, "%s", strerror(errno)); + InfoScreen_addLine(super, err); + free(err); + } +} + static void TraceScreen_draw(InfoScreen* this) { InfoScreen_drawTitled(this, "Trace of process %d - %s", Process_getPid(this->process), Process_getCommand(this->process)); } @@ -209,6 +219,7 @@ const InfoScreenClass TraceScreen_class = { .extends = Class(Object), .delete = TraceScreen_delete }, + .scan = TraceScreen_scan, .draw = TraceScreen_draw, .onErr = TraceScreen_updateTrace, .onKey = TraceScreen_onKey, From 76e7f5d088b40efe08c325b09455aeb249bb9ba0 Mon Sep 17 00:00:00 2001 From: dengzhongyuan Date: Wed, 1 Jul 2026 14:56:34 +0800 Subject: [PATCH 2/2] trace: preserve errno across close() calls in error path Save and restore errno in the TraceScreen_forkTracer error path so that close() calls in the cleanup do not clobber the original error value before it is read by TraceScreen_scan(). --- TraceScreen.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/TraceScreen.c b/TraceScreen.c index 5b0ec661b..87f99d01d 100644 --- a/TraceScreen.c +++ b/TraceScreen.c @@ -135,11 +135,14 @@ bool TraceScreen_forkTracer(TraceScreen* this) { return true; -err: +err: { + 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;