@@ -100,6 +100,8 @@ enum CItemKind {
100
100
ImportedExtern ,
101
101
/// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
102
102
ExportedFunction ,
103
+ /// `no_mangle`/`export_name` static variables, assumed to be used from across an FFI boundary,
104
+ ExportedStatic ,
103
105
/// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
104
106
Callback ,
105
107
}
@@ -438,6 +440,7 @@ bitflags! {
438
440
// unfortunately, "cannot call non-const operator in constants" (bitwise or?).
439
441
const None = 0b000000 ;
440
442
const StaticTy = 0b000001 ; //Self::STATIC
443
+ const ExportedStaticTy = 0b001001 ; //Self::STATIC | Self::DEFINED
441
444
const ArgumentTyInDefinition = 0b001010 ; //Self::FUNC | Self::DEFINED
442
445
const ReturnTyInDefinition = 0b001110 ; //Self::FUNC | Self::FN_RETURN | Self::DEFINED
443
446
const ArgumentTyInDeclaration = 0b000010 ; //Self::FUNC
@@ -1485,6 +1488,14 @@ impl<'tcx> ImproperCTypesLint {
1485
1488
self . process_ffi_result ( cx, span, ffi_res, CItemKind :: ImportedExtern ) ;
1486
1489
}
1487
1490
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
+
1488
1499
/// Check if a function's argument types and result type are "ffi-safe".
1489
1500
fn check_foreign_fn (
1490
1501
& mut self ,
@@ -1585,11 +1596,13 @@ impl<'tcx> ImproperCTypesLint {
1585
1596
let lint = match fn_mode {
1586
1597
CItemKind :: ImportedExtern => IMPROPER_CTYPES ,
1587
1598
CItemKind :: ExportedFunction => IMPROPER_C_FN_DEFINITIONS ,
1599
+ CItemKind :: ExportedStatic => IMPROPER_C_VAR_DEFINITIONS ,
1588
1600
CItemKind :: Callback => IMPROPER_C_CALLBACKS ,
1589
1601
} ;
1590
1602
let desc = match fn_mode {
1591
1603
CItemKind :: ImportedExtern => "`extern` block" ,
1592
1604
CItemKind :: ExportedFunction => "`extern` fn" ,
1605
+ CItemKind :: ExportedStatic => "foreign-code-reachable static" ,
1593
1606
CItemKind :: Callback => "`extern` callback" ,
1594
1607
} ;
1595
1608
for reason in reasons. iter_mut ( ) {
@@ -1657,6 +1670,25 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1657
1670
ty,
1658
1671
cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) ,
1659
1672
) ;
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
+ }
1660
1692
}
1661
1693
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
1662
1694
hir:: ItemKind :: Fn { .. } => { }
@@ -1823,6 +1855,37 @@ declare_lint! {
1823
1855
"proper use of libc types in foreign item definitions"
1824
1856
}
1825
1857
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
+
1826
1889
declare_lint ! {
1827
1890
/// The `improper_c_callbacks` lint detects incorrect use of
1828
1891
/// [`extern` function] pointers.
@@ -1909,6 +1972,7 @@ declare_lint! {
1909
1972
declare_lint_pass ! ( ImproperCTypesLint => [
1910
1973
IMPROPER_CTYPES ,
1911
1974
IMPROPER_C_FN_DEFINITIONS ,
1975
+ IMPROPER_C_VAR_DEFINITIONS ,
1912
1976
IMPROPER_C_CALLBACKS ,
1913
1977
USES_POWER_ALIGNMENT ,
1914
1978
] ) ;
0 commit comments