Skip to content

Commit 0bdea85

Browse files
committed
Core: Store a context field into a narrower slot through convert()
A sub-register context field is loaded zero-extended to i64, and the assignment path accepted it only into a 64-bit slot or one whose type was exactly the field's declared type. The second case never worked in practice: `data_end = skb.data_end` into a c_uint32 global died in llvmlite with "cannot store i64 to i32*" because the value was still i64. Route the store through convert(), sizing from the physical value and signing from the field, like every other integer store since the signedness work: a no-op into an i64 slot, a trunc into anything narrower. Found by porting cgroup_skb_direct_packet_access.c, which is that exact statement. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DLMW3X7opqAPH6bjmTVkr7
1 parent 3ffba47 commit 0bdea85

2 files changed

Lines changed: 39 additions & 15 deletions

File tree

‎pythonbpf/assign_pass.py‎

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -197,22 +197,14 @@ def handle_variable_assignment(
197197
logger.info("Handling assignment to struct field")
198198
field_ir_type = ctypes_to_ir(val_type.type.__name__)
199199
# Sub-register-width context fields are zero-extended to i64 by
200-
# load_ctx_field, so val is already i64 even though the field type
201-
# says otherwise (c_uint for xdp_md, c_ushort for pt_regs.cs/ss).
202-
if (
203-
isinstance(field_ir_type, ir.IntType)
204-
and field_ir_type.width < 64
205-
and isinstance(var_type, ir.IntType)
206-
and var_type.width == 64
200+
# load_ctx_field, so val may be wider than the field type says
201+
# (c_uint for xdp_md, c_ushort for pt_regs.cs/ss). convert()
202+
# sizes from the physical value and signs from the field, so it
203+
# is a no-op into an i64 slot and a trunc into a narrower one.
204+
if isinstance(field_ir_type, ir.IntType) and isinstance(
205+
var_type, ir.IntType
207206
):
208-
builder.store(val, var_ptr)
209-
logger.info(
210-
f"Assigned zero-extended i{field_ir_type.width} context field "
211-
f"to {var_name} (i64)"
212-
)
213-
return True
214-
# TODO: handling only ctype struct fields for now. Handle other stuff too later.
215-
elif var_type == field_ir_type:
207+
val = convert(builder, val, field_ir_type, var_type)
216208
builder.store(val, var_ptr)
217209
logger.info(f"Assigned ctype struct field to {var_name}")
218210
return True
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# A context field is loaded widened to i64, but it can be stored into a slot
2+
# of its own declared width, or narrower: the store truncates like any other
3+
# integer conversion. The cgroup_skb_direct_packet_access.c selftest does
4+
# exactly this with `__u32 data_end = skb->data_end`.
5+
from ctypes import c_int64, c_uint16, c_uint32
6+
from pythonbpf import bpf, section, bpfglobal, compile
7+
from vmlinux import struct_xdp_md
8+
9+
10+
@bpf
11+
@bpfglobal
12+
def ifindex() -> c_uint32:
13+
return c_uint32(0)
14+
15+
16+
@bpf
17+
@section("xdp")
18+
def prog(ctx: struct_xdp_md) -> c_int64:
19+
global ifindex
20+
ifindex = ctx.ingress_ifindex
21+
queue = c_uint16(0)
22+
queue = ctx.rx_queue_index
23+
return c_int64(queue)
24+
25+
26+
@bpf
27+
@bpfglobal
28+
def LICENSE() -> str:
29+
return "GPL"
30+
31+
32+
compile()

0 commit comments

Comments
 (0)