From c36931f6a86ee7a761ae41b6796087ae1c9a73e1 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Tue, 29 Aug 2023 13:00:27 -0400 Subject: [PATCH] Support intermediate casts in calls. 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`. --- c2rust-analyze/src/c_void_casts.rs | 30 ++++++++++++++++------ c2rust-analyze/src/dataflow/type_check.rs | 16 ++++++++---- c2rust-analyze/tests/filecheck/algo_md5.rs | 2 +- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index 7b9795c576..0d26413efb 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -407,6 +407,8 @@ impl<'tcx> CVoidCasts<'tcx> { /// * `calloc` /// * `realloc` /// * `free` + /// * `memcpy` + /// * `memset` /// /// and insert their casts to and from [`*c_void`]. /// @@ -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, ); } } @@ -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(¤t_block_data.statements, c_void_ptr) { assert!( @@ -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); } } diff --git a/c2rust-analyze/src/dataflow/type_check.rs b/c2rust-analyze/src/dataflow/type_check.rs index 3b7ae89b03..8aeb861707 100644 --- a/c2rust-analyze/src/dataflow/type_check.rs +++ b/c2rust-analyze/src/dataflow/type_check.rs @@ -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 => { diff --git a/c2rust-analyze/tests/filecheck/algo_md5.rs b/c2rust-analyze/tests/filecheck/algo_md5.rs index d04a2fd53c..f14c196102 100644 --- a/c2rust-analyze/tests/filecheck/algo_md5.rs +++ b/c2rust-analyze/tests/filecheck/algo_md5.rs @@ -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(