Skip to content

Commit

Permalink
Support intermediate casts in calls.
Browse files Browse the repository at this point in the history
In lighttpd there are intermediate casts
where the final cast is an argument to memcpy.
Prior to this, only one cast was exempted, the final
one. Now, all casts are skipped/allowed as long as
the final cast serves as input to a function like
`memcpy` or `free` or `realloc`.
  • Loading branch information
aneksteind committed Aug 29, 2023
1 parent df75790 commit c36931f
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 14 deletions.
30 changes: 22 additions & 8 deletions c2rust-analyze/src/c_void_casts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,8 @@ impl<'tcx> CVoidCasts<'tcx> {
/// * `calloc`
/// * `realloc`
/// * `free`
/// * `memcpy`
/// * `memset`
///
/// and insert their casts to and from [`*c_void`].
///
Expand Down Expand Up @@ -462,7 +464,7 @@ impl<'tcx> CVoidCasts<'tcx> {
tcx,
) {
self.find_and_insert_pred_cast(
body, c_void_ptr, direction, bb_data,
body, c_void_ptr, direction, block, bb_data,
);
}
}
Expand Down Expand Up @@ -506,19 +508,36 @@ impl<'tcx> CVoidCasts<'tcx> {
body: &Body<'tcx>,
c_void_ptr: CVoidPtr<'tcx>,
direction: CVoidCastDirection,
block: BasicBlock,
bb_data: &BasicBlockData<'tcx>,
) {
let mut inserted_places = HashSet::new();
let mut modifying_statements = Vec::new();

for (current_block, current_block_data) in body.basic_blocks().iter_enumerated() {
let mut current_place = c_void_ptr.place;

for (current_block, current_block_data) in body.basic_blocks().iter_enumerated().rev() {
for (index, stmt) in current_block_data.statements.iter().enumerate().rev() {
if let Some(cast_place) = get_assign_sides(stmt)
.filter(|(lhs, _)| *lhs == current_place)
.and_then(|(_, rhs)| get_cast_place(rhs))
{
let location = Location {
statement_index: index,
block: current_block,
};
self.insert_cast(direction, location);
current_place = cast_place;
}
}

modifying_statements.extend(Self::find_modifying_assignments(
current_block,
current_block_data,
&c_void_ptr,
));

if let Some((statement_index, cast)) =
if let Some((_, cast)) =
Self::find_last_cast(&current_block_data.statements, c_void_ptr)
{
assert!(
Expand All @@ -530,11 +549,6 @@ impl<'tcx> CVoidCasts<'tcx> {
body.local_kind(c_void_ptr.place.local) == LocalKind::Temp,
"Unsupported cast into non-temporary local"
);
let location = Location {
statement_index,
block: current_block,
};
self.insert_cast(direction, location);
self.insert_call(direction, terminator_location(current_block, bb_data), cast);
}
}
Expand Down
16 changes: 11 additions & 5 deletions c2rust-analyze/src/dataflow/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,22 +521,28 @@ impl<'tcx> TypeChecker<'tcx, '_> {
let src_ptr = args[1]
.place()
.expect("Casts to/from null pointer are not yet supported");
let src_ptr = self.acx.c_void_casts.get_adjusted_place_or_default_to(
let src_ptr_casted_from = self.acx.c_void_casts.get_adjusted_place_or_default_to(
loc,
CVoidCastDirection::To,
src_ptr,
);

self.visit_place(out_ptr, Mutability::Mut);
let dest_ptr_lty = self.acx.type_of(out_ptr);
assert!(args.len() == 3);
self.visit_place(src_ptr, Mutability::Not);
let src_ptr_lty = self.acx.type_of(src_ptr);
self.visit_place(src_ptr_casted_from, Mutability::Not);
let src_ptr_casted_lty = self.acx.type_of(src_ptr_casted_from);

// input needs READ permission
let perms = PermissionSet::READ;
self.constraints.add_all_perms(src_ptr_lty.label, perms);
self.constraints
.add_all_perms(src_ptr_casted_lty.label, perms);

// Perform a pseudo-assignment for *dest = *src
// Perform a pseudo-assignment for *dest = *src.
// We use `src_ptr` instead of `src_ptr_casted_from` because the type that was
// casted to the libc::c_void_ptr that `memcpy` takes likely differs from the
// type that's pointed to by `dest_ptr`
let src_ptr_lty = self.acx.type_of(src_ptr);
self.do_equivalence_nested(dest_ptr_lty.args[0], src_ptr_lty.args[0]);
}
Callee::Memset => {
Expand Down
2 changes: 1 addition & 1 deletion c2rust-analyze/tests/filecheck/algo_md5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub unsafe extern "C" fn MD5_Update(
memcpy(
&mut *((*context).buffer).as_mut_ptr().offset(ndx as isize) as *mut libc::c_uchar
as *mut libc::c_void,
input /* as *mut libc::c_uchar */ as *const libc::c_void,
input as *mut libc::c_uchar as *const libc::c_void,
partLen as libc::c_ulong,
);
li_MD5Transform(
Expand Down

0 comments on commit c36931f

Please sign in to comment.