Skip to content

Commit 7b382a2

Browse files
authored
Merge pull request #14 from SiyuanSun0736/fix_in_ringbuf_demo
Auto-deref map access in assignments and Add Forward Declarations
2 parents 46c596f + ed61c06 commit 7b382a2

4 files changed

Lines changed: 164 additions & 2 deletions

File tree

src/ebpf_c_codegen.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2559,7 +2559,10 @@ and generate_assignment ctx dest_val expr is_const =
25592559
| IRValue src_val ->
25602560
(* Simple value assignment *)
25612561
let dest_str = generate_c_value ctx dest_val in
2562-
let src_str = generate_c_value ctx src_val in
2562+
(* Auto-dereference map access to get the value, not the pointer *)
2563+
let src_str = (match src_val.value_desc with
2564+
| IRMapAccess (_, _, _) -> generate_c_value ~auto_deref_map_access:true ctx src_val
2565+
| _ -> generate_c_value ctx src_val) in
25632566
emit_line ctx (sprintf "%s%s = %s;" assignment_prefix dest_str src_str)
25642567
| _ ->
25652568
(* Other expressions *)

src/userspace_codegen.ml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2817,6 +2817,19 @@ let generate_pinned_globals_support _project_name global_variables =
28172817

28182818
(** Generate ring buffer event handler functions *)
28192819
let generate_ringbuf_handlers_from_registry (registry : Ir.ir_ring_buffer_registry) ~dispatch_used =
2820+
(* Generate forward declarations for callback functions *)
2821+
let forward_declarations = List.map (fun rb_decl ->
2822+
let ringbuf_name = rb_decl.rb_name in
2823+
let value_type = c_type_from_ir_type rb_decl.rb_value_type in
2824+
let handler_name = match List.assoc_opt ringbuf_name registry.event_handler_registrations with
2825+
| Some handler -> handler
2826+
| None ->
2827+
(* Try callback function naming convention: {ringbuf_name}_callback *)
2828+
ringbuf_name ^ "_callback"
2829+
in
2830+
sprintf "int %s(%s *event);" handler_name value_type
2831+
) registry.ring_buffer_declarations |> String.concat "\n" in
2832+
28202833
let event_handlers = List.map (fun rb_decl ->
28212834
let ringbuf_name = rb_decl.rb_name in
28222835
let value_type = c_type_from_ir_type rb_decl.rb_value_type in
@@ -2842,7 +2855,11 @@ static int %s_event_handler(void *ctx, void *data, size_t data_sz) {
28422855
else "" in
28432856

28442857
(* Only generate event handlers if dispatch is actually used *)
2845-
let final_event_handlers = if dispatch_used then event_handlers else "" in
2858+
let final_event_handlers = if dispatch_used then
2859+
if List.length registry.ring_buffer_declarations > 0 then
2860+
sprintf "\n// Forward declarations for ring buffer callbacks\n%s\n%s" forward_declarations event_handlers
2861+
else ""
2862+
else "" in
28462863

28472864
final_event_handlers ^ combined_rb_declaration
28482865

tests/test_ebpf_c_codegen.ml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,37 @@ let test_global_map_redefinition_fix () =
11461146

11471147
()
11481148

1149+
(** Test map access auto-dereference in variable assignment (covers lines 2559-2566) *)
1150+
let test_map_access_auto_deref_in_assignment () =
1151+
let ctx = create_c_context () in
1152+
1153+
(* Build: count = my_map[user_key]
1154+
IRMapAccess carries the raw lookup-pointer as its underlying value. *)
1155+
let key_val = make_ir_value (IRVariable "user_key") IRU32 test_pos in
1156+
let underlying_desc = IRVariable "map_ptr_0" in
1157+
let underlying_type = IRPointer (IRU64, make_bounds_info ()) in
1158+
let src_val = make_ir_value
1159+
(IRMapAccess ("my_map", key_val, (underlying_desc, underlying_type)))
1160+
IRU64 test_pos in
1161+
1162+
let dest_val = make_ir_value (IRVariable "count") IRU64 test_pos in
1163+
let assign_instr = make_ir_instruction
1164+
(IRAssign (dest_val, make_ir_expr (IRValue src_val) IRU64 test_pos))
1165+
test_pos in
1166+
1167+
generate_c_instruction ctx assign_instr;
1168+
1169+
let output = String.concat "\n" ctx.output_lines in
1170+
1171+
(* auto_deref_map_access:true emits a guarded dereference:
1172+
count = ({ __u64 __val = {0}; if (map_ptr_0) { __val = *(map_ptr_0); } __val; }); *)
1173+
check bool "dest variable present in output" true (contains_substr output "count =");
1174+
check bool "__val used for safe dereference" true (contains_substr output "__val");
1175+
check bool "null-guard if-check emitted" true (contains_substr output "if (map_ptr_0)");
1176+
check bool "pointer dereference emitted" true (contains_substr output "*(map_ptr_0)");
1177+
(* Without the fix this branch would fall through to the raw-pointer path *)
1178+
check bool "no raw pointer assignment" false (contains_substr output "count = map_ptr_0")
1179+
11491180
(** Test suite definition *)
11501181
let suite =
11511182
[
@@ -1191,6 +1222,8 @@ let suite =
11911222
("eBPF function generation bug fix", `Quick, test_ebpf_function_generation_bug_fix);
11921223
(* Test to prevent global variable map redefinition regression *)
11931224
("Global map redefinition fix", `Quick, test_global_map_redefinition_fix);
1225+
(* Coverage for IRMapAccess auto-dereference path in generate_assignment *)
1226+
("Map access auto-deref in assignment", `Quick, test_map_access_auto_deref_in_assignment);
11941227
]
11951228

11961229
(** Run all tests *)

tests/test_ringbuf.ml

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,107 @@ fn main() -> i32 {
10951095
check bool "Should generate user handler functions" true
10961096
(contains_substr c_code "handle_network" && contains_substr c_code "handle_security")
10971097

1098+
(** ── Unit tests for generate_ringbuf_handlers_from_registry (lines 2812-2826) ── *)
1099+
1100+
(** Helper: build a minimal ir_ring_buffer_registry for unit testing *)
1101+
let make_registry ?(event_handler_registrations = []) rb_decls =
1102+
{
1103+
Ir.ring_buffer_declarations = rb_decls;
1104+
Ir.event_handler_registrations = event_handler_registrations;
1105+
Ir.usage_summary = {
1106+
Ir.used_in_ebpf = [];
1107+
Ir.used_in_userspace = [];
1108+
Ir.needs_event_processing = [];
1109+
};
1110+
}
1111+
1112+
let make_rb_decl name value_type =
1113+
{
1114+
Ir.rb_name = name;
1115+
Ir.rb_value_type = value_type;
1116+
Ir.rb_size = 4096;
1117+
Ir.rb_is_global = true;
1118+
Ir.rb_declaration_pos = { Ast.line = 1; column = 1; filename = "test.ks" };
1119+
}
1120+
1121+
(** Test: empty registry produces empty output regardless of dispatch_used *)
1122+
let test_handlers_empty_registry () =
1123+
let registry = make_registry [] in
1124+
let out_true = Userspace_codegen.generate_ringbuf_handlers_from_registry
1125+
registry ~dispatch_used:true in
1126+
let out_false = Userspace_codegen.generate_ringbuf_handlers_from_registry
1127+
registry ~dispatch_used:false in
1128+
check string "empty registry + dispatch_used:true → empty" "" out_true;
1129+
check string "empty registry + dispatch_used:false → empty" "" out_false
1130+
1131+
(** Test: None branch – no event_handler_registrations entry → fallback to {rb_name}_callback *)
1132+
let test_handlers_none_branch_fallback () =
1133+
(* No registration entry for "events" → handler name must fall back to "events_callback" *)
1134+
let decl = make_rb_decl "events" Ir.IRU32 in
1135+
let registry = make_registry [decl] in (* event_handler_registrations = [] *)
1136+
let out = Userspace_codegen.generate_ringbuf_handlers_from_registry
1137+
registry ~dispatch_used:true in
1138+
check bool "None branch: _callback fallback in event handler wrapper"
1139+
true (contains_substr out "events_callback");
1140+
check bool "None branch: event handler wrapper function generated"
1141+
true (contains_substr out "events_event_handler");
1142+
check bool "None branch: wrapper calls fallback handler"
1143+
true (contains_substr out "return events_callback(event)")
1144+
1145+
(** Test: Some branch – registered handler name is used instead of fallback *)
1146+
let test_handlers_some_branch_registered_name () =
1147+
let decl = make_rb_decl "events" (Ir.IRStruct ("Event", [("id", Ir.IRU32)])) in
1148+
let registry = make_registry ~event_handler_registrations:[("events", "handle_event")] [decl] in
1149+
let out = Userspace_codegen.generate_ringbuf_handlers_from_registry
1150+
registry ~dispatch_used:true in
1151+
check bool "Some branch: registered handler name used in wrapper"
1152+
true (contains_substr out "handle_event");
1153+
check bool "Some branch: wrapper calls registered handler"
1154+
true (contains_substr out "return handle_event(event)");
1155+
check bool "Some branch: fallback name NOT used"
1156+
false (contains_substr out "events_callback")
1157+
1158+
(** Test: dispatch_used:false → no event handler wrappers emitted *)
1159+
let test_handlers_dispatch_false_no_wrappers () =
1160+
let decl = make_rb_decl "events" Ir.IRU32 in
1161+
let registry = make_registry ~event_handler_registrations:[("events", "handle_event")] [decl] in
1162+
let out = Userspace_codegen.generate_ringbuf_handlers_from_registry
1163+
registry ~dispatch_used:false in
1164+
check bool "dispatch_used:false → no event_handler wrapper"
1165+
false (contains_substr out "events_event_handler");
1166+
check bool "dispatch_used:false → no combined_rb declaration"
1167+
false (contains_substr out "combined_rb")
1168+
1169+
(** Test: dispatch_used:true → combined_rb declaration emitted *)
1170+
let test_handlers_dispatch_true_combined_rb () =
1171+
let decl = make_rb_decl "events" Ir.IRU32 in
1172+
let registry = make_registry ~event_handler_registrations:[("events", "handle_event")] [decl] in
1173+
let out = Userspace_codegen.generate_ringbuf_handlers_from_registry
1174+
registry ~dispatch_used:true in
1175+
check bool "dispatch_used:true → combined_rb NULL declaration emitted"
1176+
true (contains_substr out "combined_rb = NULL")
1177+
1178+
(** Test: multiple ring buffers – every buffer gets its own event handler wrapper *)
1179+
let test_handlers_multiple_ringbufs () =
1180+
let decl1 = make_rb_decl "net_events" (Ir.IRStruct ("NetEvent", [("src_ip", Ir.IRU32)])) in
1181+
let decl2 = make_rb_decl "sec_events" (Ir.IRStruct ("SecEvent", [("severity", Ir.IRU32)])) in
1182+
let registry = make_registry
1183+
~event_handler_registrations:[
1184+
("net_events", "handle_net");
1185+
("sec_events", "handle_sec");
1186+
]
1187+
[decl1; decl2] in
1188+
let out = Userspace_codegen.generate_ringbuf_handlers_from_registry
1189+
registry ~dispatch_used:true in
1190+
check bool "multiple: net_events_event_handler generated"
1191+
true (contains_substr out "net_events_event_handler");
1192+
check bool "multiple: sec_events_event_handler generated"
1193+
true (contains_substr out "sec_events_event_handler");
1194+
check bool "multiple: handle_net referenced"
1195+
true (contains_substr out "handle_net");
1196+
check bool "multiple: handle_sec referenced"
1197+
true (contains_substr out "handle_sec")
1198+
10981199
(** Run all tests *)
10991200
let () =
11001201
run "Ring Buffer Tests" [
@@ -1151,4 +1252,12 @@ let () =
11511252
test_case "complex operations" `Quick test_ringbuf_complex_operations;
11521253
test_case "on_event and dispatch integration" `Quick test_on_event_dispatch_integration;
11531254
];
1255+
"handler registry unit tests", [
1256+
test_case "empty registry" `Quick test_handlers_empty_registry;
1257+
test_case "None branch fallback to _callback" `Quick test_handlers_none_branch_fallback;
1258+
test_case "Some branch registered handler name" `Quick test_handlers_some_branch_registered_name;
1259+
test_case "dispatch_used false suppresses wrappers" `Quick test_handlers_dispatch_false_no_wrappers;
1260+
test_case "dispatch_used true emits combined_rb" `Quick test_handlers_dispatch_true_combined_rb;
1261+
test_case "multiple ring buffers each get wrapper" `Quick test_handlers_multiple_ringbufs;
1262+
];
11541263
]

0 commit comments

Comments
 (0)