Skip to content

Commit 08db5c0

Browse files
committed
ImproperCTypes: also check 'exported' static variables
1 parent 302842c commit 08db5c0

File tree

7 files changed

+95
-3
lines changed

7 files changed

+95
-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: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ enum CItemKind {
9999
ImportedExtern,
100100
/// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
101101
ExportedFunction,
102+
/// `no_mangle`/`export_name` static variables, assumed to be used from across an FFI boundary
103+
ExportedStatic,
102104
/// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
103105
Callback,
104106
}
@@ -439,6 +441,7 @@ enum CTypesVisitorState {
439441
None = CTypesVisitorStateFlags::NO_FLAGS,
440442
// uses bitflags from CTypesVisitorStateFlags
441443
StaticTy = CTypesVisitorStateFlags::STATIC,
444+
ExportedStaticTy = CTypesVisitorStateFlags::STATIC | CTypesVisitorStateFlags::DEFINED,
442445
ArgumentTyInDefinition = CTypesVisitorStateFlags::FUNC | CTypesVisitorStateFlags::DEFINED,
443446
ReturnTyInDefinition = CTypesVisitorStateFlags::FUNC
444447
| CTypesVisitorStateFlags::FN_RETURN
@@ -1471,6 +1474,14 @@ impl<'tcx> ImproperCTypesLint {
14711474
self.process_ffi_result(cx, span, ffi_res, CItemKind::ImportedExtern);
14721475
}
14731476

1477+
/// Check that a `#[no_mangle]`/`#[export_name = _]` static variable is of a ffi-safe type
1478+
fn check_exported_static(&self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
1479+
let ty = cx.tcx.type_of(id).instantiate_identity();
1480+
let visitor = ImproperCTypesVisitor::new(cx);
1481+
let ffi_res = visitor.check_for_type(CTypesVisitorState::ExportedStaticTy, ty);
1482+
self.process_ffi_result(cx, span, ffi_res, CItemKind::ExportedStatic);
1483+
}
1484+
14741485
/// Check if a function's argument types and result type are "ffi-safe".
14751486
fn check_foreign_fn(
14761487
&mut self,
@@ -1579,11 +1590,13 @@ impl<'tcx> ImproperCTypesLint {
15791590
let lint = match fn_mode {
15801591
CItemKind::ImportedExtern => IMPROPER_CTYPES,
15811592
CItemKind::ExportedFunction => IMPROPER_C_FN_DEFINITIONS,
1593+
CItemKind::ExportedStatic => IMPROPER_C_VAR_DEFINITIONS,
15821594
CItemKind::Callback => IMPROPER_C_CALLBACKS,
15831595
};
15841596
let desc = match fn_mode {
15851597
CItemKind::ImportedExtern => "`extern` block",
15861598
CItemKind::ExportedFunction => "`extern` fn",
1599+
CItemKind::ExportedStatic => "foreign-code-reachable static",
15871600
CItemKind::Callback => "`extern` callback",
15881601
};
15891602
for reason in reasons.iter_mut() {
@@ -1651,6 +1664,25 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
16511664
ty,
16521665
cx.tcx.type_of(item.owner_id).instantiate_identity(),
16531666
);
1667+
1668+
// FIXME: cx.tcx.has_attr no worky
1669+
// if matches!(item.kind, hir::ItemKind::Static(..))
1670+
// && (cx.tcx.has_attr(item.owner_id, sym::no_mangle)
1671+
// || cx.tcx.has_attr(item.owner_id, sym::export_name))
1672+
if matches!(item.kind, hir::ItemKind::Static(..)) {
1673+
let is_exported_static = cx.tcx.get_all_attrs(item.owner_id).iter().any(|x| {
1674+
matches!(
1675+
x,
1676+
hir::Attribute::Parsed(
1677+
hir::attrs::AttributeKind::NoMangle(_)
1678+
| hir::attrs::AttributeKind::ExportName { .. }
1679+
)
1680+
)
1681+
});
1682+
if is_exported_static {
1683+
self.check_exported_static(cx, item.owner_id, ty.span);
1684+
}
1685+
}
16541686
}
16551687
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
16561688
hir::ItemKind::Fn { .. } => {}
@@ -1817,6 +1849,37 @@ declare_lint! {
18171849
"proper use of libc types in foreign item definitions"
18181850
}
18191851

1852+
declare_lint! {
1853+
/// The `improper_c_var_definitions` lint detects incorrect use of
1854+
/// [`no_mangle`] and [`export_name`] static variable definitions.
1855+
/// (in other words, static variables accessible by name by foreign code)
1856+
///
1857+
/// [`no_mangle`]: https://doc.rust-lang.org/stable/reference/abi.html#the-no_mangle-attribute
1858+
/// [`export_name`]: https://doc.rust-lang.org/stable/reference/abi.html#the-export_name-attribute
1859+
///
1860+
/// ### Example
1861+
///
1862+
/// ```rust
1863+
/// # #[unsafe(no_mangle)]
1864+
/// # #[used]
1865+
/// static mut PLUGIN_ABI_MIN_VERSION: &'static str = "0.0.5";
1866+
/// ```
1867+
///
1868+
/// {{produces}}
1869+
///
1870+
/// ### Explanation
1871+
///
1872+
/// The compiler has several checks to verify that types used in
1873+
/// static variables exposed to foreign code are safe and follow
1874+
/// certain rules to ensure proper compatibility with the foreign interfaces.
1875+
/// This lint is issued when it detects a probable mistake in a definition.
1876+
/// The lint usually should provide a description of the issue,
1877+
/// along with possibly a hint on how to resolve it.
1878+
pub(crate) IMPROPER_C_VAR_DEFINITIONS,
1879+
Warn,
1880+
"proper use of libc types in foreign-reachable static variable definitions"
1881+
}
1882+
18201883
declare_lint! {
18211884
/// The `improper_c_callbacks` lint detects incorrect use of
18221885
/// [`extern` function] pointers.
@@ -1903,6 +1966,7 @@ declare_lint! {
19031966
declare_lint_pass!(ImproperCTypesLint => [
19041967
IMPROPER_CTYPES,
19051968
IMPROPER_C_FN_DEFINITIONS,
1969+
IMPROPER_C_VAR_DEFINITIONS,
19061970
IMPROPER_C_CALLBACKS,
19071971
USES_POWER_ALIGNMENT,
19081972
]);

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)