Skip to content

Commit c0fda58

Browse files
r41k0uclaude
andcommitted
Tests: Cover global variable reads, writes, and the error cases
Five passing tests: read in condition and print; the get_cgroup_id_kern.c read-one-write-one shape; the counter += 1 idiom; two programs sharing global state (the test_autoattach.c shape); and mixed .bss/.data placement with mixed widths and signedness. Three strict expected failures documenting deliberate errors: assignment without the global statement (shadowing), a global statement naming a non-global, and a non-integer global type. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L1PX8EuP9C3o3veWGA84RF
1 parent 26ee4d4 commit c0fda58

9 files changed

Lines changed: 246 additions & 0 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Only integer scalar globals are supported in milestone 1; anything else must
2+
# be a clear NotImplementedError, not a half-emitted symbol.
3+
from pythonbpf import bpf, section, bpfglobal, compile
4+
from ctypes import c_void_p, c_int64, c_double
5+
6+
7+
@bpf
8+
@bpfglobal
9+
def ratio() -> c_double:
10+
return c_double(0.5)
11+
12+
13+
@bpf
14+
@section("tracepoint/raw_syscalls/sys_enter")
15+
def prog(ctx: c_void_p) -> c_int64:
16+
return c_int64(0)
17+
18+
19+
@bpf
20+
@bpfglobal
21+
def LICENSE() -> str:
22+
return "GPL"
23+
24+
25+
compile()
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Writing a global's name without `global` must be a loud compile error, not a
2+
# silently-created shadowing local (real Python) or a silent global store.
3+
from pythonbpf import bpf, section, bpfglobal, compile
4+
from ctypes import c_void_p, c_int64, c_uint64
5+
6+
7+
@bpf
8+
@bpfglobal
9+
def counter() -> c_uint64:
10+
return c_uint64(0)
11+
12+
13+
@bpf
14+
@section("tracepoint/raw_syscalls/sys_enter")
15+
def prog(ctx: c_void_p) -> c_int64:
16+
counter = 1 # noqa: F841 -- missing `global counter` on purpose
17+
return c_int64(0)
18+
19+
20+
@bpf
21+
@bpfglobal
22+
def LICENSE() -> str:
23+
return "GPL"
24+
25+
26+
compile()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# `global x` naming something that is not a @bpfglobal is a compile error.
2+
from pythonbpf import bpf, section, bpfglobal, compile
3+
from ctypes import c_void_p, c_int64
4+
5+
6+
@bpf
7+
@section("tracepoint/raw_syscalls/sys_enter")
8+
def prog(ctx: c_void_p) -> c_int64:
9+
global nosuch
10+
return c_int64(0)
11+
12+
13+
@bpf
14+
@bpfglobal
15+
def LICENSE() -> str:
16+
return "GPL"
17+
18+
19+
compile()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# The canonical selftest idiom: a per-object event counter. `counter += 1`
2+
# desugars to load/add/store on the global; the local augassign checks the
3+
# desugaring path for stack variables too.
4+
from pythonbpf import bpf, section, bpfglobal, compile
5+
from ctypes import c_void_p, c_int64, c_uint64
6+
7+
8+
@bpf
9+
@bpfglobal
10+
def counter() -> c_uint64:
11+
return c_uint64(0)
12+
13+
14+
@bpf
15+
@section("tracepoint/raw_syscalls/sys_enter")
16+
def tick(ctx: c_void_p) -> c_int64:
17+
global counter
18+
counter += 1
19+
x = 5
20+
x += 2
21+
print(f"count {counter} x {x}")
22+
return c_int64(0)
23+
24+
25+
@bpf
26+
@bpfglobal
27+
def LICENSE() -> str:
28+
return "GPL"
29+
30+
31+
compile()
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Section placement needs no marker: a zero initializer lands the global in
2+
# .bss, a non-zero one in .data, decided by LLVM exactly as for C. Mixed
3+
# widths and signedness also exercise the BTF basic-type emission.
4+
from pythonbpf import bpf, section, bpfglobal, compile
5+
from ctypes import c_void_p, c_int64, c_uint64, c_int32
6+
7+
8+
@bpf
9+
@bpfglobal
10+
def zeroed() -> c_uint64:
11+
return c_uint64(0)
12+
13+
14+
@bpf
15+
@bpfglobal
16+
def preset() -> c_int32:
17+
return c_int32(42)
18+
19+
20+
@bpf
21+
@section("tracepoint/raw_syscalls/sys_enter")
22+
def prog(ctx: c_void_p) -> c_int64:
23+
global zeroed
24+
zeroed = preset + 1
25+
return c_int64(0)
26+
27+
28+
@bpf
29+
@bpfglobal
30+
def LICENSE() -> str:
31+
return "GPL"
32+
33+
34+
compile()
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# A @bpfglobal read in a condition and in a print. Reads need no marker;
2+
# they compile to a plain `load i64, ptr @expected_pid`.
3+
from pythonbpf import bpf, section, bpfglobal, compile
4+
from pythonbpf.helper import pid
5+
from ctypes import c_void_p, c_int64, c_uint64
6+
7+
8+
@bpf
9+
@bpfglobal
10+
def expected_pid() -> c_uint64:
11+
return c_uint64(0)
12+
13+
14+
@bpf
15+
@section("tracepoint/syscalls/sys_enter_nanosleep")
16+
def trace(ctx: c_void_p) -> c_int64:
17+
if expected_pid == pid():
18+
print(f"matched {expected_pid}")
19+
return c_int64(0)
20+
21+
22+
@bpf
23+
@bpfglobal
24+
def LICENSE() -> str:
25+
return "GPL"
26+
27+
28+
compile()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# The test_autoattach.c shape: two programs on different attach points writing
2+
# flags into shared global state. Both write the same section's globals.
3+
from pythonbpf import bpf, section, bpfglobal, compile
4+
from ctypes import c_void_p, c_int64, c_uint64
5+
6+
7+
@bpf
8+
@bpfglobal
9+
def prog1_called() -> c_uint64:
10+
return c_uint64(0)
11+
12+
13+
@bpf
14+
@bpfglobal
15+
def prog2_called() -> c_uint64:
16+
return c_uint64(0)
17+
18+
19+
@bpf
20+
@section("raw_tp/sys_enter")
21+
def prog1(ctx: c_void_p) -> c_int64:
22+
global prog1_called
23+
prog1_called = 1
24+
return c_int64(0)
25+
26+
27+
@bpf
28+
@section("raw_tp/sys_exit")
29+
def prog2(ctx: c_void_p) -> c_int64:
30+
global prog2_called
31+
prog2_called = 1
32+
return c_int64(0)
33+
34+
35+
@bpf
36+
@bpfglobal
37+
def LICENSE() -> str:
38+
return "GPL"
39+
40+
41+
compile()
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# The get_cgroup_id_kern.c shape from the kernel selftests: read one global,
2+
# write another, gated on a pid check. Writes require Python's own `global`
3+
# statement and compile to `store i64 %v, ptr @cg_id`.
4+
from pythonbpf import bpf, section, bpfglobal, compile
5+
from pythonbpf.helper import pid, get_current_cgroup_id
6+
from ctypes import c_void_p, c_int64, c_uint64
7+
8+
9+
@bpf
10+
@bpfglobal
11+
def expected_pid() -> c_uint64:
12+
return c_uint64(0)
13+
14+
15+
@bpf
16+
@bpfglobal
17+
def cg_id() -> c_uint64:
18+
return c_uint64(0)
19+
20+
21+
@bpf
22+
@section("tracepoint/syscalls/sys_enter_nanosleep")
23+
def trace(ctx: c_void_p) -> c_int64:
24+
global cg_id
25+
if expected_pid == pid():
26+
cg_id = get_current_cgroup_id()
27+
return c_int64(0)
28+
29+
30+
@bpf
31+
@bpfglobal
32+
def LICENSE() -> str:
33+
return "GPL"
34+
35+
36+
compile()

tests/test_config.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,9 @@
3232
"failing_tests/vmlinux/assignment_handling.py" = {reason = "Assigning vmlinux enum value (XDP_PASS) to a local variable not yet supported", level = "ir"}
3333

3434
"failing_tests/xdp_pass.py" = {reason = "XDP program using vmlinux structs (struct_xdp_md) and complex map/struct interaction not yet supported", level = "ir"}
35+
36+
"failing_tests/globals_shadowing.py" = {reason = "Assignment to a global name without a `global` statement is a deliberate compile error (would shadow the BPF global)", level = "ir"}
37+
38+
"failing_tests/globals_undeclared_name.py" = {reason = "`global x` naming something that is not a @bpfglobal is a compile error", level = "ir"}
39+
40+
"failing_tests/globals_bad_type.py" = {reason = "Non-integer-scalar globals are not supported in milestone 1 (NotImplementedError by design)", level = "ir"}

0 commit comments

Comments
 (0)