Skip to content

Commit a5eeaaf

Browse files
r41k0uclaude
andcommitted
Tests: Context fields into slots of every width, and c_bool
ctx_field_into_slots.py stores 8-, 32- and 64-bit sk_buff fields into locals declared at every width and into struct fields of every width, with IR assertions on the slot widths and the truncation before each store. It is the compact form of a 52-case matrix (four field widths, nine local and four struct-field destinations) compiled on master and here: every case compiles, nothing sign-extends a field on the way in, and where master compiled the IR is identical except where master put a narrow local in a 64-bit slot. c_bool.py covers the local, struct field, map value and global. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 20a1e2f commit a5eeaaf

3 files changed

Lines changed: 115 additions & 0 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# c_bool is C's _Bool: a value narrows to it by comparing with zero (5 is
2+
# true), and it widens to 0 or 1 (zero-extended, never sign-extended), as a
3+
# local, a struct field, a map value and a global. In BTF it is a one-byte
4+
# _Bool, so the map's value size is 1.
5+
from ctypes import c_bool, c_int64, c_uint32, c_void_p
6+
from pythonbpf import bpf, map, struct, section, bpfglobal, compile
7+
from pythonbpf.maps import HashMap
8+
9+
10+
@bpf
11+
@struct
12+
class flags:
13+
on: c_bool
14+
n: c_uint32
15+
16+
17+
@bpf
18+
@map
19+
def seen() -> HashMap:
20+
return HashMap(key=c_uint32, value=c_bool, max_entries=4)
21+
22+
23+
@bpf
24+
@bpfglobal
25+
def armed() -> c_bool:
26+
return c_bool(1)
27+
28+
29+
@bpf
30+
@section("tracepoint/raw_syscalls/sys_enter")
31+
def prog(ctx: c_void_p) -> c_int64:
32+
global armed
33+
b = c_bool(5)
34+
f = flags()
35+
f.on = 2
36+
k = c_uint32(1)
37+
seen.update(k, c_bool(1))
38+
armed = 7
39+
print(f"{b} {f.on} {armed}")
40+
return c_int64(b)
41+
42+
43+
@bpf
44+
@bpfglobal
45+
def LICENSE() -> str:
46+
return "GPL"
47+
48+
49+
compile()
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# A context field stored into a slot of any integer width: the field is loaded
2+
# at its declared width, zero-extended (all of these are unsigned), then cut to
3+
# the slot's width, as C's `__u8 x = skb->len` does. Covers locals declared
4+
# with every width and struct fields of every width.
5+
from ctypes import c_int8, c_uint16, c_int32, c_uint64, c_uint8, c_uint32, c_int64
6+
from pythonbpf import bpf, struct, section, bpfglobal, compile
7+
from vmlinux import struct___sk_buff
8+
9+
10+
@bpf
11+
@struct
12+
class rec:
13+
f8: c_uint8
14+
f16: c_uint16
15+
f32: c_uint32
16+
f64: c_uint64
17+
18+
19+
@bpf
20+
@section("tc")
21+
def prog(ctx: struct___sk_buff) -> c_int64:
22+
a8 = c_int8(0)
23+
a8 = ctx.len # u32 -> i8
24+
b16 = c_uint16(0)
25+
b16 = ctx.len # u32 -> u16
26+
c32 = c_int32(0)
27+
c32 = ctx.tstamp # u64 -> i32
28+
d64 = c_uint64(0)
29+
d64 = ctx.tstamp_type # u8 -> u64
30+
e = ctx.len # undeclared: a 64-bit slot
31+
r = rec()
32+
r.f8 = ctx.len
33+
r.f16 = ctx.tstamp
34+
r.f32 = ctx.tstamp
35+
r.f64 = ctx.tstamp_type
36+
print(f"{a8} {b16} {c32}")
37+
print(f"{d64} {e}")
38+
return c_int64(0)
39+
40+
41+
@bpf
42+
@bpfglobal
43+
def LICENSE() -> str:
44+
return "GPL"
45+
46+
47+
compile()

‎tests/test_signedness_ir.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,25 @@
7474
[r'%"queue" = alloca i16', r"trunc i64 .* to i16"],
7575
[r'%"queue" = alloca i64'],
7676
),
77+
# A context field into slots of every width: loaded, zero-extended,
78+
# truncated to the slot; nothing sign-extended on the way in.
79+
"vmlinux/ctx_field_into_slots.py": (
80+
[
81+
r'%"a8" = alloca i8',
82+
r'%"b16" = alloca i16',
83+
r'%"c32" = alloca i32',
84+
r'%"d64" = alloca i64',
85+
r'trunc i64 %[^\n]* to i8\n\s*store i8 [^\n]*%"a8"',
86+
r'trunc i64 %[^\n]* to i16\n\s*store i16 [^\n]*%"b16"',
87+
r'trunc i64 %[^\n]* to i32\n\s*store i32 [^\n]*%"c32"',
88+
],
89+
[r'alloca i64[^\n]*\n[^\n]*%"a8"'],
90+
),
91+
# c_bool: narrowing is != 0, widening is zext; never trunc to i1 or sext.
92+
"signedness/c_bool.py": (
93+
[r"icmp ne i64 5, 0", r"icmp ne i64 2, 0", r"icmp ne i64 7, 0", r"zext i1"],
94+
[r"sext i1 ", r"trunc i64 [^\n]* to i1"],
95+
),
7796
# A bool widens with zext and an integer narrows to it by != 0, never by
7897
# trunc; sext of an i1 would return -1 for True.
7998
"signedness/bool_int.py": (

0 commit comments

Comments
 (0)