Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for emitting casts to and from *mut T and Cell<T> #968

Merged
merged 14 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 45 additions & 45 deletions analysis/tests/lighttpd-minimal/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1182,10 +1182,10 @@ unsafe extern "C" fn connection_init(
mut srv: *mut server,
mut con: *mut connection,
) -> *mut connection {
// let con: *mut connection = calloc(
// 1 as libc::c_int as libc::c_ulong,
// ::std::mem::size_of::<connection>() as libc::c_ulong,
// ) as *mut connection;
let con: *mut connection = calloc(
1 as libc::c_int as libc::c_ulong,
::std::mem::size_of::<connection>() as libc::c_ulong,
) as *mut connection;
if con.is_null() {
// ck_assert_failed
(
Expand All @@ -1195,17 +1195,17 @@ unsafe extern "C" fn connection_init(
);
}
(*con).srv = srv;
// (*con).plugin_slots = (*srv).plugin_slots;
// (*con).config_data_base = (*srv).config_data_base;
(*con).plugin_slots = (*srv).plugin_slots;
(*con).config_data_base = (*srv).config_data_base;
let r: *mut request_st = &mut (*con).request;
// request_init_data(r, con, srv);
// (*con).write_queue = &mut (*r).write_queue;
// (*con).read_queue = &mut (*r).read_queue;
// (*con).plugin_ctx = calloc(
// 1 as libc::c_int as libc::c_ulong,
// (((*srv).plugins.used).wrapping_add(1 as libc::c_int as libc::c_uint) as libc::c_ulong)
// .wrapping_mul(::std::mem::size_of::<*mut libc::c_void>() as libc::c_ulong),
// ) as *mut *mut libc::c_void;
(*con).write_queue = &mut (*r).write_queue;
(*con).read_queue = &mut (*r).read_queue;
(*con).plugin_ctx = calloc(
1 as libc::c_int as libc::c_ulong,
(((*srv).plugins.used).wrapping_add(1 as libc::c_int as libc::c_uint) as libc::c_ulong)
.wrapping_mul(::std::mem::size_of::<*mut libc::c_void>() as libc::c_ulong),
) as *mut *mut libc::c_void;
if ((*con).plugin_ctx).is_null() {
// ck_assert_failed
(
Expand All @@ -1221,20 +1221,20 @@ unsafe extern "C" fn connections_get_new_connection(
mut srv: *mut server,
mut con: *mut connection,
) -> *mut connection {
// let mut con: *mut connection = 0 as *mut connection;
let mut con: *mut connection = 0 as *mut connection;
(*srv).lim_conns = ((*srv).lim_conns).wrapping_sub(1);
// if !((*srv).conns_pool).is_null() {
// con = (*srv).conns_pool;
// (*srv).conns_pool = (*con).next;
// } else {
if !((*srv).conns_pool).is_null() {
con = (*srv).conns_pool;
(*srv).conns_pool = (*con).next;
} else {
con = connection_init(srv, con);
connection_reset(con);
// }
// (*con).next = (*srv).conns;
// if !((*con).next).is_null() {
// (*(*con).next).prev = con;
// }
// (*srv).conns = con;
}
(*con).next = (*srv).conns;
if !((*con).next).is_null() {
(*(*con).next).prev = con;
}
(*srv).conns = con;
return (*srv).conns;
}

Expand All @@ -1258,10 +1258,10 @@ pub unsafe extern "C" fn fdevent_register(
}

unsafe extern "C" fn fdnode_init(fdn: *mut fdnode) -> *mut fdnode {
// let fdn: *mut fdnode = calloc(
// 1 as libc::c_int as libc::c_ulong,
// ::std::mem::size_of::<fdnode>() as libc::c_ulong,
// ) as *mut fdnode;
let fdn: *mut fdnode = calloc(
1 as libc::c_int as libc::c_ulong,
::std::mem::size_of::<fdnode>() as libc::c_ulong,
) as *mut fdnode;
if fdn.is_null() {
// ck_assert_failed
(
Expand All @@ -1275,17 +1275,17 @@ unsafe extern "C" fn fdnode_init(fdn: *mut fdnode) -> *mut fdnode {
}

unsafe extern "C" fn connection_del(mut srv: *mut server, mut con: *mut connection) {
// if !((*con).next).is_null() {
// (*(*con).next).prev = (*con).prev;
// }
// if !((*con).prev).is_null() {
// (*(*con).prev).next = (*con).next;
// } else {
// (*srv).conns = (*con).next;
// }
// (*con).prev = con; // 0 as *mut connection;
// (*con).next = (*srv).conns_pool;
// (*srv).conns_pool = con;
if !((*con).next).is_null() {
(*(*con).next).prev = (*con).prev;
}
if !((*con).prev).is_null() {
(*(*con).prev).next = (*con).next;
} else {
(*srv).conns = (*con).next;
}
(*con).prev = con; // 0 as *mut connection;
(*con).next = (*srv).conns_pool;
(*srv).conns_pool = con;
(*srv).lim_conns = ((*srv).lim_conns).wrapping_add(1);
}

Expand All @@ -1302,7 +1302,7 @@ unsafe extern "C" fn connection_close(mut con: *mut connection) {
(*con).request_count = 0 as libc::c_int as uint32_t;
(*con).is_ssl_sock = 0 as libc::c_int as libc::c_char;
(*con).revents_err = 0 as libc::c_int as uint16_t;
// fdevent_fdnode_event_del((*srv).ev, (*con).fdn);
fdevent_fdnode_event_del((*srv).ev, (*con).fdn);
fdevent_unregister((*srv).ev, (*con).fd);
// (*con).fdn = 0 as *mut fdnode;
if 0 as libc::c_int == close((*con).fd) {
Expand Down Expand Up @@ -1358,20 +1358,20 @@ pub unsafe extern "C" fn fdevent_unregister(mut ev: *mut fdevents, mut fd: libc:
}

unsafe extern "C" fn fdnode_free(fdn: *mut libc::c_void) {
free(fdn /* TODO: handle cast as *mut libc::c_void */);
free(fdn as *mut libc::c_void);
}

pub unsafe extern "C" fn lighttpd_test() {
let fdarr = calloc(
0 as libc::c_int as libc::c_ulong,
::std::mem::size_of::<*mut fdnode>() as libc::c_ulong,
); // TODO: handle cast as *mut *mut fdnode;
) as *mut *mut fdnode;
let fdes = calloc(
0 as libc::c_int as libc::c_ulong,
::std::mem::size_of::<fdevents>() as libc::c_ulong,
); // TODO: handle cast as *mut fdevents;
free(fdarr /* TODO: handle cast as *mut libc::c_void */);
free(fdes /* TODO: handle cast as *mut libc::c_void */);
) as *mut fdevents;
free(fdarr as *mut libc::c_void);
free(fdes as *mut libc::c_void);
}

#[no_mangle]
Expand Down
14 changes: 9 additions & 5 deletions c2rust-analyze/src/rewrite/expr/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,7 @@ impl<'tcx> Visitor<'tcx> for ConvertVisitor<'tcx> {
// the rewrite should occur at the callsite
let callsite_span = ex.span.source_callsite();

let mir_rws = self
.mir_rewrites
.remove(&ex.hir_id)
.unwrap_or_else(Vec::new);
let mir_rws = self.mir_rewrites.remove(&ex.hir_id).unwrap_or_default();

let rewrite_from_mir_rws = |rw: &mir_op::RewriteKind, hir_rw: Rewrite| -> Rewrite {
match rw {
Expand Down Expand Up @@ -156,7 +153,6 @@ impl<'tcx> Visitor<'tcx> for ConvertVisitor<'tcx> {
let rhs = self.get_subexpr(ex, 1);
Rewrite::MethodCall("set".to_string(), Box::new(lhs), vec![rhs])
}

_ => convert_cast_rewrite(rw, hir_rw),
}
};
Expand Down Expand Up @@ -232,6 +228,7 @@ fn materialize_adjustments<'tcx>(
hir_rw
}
(rw @ Rewrite::Ref(..), &[Adjust::Deref(..), Adjust::Borrow(..)]) => rw,
(rw @ Rewrite::MethodCall(..), &[Adjust::Deref(..), Adjust::Borrow(..)]) => rw,
(rw, &[]) => rw,
(rw, adjs) => panic!("rewrite {rw:?} and materializations {adjs:?} NYI"),
}
Expand Down Expand Up @@ -283,6 +280,13 @@ pub fn convert_cast_rewrite(kind: &mir_op::RewriteKind, hir_rw: Rewrite) -> Rewr
vec![Rewrite::Identity],
)
}
mir_op::RewriteKind::AsPtr => {
// `x` to `x.as_ptr()`
Rewrite::MethodCall("as_ptr".to_string(), Box::new(hir_rw), vec![])
}
mir_op::RewriteKind::CastRawMutToCellPtr { ref ty } => {
Rewrite::Cast(Box::new(hir_rw), format!("*const std::cell::Cell<{}>", ty))
}

_ => panic!(
"rewrite {:?} is not supported by convert_cast_rewrite",
Expand Down
23 changes: 22 additions & 1 deletion c2rust-analyze/src/rewrite/expr/mir_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ use rustc_middle::mir::{
BasicBlock, Body, Location, Operand, Place, Rvalue, Statement, StatementKind, Terminator,
TerminatorKind,
};
use rustc_middle::ty::print::FmtPrinter;
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{Ty, TyCtxt, TyKind};
use std::collections::HashMap;
use std::ops::Index;

use rustc_hir::def::Namespace;

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum SubLoc {
/// The LHS of an assignment or call. `StatementKind::Assign/TerminatorKind::Call -> Place`
Expand Down Expand Up @@ -61,6 +65,8 @@ pub enum RewriteKind {
CastRawToRaw { to_mutbl: bool },
/// Cast `*const T` to `& T` or `*mut T` to `&mut T`.
UnsafeCastRawToRef { mutbl: bool },
/// Cast *mut T to *const Cell<T>
CastRawMutToCellPtr { ty: String },

/// Replace `y` in `let x = y` with `Cell::new(y)`, i.e. `let x = Cell::new(y)`
/// TODO: ensure `y` implements `Copy`
Expand All @@ -71,6 +77,8 @@ pub enum RewriteKind {
CellSet,
/// Wrap `&mut T` in `Cell::from_mut` to get `&Cell<T>`.
CellFromMut,
/// `x` to `x.as_ptr()`
AsPtr,
}

#[derive(Clone, PartialEq, Eq, Debug)]
Expand Down Expand Up @@ -678,7 +686,13 @@ where
}
_ => None,
},
Ownership::Cell => None,
Ownership::Cell => match to.own {
Ownership::RawMut | Ownership::Raw if !early => {
(self.emit)(RewriteKind::AsPtr);
Some(Ownership::RawMut)
}
_ => None,
},
Ownership::Imm => match to.own {
Ownership::Raw | Ownership::RawMut if !early => {
(self.emit)(RewriteKind::CastRefToRaw { mutbl: false });
Expand All @@ -697,6 +711,13 @@ where
(self.emit)(RewriteKind::UnsafeCastRawToRef { mutbl: true });
Some(Ownership::Mut)
}
Ownership::Cell if !early => {
let printer = FmtPrinter::new(self.tcx, Namespace::TypeNS);
let ty = to.pointee_ty.print(printer).unwrap().into_buffer();
(self.emit)(RewriteKind::CastRawMutToCellPtr { ty });
(self.emit)(RewriteKind::UnsafeCastRawToRef { mutbl: false });
Some(Ownership::Cell)
}
_ => None,
},
Ownership::Raw => match to.own {
Expand Down
37 changes: 21 additions & 16 deletions c2rust-analyze/src/rewrite/expr/unlower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::HirId;
use rustc_middle::hir::nested_filter;
use rustc_middle::mir::{self, Body, Location};
use rustc_middle::mir::{self, Body, Location, Operand};
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
use std::collections::btree_map::{BTreeMap, Entry};
Expand Down Expand Up @@ -97,6 +97,19 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
}
}

fn operand_desc(&self, op: &Operand<'tcx>) -> MirOriginDesc {
match *op {
mir::Operand::Copy(pl) | mir::Operand::Move(pl) => {
if is_var(pl) && self.mir.local_kind(pl.local) == mir::LocalKind::Temp {
MirOriginDesc::LoadFromTemp
} else {
MirOriginDesc::Expr
}
}
mir::Operand::Constant(..) => MirOriginDesc::Expr,
}
}

/// Special `record` variant for MIR [`Operand`]s. This sets the [`MirOriginDesc`] to
/// `LoadFromLocal` if `op` is a MIR temporary and otherwise sets it to `Expr`.
///
Expand All @@ -108,19 +121,7 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
ex: &hir::Expr,
op: &mir::Operand<'tcx>,
) {
let op_is_temp = match *op {
mir::Operand::Copy(pl) | mir::Operand::Move(pl) => {
is_var(pl) && self.mir.local_kind(pl.local) == mir::LocalKind::Temp
}
mir::Operand::Constant(..) => false,
};

let desc = if op_is_temp {
MirOriginDesc::LoadFromTemp
} else {
MirOriginDesc::Expr
};
self.record_desc(loc, sub_loc, ex, desc);
self.record_desc(loc, sub_loc, ex, self.operand_desc(op));
}

fn get_sole_assign(
Expand Down Expand Up @@ -210,16 +211,20 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> {
match ex.kind {
hir::ExprKind::Assign(pl, rv, _span) => {
// For `Assign`, we expect the assignment to be the whole thing.
let (loc, _mir_pl, _mir_rv) = match self.get_sole_assign(&locs) {
let (loc, _mir_pl, mir_rv) = match self.get_sole_assign(&locs) {
Some(x) => x,
None => {
warn("expected exactly one StatementKind::Assign");
return;
}
};
let desc = match mir_rv {
mir::Rvalue::Use(op) => self.operand_desc(op),
_ => MirOriginDesc::Expr,
};
self.record(loc, &[], ex);
self.record(loc, &[SubLoc::Dest], pl);
self.record(loc, &[SubLoc::Rvalue], rv);
self.record_desc(loc, &[SubLoc::Rvalue], rv, desc);
}

hir::ExprKind::Call(_, args) | hir::ExprKind::MethodCall(_, args, _) => {
Expand Down
23 changes: 23 additions & 0 deletions c2rust-analyze/tests/filecheck/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,26 @@ pub unsafe fn null_ptr() {
let s = 0 as *mut S;
(*s).i = 0 as *const i32;
}

#[repr(C)]
pub struct Foo {
y: *mut i32,
}

extern "C" {
// necessary to fix the type of Foo::y
fn bar(f: Foo);
}
spernsteiner marked this conversation as resolved.
Show resolved Hide resolved

// CHECK-LABEL: pub unsafe fn cell_as_mut_as_cell(mut x: &core::cell::Cell<(i32)>, mut f: Foo) {
pub unsafe fn cell_as_mut_as_cell(mut x: *mut i32, mut f: Foo) {
let z = x;
let r = x;
*z = 1;
*r = 1;
*z = 4;
// CHECK-DAG: f.y = (x).as_ptr();
f.y = x;
// CHECK-DAG: x = &*((f.y) as *const std::cell::Cell<i32>);
x = f.y;
}