Skip to content

Commit 274bac9

Browse files
r41k0uclaude
andcommitted
Tests: Pin name-resolution order under vmlinux collisions
Two tests locking the shadowing semantics: a local named XDP_PASS returned from a program (the exact case the return fast path used to hijack), and a vmlinux-importing program where a local shadows one enum constant while a @bpfglobal shadows another, read in expressions and f-strings. The vmlinux test needs noqa on its import and both collision sites: ruff rightly flags unused imports and redefinitions in normal Python, and this file is deliberately made of them. These pin compilation; the value-level proof (ret of 55, not 2) was verified against the emitted IR and the clang reference for the same collision shapes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L1PX8EuP9C3o3veWGA84RF
1 parent 7f5773e commit 274bac9

2 files changed

Lines changed: 63 additions & 0 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# A local named after an XDP action must shadow the helper constant table,
2+
# in return position too. clang agrees: a local legally shadows an enum
3+
# constant, and the local's value is what returns (tests/c-form reference).
4+
# Before the fix this returned the hardcoded 2 while XDP_PASS held 55.
5+
from pythonbpf import bpf, section, bpfglobal, compile
6+
from ctypes import c_void_p, c_int64
7+
8+
9+
@bpf
10+
@section("tracepoint/raw_syscalls/sys_enter")
11+
def prog(ctx: c_void_p) -> c_int64:
12+
XDP_PASS = 55
13+
return XDP_PASS
14+
15+
16+
@bpf
17+
@bpfglobal
18+
def LICENSE() -> str:
19+
return "GPL"
20+
21+
22+
compile()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Name-resolution order under collision with vmlinux enum constants:
2+
# local wins over global wins over vmlinux, consistently in expressions,
3+
# f-strings, and returns.
4+
#
5+
# clang's take on the same collisions (tests/c-form): a local shadowing an
6+
# enum constant is legal and wins; a file-scope variable colliding with one is
7+
# a hard error. PythonBPF follows Python's rebinding semantics instead for the
8+
# global case -- the @bpfglobal wins -- and logs a compile-time warning so the
9+
# shadowing is never silent.
10+
# XDP_ABORTED's import is load-bearing despite being "unused": it is what
11+
# registers the enum with the compiler, so the local below has something to
12+
# shadow. Python-level unused is the point.
13+
from vmlinux import XDP_ABORTED, XDP_TX # noqa: F401
14+
from pythonbpf import bpf, section, bpfglobal, compile
15+
from ctypes import c_void_p, c_int64, c_uint64
16+
17+
18+
# Shadows the vmlinux enum constant XDP_TX (warns at compile time; reads of
19+
# XDP_TX below resolve to this global, value 77, not the enum value 3).
20+
@bpf
21+
@bpfglobal
22+
def XDP_TX() -> c_uint64: # noqa: F811 -- the collision is the test
23+
return c_uint64(77)
24+
25+
26+
@bpf
27+
@section("tracepoint/raw_syscalls/sys_enter")
28+
def prog(ctx: c_void_p) -> c_int64:
29+
XDP_ABORTED = 55 # noqa: F811 -- local shadows the enum (value 0)
30+
x = XDP_ABORTED + XDP_TX
31+
print(f"local {XDP_ABORTED} global {XDP_TX}")
32+
return c_int64(x)
33+
34+
35+
@bpf
36+
@bpfglobal
37+
def LICENSE() -> str:
38+
return "GPL"
39+
40+
41+
compile()

0 commit comments

Comments
 (0)