Skip to content

Commit f86d7e4

Browse files
authored
Do not rewrite ADTs mentioned in extern blocks (#960)
Fixes #948. Fixes an issue where we would rewrite structs and their fields even though they appear in extern blocks.
2 parents 788b474 + 7893da8 commit f86d7e4

File tree

6 files changed

+186
-50
lines changed

6 files changed

+186
-50
lines changed

analysis/tests/lighttpd-minimal/src/main.rs

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,12 +1195,12 @@ unsafe extern "C" fn connection_init(
11951195
);
11961196
}
11971197
(*con).srv = srv;
1198-
(*con).plugin_slots = (*srv).plugin_slots;
1199-
(*con).config_data_base = (*srv).config_data_base;
1198+
// (*con).plugin_slots = (*srv).plugin_slots;
1199+
// (*con).config_data_base = (*srv).config_data_base;
12001200
let r: *mut request_st = &mut (*con).request;
12011201
// request_init_data(r, con, srv);
1202-
(*con).write_queue = &mut (*r).write_queue;
1203-
(*con).read_queue = &mut (*r).read_queue;
1202+
// (*con).write_queue = &mut (*r).write_queue;
1203+
// (*con).read_queue = &mut (*r).read_queue;
12041204
// (*con).plugin_ctx = calloc(
12051205
// 1 as libc::c_int as libc::c_ulong,
12061206
// (((*srv).plugins.used).wrapping_add(1 as libc::c_int as libc::c_uint) as libc::c_ulong)
@@ -1223,18 +1223,18 @@ unsafe extern "C" fn connections_get_new_connection(
12231223
) -> *mut connection {
12241224
// let mut con: *mut connection = 0 as *mut connection;
12251225
(*srv).lim_conns = ((*srv).lim_conns).wrapping_sub(1);
1226-
if !((*srv).conns_pool).is_null() {
1227-
con = (*srv).conns_pool;
1228-
(*srv).conns_pool = (*con).next;
1229-
} else {
1226+
// if !((*srv).conns_pool).is_null() {
1227+
// con = (*srv).conns_pool;
1228+
// (*srv).conns_pool = (*con).next;
1229+
// } else {
12301230
con = connection_init(srv, con);
12311231
connection_reset(con);
1232-
}
1233-
(*con).next = (*srv).conns;
1234-
if !((*con).next).is_null() {
1235-
(*(*con).next).prev = con;
1236-
}
1237-
(*srv).conns = con;
1232+
// }
1233+
// (*con).next = (*srv).conns;
1234+
// if !((*con).next).is_null() {
1235+
// (*(*con).next).prev = con;
1236+
// }
1237+
// (*srv).conns = con;
12381238
return (*srv).conns;
12391239
}
12401240

@@ -1246,15 +1246,15 @@ pub unsafe extern "C" fn fdevent_register(
12461246
// mut ctx: *mut libc::c_void,
12471247
fdn: *mut fdnode,
12481248
) -> *mut fdnode {
1249-
let ref mut fresh0 = *((*ev).fdarray).offset(fd as isize);
1250-
*fresh0 = fdnode_init(fdn);
1251-
let mut fdn: *mut fdnode = *fresh0;
1249+
// let ref mut fresh0 = *((*ev).fdarray).offset(fd as isize);
1250+
// *fresh0 = fdnode_init(fdn);
1251+
// let mut fdn: *mut fdnode = *fresh0;
12521252
// (*fdn).handler = handler;
1253-
(*fdn).fd = fd;
1253+
// (*fdn).fd = fd;
12541254
// (*fdn).ctx = ctx;
1255-
(*fdn).events = 0 as libc::c_int;
1256-
(*fdn).fde_ndx = -(1 as libc::c_int);
1257-
return fdn;
1255+
// (*fdn).events = 0 as libc::c_int;
1256+
// (*fdn).fde_ndx = -(1 as libc::c_int);
1257+
return 0 as *mut fdnode;
12581258
}
12591259

12601260
unsafe extern "C" fn fdnode_init(fdn: *mut fdnode) -> *mut fdnode {
@@ -1275,17 +1275,17 @@ unsafe extern "C" fn fdnode_init(fdn: *mut fdnode) -> *mut fdnode {
12751275
}
12761276

12771277
unsafe extern "C" fn connection_del(mut srv: *mut server, mut con: *mut connection) {
1278-
if !((*con).next).is_null() {
1279-
(*(*con).next).prev = (*con).prev;
1280-
}
1281-
if !((*con).prev).is_null() {
1282-
(*(*con).prev).next = (*con).next;
1283-
} else {
1284-
(*srv).conns = (*con).next;
1285-
}
1286-
(*con).prev = con; // 0 as *mut connection;
1287-
(*con).next = (*srv).conns_pool;
1288-
(*srv).conns_pool = con;
1278+
// if !((*con).next).is_null() {
1279+
// (*(*con).next).prev = (*con).prev;
1280+
// }
1281+
// if !((*con).prev).is_null() {
1282+
// (*(*con).prev).next = (*con).next;
1283+
// } else {
1284+
// (*srv).conns = (*con).next;
1285+
// }
1286+
// (*con).prev = con; // 0 as *mut connection;
1287+
// (*con).next = (*srv).conns_pool;
1288+
// (*srv).conns_pool = con;
12891289
(*srv).lim_conns = ((*srv).lim_conns).wrapping_add(1);
12901290
}
12911291

@@ -1302,7 +1302,7 @@ unsafe extern "C" fn connection_close(mut con: *mut connection) {
13021302
(*con).request_count = 0 as libc::c_int as uint32_t;
13031303
(*con).is_ssl_sock = 0 as libc::c_int as libc::c_char;
13041304
(*con).revents_err = 0 as libc::c_int as uint16_t;
1305-
fdevent_fdnode_event_del((*srv).ev, (*con).fdn);
1305+
// fdevent_fdnode_event_del((*srv).ev, (*con).fdn);
13061306
fdevent_unregister((*srv).ev, (*con).fd);
13071307
// (*con).fdn = 0 as *mut fdnode;
13081308
if 0 as libc::c_int == close((*con).fd) {
@@ -1348,11 +1348,11 @@ unsafe extern "C" fn fdevent_fdnode_event_unsetter(mut ev: *mut fdevents, mut fd
13481348

13491349
#[no_mangle]
13501350
pub unsafe extern "C" fn fdevent_unregister(mut ev: *mut fdevents, mut fd: libc::c_int) {
1351-
let mut fdn: *mut fdnode = *((*ev).fdarray).offset(fd as isize);
1352-
if fdn as uintptr_t & 0x3 as libc::c_int as libc::c_ulong != 0 {
1353-
return;
1354-
}
1355-
let ref mut fresh1 = *((*ev).fdarray).offset(fd as isize);
1351+
// let mut fdn: *mut fdnode = *((*ev).fdarray).offset(fd as isize);
1352+
// if fdn as uintptr_t & 0x3 as libc::c_int as libc::c_ulong != 0 {
1353+
// return;
1354+
// }
1355+
// let ref mut fresh1 = *((*ev).fdarray).offset(fd as isize);
13561356
// *fresh1 = 0 as *mut fdnode;
13571357
// fdnode_free(fdn);
13581358
}

c2rust-analyze/src/context.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use rustc_middle::ty::{
2525
tls, AdtDef, FieldDef, GenericArgKind, GenericParamDefKind, Ty, TyCtxt, TyKind,
2626
};
2727
use rustc_type_ir::RegionKind::{ReEarlyBound, ReStatic};
28-
use std::collections::HashMap;
28+
use std::collections::{HashMap, HashSet};
2929
use std::fmt::Debug;
3030
use std::ops::Index;
3131

@@ -287,6 +287,8 @@ pub struct GlobalAnalysisCtxt<'tcx> {
287287
pub addr_of_static: HashMap<DefId, PointerId>,
288288

289289
pub adt_metadata: AdtMetadataTable<'tcx>,
290+
291+
pub foreign_mentioned_tys: HashSet<DefId>,
290292
}
291293

292294
pub struct AnalysisCtxt<'a, 'tcx> {
@@ -536,6 +538,7 @@ impl<'tcx> GlobalAnalysisCtxt<'tcx> {
536538
static_tys: HashMap::new(),
537539
addr_of_static: HashMap::new(),
538540
adt_metadata: construct_adt_metadata(tcx),
541+
foreign_mentioned_tys: HashSet::new(),
539542
}
540543
}
541544

@@ -582,6 +585,7 @@ impl<'tcx> GlobalAnalysisCtxt<'tcx> {
582585
ref mut static_tys,
583586
ref mut addr_of_static,
584587
adt_metadata: _,
588+
foreign_mentioned_tys: _,
585589
} = *self;
586590

587591
*ptr_info = remap_global_ptr_info(ptr_info, map, counter.num_pointers());

c2rust-analyze/src/main.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use rustc_middle::mir::{
3434
AggregateKind, BindingForm, Body, Constant, LocalDecl, LocalInfo, LocalKind, Location, Operand,
3535
Rvalue, StatementKind,
3636
};
37-
use rustc_middle::ty::{Ty, TyCtxt, TyKind, WithOptConstParam};
37+
use rustc_middle::ty::{GenericArgKind, Ty, TyCtxt, TyKind, WithOptConstParam};
3838
use rustc_span::Span;
3939
use std::collections::{HashMap, HashSet};
4040
use std::env;
@@ -278,6 +278,49 @@ fn update_pointer_info<'tcx>(acx: &mut AnalysisCtxt<'_, 'tcx>, mir: &Body<'tcx>)
278278
}
279279
}
280280

281+
fn foreign_mentioned_tys(tcx: TyCtxt) -> HashSet<DefId> {
282+
let mut foreign_mentioned_tys = HashSet::new();
283+
for ty in tcx
284+
.hir_crate_items(())
285+
.foreign_items()
286+
.map(|item| item.def_id.to_def_id())
287+
.filter_map(|did| match tcx.def_kind(did) {
288+
DefKind::Fn | DefKind::AssocFn => Some(tcx.mk_fn_ptr(tcx.fn_sig(did))),
289+
DefKind::Static(_) => Some(tcx.type_of(did)),
290+
_ => None,
291+
})
292+
{
293+
walk_adts(tcx, ty, &mut |did| foreign_mentioned_tys.insert(did));
294+
}
295+
foreign_mentioned_tys
296+
}
297+
298+
/// Walks the type `ty` and applies a function `f` to it if it's an ADT
299+
/// `f` gets applied recursively to `ty`'s generic types and fields (if applicable)
300+
/// If `f` returns false, the fields of the ADT are not recursed into.
301+
/// Otherwise, the function will naturally terminate given that the generic types
302+
/// of a type are finite in length.
303+
/// We only look for ADTs rather than other FFI-crossing types because ADTs
304+
/// are the only nominal ones, which are the ones that we may rewrite.
305+
fn walk_adts<'tcx, F>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, f: &mut F)
306+
where
307+
F: FnMut(DefId) -> bool,
308+
{
309+
for arg in ty.walk() {
310+
if let GenericArgKind::Type(ty) = arg.unpack() {
311+
if let TyKind::Adt(adt_def, _) = ty.kind() {
312+
if !f(adt_def.did()) {
313+
continue;
314+
}
315+
for field in adt_def.all_fields() {
316+
let field_ty = tcx.type_of(field.did);
317+
walk_adts(tcx, field_ty, f);
318+
}
319+
}
320+
}
321+
}
322+
}
323+
281324
fn run(tcx: TyCtxt) {
282325
let mut gacx = GlobalAnalysisCtxt::new(tcx);
283326
let mut func_info = HashMap::new();
@@ -474,6 +517,10 @@ fn run(tcx: TyCtxt) {
474517
|| info.contains(PointerInfo::NOT_TEMPORARY_REF))
475518
}
476519

520+
// track all types mentioned in extern blocks, we
521+
// don't want to rewrite those
522+
gacx.foreign_mentioned_tys = foreign_mentioned_tys(tcx);
523+
477524
let mut gasn =
478525
GlobalAssignment::new(gacx.num_pointers(), PermissionSet::UNIQUE, FlagSet::empty());
479526
for (ptr, &info) in gacx.ptr_info().iter() {
@@ -482,6 +529,22 @@ fn run(tcx: TyCtxt) {
482529
}
483530
}
484531

532+
// FIX the fields of structs mentioned in extern blocks
533+
for adt_did in &gacx.adt_metadata.struct_dids {
534+
if gacx.foreign_mentioned_tys.contains(adt_did) {
535+
let adt_def = tcx.adt_def(adt_did);
536+
let fields = adt_def.all_fields();
537+
for field in fields {
538+
let field_lty = gacx.field_ltys[&field.did];
539+
eprintln!(
540+
"adding FIXED permission for {adt_did:?} field {:?}",
541+
field.did
542+
);
543+
make_ty_fixed(&mut gasn, field_lty);
544+
}
545+
}
546+
}
547+
485548
for info in func_info.values_mut() {
486549
let num_pointers = info.acx_data.num_pointers();
487550
let mut lasn = LocalAssignment::new(num_pointers, PermissionSet::UNIQUE, FlagSet::empty());

c2rust-analyze/src/rewrite/ty.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,10 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for HirTyVisitor<'a, 'tcx> {
473473
#[allow(clippy::single_match)]
474474
match &item.kind {
475475
ItemKind::Struct(VariantData::Struct(field_defs, _), generics) => {
476+
if self.acx.gacx.foreign_mentioned_tys.contains(&did) {
477+
eprintln!("Avoiding rewrite for foreign-mentioned type: {did:?}");
478+
return;
479+
}
476480
let adt_metadata = &self.acx.gacx.adt_metadata.table[&did];
477481
let updated_lifetime_params = &adt_metadata.lifetime_params;
478482

@@ -538,16 +542,14 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for HirTyVisitor<'a, 'tcx> {
538542
f_lty,
539543
field_metadata.origin_args,
540544
&mut |pointer_lty, lifetime_lty, args| {
541-
{
542-
create_rewrite_label(
543-
pointer_lty,
544-
args,
545-
&self.asn.perms(),
546-
&self.asn.flags(),
547-
lifetime_lty.label,
548-
&self.acx.gacx.adt_metadata,
549-
)
550-
}
545+
create_rewrite_label(
546+
pointer_lty,
547+
args,
548+
&self.asn.perms(),
549+
&self.asn.flags(),
550+
lifetime_lty.label,
551+
&self.acx.gacx.adt_metadata,
552+
)
551553
},
552554
);
553555

c2rust-analyze/tests/filecheck.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ define_tests! {
4848
fields,
4949
field_temp,
5050
fixed,
51+
foreign,
5152
insertion_sort,
5253
insertion_sort_driver,
5354
insertion_sort_rewrites,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
extern "C" {
2+
fn foo(bar: Alias) -> Baz;
3+
}
4+
5+
type Alias = Bar;
6+
7+
// CHECK-DAG: br: ({{.*}}) perms = UNIQUE, flags = FIXED
8+
// CHECK-DAG: bz: ({{.*}}) perms = UNIQUE, flags = FIXED
9+
// CHECK-DAG: x: ({{.*}}) perms = UNIQUE, flags = FIXED
10+
// CHECK-DAG: y: ({{.*}}) perms = UNIQUE, flags = FIXED
11+
12+
// CHECK-LABEL: BEGIN{{.*}}foreign.rs
13+
14+
// CHECK-LABEL: struct Bar
15+
#[repr(C)]
16+
struct Bar {
17+
// CHECK-DAG: br: *mut i32
18+
br: *mut i32
19+
}
20+
21+
// CHECK-LABEL: struct Baz
22+
#[repr(C)]
23+
struct Baz {
24+
// CHECK-DAG: bz: *mut i32
25+
bz: *mut i32
26+
}
27+
28+
// we need something to get rewritten in order
29+
// to check that `Bar` and `Baz` get output
30+
// in the rewrite string
31+
fn fizz(i: *const i32) {}
32+
33+
extern "C" {
34+
static mut s: S;
35+
}
36+
37+
#[derive(Copy, Clone)]
38+
#[repr(C)]
39+
// CHECK-LABEL: struct S
40+
pub struct S {
41+
// CHECK-DAG: pub x: *const i32
42+
pub x: *const i32,
43+
// CHECK-DAG: pub y: *const i32
44+
pub y: *const i32,
45+
}
46+
47+
// CHECK-LABEL: struct Nit
48+
#[repr(C)]
49+
struct Nit {
50+
// CHECK-DAG: x: *mut i32
51+
x: *mut i32,
52+
// CHECK-DAG: y: *mut i32
53+
y: *mut i32,
54+
}
55+
56+
// CHECK-LABEL: struct Bin
57+
#[repr(C)]
58+
struct Bin {
59+
// CHECK-DAG: nit: *mut Nit
60+
nit: *mut Nit,
61+
}
62+
63+
extern "C" {
64+
// CHECK-DAG: fn f(bin: *mut Bin)
65+
fn f(bin: *mut Bin);
66+
}

0 commit comments

Comments
 (0)