Skip to content

Commit 1dfb22d

Browse files
Core: Compare map values by value, not by address
With a map lookup on both sides, both operands are pointers of one type, so the depth-normalising path emitted a pointer compare. Load both sides through get_typed_operand instead, which also picks the predicate from the map's declared value sign.
1 parent 95a986e commit 1dfb22d

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

‎pythonbpf/expr/expr_pass.py‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,12 +383,57 @@ def _handle_ctypes_call(
383383
return value, expected_type
384384

385385

386+
def _is_map_int_value(operand, compilation_context, local_sym_tab):
387+
"""Whether the operand is an integer held in a map: a `m.lookup(k)` call on
388+
a map with an integer value, or a local bound to one. Both evaluate to a
389+
pointer into the map, and comparing one means comparing the value."""
390+
if isinstance(operand, ast.Name):
391+
sym = local_sym_tab.get(operand.id)
392+
if sym is None or not isinstance(sym.var.type, ir.PointerType):
393+
return False
394+
_, depth = get_base_type_and_depth(sym.var.type)
395+
return depth == 2 and isinstance(sym.metadata, str) and is_ctypes(sym.metadata)
396+
if (
397+
isinstance(operand, ast.Call)
398+
and isinstance(operand.func, ast.Attribute)
399+
and operand.func.attr == "lookup"
400+
and isinstance(operand.func.value, ast.Name)
401+
):
402+
map_sym = compilation_context.map_sym_tab.get(operand.func.value.id)
403+
if map_sym is None:
404+
return False
405+
value_type = map_sym.params.get("value")
406+
return isinstance(value_type, str) and is_ctypes(value_type)
407+
return False
408+
409+
386410
def _handle_compare(func, compilation_context, builder, cond, local_sym_tab):
387411
"""Handle ast.Compare expressions."""
388412

389413
if len(cond.ops) != 1 or len(cond.comparators) != 1:
390414
logger.error("Only single comparisons are supported")
391415
return None
416+
417+
if any(
418+
_is_map_int_value(operand, compilation_context, local_sym_tab)
419+
for operand in (cond.left, cond.comparators[0])
420+
):
421+
# A map value compares by what it holds (null-checked, 0 when the key
422+
# is absent), never by address: `x == m.lookup(i)` with both sides
423+
# pointers would otherwise compare two map slots' addresses.
424+
lhs, lhs_ty = get_typed_operand(
425+
func, compilation_context, cond.left, builder, local_sym_tab
426+
)
427+
rhs, rhs_ty = get_typed_operand(
428+
func, compilation_context, cond.comparators[0], builder, local_sym_tab
429+
)
430+
cmp_ty = usual_arithmetic_conversions(lhs_ty, rhs_ty)
431+
lhs = to_promoted(builder, lhs, lhs_ty, cmp_ty)
432+
rhs = to_promoted(builder, rhs, rhs_ty, cmp_ty)
433+
return handle_comparator(
434+
func, builder, cond.ops[0], lhs, rhs, signed=signedness(cmp_ty)
435+
)
436+
392437
lhs = eval_expr(
393438
func,
394439
compilation_context,

0 commit comments

Comments
 (0)