Skip to content

Commit 1ea05b1

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 fb70d73 commit 1ea05b1

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
@@ -100,6 +100,8 @@ enum CItemKind {
100100
ImportedExtern,
101101
/// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
102102
ExportedFunction,
103+
/// `no_mangle`/`export_name` static variables, assumed to be used from across an FFI boundary,
104+
ExportedStatic,
103105
/// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
104106
Callback,
105107
}
@@ -438,6 +440,7 @@ bitflags! {
438440
// unfortunately, "cannot call non-const operator in constants" (bitwise or?).
439441
const None = 0b000000;
440442
const StaticTy = 0b000001; //Self::STATIC
443+
const ExportedStaticTy = 0b001001; //Self::STATIC | Self::DEFINED
441444
const ArgumentTyInDefinition = 0b001010; //Self::FUNC | Self::DEFINED
442445
const ReturnTyInDefinition = 0b001110; //Self::FUNC | Self::FN_RETURN | Self::DEFINED
443446
const ArgumentTyInDeclaration = 0b000010; //Self::FUNC
@@ -1485,6 +1488,14 @@ impl<'tcx> ImproperCTypesLint {
14851488
self.process_ffi_result(cx, span, ffi_res, CItemKind::ImportedExtern);
14861489
}
14871490

1491+
/// Check that a `#[no_mangle]`/`#[export_name = _]` static variable is of a ffi-safe type.
1492+
fn check_exported_static(&self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
1493+
let ty = cx.tcx.type_of(id).instantiate_identity();
1494+
let visitor = ImproperCTypesVisitor::new(cx);
1495+
let ffi_res = visitor.check_for_type(VisitorState::ExportedStaticTy, ty);
1496+
self.process_ffi_result(cx, span, ffi_res, CItemKind::ExportedStatic);
1497+
}
1498+
14881499
/// Check if a function's argument types and result type are "ffi-safe".
14891500
fn check_foreign_fn(
14901501
&mut self,
@@ -1585,11 +1596,13 @@ impl<'tcx> ImproperCTypesLint {
15851596
let lint = match fn_mode {
15861597
CItemKind::ImportedExtern => IMPROPER_CTYPES,
15871598
CItemKind::ExportedFunction => IMPROPER_C_FN_DEFINITIONS,
1599+
CItemKind::ExportedStatic => IMPROPER_C_VAR_DEFINITIONS,
15881600
CItemKind::Callback => IMPROPER_C_CALLBACKS,
15891601
};
15901602
let desc = match fn_mode {
15911603
CItemKind::ImportedExtern => "`extern` block",
15921604
CItemKind::ExportedFunction => "`extern` fn",
1605+
CItemKind::ExportedStatic => "foreign-code-reachable static",
15931606
CItemKind::Callback => "`extern` callback",
15941607
};
15951608
for reason in reasons.iter_mut() {
@@ -1657,6 +1670,25 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
16571670
ty,
16581671
cx.tcx.type_of(item.owner_id).instantiate_identity(),
16591672
);
1673+
1674+
// FIXME: cx.tcx.has_attr no worky
1675+
// if matches!(item.kind, hir::ItemKind::Static(..))
1676+
// && (cx.tcx.has_attr(item.owner_id, sym::no_mangle)
1677+
// || cx.tcx.has_attr(item.owner_id, sym::export_name))
1678+
if matches!(item.kind, hir::ItemKind::Static(..)) {
1679+
let is_exported_static = cx.tcx.get_all_attrs(item.owner_id).iter().any(|x| {
1680+
matches!(
1681+
x,
1682+
hir::Attribute::Parsed(
1683+
hir::attrs::AttributeKind::NoMangle(_)
1684+
| hir::attrs::AttributeKind::ExportName { .. }
1685+
)
1686+
)
1687+
});
1688+
if is_exported_static {
1689+
self.check_exported_static(cx, item.owner_id, ty.span);
1690+
}
1691+
}
16601692
}
16611693
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
16621694
hir::ItemKind::Fn { .. } => {}
@@ -1823,6 +1855,37 @@ declare_lint! {
18231855
"proper use of libc types in foreign item definitions"
18241856
}
18251857

1858+
declare_lint! {
1859+
/// The `improper_c_var_definitions` lint detects incorrect use of
1860+
/// [`no_mangle`] and [`export_name`] static variable definitions.
1861+
/// (In other words, static variables accessible by name by foreign code.)
1862+
///
1863+
/// [`no_mangle`]: https://doc.rust-lang.org/stable/reference/abi.html#the-no_mangle-attribute
1864+
/// [`export_name`]: https://doc.rust-lang.org/stable/reference/abi.html#the-export_name-attribute
1865+
///
1866+
/// ### Example
1867+
///
1868+
/// ```rust
1869+
/// # #[unsafe(no_mangle)]
1870+
/// # #[used]
1871+
/// static mut PLUGIN_ABI_MIN_VERSION: &'static str = "0.0.5";
1872+
/// ```
1873+
///
1874+
/// {{produces}}
1875+
///
1876+
/// ### Explanation
1877+
///
1878+
/// The compiler has several checks to verify that types used in
1879+
/// static variables exposed to foreign code are safe and follow
1880+
/// certain rules to ensure proper compatibility with the foreign interfaces.
1881+
/// This lint is issued when it detects a probable mistake in a definition.
1882+
/// The lint usually should provide a description of the issue,
1883+
/// along with possibly a hint on how to resolve it.
1884+
pub(crate) IMPROPER_C_VAR_DEFINITIONS,
1885+
Warn,
1886+
"proper use of libc types in foreign-reachable static variable definitions"
1887+
}
1888+
18261889
declare_lint! {
18271890
/// The `improper_c_callbacks` lint detects incorrect use of
18281891
/// [`extern` function] pointers.
@@ -1909,6 +1972,7 @@ declare_lint! {
19091972
declare_lint_pass!(ImproperCTypesLint => [
19101973
IMPROPER_CTYPES,
19111974
IMPROPER_C_FN_DEFINITIONS,
1975+
IMPROPER_C_VAR_DEFINITIONS,
19121976
IMPROPER_C_CALLBACKS,
19131977
USES_POWER_ALIGNMENT,
19141978
]);

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)