fn handle_write_bytes()

in checker/src/call_visitor.rs [2424:2512]


    fn handle_write_bytes(&mut self) {
        checked_assume!(self.actual_args.len() == 3);
        let target_type = ExpressionType::from(
            self.type_visitor()
                .get_dereferenced_type(self.actual_argument_types[0])
                .kind(),
        );
        let dest_path = Path::new_deref(self.actual_args[0].0.clone(), target_type)
            .canonicalize(&self.block_visitor.bv.current_environment);
        let dest_type = self.actual_argument_types[0];
        let source_path = self.actual_args[1]
            .0
            .canonicalize(&self.block_visitor.bv.current_environment);
        let byte_value = &self.actual_args[1].1;
        let count_value = self.actual_args[2].1.clone();
        let elem_type = self
            .callee_generic_arguments
            .expect("write_bytes<T>")
            .get(0)
            .expect("write_bytes<T>")
            .expect_ty();
        let mut elem_size = self.type_visitor().get_type_size(elem_type);
        fn repeated_bytes(mut elem_size: u64, byte_value: &Rc<AbstractValue>) -> Rc<AbstractValue> {
            let const_8: Rc<AbstractValue> = Rc::new(8u128.into());
            let mut source_value = byte_value.clone();
            while elem_size > 1 {
                source_value = source_value
                    .shift_left(const_8.clone())
                    .bit_or(byte_value.clone());
                elem_size -= 1;
            }
            source_value
        }
        if elem_type.is_primitive() {
            let dest_pattern = Path::new_slice(dest_path, count_value);
            let source_value = repeated_bytes(elem_size, byte_value);
            self.block_visitor
                .bv
                .update_value_at(dest_pattern, source_value);
        } else if let Expression::CompileTimeConstant(ConstantDomain::U128(count)) =
            &count_value.expression
        {
            if let TyKind::Adt(..) | TyKind::Tuple(..) = &elem_type.kind() {
                for i in 0..(*count as usize) {
                    let dest_field = Path::new_field(dest_path.clone(), i);
                    let field_type = self
                        .type_visitor()
                        .get_path_rustc_type(&dest_field, self.block_visitor.bv.current_span);
                    let field_size = self.type_visitor().get_type_size(field_type);
                    elem_size -= field_size;
                    let field_value = repeated_bytes(field_size, byte_value);
                    self.block_visitor
                        .bv
                        .update_value_at(dest_field, field_value);
                    if elem_size == 0 {
                        break;
                    }
                }
            } else {
                if *count > 1 {
                    warn!(
                        "unhandled call to write_bytes<{:?}>({:?}: {:?}, {:?}, {:?})",
                        elem_type,
                        self.actual_args[0],
                        dest_type,
                        self.actual_args[1],
                        self.actual_args[2]
                    );
                }
                self.block_visitor.bv.copy_or_move_elements(
                    dest_path,
                    source_path,
                    elem_type,
                    false,
                );
            }
        } else {
            warn!(
                "unhandled call to write_bytes at {:?}",
                self.block_visitor.bv.current_span
            );
            info!("elem_type {:?}", elem_type);
            info!("dest {:?}", self.actual_args[0]);
            info!("dest_type {:?}", dest_type);
            info!("val {:?}", self.actual_args[1]);
            info!("count {:?}", self.actual_args[2]);
        }
        self.use_entry_condition_as_exit_condition();
    }