@@ -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+
18261889declare_lint ! {
18271890 /// The `improper_c_callbacks` lint detects incorrect use of
18281891 /// [`extern` function] pointers.
@@ -1909,6 +1972,7 @@ declare_lint! {
19091972declare_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] ) ;
0 commit comments