diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-30 10:13:17 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-30 10:13:17 +0300 |
| commit | 768e53d90be2d15242266b898023c9c39dacf47d (patch) | |
| tree | 94bc78a2c02979e868836b127b4d6bbb6beb213c /internal/generate/codegen_test.go | |
| parent | 23579dbdac320884bcdd670e46744b5f4ab45d5d (diff) | |
fix(z10): skip enter-state write for noreturn syscalls
After p10 suppressed the sys_exit_exit/sys_exit_exit_group handlers, the
enter handlers for exit/exit_group still called ior_on_syscall_enter,
which writes a per-tid entry into syscall_enter_state_map. With the exit
handler gone, nothing ever bpf_map_delete_elem'd that entry, so stale
per-tid state accumulated in the bounded (32768) map on hosts churning
many distinct tids and could starve legitimate inserts.
Add ior_on_noreturn_syscall_enter in internal/c/filter.c: it only makes
the sampling decision (ior_should_emit_trace) and deliberately does NOT
record enter-state. The code generator now emits this hook for noreturn
enter handlers (detected via isNoreturnSyscall(syscallName(name))) so the
enter null_event is still emitted while the dead, unreclaimable map write
is skipped. Regenerated generated_tracepoints.c accordingly.
Extend TestGenerateExitNoreturnHandlers with a negative assertion (no
ior_on_syscall_enter for noreturn) and add
TestGenerateReturningSyscallEnterRecordsState as a positive contrast.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'internal/generate/codegen_test.go')
| -rw-r--r-- | internal/generate/codegen_test.go | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go index 7e0e122..7f9c223 100644 --- a/internal/generate/codegen_test.go +++ b/internal/generate/codegen_test.go @@ -1409,10 +1409,51 @@ func TestGenerateExitNoreturnHandlers(t *testing.T) { if strings.Contains(enterBody, "ctx->args[") { t.Errorf("%s: enter handler unexpectedly captures an arg; the int status must be ignored", syscall) } + + // Regression guard (task z10): the noreturn enter handler must emit + // the enter null_event WITHOUT recording enter-state. Because the + // exit handler is suppressed, nothing would ever look up or delete a + // syscall_enter_state_map entry, so recording one would leak a stale + // per-tid entry in the bounded map. The handler must therefore call + // the dedicated ior_on_noreturn_syscall_enter hook (which only makes + // the sampling decision) and must NOT call the state-recording + // ior_on_syscall_enter that normal returning syscalls use. + requireContains(t, output, "ior_on_noreturn_syscall_enter("+strings.ToUpper("sys_enter_"+syscall)+")") + if strings.Contains(enterBody, "ior_on_syscall_enter(") { + t.Errorf("%s: noreturn enter handler must not record enter-state "+ + "(found ior_on_syscall_enter, which writes syscall_enter_state_map)", syscall) + } }) } } +// TestGenerateReturningSyscallEnterRecordsState is the positive contrast to +// TestGenerateExitNoreturnHandlers: a normal returning syscall's enter handler +// DOES record enter-state via ior_on_syscall_enter (so its later exit handler +// can pair durations and delete the entry), and must NOT use the noreturn hook. +func TestGenerateReturningSyscallEnterRecordsState(t *testing.T) { + syscall := "sched_get_priority_min" // a returning KindNull syscall + output := GenerateTracepointsC(mustParseAll(t, syntheticPair(syscall))) + + enterSec := `SEC("tracepoint/syscalls/sys_enter_` + syscall + `")` + enterStart := strings.Index(output, enterSec) + if enterStart < 0 { + t.Fatalf("%s: enter handler not found", syscall) + } + enterEnd := strings.Index(output[enterStart+len(enterSec):], `SEC("tracepoint/`) + enterBody := output[enterStart:] + if enterEnd >= 0 { + enterBody = output[enterStart : enterStart+len(enterSec)+enterEnd] + } + + if !strings.Contains(enterBody, "ior_on_syscall_enter(tid, "+strings.ToUpper("sys_enter_"+syscall)+")") { + t.Errorf("%s: returning syscall enter handler must record enter-state via ior_on_syscall_enter", syscall) + } + if strings.Contains(enterBody, "ior_on_noreturn_syscall_enter(") { + t.Errorf("%s: returning syscall enter handler must not use the noreturn hook", syscall) + } +} + // TestGenerateSchedGetPriorityMinHandler locks in how sched_get_priority_min // (and its identical sibling sched_get_priority_max) are generated. Per // sched_get_priority_min(2): `int sched_get_priority_min(int policy)` takes a |
