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