Skip to content

Commit 26fcbd7

Browse files
committed
Added a unsafe_ffi_drop_implementations lint.
This detects cases where a struct or enum are annotated with `#[repr(C)]`, and *do not* have `#[unsafe_no_drop_flag]`, whereby it warns the user that the type may not have the expected size or layout. Also includes tests to ensure the lint is triggered by FFI+Drop structs and enums, *not* triggered by FFI+Drop+unsafe_no_drop_flag structs and enums, and *not* triggered by FFI+!Drop structs and enums. It also contains a tangential change to libstd/sys/windows/backtrace.rs. Specifically, the `Cleanup` type had `#[repr(C)]` and Drop, but was never passed to any FFI function.
1 parent de8bc44 commit 26fcbd7

File tree

5 files changed

+138
-1
lines changed

5 files changed

+138
-1
lines changed

src/librustc/lint/builtin.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2121,3 +2121,52 @@ impl LintPass for UnstableFeatures {
21212121
}
21222122
}
21232123
}
2124+
2125+
declare_lint! {
2126+
UNSAFE_FFI_DROP_IMPLEMENTATIONS,
2127+
Warn,
2128+
"ffi types that may have unexpected layout due to a Drop implementation"
2129+
}
2130+
2131+
/// Forbids FFI types implementing `Drop` without `#[unsafe_no_drop_flag]`.
2132+
#[derive(Copy)]
2133+
pub struct UnsafeFfiDropImplementations;
2134+
2135+
impl LintPass for UnsafeFfiDropImplementations {
2136+
fn get_lints(&self) -> LintArray {
2137+
lint_array!(UNSAFE_FFI_DROP_IMPLEMENTATIONS)
2138+
}
2139+
2140+
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
2141+
// We only care about structs and enums.
2142+
match item.node {
2143+
ast::ItemEnum(..) | ast::ItemStruct(..) => (),
2144+
_ => return
2145+
}
2146+
let &ast::Item { ident, id, span, .. } = item;
2147+
let tcx = &cx.tcx;
2148+
2149+
// Is the type annotated with #[repr(C)]?
2150+
let s_ty = tcx.node_types.borrow()[id];
2151+
let def_id = match s_ty.sty {
2152+
ty::ty_enum(def_id, _) => def_id,
2153+
ty::ty_struct(def_id, _) => def_id,
2154+
_ => panic!("expected an enum or struct type")
2155+
};
2156+
let reprs = ty::lookup_repr_hints(tcx, def_id);
2157+
if !reprs.contains(&attr::ReprExtern) {
2158+
return;
2159+
}
2160+
2161+
// It is. Does it have #[unsafe_no_drop_flag]?
2162+
if !ty::ty_dtor(tcx, def_id).has_drop_flag() {
2163+
return;
2164+
}
2165+
2166+
// It doesn't. Oh *dear*.
2167+
cx.span_lint(UNSAFE_FFI_DROP_IMPLEMENTATIONS, span,
2168+
&format!("{} is marked for use with FFI, but has a `Drop` implementation; \
2169+
this may cause the type to have an unexpected size and layout",
2170+
ident));
2171+
}
2172+
}

src/librustc/lint/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ impl LintStore {
214214
Stability,
215215
UnconditionalRecursion,
216216
PrivateNoMangleFns,
217+
UnsafeFfiDropImplementations,
217218
);
218219

219220
add_builtin_with_new!(sess,

src/libstd/sys/windows/backtrace.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,6 @@ mod arch {
284284
}
285285
}
286286

287-
#[repr(C)]
288287
struct Cleanup {
289288
handle: libc::HANDLE,
290289
SymCleanup: SymCleanupFn,

src/test/compile-fail/issue-18308.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![deny(unsafe_ffi_drop_implementations)]
12+
#![allow(dead_code)]
13+
14+
extern {
15+
fn f(x: *const FfiUnsafeStruct, y: *const FfiUnsafeEnum);
16+
}
17+
18+
#[repr(C)]
19+
struct FfiUnsafeStruct { //~ ERROR: unexpected size and layout
20+
i: i32,
21+
}
22+
23+
impl Drop for FfiUnsafeStruct {
24+
fn drop(&mut self) {}
25+
}
26+
27+
#[repr(C)]
28+
enum FfiUnsafeEnum { //~ ERROR: unexpected size and layout
29+
Kaboom = 0,
30+
Splang = 1,
31+
}
32+
33+
impl Drop for FfiUnsafeEnum {
34+
fn drop(&mut self) {}
35+
}
36+
37+
fn main() {}

src/test/run-pass/issue-18308.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![deny(unsafe_ffi_drop_implementations)]
12+
#![allow(dead_code)]
13+
14+
extern {
15+
fn f(x: *const FfiSafeStruct, y: *const FfiSafeEnum);
16+
}
17+
18+
#[repr(C)]
19+
#[unsafe_no_drop_flag]
20+
struct FfiSafeStruct {
21+
i: i32,
22+
}
23+
24+
impl Drop for FfiSafeStruct {
25+
fn drop(&mut self) {}
26+
}
27+
28+
#[repr(C)]
29+
#[unsafe_no_drop_flag]
30+
enum FfiSafeEnum {
31+
Kaboom = 0,
32+
Splang = 1,
33+
}
34+
35+
impl Drop for FfiSafeEnum {
36+
fn drop(&mut self) {}
37+
}
38+
39+
// These two should not be affected as they have no Drop impl.
40+
#[repr(C)]
41+
struct FfiSafeStructNoDrop {
42+
i: i32,
43+
}
44+
45+
#[repr(C)]
46+
enum FfiSafeEnumNoDrop {
47+
Peace = 0,
48+
WhaleSong = 1,
49+
}
50+
51+
fn main() {}

0 commit comments

Comments
 (0)