(cx: &mut LiftContext<'_>, ty: TypeMapIndex, ptr: usize, len: usize)
| 983 | } |
| 984 | |
| 985 | fn load_map(cx: &mut LiftContext<'_>, ty: TypeMapIndex, ptr: usize, len: usize) -> Result<Val> { |
| 986 | // Maps are stored as list<tuple<k, v>> in canonical ABI |
| 987 | let map_ty = &cx.types[ty]; |
| 988 | let key_ty = map_ty.key; |
| 989 | let value_ty = map_ty.value; |
| 990 | |
| 991 | let key_abi = cx.types.canonical_abi(&key_ty); |
| 992 | let value_abi = cx.types.canonical_abi(&value_ty); |
| 993 | let key_size = usize::try_from(key_abi.size32).unwrap(); |
| 994 | let value_size = usize::try_from(value_abi.size32).unwrap(); |
| 995 | let value_offset = usize::try_from(map_ty.value_offset32).unwrap(); |
| 996 | let tuple_alignment = map_ty.entry_abi.align32; |
| 997 | let tuple_size = usize::try_from(map_ty.entry_abi.size32).unwrap(); |
| 998 | |
| 999 | // Bounds check |
| 1000 | match len |
| 1001 | .checked_mul(tuple_size) |
| 1002 | .and_then(|len| ptr.checked_add(len)) |
| 1003 | { |
| 1004 | Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<(Val, Val)>())?, |
| 1005 | _ => bail!("map pointer/length out of bounds of memory"), |
| 1006 | } |
| 1007 | if ptr % usize::try_from(tuple_alignment)? != 0 { |
| 1008 | bail!("map pointer is not aligned") |
| 1009 | } |
| 1010 | |
| 1011 | // Load each tuple (key, value) into a Vec |
| 1012 | let mut map = Vec::with_capacity(len); |
| 1013 | for index in 0..len { |
| 1014 | let tuple_ptr = ptr + (index * tuple_size); |
| 1015 | let key = Val::load(cx, key_ty, &cx.memory()[tuple_ptr..][..key_size])?; |
| 1016 | let value = Val::load( |
| 1017 | cx, |
| 1018 | value_ty, |
| 1019 | &cx.memory()[tuple_ptr + value_offset..][..value_size], |
| 1020 | )?; |
| 1021 | map.push((key, value)); |
| 1022 | } |
| 1023 | |
| 1024 | Ok(Val::Map(map)) |
| 1025 | } |
| 1026 | |
| 1027 | fn load_variant( |
| 1028 | cx: &mut LiftContext<'_>, |
no test coverage detected