diff --git a/src/obj/btf/relocation.rs b/src/obj/btf/relocation.rs index 374c6715..77485b92 100644 --- a/src/obj/btf/relocation.rs +++ b/src/obj/btf/relocation.rs @@ -364,7 +364,7 @@ fn match_candidate<'target>( | RelocationKind::FieldLShift64 | RelocationKind::FieldRShift64 => { let mut target_id = candidate.type_id; - for accessor in &local_spec.accessors { + for (i, accessor) in local_spec.accessors.iter().enumerate() { target_id = candidate.btf.resolve_type(target_id)?; if accessor.name.is_some() { @@ -381,7 +381,29 @@ fn match_candidate<'target>( return Ok(None); } } else { - // array access + // i = 0 is the base struct. for i > 0, we need to potentially do bounds checking + if i > 0 { + let target_ty = candidate.btf.type_by_id(target_id)?; + let array = match target_ty { + BtfType::Array(_, array) => array, + _ => return Ok(None), + }; + + let var_len = array.nelems == 0 && { + // an array is potentially variable length if it's the last field + // of the parent struct and has 0 elements + let parent = target_spec.accessors.last().unwrap(); + let parent_ty = candidate.btf.type_by_id(parent.type_id)?; + match parent_ty { + BtfType::Struct(_, members) => parent.index == members.len() - 1, + _ => false, + } + }; + if !var_len && accessor.index >= array.nelems as usize { + return Ok(None); + } + target_id = candidate.btf.resolve_type(array.type_)?; + } if target_spec.parts.len() == MAX_SPEC_LEN { return Err(BtfRelocationError::MaximumNestingLevelReached {