@@ -80,6 +80,37 @@ declare_lint! {
80
80
"proper use of libc types in foreign item definitions"
81
81
}
82
82
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
+
83
114
declare_lint ! {
84
115
/// The `improper_c_callbacks` lint detects incorrect use of
85
116
/// [`extern` function] pointers.
@@ -166,6 +197,7 @@ declare_lint! {
166
197
declare_lint_pass ! ( ImproperCTypesLint => [
167
198
IMPROPER_CTYPES ,
168
199
IMPROPER_C_FN_DEFINITIONS ,
200
+ IMPROPER_C_VAR_DEFINITIONS ,
169
201
IMPROPER_C_CALLBACKS ,
170
202
USES_POWER_ALIGNMENT ,
171
203
] ) ;
@@ -247,6 +279,8 @@ enum CItemKind {
247
279
ImportedExtern ,
248
280
/// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
249
281
ExportedFunction ,
282
+ /// `no_mangle`/`export_name` static variables, assumed to be used from across an FFI boundary,
283
+ ExportedStatic ,
250
284
/// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
251
285
Callback ,
252
286
}
@@ -595,6 +629,8 @@ impl VisitorState {
595
629
// Unfortunately, "cannot call non-const operator in constants" (bitwise or?).
596
630
const NONE : Self = Self :: empty ( ) ;
597
631
const STATIC_TY : Self = Self :: STATIC ;
632
+ const EXPORTED_STATIC_TY : Self =
633
+ Self :: from_bits ( Self :: STATIC . bits ( ) | Self :: DEFINED . bits ( ) ) . unwrap ( ) ;
598
634
const ARGUMENT_TY_IN_DEFINITION : Self =
599
635
Self :: from_bits ( Self :: FUNC . bits ( ) | Self :: DEFINED . bits ( ) ) . unwrap ( ) ;
600
636
const RETURN_TY_IN_DEFINITION : Self =
@@ -1645,6 +1681,14 @@ impl<'tcx> ImproperCTypesLint {
1645
1681
self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
1646
1682
}
1647
1683
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
+
1648
1692
/// Check if a function's argument types and result type are "ffi-safe".
1649
1693
fn check_foreign_fn (
1650
1694
& mut self ,
@@ -1745,11 +1789,13 @@ impl<'tcx> ImproperCTypesLint {
1745
1789
let lint = match fn_mode {
1746
1790
CItemKind :: ImportedExtern => IMPROPER_CTYPES ,
1747
1791
CItemKind :: ExportedFunction => IMPROPER_C_FN_DEFINITIONS ,
1792
+ CItemKind :: ExportedStatic => IMPROPER_C_VAR_DEFINITIONS ,
1748
1793
CItemKind :: Callback => IMPROPER_C_CALLBACKS ,
1749
1794
} ;
1750
1795
let desc = match fn_mode {
1751
1796
CItemKind :: ImportedExtern => "`extern` block" ,
1752
1797
CItemKind :: ExportedFunction => "`extern` fn" ,
1798
+ CItemKind :: ExportedStatic => "foreign-code-reachable static" ,
1753
1799
CItemKind :: Callback => "`extern` callback" ,
1754
1800
} ;
1755
1801
for reason in reasons. iter_mut ( ) {
@@ -1817,6 +1863,25 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1817
1863
ty,
1818
1864
cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1819
1865
) ;
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
+ }
1820
1885
}
1821
1886
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
1822
1887
hir:: ItemKind :: Fn { .. } => { }
0 commit comments