fn deserialize_constant_bytes()

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()));
                &[]
            }
        }
    }