Skip to content

Commit 24adf70

Browse files
committed
ImproperCTypes: also check 'exported' static variables
Added the missing case for FFI-exposed pieces of code: static variables with the `no_mangle` or `export_name` annotations. This adds a new lint, which is managed by the rest of the ImproperCTypes architecture.
1 parent 8a5d6ae commit 24adf70

File tree

7 files changed

+96
-3
lines changed

7 files changed

+96
-3
lines changed

compiler/rustc_lint/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ fn register_builtins(store: &mut LintStore) {
339339
"improper_c_boundaries",
340340
IMPROPER_C_CALLBACKS,
341341
IMPROPER_C_FN_DEFINITIONS,
342+
IMPROPER_C_VAR_DEFINITIONS,
342343
IMPROPER_CTYPES
343344
);
344345

compiler/rustc_lint/src/types.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use {rustc_ast as ast, rustc_hir as hir};
1212

1313
mod improper_ctypes; // these filed do the implementation for ImproperCTypesDefinitions,ImproperCTypesDeclarations
1414
pub(crate) use improper_ctypes::{
15-
IMPROPER_C_CALLBACKS, IMPROPER_C_FN_DEFINITIONS, IMPROPER_CTYPES, ImproperCTypesLint,
15+
IMPROPER_C_CALLBACKS, IMPROPER_C_FN_DEFINITIONS, IMPROPER_C_VAR_DEFINITIONS, IMPROPER_CTYPES,
16+
ImproperCTypesLint,
1617
};
1718

1819
use crate::lints::{

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,37 @@ declare_lint! {
8080
"proper use of libc types in foreign item definitions"
8181
}
8282

83+
declare_lint! {
84+
/// The `improper_c_var_definitions` lint detects incorrect use of
85+
/// [`no_mangle`] and [`export_name`] static variable definitions.
86+
/// (In other words, static variables accessible by name by foreign code.)
87+
///
88+
/// [`no_mangle`]: https://doc.rust-lang.org/stable/reference/abi.html#the-no_mangle-attribute
89+
/// [`export_name`]: https://doc.rust-lang.org/stable/reference/abi.html#the-export_name-attribute
90+
///
91+
/// ### Example
92+
///
93+
/// ```rust
94+
/// # #[unsafe(no_mangle)]
95+
/// # #[used]
96+
/// static mut PLUGIN_ABI_MIN_VERSION: &'static str = "0.0.5";
97+
/// ```
98+
///
99+
/// {{produces}}
100+
///
101+
/// ### Explanation
102+
///
103+
/// The compiler has several checks to verify that types used in
104+
/// static variables exposed to foreign code are safe and follow
105+
/// certain rules to ensure proper compatibility with the foreign interfaces.
106+
/// This lint is issued when it detects a probable mistake in a definition.
107+
/// The lint usually should provide a description of the issue,
108+
/// along with possibly a hint on how to resolve it.
109+
pub(crate) IMPROPER_C_VAR_DEFINITIONS,
110+
Warn,
111+
"proper use of libc types in foreign-reachable static variable definitions"
112+
}
113+
83114
declare_lint! {
84115
/// The `improper_c_callbacks` lint detects incorrect use of
85116
/// [`extern` function] pointers.
@@ -166,6 +197,7 @@ declare_lint! {
166197
declare_lint_pass!(ImproperCTypesLint => [
167198
IMPROPER_CTYPES,
168199
IMPROPER_C_FN_DEFINITIONS,
200+
IMPROPER_C_VAR_DEFINITIONS,
169201
IMPROPER_C_CALLBACKS,
170202
USES_POWER_ALIGNMENT,
171203
]);
@@ -247,6 +279,8 @@ enum CItemKind {
247279
ImportedExtern,
248280
/// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
249281
ExportedFunction,
282+
/// `no_mangle`/`export_name` static variables, assumed to be used from across an FFI boundary,
283+
ExportedStatic,
250284
/// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
251285
Callback,
252286
}
@@ -595,6 +629,8 @@ impl VisitorState {
595629
// Unfortunately, "cannot call non-const operator in constants" (bitwise or?).
596630
const NONE: Self = Self::empty();
597631
const STATIC_TY: Self = Self::STATIC;
632+
const EXPORTED_STATIC_TY: Self =
633+
Self::from_bits(Self::STATIC.bits() | Self::DEFINED.bits()).unwrap();
598634
const ARGUMENT_TY_IN_DEFINITION: Self =
599635
Self::from_bits(Self::FUNC.bits() | Self::DEFINED.bits()).unwrap();
600636
const RETURN_TY_IN_DEFINITION: Self =
@@ -1645,6 +1681,14 @@ impl<'tcx> ImproperCTypesLint {
16451681
self.process_ffi_result(cx, span, ffi_res, CItemKind::ImportedExtern);
16461682
}
16471683

1684+
/// Check that a `#[no_mangle]`/`#[export_name = _]` static variable is of a ffi-safe type.
1685+
fn check_exported_static(&self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
1686+
let ty = cx.tcx.type_of(id).instantiate_identity();
1687+
let visitor = ImproperCTypesVisitor::new(cx);
1688+
let ffi_res = visitor.check_type(VisitorState::EXPORTED_STATIC_TY, ty);
1689+
self.process_ffi_result(cx, span, ffi_res, CItemKind::ExportedStatic);
1690+
}
1691+
16481692
/// Check if a function's argument types and result type are "ffi-safe".
16491693
fn check_foreign_fn(
16501694
&mut self,
@@ -1745,11 +1789,13 @@ impl<'tcx> ImproperCTypesLint {
17451789
let lint = match fn_mode {
17461790
CItemKind::ImportedExtern => IMPROPER_CTYPES,
17471791
CItemKind::ExportedFunction => IMPROPER_C_FN_DEFINITIONS,
1792+
CItemKind::ExportedStatic => IMPROPER_C_VAR_DEFINITIONS,
17481793
CItemKind::Callback => IMPROPER_C_CALLBACKS,
17491794
};
17501795
let desc = match fn_mode {
17511796
CItemKind::ImportedExtern => "`extern` block",
17521797
CItemKind::ExportedFunction => "`extern` fn",
1798+
CItemKind::ExportedStatic => "foreign-code-reachable static",
17531799
CItemKind::Callback => "`extern` callback",
17541800
};
17551801
for reason in reasons.iter_mut() {
@@ -1817,6 +1863,25 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
18171863
ty,
18181864
cx.tcx.type_of(item.owner_id).instantiate_identity(),
18191865
);
1866+
1867+
// FIXME: cx.tcx.has_attr no worky
1868+
// if matches!(item.kind, hir::ItemKind::Static(..))
1869+
// && (cx.tcx.has_attr(item.owner_id, sym::no_mangle)
1870+
// || cx.tcx.has_attr(item.owner_id, sym::export_name))
1871+
if matches!(item.kind, hir::ItemKind::Static(..)) {
1872+
let is_exported_static = cx.tcx.get_all_attrs(item.owner_id).iter().any(|x| {
1873+
matches!(
1874+
x,
1875+
hir::Attribute::Parsed(
1876+
hir::attrs::AttributeKind::NoMangle(_)
1877+
| hir::attrs::AttributeKind::ExportName { .. }
1878+
)
1879+
)
1880+
});
1881+
if is_exported_static {
1882+
self.check_exported_static(cx, item.owner_id, ty.span);
1883+
}
1884+
}
18201885
}
18211886
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
18221887
hir::ItemKind::Fn { .. } => {}

src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_type.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#[no_mangle]
2+
#[allow(improper_c_var_definitions)]
23
static FOO: () = ();
34

45
fn main() {

tests/ui/lint/improper_ctypes/lint-ctypes.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#![allow(private_interfaces)]
77
#![deny(improper_ctypes, improper_c_callbacks)]
8-
#![deny(improper_c_fn_definitions)]
8+
#![deny(improper_c_fn_definitions, improper_c_var_definitions)]
99

1010
use std::cell::UnsafeCell;
1111
use std::marker::PhantomData;
@@ -138,6 +138,15 @@ extern "C" {
138138
pub fn good19(_: &String);
139139
}
140140

141+
static DEFAULT_U32: u32 = 42;
142+
#[no_mangle]
143+
static EXPORTED_STATIC: &u32 = &DEFAULT_U32;
144+
#[no_mangle]
145+
static EXPORTED_STATIC_BAD: &'static str = "is this reaching you, plugin?";
146+
//~^ ERROR: uses type `&str`
147+
#[export_name="EXPORTED_STATIC_MUT_BUT_RENAMED"]
148+
static mut EXPORTED_STATIC_MUT: &u32 = &DEFAULT_U32;
149+
141150
#[cfg(not(target_arch = "wasm32"))]
142151
extern "C" {
143152
pub fn good1(size: *const c_int);

tests/ui/lint/improper_ctypes/lint-ctypes.stderr

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,5 +208,19 @@ LL | pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
208208
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
209209
= note: enum has no representation hint
210210

211-
error: aborting due to 20 previous errors
211+
error: foreign-code-reachable static uses type `&str`, which is not FFI-safe
212+
--> $DIR/lint-ctypes.rs:145:29
213+
|
214+
LL | static EXPORTED_STATIC_BAD: &'static str = "is this reaching you, plugin?";
215+
| ^^^^^^^^^^^^ not FFI-safe
216+
|
217+
= help: consider using `*const u8` and a length instead
218+
= note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
219+
note: the lint level is defined here
220+
--> $DIR/lint-ctypes.rs:8:36
221+
|
222+
LL | #![deny(improper_c_fn_definitions, improper_c_var_definitions)]
223+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
224+
225+
error: aborting due to 21 previous errors
212226

tests/ui/statics/nested-allocations-dont-inherit-codegen-attrs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//@ build-pass
22

3+
#![allow(improper_c_var_definitions)]
4+
35
// Make sure that the nested static allocation for `FOO` doesn't inherit `no_mangle`.
46
#[no_mangle]
57
pub static mut FOO: &mut [i32] = &mut [42];

0 commit comments

Comments
 (0)