summaryrefslogtreecommitdiff
path: root/internal/generate/codegen.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-30 22:25:49 +0300
committerPaul Buetow <paul@buetow.org>2026-05-30 22:25:49 +0300
commit136c4dfb6846595b98cf2b04a93525ce91d86d5e (patch)
tree32c4eb7a6203879796c4598d82f51c028a182971 /internal/generate/codegen.go
parentdb7c18b976c6bb87ca3dbbfdf436c1945aab3289 (diff)
generate: treat rt_sigreturn as noreturn (suppress dead exit handler)
rt_sigreturn(2) restores the pre-signal execution context off the signal stack frame and resumes the interrupted instruction; it never returns to the instruction after the syscall. man sigreturn(2) states plainly that "sigreturn() never returns", and tracing against /sys/kernel/tracing confirms it: sys_enter_rt_sigreturn fires once per signal-handler return while sys_exit_rt_sigreturn never fires. The generator previously emitted a dead handle_sys_exit_rt_sigreturn (it can never run) and recorded a per-tid syscall_enter_state_map entry on the enter path that nothing would ever delete (no exit fires), leaking entries in the bounded map on every signal-handler return. Add rt_sigreturn to noreturnSyscalls so codegen suppresses the dead exit handler and routes the enter handler through ior_on_noreturn_syscall_enter (sampling decision only, no map write), exactly like exit/exit_group. The enter null_event is still emitted, and the FamilySignals/KindNull classification is unchanged. Regenerated the C/Go artifacts and the result baseline accordingly, and generalized the related comments. Lock-in tests: TestRtSigreturnIsNoreturn asserts rt_sigreturn is noreturn; TestRtSigSiblingsAreNotNoreturn guards that the returning rt_sig* siblings are not; TestGenerateExitNoreturnHandlers now also covers rt_sigreturn. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'internal/generate/codegen.go')
-rw-r--r--internal/generate/codegen.go27
1 files changed, 20 insertions, 7 deletions
diff --git a/internal/generate/codegen.go b/internal/generate/codegen.go
index 339dc1f..5b9ea7c 100644
--- a/internal/generate/codegen.go
+++ b/internal/generate/codegen.go
@@ -126,9 +126,10 @@ func classifySyscall(sc Syscall) ([]GeneratedTracepoint, string) {
result = append(result, GeneratedTracepoint{Format: sc.Enter, Classification: enterClass})
}
// Emit the exit handler only for syscalls that can actually return.
- // Noreturn syscalls (exit, exit_group) never return to userspace, so their
- // sys_exit tracepoint never fires; emitting a handler would be dead code in
- // the generated BPF program. We still emit their enter handler above.
+ // Noreturn syscalls (exit, exit_group, rt_sigreturn) never return to the
+ // syscall site, so their sys_exit tracepoint never fires; emitting a handler
+ // would be dead code in the generated BPF program. We still emit their enter
+ // handler above.
if sc.Exit != nil && !isNoreturnSyscall(sc.Name) {
result = append(result, GeneratedTracepoint{Format: sc.Exit, Classification: exitClass})
}
@@ -150,13 +151,25 @@ func isEnterRejected(kind TracepointKind) bool {
return !lookupKind(kind).enterAccepted
}
-// noreturnSyscalls lists syscalls that never return control to userspace.
+// noreturnSyscalls lists syscalls that never return to the syscall site.
// Their sys_exit tracepoint can never fire, so the generator suppresses the
// matching exit handler (see classifySyscall) to avoid dead code in the
-// generated BPF program.
+// generated BPF program, and the enter handler uses the noreturn enter hook
+// that skips the (otherwise un-reclaimable) syscall_enter_state_map write.
+//
+// - exit / exit_group terminate the thread/process; control never returns.
+// - rt_sigreturn restores the pre-signal execution context off the signal
+// stack frame and resumes the interrupted instruction. It does NOT return
+// to the instruction after the rt_sigreturn syscall, so the kernel never
+// fires sys_exit_rt_sigreturn. Verified empirically against
+// /sys/kernel/tracing: sys_enter_rt_sigreturn fires once per signal-handler
+// return while sys_exit_rt_sigreturn never does. The man page (sigreturn(2))
+// states plainly that "sigreturn() never returns". rt_sigreturn is emitted
+// by the signal trampoline, not called directly by applications.
var noreturnSyscalls = map[string]bool{
- "exit": true,
- "exit_group": true,
+ "exit": true,
+ "exit_group": true,
+ "rt_sigreturn": true,
}
// isNoreturnSyscall reports whether the named syscall never returns and thus