summaryrefslogtreecommitdiff
path: root/internal/generate/classify_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-29 17:53:10 +0300
committerPaul Buetow <paul@buetow.org>2026-05-29 17:53:10 +0300
commitb86b817594ac8a4dc7fe2b80649df2c7a62f1b59 (patch)
treebfe09e28771102384cb3f04cae68f7bc907d8eab /internal/generate/classify_test.go
parent2d87d048eb0c629990445eac81229424fe50c215 (diff)
test(fallocate): lock in FS family, KindFd enter, UNCLASSIFIED ret
Audit of fallocate(2) found the tracing correct and consistent with its fd-based siblings, so add lock-in tests rather than fixing anything: - fallocate(int fd, int mode, off_t offset, off_t len) returns int 0/-1 (a status code, NOT a transferred byte count). Its exit must stay a plain ret_event with ret_type UNCLASSIFIED so it is never mistaken for a READ/WRITE/TRANSFER byte count. - The enter tracepoint carries a leading fd field (args[0]); only fd is captured into a fd_event (KindFd), matching fadvise64/ftruncate/ sync_file_range which likewise drop their trailing offset/len/advice args. - fallocate belongs to FamilyFS alongside fadvise64/ftruncate/ sync_file_range. TestClassifyFallocateEnterFd and TestClassifyExitFallocateUnclassifiedRet assert the per-syscall behavior; TestClassifySyscallFamily now also covers fallocate/fadvise64/ftruncate so a stray reclassification trips a test. No classification logic or generated artifacts changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'internal/generate/classify_test.go')
-rw-r--r--internal/generate/classify_test.go55
1 files changed, 55 insertions, 0 deletions
diff --git a/internal/generate/classify_test.go b/internal/generate/classify_test.go
index 41e1bf8..92b6e58 100644
--- a/internal/generate/classify_test.go
+++ b/internal/generate/classify_test.go
@@ -368,6 +368,61 @@ func TestClassifyExitSyncfs(t *testing.T) {
}
}
+// TestClassifyFallocateEnterFd locks in that the fallocate enter tracepoint is
+// classified as KindFd with the fd captured at args[0].
+//
+// int fallocate(int fd, int mode, off_t offset, off_t len)
+//
+// fallocate(2) manipulates the allocated disk space for the file referred to
+// by fd (args[0]); the remaining mode/offset/len args are NOT captured, exactly
+// like its fd-based siblings fadvise64(2)/ftruncate(2)/sync_file_range(2) which
+// also carry trailing offset/len/advice args but only record args[0]. The
+// leading "fd" external field must select KindFd so the generated
+// handle_sys_enter_fallocate emits ev->fd = ctx->args[0] into a fd_event.
+func TestClassifyFallocateEnterFd(t *testing.T) {
+ f := &Format{
+ Name: "sys_enter_fallocate",
+ ExternalFields: []Field{
+ {Type: "long", Name: "__syscall_nr"},
+ {Type: "int", Name: "fd"},
+ {Type: "int", Name: "mode"},
+ {Type: "loff_t", Name: "offset"},
+ {Type: "loff_t", Name: "len"},
+ },
+ }
+ r := ClassifyFormat(f)
+ if r.Kind != KindFd {
+ t.Fatalf("enter_fallocate: got kind %d, want KindFd", r.Kind)
+ }
+ // fd is the first real argument (args[0]); FieldNumber skips __syscall_nr.
+ if got := f.FieldNumber("fd"); got != 0 {
+ t.Errorf("enter_fallocate: fd field number = %d, want 0 (args[0])", got)
+ }
+}
+
+// TestClassifyExitFallocateUnclassifiedRet locks in that the fallocate exit
+// tracepoint is classified as KindRet and Unclassified. fallocate(2) returns
+// int (0 on success, -1 on error) — that return is a status code, NOT a
+// transferred byte count, so its exit format carries a single "ret" field and
+// must map to a plain ret_event (KindRet) whose ret_type stays UNCLASSIFIED.
+// Misclassifying it as a READ/WRITE/TRANSFER byte count would be a real bug,
+// since fallocate allocates space but reports no transferred bytes.
+func TestClassifyExitFallocateUnclassifiedRet(t *testing.T) {
+ r := ClassifyFormat(&Format{
+ Name: "sys_exit_fallocate",
+ ExternalFields: []Field{
+ {Type: "long", Name: "__syscall_nr"},
+ {Type: "long", Name: "ret"},
+ },
+ })
+ if r.Kind != KindRet {
+ t.Fatalf("exit_fallocate: got kind %d, want KindRet", r.Kind)
+ }
+ if got := ClassifyRet("sys_exit_fallocate"); got != Unclassified {
+ t.Errorf("ClassifyRet(sys_exit_fallocate) = %q, want UNCLASSIFIED", got)
+ }
+}
+
// TestClassifyExitGetpeername locks in that the getpeername exit tracepoint is
// classified as KindRet. getpeername(2) returns int (0 on success, -1 on
// error), so its exit format carries a single "ret" field and must map to a