Skip to content

Commit

Permalink
Test.lighttpd.md5 (#1020)
Browse files Browse the repository at this point in the history
Initial `algo_md5` module test, with offending portions of the module
commented out for now, until they are addressed
  • Loading branch information
aneksteind authored Sep 8, 2023
2 parents f22c692 + df75790 commit f1c9c44
Show file tree
Hide file tree
Showing 7 changed files with 976 additions and 90 deletions.
13 changes: 13 additions & 0 deletions c2rust-analyze/src/borrowck/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,19 @@ impl<'tcx> TypeChecker<'tcx, '_> {
self.visit_operand(p)
});
}
Callee::Memcpy => {
let _pl_lty = self.visit_place(destination);
let _rv_lty = assert_matches!(&args[..], [dest, src, _] => {
self.visit_operand(dest);
self.visit_operand(src);
});
}
Callee::Memset => {
let _pl_lty = self.visit_place(destination);
let _rv_lty = assert_matches!(&args[..], [dest, ..] => {
self.visit_operand(dest)
});
}
Callee::IsNull => {
let _rv_lty = assert_matches!(&args[..], [p] => {
self.visit_operand(p)
Expand Down
245 changes: 165 additions & 80 deletions c2rust-analyze/src/c_void_casts.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::borrow::Borrow;
use std::collections::{HashMap, HashSet};

use rustc_middle::mir::{BasicBlock, LocalKind};
use rustc_middle::{
mir::{
Body, LocalDecls, Location, Place, Rvalue, Statement, StatementKind, Terminator,
BasicBlockData, Body, LocalDecls, Location, Place, Rvalue, Statement, StatementKind,
TerminatorKind,
},
ty::{TyCtxt, TyKind},
};

use assert_matches::assert_matches;

use crate::util::{get_assign_sides, get_cast_place, terminator_location, ty_callee, Callee};

/// The direction of a [`*c_void`](core::ffi::c_void) cast.
Expand Down Expand Up @@ -48,6 +47,7 @@ impl CVoidCastDirection {
Malloc | Calloc => &[From][..],
Realloc => &[To, From][..],
Free => &[To][..],
Memcpy | Memset => &[To][..],
_ => &[],
}
}
Expand All @@ -69,18 +69,25 @@ impl<'tcx> CVoidPtr<'tcx> {
///
/// This panics on failure.
pub fn checked(place: Place<'tcx>, local_decls: &LocalDecls<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
let deref_ty = place
.ty(local_decls, tcx)
.ty
.builtin_deref(true)
.unwrap()
.ty
.kind();
assert_matches!(deref_ty, TyKind::Adt(adt, _) => {
assert_eq!(tcx.def_path(adt.did()).data[0].to_string(), "ffi");
assert_eq!(tcx.item_name(adt.did()).as_str(), "c_void");
});
Self { place }
Self::checked_optional(place, local_decls, tcx).unwrap()
}

pub fn checked_optional(
place: Place<'tcx>,
local_decls: &LocalDecls<'tcx>,
tcx: TyCtxt<'tcx>,
) -> Option<Self> {
let deref_ty = place.ty(local_decls, tcx).ty.builtin_deref(true)?;

if let TyKind::Adt(adt, _) = deref_ty.ty.kind() {
if tcx.def_path(adt.did()).data[0].to_string() == "ffi"
&& tcx.item_name(adt.did()).as_str() == "c_void"
{
return Some(Self { place });
}
}

None
}

/// Check another [`Place`] for being a [`*c_void`](core::ffi::c_void)
Expand Down Expand Up @@ -137,7 +144,7 @@ impl<'tcx> Borrow<Place<'tcx>> for CVoidPtr<'tcx> {
}
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
/// A cast to/from a [`*c_void`](core::ffi::c_void) to/from a properly typed pointer.
pub struct CVoidCast<'tcx> {
/// The [`*c_void`](core::ffi::c_void) side of the cast.
Expand All @@ -162,35 +169,37 @@ pub struct CVoidCast<'tcx> {
pub struct CVoidCastsUniDirectional<'tcx> {
/// Mapping from location of a call that either
/// produces or consumes a [`CVoidPtr`] to its
/// succeeding or preceding [`CVoidCast`]
calls: HashMap<Location, CVoidCast<'tcx>>,
/// succeeding or preceding [`CVoidCast`]s
calls: HashMap<Location, HashSet<CVoidCast<'tcx>>>,
/// Set of locations where [`CVoidCast`]s occur.
casts: HashSet<Location>,
}

impl<'tcx> CVoidCastsUniDirectional<'tcx> {
/// Get the adjusted [`Place`] from a cast at a particulat [`Location`].
/// Get the adjusted [`Place`] from a cast at a particular [`Location`].
///
/// Otherwise, the same `place` is returned, as no adjustments are necessary.
pub fn get_adjusted_place_or_default_to(
&self,
loc: Location,
place: Place<'tcx>,
) -> Place<'tcx> {
*self
.calls
.get(&loc)
.map(|cast| {
assert_eq!(cast.c_void_ptr.place, place);
&cast.other_ptr
})
.unwrap_or(&place)
// If there are multiple CVoidCasts for a Location, this logic may need to be adjusted
// depending on the intended behavior.
if let Some(casts) = self.calls.get(&loc) {
for cast in casts {
if cast.c_void_ptr.place == place {
return cast.other_ptr;
}
}
}
place
}

/// Tracks the [Location] of the use of a casted pointer in a [TerminatorKind::Call]
pub fn insert_call(&mut self, loc: Location, cast: CVoidCast<'tcx>) {
assert!(!self.calls.contains_key(&loc));
self.calls.insert(loc, cast);
let entry = self.calls.entry(loc).or_insert_with(HashSet::new);
entry.insert(cast);
}

/// Tracks the [Location] of void pointer [Rvalue::Cast]
Expand Down Expand Up @@ -346,8 +355,10 @@ impl<'tcx> CVoidCasts<'tcx> {
/// in a sequence of [Statement]s. We expect that the
/// cast is the first non-[StatementKind::StorageDead]
/// statement in the block, a special case for
/// [Terminator]s whose destination is casted from a
/// [`Terminator`]s whose destination is casted from a
/// void pointer to some other pointer type.
///
/// [`Terminator`]: rustc_middle::mir::Terminator
fn find_first_cast(
statements: &[Statement<'tcx>],
c_void_ptr: CVoidPtr<'tcx>,
Expand Down Expand Up @@ -377,7 +388,9 @@ impl<'tcx> CVoidCasts<'tcx> {
for (sidx, stmt) in statements.iter().enumerate().rev() {
let cast = c_void_ptr.get_cast_from_stmt(CVoidCastDirection::To, stmt);
if let Some(cast) = cast {
return Some((sidx, cast));
if cast.c_void_ptr == c_void_ptr {
return Some((sidx, cast));
}
} else if Self::is_place_modified_by_statement(&c_void_ptr.place, stmt) {
return None;
}
Expand All @@ -403,62 +416,134 @@ impl<'tcx> CVoidCasts<'tcx> {
/// [`*c_void`]: core::ffi::c_void
fn insert_all_from_body(&mut self, body: &Body<'tcx>, tcx: TyCtxt<'tcx>) {
for (block, bb_data) in body.basic_blocks().iter_enumerated() {
let term: &Terminator = match &bb_data.terminator {
Some(term) => term,
None => continue,
};
let (func, args, destination, target) = match term.kind {
TerminatorKind::Call {
ref func,
ref args,
if let Some(term) = &bb_data.terminator {
if let TerminatorKind::Call {
func,
args,
destination,
target,
..
} => (func, args, destination, target),
_ => continue,
};
let func_ty = func.ty(&body.local_decls, tcx);

for direction in CVoidCastDirection::from_callee(ty_callee(tcx, func_ty))
.iter()
.copied()
} = &term.kind
{
let func_ty = func.ty(&body.local_decls, tcx);
let directions = CVoidCastDirection::from_callee(ty_callee(tcx, func_ty));

for direction in directions.iter().copied() {
use CVoidCastDirection::*;

match direction {
From => {
let c_void_ptr =
CVoidPtr::checked(*destination, &body.local_decls, tcx);
if let Some((statement_index, cast)) = Self::find_first_cast(
&body.basic_blocks()[target.unwrap()].statements,
c_void_ptr,
) {
self.insert_cast(
direction,
Location {
statement_index,
block: target.unwrap(),
},
);
self.insert_call(
direction,
terminator_location(block, bb_data),
cast,
);
}
}
To => {
for arg in args {
if let Some(place) = arg.place() {
if let Some(c_void_ptr) = CVoidPtr::checked_optional(
place,
&body.local_decls,
tcx,
) {
self.find_and_insert_pred_cast(
body, c_void_ptr, direction, bb_data,
);
}
}
}
}
}
}
}
}
}
}

fn find_modifying_assignments(
current_block: BasicBlock,
current_block_data: &BasicBlockData<'tcx>,
c_void_ptr: &CVoidPtr<'tcx>,
) -> Vec<(BasicBlock, usize)> {
let mut modifying_statements = current_block_data
.statements
.iter()
.enumerate()
.filter(|(_, stmt)| {
matches!(stmt.kind, StatementKind::Assign(..))
&& Self::is_place_modified_by_statement(&c_void_ptr.place, stmt)
})
.map(|(index, _stmt)| (current_block, index))
.collect::<Vec<_>>();

if let Some(terminator) = &current_block_data.terminator {
if matches!(terminator.kind, TerminatorKind::Call { destination, .. } if destination == c_void_ptr.place)
{
use CVoidCastDirection::*;
let c_void_ptr = match direction {
From => destination,
To => args[0]
.place()
.expect("Casts to/from null pointer are not yet supported"),
};
let c_void_ptr = CVoidPtr::checked(c_void_ptr, &body.local_decls, tcx);
let cast = match direction {
// For [`CVoidCastDirection::From`], we only count
// a cast from `*c_void` to an arbitrary type in the subsequent block,
// searching forward.
From => Self::find_first_cast(
&body.basic_blocks()[target.unwrap()].statements,
c_void_ptr,
),
// For [`CVoidCastDirection::To`], we only count
// a cast to `*c_void` from an arbitrary type in the same block,
// searching backwards.
To => Self::find_last_cast(&bb_data.statements, c_void_ptr),
modifying_statements.push((current_block, usize::MAX));
}
}

modifying_statements
}

fn find_and_insert_pred_cast(
&mut self,
body: &Body<'tcx>,
c_void_ptr: CVoidPtr<'tcx>,
direction: CVoidCastDirection,
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() {
modifying_statements.extend(Self::find_modifying_assignments(
current_block,
current_block_data,
&c_void_ptr,
));

if let Some((statement_index, cast)) =
Self::find_last_cast(&current_block_data.statements, c_void_ptr)
{
assert!(
inserted_places.insert(c_void_ptr.place),
"Duplicate c_void_ptr.place found: {:?}",
c_void_ptr.place
);
assert!(
body.local_kind(c_void_ptr.place.local) == LocalKind::Temp,
"Unsupported cast into non-temporary local"
);
let location = Location {
statement_index,
block: current_block,
};
if let Some((statement_index, cast)) = cast {
self.insert_cast(
direction,
Location {
statement_index,
block: match direction {
To => block,
From => target.unwrap(),
},
},
);
self.insert_call(direction, terminator_location(block, bb_data), cast);
}
self.insert_cast(direction, location);
self.insert_call(direction, terminator_location(current_block, bb_data), cast);
}
}

assert!(
modifying_statements.len() == 1,
"c_void_ptr.place modified multiple times: {:?}",
modifying_statements
);
}

pub fn new(body: &Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
Expand Down
Loading

0 comments on commit f1c9c44

Please sign in to comment.