in checker/src/block_visitor.rs [2816:3055]
fn deserialize_constant_bytes<'a>(
&mut self,
target_path: Rc<Path>,
bytes: &'a [u8],
ty: Ty<'tcx>,
) -> &'a [u8] {
self.type_visitor_mut()
.set_path_rustc_type(target_path.clone(), ty);
match ty.kind() {
TyKind::Adt(def, substs) if def.is_enum() => {
trace!("deserializing {:?} {:?}", def, substs);
let discr_val_path = Path::new_discriminant(target_path.clone());
// Assume (probably incorrectly) that the discriminant is encoded into a single byte
// todo: somehow figure out what the Rust compiler is actually doing here. (Not easy.)
self.bv
.update_value_at(discr_val_path, Rc::new((bytes[0] as u128).into()));
let mut bytes_left_to_deserialize = bytes;
if let Ok(enum_ty_layout) = self.type_visitor().layout_of(ty) {
let (_, _, discr_index, discr_has_data) =
self.get_discriminator_info(bytes[0] as u128, &enum_ty_layout);
trace!("discr_index {:?}", discr_index);
trace!("discr_has_data {:?}", discr_has_data);
if !discr_has_data {
bytes_left_to_deserialize = &bytes_left_to_deserialize[1..];
}
let variant = &def.variants()[discr_index];
trace!("deserializing variant {:?}", variant);
for (i, field) in variant.fields.iter().enumerate() {
trace!("deserializing field({}) {:?}", i, field);
trace!("bytes_left_deserialize {:?}", bytes_left_to_deserialize);
let field_path = Path::new_field(target_path.clone(), i);
let field_ty = field.ty(self.bv.tcx, substs);
trace!(
"field ty layout {:?}",
self.type_visitor().layout_of(field_ty)
);
bytes_left_to_deserialize = self.deserialize_constant_bytes(
field_path,
bytes_left_to_deserialize,
field_ty,
);
}
}
bytes_left_to_deserialize
}
TyKind::Adt(def, substs) => {
trace!("deserializing {:?} {:?}", def, substs);
let mut bytes_left_to_deserialize = bytes;
for variant in def.variants().iter() {
trace!("deserializing variant {:?}", variant);
bytes_left_to_deserialize = bytes;
for (i, field) in variant.fields.iter().enumerate() {
trace!("deserializing field({}) {:?}", i, field);
trace!("bytes_left_deserialize {:?}", bytes_left_to_deserialize);
let field_path = Path::new_field(target_path.clone(), i);
let field_ty = field.ty(self.bv.tcx, substs);
trace!(
"field ty layout {:?}",
self.type_visitor().layout_of(field_ty)
);
bytes_left_to_deserialize = self.deserialize_constant_bytes(
field_path,
bytes_left_to_deserialize,
field_ty,
);
}
}
bytes_left_to_deserialize
}
TyKind::Array(elem_type, length) => {
let length = self.bv.get_array_length(length);
self.deserialize_constant_array(target_path, bytes, length, *elem_type)
}
TyKind::Bool => {
let val = if bytes[0] == 0 {
abstract_value::FALSE
} else {
abstract_value::TRUE
};
self.bv.update_value_at(target_path, Rc::new(val));
&bytes[1..]
}
TyKind::Char => unsafe {
let ch_ptr = bytes.as_ptr() as *const char;
let ch = self
.bv
.cv
.constant_value_cache
.get_char_for(*ch_ptr)
.clone();
self.bv.update_value_at(target_path, Rc::new(ch.into()));
&bytes[4..]
},
TyKind::Int(IntTy::Isize) => unsafe {
let int_ptr = bytes.as_ptr() as *const isize;
let i = self.bv.get_i128_const_val((*int_ptr) as i128);
self.bv.update_value_at(target_path, i);
let size = std::mem::size_of::<isize>();
&bytes[size..]
},
TyKind::Int(IntTy::I8) => unsafe {
let int_ptr = bytes.as_ptr() as *const i8;
let i = self.bv.get_i128_const_val((*int_ptr) as i128);
self.bv.update_value_at(target_path, i);
&bytes[1..]
},
TyKind::Int(IntTy::I16) => unsafe {
let int_ptr = bytes.as_ptr() as *const i16;
let i = self.bv.get_i128_const_val((*int_ptr) as i128);
self.bv.update_value_at(target_path, i);
&bytes[2..]
},
TyKind::Int(IntTy::I32) => unsafe {
let int_ptr = bytes.as_ptr() as *const i32;
let i = self.bv.get_i128_const_val((*int_ptr) as i128);
self.bv.update_value_at(target_path, i);
&bytes[4..]
},
TyKind::Int(IntTy::I64) => unsafe {
let int_ptr = bytes.as_ptr() as *const i64;
let i = self.bv.get_i128_const_val((*int_ptr) as i128);
self.bv.update_value_at(target_path, i);
&bytes[8..]
},
TyKind::Int(IntTy::I128) => unsafe {
let int_ptr = bytes.as_ptr() as *const i128;
let i = self.bv.get_i128_const_val(*int_ptr);
self.bv.update_value_at(target_path, i);
&bytes[16..]
},
TyKind::Uint(UintTy::Usize) => unsafe {
let uint_ptr = bytes.as_ptr() as *const usize;
let u = self.bv.get_u128_const_val((*uint_ptr) as u128);
self.bv.update_value_at(target_path, u);
let size = std::mem::size_of::<isize>();
&bytes[size..]
},
TyKind::Uint(UintTy::U8) => unsafe {
let uint_ptr = bytes.as_ptr() as *const u8;
let u = self.bv.get_u128_const_val((*uint_ptr) as u128);
self.bv.update_value_at(target_path, u);
&bytes[1..]
},
TyKind::Uint(UintTy::U16) => unsafe {
let uint_ptr = bytes.as_ptr() as *const u16;
let u = self.bv.get_u128_const_val((*uint_ptr) as u128);
self.bv.update_value_at(target_path, u);
&bytes[2..]
},
TyKind::Uint(UintTy::U32) => unsafe {
let uint_ptr = bytes.as_ptr() as *const u32;
let u = self.bv.get_u128_const_val((*uint_ptr) as u128);
self.bv.update_value_at(target_path, u);
&bytes[4..]
},
TyKind::Uint(UintTy::U64) => unsafe {
let uint_ptr = bytes.as_ptr() as *const u64;
let u = self.bv.get_u128_const_val((*uint_ptr) as u128);
self.bv.update_value_at(target_path, u);
&bytes[8..]
},
TyKind::Uint(UintTy::U128) => unsafe {
let uint_ptr = bytes.as_ptr() as *const u128;
let u = self.bv.get_u128_const_val(*uint_ptr);
self.bv.update_value_at(target_path, u);
&bytes[16..]
},
TyKind::Float(FloatTy::F32) => unsafe {
let uint_ptr = bytes.as_ptr() as *const u32;
let f = self
.bv
.cv
.constant_value_cache
.get_f32_for(*uint_ptr)
.clone();
self.bv.update_value_at(target_path, Rc::new(f.into()));
&bytes[4..]
},
TyKind::Float(FloatTy::F64) => unsafe {
let uint_ptr = bytes.as_ptr() as *const u64;
let f = self
.bv
.cv
.constant_value_cache
.get_f64_for(*uint_ptr)
.clone();
self.bv.update_value_at(target_path, Rc::new(f.into()));
&bytes[8..]
},
TyKind::FnPtr(..)
| TyKind::RawPtr(rustc_middle::ty::TypeAndMut { .. })
| TyKind::Ref(..) => {
// serialized pointers are not the values pointed to, just some number.
// todo: figure out how to deference that number and deserialize the
// value to which this pointer refers.
self.deserialize_constant_bytes(target_path, bytes, self.bv.tcx.types.usize)
}
TyKind::Slice(elem_type) => {
let elem_size = self.type_visitor().get_type_size(*elem_type) as usize;
checked_assume!(elem_size > 0); // serializing a slice of zero sized elements makes no sense
let num_elems = bytes.len() / elem_size;
self.deserialize_constant_array(target_path, bytes, num_elems, *elem_type)
}
TyKind::Str => {
let s = std::str::from_utf8(bytes).expect("string should be serialized as utf8");
let string_const = &mut self.bv.cv.constant_value_cache.get_string_for(s);
let string_val: Rc<AbstractValue> = Rc::new(string_const.clone().into());
let len_val: Rc<AbstractValue> =
Rc::new(ConstantDomain::U128(s.len() as u128).into());
let str_path = Path::new_computed(string_val.clone());
self.bv.update_value_at(str_path.clone(), string_val);
let len_path = Path::new_length(str_path.clone());
self.bv.update_value_at(len_path, len_val);
self.bv
.update_value_at(target_path, AbstractValue::make_reference(str_path));
&[]
}
TyKind::Tuple(types) => {
let mut bytes_left_deserialize = bytes;
for (i, field_ty) in types.iter().enumerate() {
let field_path = Path::new_field(target_path.clone(), i);
bytes_left_deserialize = self.deserialize_constant_bytes(
field_path,
bytes_left_deserialize,
field_ty,
);
}
bytes_left_deserialize
}
_ => {
debug!("Type {:?} is not expected to be serializable", ty.kind());
self.bv
.update_value_at(target_path, Rc::new(ConstantDomain::Unimplemented.into()));
&[]
}
}
}