@@ -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+
18201883declare_lint ! {
18211884 /// The `improper_c_callbacks` lint detects incorrect use of
18221885 /// [`extern` function] pointers.
@@ -1903,6 +1966,7 @@ declare_lint! {
19031966declare_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] ) ;
0 commit comments