| author | bors <bors@rust-lang.org> 2026-06-26 18:28:45 UTC |
| committer | bors <bors@rust-lang.org> 2026-06-26 18:28:45 UTC |
| log | ce9954c0cfc4bf26b82aef16e6fd8b020c237992 |
| tree | c24ebfa039fba107ec21ef2eff5aaa5a62922622 |
| parent | eb6346c659ccb0468a1477c716ca5450a1fa9ba1 |
| parent | 56d17c4d191feba4e4a016e1ffa74420f61a2703 |
Add lint against invalid runtime symbol definitions
This PR adds a deny-by-default lint againts invalid runtime symbol definitions, those runtime symbols are assumed and used by `core`[^1] and `rustc` with a specific definition.
We have had multiple reports of users tripping over `std` symbols (addressed in a future PR):
- [Why does `#[no_mangle] fn open() {}` make `cargo t` hang?](https://users.rust-lang.org/t/why-does-no-mangle-fn-open-make-cargo-t-hang/103423)
- [Pointer becomes misaligned in test with `no_mangle`](https://users.rust-lang.org/t/pointer-becomes-misaligned-in-test-with-no-mangle/126580)
This PR is a second attempt after https://github.com/rust-lang/rust/pull/146505, where T-lang had [some reservations](https://github.com/rust-lang/rust/pull/146505#issuecomment-3492657109) about a blanket lint that does not check the signature, which is now done with this PR, and about linting of `std` runtime symbols when std is not linked, which this PR omits by not including any std runtime symbols (for now).
## `invalid_runtime_symbol_definitions`
*(deny-by-default)*
The `invalid_runtime_symbol_definitions` lint checks the signature of items whose symbol name is a runtime symbols expected by `core` differs significantly from the expected signature (like mismatch ABI, mismatch C variadics, mismatch argument count, missing return type, ...).
### Example
```rust,compile_fail
#[unsafe(no_mangle)]
pub fn memcmp() {} // invalid definition of the `memcmp` runtime symbol
```
```text
error: invalid definition of the runtime `memcmp` symbol used by the standard library
--> a.rs:2:1
|
4 | fn memcmp() {}
| ^^^^^^^^^^^
|
= note: expected `unsafe extern "C" fn(*const c_void, *const c_void, usize) -> i32`
found `fn()`
= help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcmp")]`, or `#[link_name = "memcmp"]`
= note: `#[deny(invalid_runtime_symbol_definitions)]` on by default
```
### Explanation
Up-most care is required when defining runtime symbols assumed and used by the standard library. They must follow the C specification, not use any standard-library facility or undefined behavior may occur.
The symbols currently checked are `memcpy`, `memmove`, `memset`, `memcmp`, `bcmp` and `strlen`.
## `suspicious_runtime_symbol_definitions`
(warn-by-default, asked in [this comment](https://github.com/rust-lang/rust/pull/155521#issuecomment-4696528297))
The `suspicious_runtime_symbol_definitions` lint checks the signature of items whose symbol name is a runtime symbol expected by `core`.
### Example
```rust
#[unsafe(no_mangle)]
pub extern "C" fn strlen(ptr: *mut f32) -> usize { 0 }
// suspicious definition of the `strlen` function
// `ptr` should be `*const std::ffi::c_char`
```
### Explanation
Up-most care is required when defining runtime symbols assumed and used by the standard library. They must follow the C specification, not use any standard-library facility or undefined behavior may occur.
[^1]: https://doc.rust-lang.org/core/index.html#how-to-use-the-core-library
20 files changed, 744 insertions(+), 56 deletions(-)
Cargo.lock+1| ... | ... | @@ -4312,6 +4312,7 @@ dependencies = [ |
| 4312 | 4312 | "rustc_parse_format", |
| 4313 | 4313 | "rustc_session", |
| 4314 | 4314 | "rustc_span", |
| 4315 | "rustc_symbol_mangling", | |
| 4315 | 4316 | "rustc_target", |
| 4316 | 4317 | "rustc_trait_selection", |
| 4317 | 4318 | "smallvec", |
compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs+3-1| ... | ... | @@ -582,7 +582,7 @@ impl SingleAttributeParser for LangParser { |
| 582 | 582 | // Only weak lang items may be applied to foreign items |
| 583 | 583 | if [Target::ForeignFn, Target::ForeignStatic, Target::ForeignTy, Target::ForeignMod] |
| 584 | 584 | .contains(&cx.target) |
| 585 | && !lang_item.is_weak() | |
| 585 | && !(lang_item.is_weak() || lang_item.is_weak_only()) | |
| 586 | 586 | { |
| 587 | 587 | cx.emit_err(UnknownExternLangItem { span: cx.attr_span, lang_item: lang_item.name() }); |
| 588 | 588 | return None; |
| ... | ... | @@ -591,6 +591,8 @@ impl SingleAttributeParser for LangParser { |
| 591 | 591 | // Check the target |
| 592 | 592 | let allowed_targets: &[_] = if lang_item == LangItem::PanicImpl { |
| 593 | 593 | &[Allow(Target::Fn), Allow(Target::ForeignFn)] |
| 594 | } else if lang_item.is_weak_only() { | |
| 595 | &[Allow(Target::ForeignFn)] | |
| 594 | 596 | } else { |
| 595 | 597 | &[Allow(lang_item.target())] |
| 596 | 598 | }; |
compiler/rustc_error_codes/src/error_codes/E0755.md+1-1| ... | ... | @@ -20,7 +20,7 @@ side effects or infinite loops: |
| 20 | 20 | |
| 21 | 21 | extern "C" { |
| 22 | 22 | #[unsafe(ffi_pure)] // ok! |
| 23 | pub fn strlen(s: *const i8) -> isize; | |
| 23 | pub fn strlen(s: *const std::ffi::c_char) -> usize; | |
| 24 | 24 | } |
| 25 | 25 | # fn main() {} |
| 26 | 26 | ``` |
compiler/rustc_error_codes/src/error_codes/E0756.md+1-1| ... | ... | @@ -21,7 +21,7 @@ which have no side effects except for their return value: |
| 21 | 21 | |
| 22 | 22 | extern "C" { |
| 23 | 23 | #[unsafe(ffi_const)] // ok! |
| 24 | pub fn strlen(s: *const i8) -> i32; | |
| 24 | pub fn strlen(s: *const std::ffi::c_char) -> usize; | |
| 25 | 25 | } |
| 26 | 26 | # fn main() {} |
| 27 | 27 | ``` |
compiler/rustc_hir/src/lang_items.rs+8| ... | ... | @@ -447,6 +447,14 @@ language_item_table! { |
| 447 | 447 | |
| 448 | 448 | // Used to fallback `{float}` to `f32` when `f32: From<{float}>` |
| 449 | 449 | From, sym::From, from_trait, Target::Trait, GenericRequirement::Exact(1); |
| 450 | ||
| 451 | // Runtime symbols | |
| 452 | MemCpy, sym::memcpy_fn, memcpy_fn, Target::Fn, GenericRequirement::None; | |
| 453 | MemMove, sym::memmove_fn, memmove_fn, Target::Fn, GenericRequirement::None; | |
| 454 | MemSet, sym::memset_fn, memset_fn, Target::Fn, GenericRequirement::None; | |
| 455 | MemCmp, sym::memcmp_fn, memcmp_fn, Target::Fn, GenericRequirement::None; | |
| 456 | Bcmp, sym::bcmp_fn, bcmp_fn, Target::Fn, GenericRequirement::None; | |
| 457 | StrLen, sym::strlen_fn, strlen_fn, Target::Fn, GenericRequirement::None; | |
| 450 | 458 | } |
| 451 | 459 | |
| 452 | 460 | /// The requirement imposed on the generics of a lang item |
compiler/rustc_hir/src/weak_lang_items.rs+21| ... | ... | @@ -23,7 +23,28 @@ macro_rules! weak_lang_items { |
| 23 | 23 | } |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | macro_rules! weak_only_lang_items { | |
| 27 | ($($item:ident,)*) => { | |
| 28 | pub static WEAK_ONLY_LANG_ITEMS: &[LangItem] = &[$(LangItem::$item,)*]; | |
| 29 | ||
| 30 | impl LangItem { | |
| 31 | pub fn is_weak_only(self) -> bool { | |
| 32 | matches!(self, $(LangItem::$item)|*) | |
| 33 | } | |
| 34 | } | |
| 35 | } | |
| 36 | } | |
| 37 | ||
| 26 | 38 | weak_lang_items! { |
| 27 | 39 | PanicImpl, rust_begin_unwind; |
| 28 | 40 | EhPersonality, rust_eh_personality; |
| 29 | 41 | } |
| 42 | ||
| 43 | weak_only_lang_items! { | |
| 44 | MemCpy, | |
| 45 | MemMove, | |
| 46 | MemSet, | |
| 47 | MemCmp, | |
| 48 | Bcmp, | |
| 49 | StrLen, | |
| 50 | } |
compiler/rustc_lint/Cargo.toml+1| ... | ... | @@ -22,6 +22,7 @@ rustc_middle = { path = "../rustc_middle" } |
| 22 | 22 | rustc_parse_format = { path = "../rustc_parse_format" } |
| 23 | 23 | rustc_session = { path = "../rustc_session" } |
| 24 | 24 | rustc_span = { path = "../rustc_span" } |
| 25 | rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } | |
| 25 | 26 | rustc_target = { path = "../rustc_target" } |
| 26 | 27 | rustc_trait_selection = { path = "../rustc_trait_selection" } |
| 27 | 28 | smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } |
compiler/rustc_lint/src/lib.rs+3| ... | ... | @@ -72,6 +72,7 @@ mod precedence; |
| 72 | 72 | mod ptr_nulls; |
| 73 | 73 | mod redundant_semicolon; |
| 74 | 74 | mod reference_casting; |
| 75 | mod runtime_symbols; | |
| 75 | 76 | mod shadowed_into_iter; |
| 76 | 77 | mod static_mut_refs; |
| 77 | 78 | mod traits; |
| ... | ... | @@ -117,6 +118,7 @@ use precedence::*; |
| 117 | 118 | use ptr_nulls::*; |
| 118 | 119 | use redundant_semicolon::*; |
| 119 | 120 | use reference_casting::*; |
| 121 | use runtime_symbols::*; | |
| 120 | 122 | use rustc_data_structures::unord::UnordSet; |
| 121 | 123 | use rustc_hir::def_id::LocalModDefId; |
| 122 | 124 | use rustc_middle::query::Providers; |
| ... | ... | @@ -259,6 +261,7 @@ late_lint_methods!( |
| 259 | 261 | AsyncFnInTrait: AsyncFnInTrait, |
| 260 | 262 | NonLocalDefinitions: NonLocalDefinitions::default(), |
| 261 | 263 | InteriorMutableConsts: InteriorMutableConsts, |
| 264 | RuntimeSymbols: RuntimeSymbols, | |
| 262 | 265 | ImplTraitOvercaptures: ImplTraitOvercaptures, |
| 263 | 266 | IfLetRescope: IfLetRescope::default(), |
| 264 | 267 | StaticMutRefs: StaticMutRefs, |
compiler/rustc_lint/src/lints.rs+39| ... | ... | @@ -808,6 +808,45 @@ pub(crate) enum UseLetUnderscoreIgnoreSuggestion { |
| 808 | 808 | }, |
| 809 | 809 | } |
| 810 | 810 | |
| 811 | // runtime_symbols.rs | |
| 812 | #[derive(Diagnostic)] | |
| 813 | pub(crate) enum RedefiningRuntimeSymbolsDiag<'tcx> { | |
| 814 | #[diag( | |
| 815 | "invalid definition of the runtime `{$symbol_name}` symbol used by the standard library" | |
| 816 | )] | |
| 817 | #[note( | |
| 818 | "expected `{$expected_fn_sig}` | |
| 819 | found `{$found_fn_sig}`" | |
| 820 | )] | |
| 821 | #[help( | |
| 822 | "either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = \"{$symbol_name}\")]`, or `#[link_name = \"{$symbol_name}\"]`" | |
| 823 | )] | |
| 824 | FnDefInvalid { symbol_name: String, expected_fn_sig: Ty<'tcx>, found_fn_sig: Ty<'tcx> }, | |
| 825 | #[diag( | |
| 826 | "suspicious definition of the runtime `{$symbol_name}` symbol used by the standard library" | |
| 827 | )] | |
| 828 | #[note( | |
| 829 | "expected `{$expected_fn_sig}` | |
| 830 | found `{$found_fn_sig}`" | |
| 831 | )] | |
| 832 | #[help( | |
| 833 | "either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = \"{$symbol_name}\")]`, or `#[link_name = \"{$symbol_name}\"]`" | |
| 834 | )] | |
| 835 | #[help("allow this lint if the signature is compatible")] | |
| 836 | FnDefSuspicious { symbol_name: String, expected_fn_sig: Ty<'tcx>, found_fn_sig: Ty<'tcx> }, | |
| 837 | #[diag( | |
| 838 | "invalid definition of the runtime `{$symbol_name}` symbol used by the standard library" | |
| 839 | )] | |
| 840 | #[note( | |
| 841 | "expected `{$expected_fn_sig}` | |
| 842 | found `static {$symbol_name}: {$static_ty}`" | |
| 843 | )] | |
| 844 | #[help( | |
| 845 | "either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = \"{$symbol_name}\")]`" | |
| 846 | )] | |
| 847 | Static { symbol_name: String, static_ty: Ty<'tcx>, expected_fn_sig: Ty<'tcx> }, | |
| 848 | } | |
| 849 | ||
| 811 | 850 | // drop_forget_useless.rs |
| 812 | 851 | #[derive(Diagnostic)] |
| 813 | 852 | #[diag("calls to `std::mem::drop` with a reference instead of an owned value does nothing")] |
compiler/rustc_lint/src/runtime_symbols.rs created+255| ... | ... | @@ -0,0 +1,255 @@ |
| 1 | use rustc_hir::def_id::{DefId, LocalDefId}; | |
| 2 | use rustc_hir::{self as hir, FnSig, ForeignItemKind, LanguageItems}; | |
| 3 | use rustc_infer::infer::DefineOpaqueTypes; | |
| 4 | use rustc_middle::ty::{self, Instance, Ty}; | |
| 5 | use rustc_session::{declare_lint, declare_lint_pass}; | |
| 6 | use rustc_span::Span; | |
| 7 | use rustc_trait_selection::infer::TyCtxtInferExt; | |
| 8 | ||
| 9 | use crate::lints::RedefiningRuntimeSymbolsDiag; | |
| 10 | use crate::{LateContext, LateLintPass, LintContext}; | |
| 11 | ||
| 12 | declare_lint! { | |
| 13 | /// The `invalid_runtime_symbol_definitions` lint checks the signature of items whose | |
| 14 | /// symbol name is a runtime symbol expected by `core` differs significantly from the | |
| 15 | /// expected signature (like mismatch ABI, mismatch C variadics, mismatch argument count, | |
| 16 | /// missing return type, ...). | |
| 17 | /// | |
| 18 | /// ### Example | |
| 19 | /// | |
| 20 | #[cfg_attr(bootstrap, doc = "```rust")] | |
| 21 | #[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")] | |
| 22 | #[cfg_attr(not(bootstrap), doc = "#[unsafe(no_mangle)]")] | |
| 23 | /// pub fn strlen() {} // invalid definition of the `strlen` function | |
| 24 | #[doc = "```"] | |
| 25 | /// | |
| 26 | /// {{produces}} | |
| 27 | /// | |
| 28 | /// ### Explanation | |
| 29 | /// | |
| 30 | /// Up-most care is required when defining runtime symbols assumed and | |
| 31 | /// used by the standard library. They must follow the C specification, not use any | |
| 32 | /// standard-library facility or undefined behavior may occur. | |
| 33 | /// | |
| 34 | /// The symbols currently checked are `memcpy`, `memmove`, `memset`, `memcmp`, | |
| 35 | /// `bcmp` and `strlen`. | |
| 36 | /// | |
| 37 | /// [^1]: https://doc.rust-lang.org/core/index.html#how-to-use-the-core-library | |
| 38 | pub INVALID_RUNTIME_SYMBOL_DEFINITIONS, | |
| 39 | Deny, | |
| 40 | "invalid definition of a symbol used by the standard library" | |
| 41 | } | |
| 42 | ||
| 43 | declare_lint! { | |
| 44 | /// The `suspicious_runtime_symbol_definitions` lint checks the signature of items whose | |
| 45 | /// symbol name is a runtime symbol expected by `core`. | |
| 46 | /// | |
| 47 | /// ### Example | |
| 48 | /// | |
| 49 | /// ```rust,no_run,standalone_crate | |
| 50 | #[cfg_attr(not(bootstrap), doc = "#[unsafe(no_mangle)]")] | |
| 51 | /// pub extern "C" fn strlen(ptr: *mut f32) -> usize { 0 } | |
| 52 | /// // suspicious definition of the `strlen` function | |
| 53 | /// // `ptr` should be `*const std::ffi::c_char` | |
| 54 | /// ``` | |
| 55 | /// | |
| 56 | /// {{produces}} | |
| 57 | /// | |
| 58 | /// ### Explanation | |
| 59 | /// | |
| 60 | /// Up-most care is required when defining runtime symbols assumed and | |
| 61 | /// used by the standard library. They must follow the C specification, not use any | |
| 62 | /// standard-library facility or undefined behavior may occur. | |
| 63 | /// | |
| 64 | /// The symbols currently checked are `memcpy`, `memmove`, `memset`, `memcmp`, | |
| 65 | /// `bcmp` and `strlen`. | |
| 66 | /// | |
| 67 | /// [^1]: https://doc.rust-lang.org/core/index.html#how-to-use-the-core-library | |
| 68 | pub SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS, | |
| 69 | Warn, | |
| 70 | "suspicious definition of a symbol used by the standard library" | |
| 71 | } | |
| 72 | ||
| 73 | declare_lint_pass!(RuntimeSymbols => [INVALID_RUNTIME_SYMBOL_DEFINITIONS, SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS]); | |
| 74 | ||
| 75 | static EXPECTED_SYMBOLS: &[ExpectedSymbol] = &[ | |
| 76 | ExpectedSymbol { symbol: "memcpy", lang: LanguageItems::memcpy_fn }, | |
| 77 | ExpectedSymbol { symbol: "memmove", lang: LanguageItems::memmove_fn }, | |
| 78 | ExpectedSymbol { symbol: "memset", lang: LanguageItems::memset_fn }, | |
| 79 | ExpectedSymbol { symbol: "memcmp", lang: LanguageItems::memcmp_fn }, | |
| 80 | ExpectedSymbol { symbol: "bcmp", lang: LanguageItems::bcmp_fn }, | |
| 81 | ExpectedSymbol { symbol: "strlen", lang: LanguageItems::strlen_fn }, | |
| 82 | ]; | |
| 83 | ||
| 84 | #[derive(Copy, Clone, Debug)] | |
| 85 | struct ExpectedSymbol { | |
| 86 | symbol: &'static str, | |
| 87 | lang: fn(&LanguageItems) -> Option<DefId>, | |
| 88 | } | |
| 89 | ||
| 90 | impl<'tcx> LateLintPass<'tcx> for RuntimeSymbols { | |
| 91 | fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { | |
| 92 | // Bail-out if the item is not a function/method or static. | |
| 93 | match item.kind { | |
| 94 | hir::ItemKind::Fn { sig, ident: _, generics, body: _, has_body: _ } => { | |
| 95 | // Generic functions cannot have the same runtime symbol as we do not allow | |
| 96 | // any symbol attributes. | |
| 97 | if !generics.params.is_empty() { | |
| 98 | return; | |
| 99 | } | |
| 100 | ||
| 101 | // Try to get the overridden symbol name of this function (our mangling | |
| 102 | // cannot ever conflict with runtime symbols, so no need to check for those). | |
| 103 | let Some(symbol_name) = rustc_symbol_mangling::symbol_name_from_attrs( | |
| 104 | cx.tcx, | |
| 105 | rustc_middle::ty::InstanceKind::Item(item.owner_id.to_def_id()), | |
| 106 | ) else { | |
| 107 | return; | |
| 108 | }; | |
| 109 | ||
| 110 | check_fn(cx, &symbol_name, sig, item.owner_id.def_id); | |
| 111 | } | |
| 112 | hir::ItemKind::Static(..) => { | |
| 113 | // Compute the symbol name of this static (without mangling, as our mangling | |
| 114 | // cannot ever conflict with runtime symbols). | |
| 115 | let Some(symbol_name) = rustc_symbol_mangling::symbol_name_from_attrs( | |
| 116 | cx.tcx, | |
| 117 | rustc_middle::ty::InstanceKind::Item(item.owner_id.to_def_id()), | |
| 118 | ) else { | |
| 119 | return; | |
| 120 | }; | |
| 121 | ||
| 122 | let def_id = item.owner_id.def_id; | |
| 123 | ||
| 124 | check_static(cx, &symbol_name, def_id, item.span); | |
| 125 | } | |
| 126 | hir::ItemKind::ForeignMod { abi: _, items } => { | |
| 127 | for item in items { | |
| 128 | let item = cx.tcx.hir_foreign_item(*item); | |
| 129 | ||
| 130 | let did = item.owner_id.def_id; | |
| 131 | let instance = Instance::new_raw( | |
| 132 | did.to_def_id(), | |
| 133 | ty::List::identity_for_item(cx.tcx, did), | |
| 134 | ); | |
| 135 | let symbol_name = cx.tcx.symbol_name(instance); | |
| 136 | ||
| 137 | match item.kind { | |
| 138 | ForeignItemKind::Fn(fn_sig, _idents, _generics) => { | |
| 139 | check_fn(cx, &symbol_name.name, fn_sig, did); | |
| 140 | } | |
| 141 | ForeignItemKind::Static(..) => { | |
| 142 | check_static(cx, &symbol_name.name, did, item.span); | |
| 143 | } | |
| 144 | ForeignItemKind::Type => return, | |
| 145 | } | |
| 146 | } | |
| 147 | } | |
| 148 | _ => return, | |
| 149 | } | |
| 150 | } | |
| 151 | } | |
| 152 | ||
| 153 | fn check_fn(cx: &LateContext<'_>, symbol_name: &str, sig: FnSig<'_>, did: LocalDefId) { | |
| 154 | let Some(expected_symbol) = EXPECTED_SYMBOLS.iter().find(|es| es.symbol == symbol_name) else { | |
| 155 | // The symbol name does not correspond to a runtime symbols, bail out | |
| 156 | return; | |
| 157 | }; | |
| 158 | ||
| 159 | let Some(expected_def_id) = (expected_symbol.lang)(&cx.tcx.lang_items()) else { | |
| 160 | // Can't find the corresponding language item, bail out | |
| 161 | return; | |
| 162 | }; | |
| 163 | ||
| 164 | // Get the two function signatures | |
| 165 | let lang_sig = cx.tcx.normalize_erasing_regions( | |
| 166 | cx.typing_env(), | |
| 167 | cx.tcx.fn_sig(expected_def_id).instantiate_identity(), | |
| 168 | ); | |
| 169 | let user_sig = cx | |
| 170 | .tcx | |
| 171 | .normalize_erasing_regions(cx.typing_env(), cx.tcx.fn_sig(did).instantiate_identity()); | |
| 172 | ||
| 173 | // Compare the two signatures with an inference context | |
| 174 | let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); | |
| 175 | let cause = rustc_middle::traits::ObligationCause::misc(sig.span, did); | |
| 176 | let result = infcx.at(&cause, cx.param_env).eq(DefineOpaqueTypes::No, lang_sig, user_sig); | |
| 177 | ||
| 178 | // If they don't match, emit our own mismatch signatures | |
| 179 | if let Err(_terr) = result { | |
| 180 | // Create fn pointers for diagnostics purpose | |
| 181 | let expected = Ty::new_fn_ptr(cx.tcx, lang_sig); | |
| 182 | let actual = Ty::new_fn_ptr(cx.tcx, user_sig); | |
| 183 | ||
| 184 | if lang_sig.abi() != user_sig.abi() | |
| 185 | || lang_sig.c_variadic() != user_sig.c_variadic() | |
| 186 | || lang_sig.inputs().skip_binder().len() != user_sig.inputs().skip_binder().len() | |
| 187 | || (!lang_sig.output().skip_binder().is_unit() | |
| 188 | && user_sig.output().skip_binder().is_unit()) | |
| 189 | { | |
| 190 | cx.emit_span_lint( | |
| 191 | INVALID_RUNTIME_SYMBOL_DEFINITIONS, | |
| 192 | sig.span, | |
| 193 | RedefiningRuntimeSymbolsDiag::FnDefInvalid { | |
| 194 | symbol_name: symbol_name.to_string(), | |
| 195 | found_fn_sig: actual, | |
| 196 | expected_fn_sig: expected, | |
| 197 | }, | |
| 198 | ); | |
| 199 | } else { | |
| 200 | cx.emit_span_lint( | |
| 201 | SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS, | |
| 202 | sig.span, | |
| 203 | RedefiningRuntimeSymbolsDiag::FnDefSuspicious { | |
| 204 | symbol_name: symbol_name.to_string(), | |
| 205 | found_fn_sig: actual, | |
| 206 | expected_fn_sig: expected, | |
| 207 | }, | |
| 208 | ); | |
| 209 | }; | |
| 210 | } | |
| 211 | } | |
| 212 | ||
| 213 | fn check_static<'tcx>(cx: &LateContext<'tcx>, symbol_name: &str, did: LocalDefId, sp: Span) { | |
| 214 | let Some(expected_symbol) = EXPECTED_SYMBOLS.iter().find(|es| es.symbol == symbol_name) else { | |
| 215 | // The symbol name does not correspond to a runtime symbols, bail out | |
| 216 | return; | |
| 217 | }; | |
| 218 | ||
| 219 | let Some(expected_def_id) = (expected_symbol.lang)(&cx.tcx.lang_items()) else { | |
| 220 | // Can't find the corresponding language item, bail out | |
| 221 | return; | |
| 222 | }; | |
| 223 | ||
| 224 | // Get the static type | |
| 225 | let static_ty = cx.tcx.type_of(did).instantiate_identity().skip_norm_wip(); | |
| 226 | ||
| 227 | // Peel Option<...> and get the inner type (see std weak! macro with #[linkage = "extern_weak"]) | |
| 228 | let inner_static_ty: Ty<'_> = match static_ty.kind() { | |
| 229 | ty::Adt(def, args) if Some(def.did()) == cx.tcx.lang_items().option_type() => { | |
| 230 | args.type_at(0) | |
| 231 | } | |
| 232 | _ => static_ty, | |
| 233 | }; | |
| 234 | ||
| 235 | // Get the expected symbol function signature | |
| 236 | let lang_sig = cx.tcx.normalize_erasing_regions( | |
| 237 | cx.typing_env(), | |
| 238 | cx.tcx.fn_sig(expected_def_id).instantiate_identity(), | |
| 239 | ); | |
| 240 | ||
| 241 | let expected = Ty::new_fn_ptr(cx.tcx, lang_sig); | |
| 242 | ||
| 243 | // Compare the expected function signature with the static type, report an error if they don't match | |
| 244 | if expected != inner_static_ty { | |
| 245 | cx.emit_span_lint( | |
| 246 | INVALID_RUNTIME_SYMBOL_DEFINITIONS, | |
| 247 | sp, | |
| 248 | RedefiningRuntimeSymbolsDiag::Static { | |
| 249 | static_ty, | |
| 250 | symbol_name: symbol_name.to_string(), | |
| 251 | expected_fn_sig: expected, | |
| 252 | }, | |
| 253 | ); | |
| 254 | } | |
| 255 | } |
compiler/rustc_passes/src/lang_items.rs+39-9| ... | ... | @@ -27,6 +27,11 @@ pub(crate) enum Duplicate { |
| 27 | 27 | CrateDepends, |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | enum CollectWeak { | |
| 31 | Allowed, | |
| 32 | Ignore, | |
| 33 | } | |
| 34 | ||
| 30 | 35 | struct LanguageItemCollector<'ast, 'tcx> { |
| 31 | 36 | items: LanguageItems, |
| 32 | 37 | tcx: TyCtxt<'tcx>, |
| ... | ... | @@ -58,6 +63,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { |
| 58 | 63 | attrs: &'ast [ast::Attribute], |
| 59 | 64 | item_span: Span, |
| 60 | 65 | generics: Option<&'ast ast::Generics>, |
| 66 | collect_weak: CollectWeak, | |
| 61 | 67 | ) { |
| 62 | 68 | if let Some((name, attr_span)) = extract_ast(attrs) { |
| 63 | 69 | match LangItem::from_name(name) { |
| ... | ... | @@ -69,14 +75,18 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { |
| 69 | 75 | .delayed_bug("lang item target is checked in attribute parser"); |
| 70 | 76 | return; |
| 71 | 77 | } |
| 72 | self.collect_item_extended( | |
| 73 | lang_item, | |
| 74 | def_id, | |
| 75 | item_span, | |
| 76 | attr_span, | |
| 77 | generics, | |
| 78 | actual_target, | |
| 79 | ); | |
| 78 | // Weak lang items are handled separately | |
| 79 | // Weak only lang items are always handled here | |
| 80 | if !lang_item.is_weak() || matches!(collect_weak, CollectWeak::Allowed) { | |
| 81 | self.collect_item_extended( | |
| 82 | lang_item, | |
| 83 | def_id, | |
| 84 | item_span, | |
| 85 | attr_span, | |
| 86 | generics, | |
| 87 | actual_target, | |
| 88 | ); | |
| 89 | } | |
| 80 | 90 | } |
| 81 | 91 | // Unknown lang item. |
| 82 | 92 | _ => { |
| ... | ... | @@ -295,6 +305,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { |
| 295 | 305 | &i.attrs, |
| 296 | 306 | i.span, |
| 297 | 307 | i.opt_generics(), |
| 308 | CollectWeak::Allowed, | |
| 298 | 309 | ); |
| 299 | 310 | |
| 300 | 311 | let parent_item = self.parent_item.replace(i); |
| ... | ... | @@ -302,6 +313,17 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { |
| 302 | 313 | self.parent_item = parent_item; |
| 303 | 314 | } |
| 304 | 315 | |
| 316 | fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) { | |
| 317 | self.check_for_lang( | |
| 318 | Target::Fn, | |
| 319 | self.resolver.owners[&i.id].def_id, | |
| 320 | &i.attrs, | |
| 321 | i.span, | |
| 322 | None, | |
| 323 | CollectWeak::Ignore, | |
| 324 | ); | |
| 325 | } | |
| 326 | ||
| 305 | 327 | fn visit_variant(&mut self, variant: &'ast ast::Variant) { |
| 306 | 328 | self.check_for_lang( |
| 307 | 329 | Target::Variant, |
| ... | ... | @@ -309,6 +331,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { |
| 309 | 331 | &variant.attrs, |
| 310 | 332 | variant.span, |
| 311 | 333 | None, |
| 334 | CollectWeak::Allowed, | |
| 312 | 335 | ); |
| 313 | 336 | } |
| 314 | 337 | |
| ... | ... | @@ -342,7 +365,14 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { |
| 342 | 365 | } |
| 343 | 366 | }; |
| 344 | 367 | |
| 345 | self.check_for_lang(target, self.resolver.owners[&i.id].def_id, &i.attrs, i.span, generics); | |
| 368 | self.check_for_lang( | |
| 369 | target, | |
| 370 | self.resolver.owners[&i.id].def_id, | |
| 371 | &i.attrs, | |
| 372 | i.span, | |
| 373 | generics, | |
| 374 | CollectWeak::Allowed, | |
| 375 | ); | |
| 346 | 376 | |
| 347 | 377 | visit::walk_assoc_item(self, i, ctxt); |
| 348 | 378 | } |
compiler/rustc_span/src/symbol.rs+6| ... | ... | @@ -515,6 +515,7 @@ symbols! { |
| 515 | 515 | await_macro, |
| 516 | 516 | backchain, |
| 517 | 517 | backend_repr, |
| 518 | bcmp_fn, | |
| 518 | 519 | begin_panic, |
| 519 | 520 | bench, |
| 520 | 521 | bevy_ecs, |
| ... | ... | @@ -1280,7 +1281,11 @@ symbols! { |
| 1280 | 1281 | mem_variant_count, |
| 1281 | 1282 | mem_zeroed, |
| 1282 | 1283 | member_constraints, |
| 1284 | memcmp_fn, | |
| 1285 | memcpy_fn, | |
| 1286 | memmove_fn, | |
| 1283 | 1287 | memory, |
| 1288 | memset_fn, | |
| 1284 | 1289 | memtag, |
| 1285 | 1290 | message, |
| 1286 | 1291 | meta, |
| ... | ... | @@ -2036,6 +2041,7 @@ symbols! { |
| 2036 | 2041 | strict_provenance_lints, |
| 2037 | 2042 | string_deref_patterns, |
| 2038 | 2043 | stringify, |
| 2044 | strlen_fn, | |
| 2039 | 2045 | struct_field_attributes, |
| 2040 | 2046 | struct_inherit, |
| 2041 | 2047 | struct_variant, |
compiler/rustc_symbol_mangling/src/lib.rs+30-17| ... | ... | @@ -92,7 +92,7 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; |
| 92 | 92 | use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; |
| 93 | 93 | use rustc_middle::mono::{InstantiationMode, MonoItem}; |
| 94 | 94 | use rustc_middle::query::Providers; |
| 95 | use rustc_middle::ty::{self, Instance, TyCtxt}; | |
| 95 | use rustc_middle::ty::{self, Instance, InstanceKind, TyCtxt}; | |
| 96 | 96 | use rustc_session::config::SymbolManglingVersion; |
| 97 | 97 | use tracing::debug; |
| 98 | 98 | |
| ... | ... | @@ -149,29 +149,22 @@ pub fn typeid_for_trait_ref<'tcx>( |
| 149 | 149 | v0::mangle_typeid_for_trait_ref(tcx, trait_ref) |
| 150 | 150 | } |
| 151 | 151 | |
| 152 | /// Computes the symbol name for the given instance. This function will call | |
| 153 | /// `compute_instantiating_crate` if it needs to factor the instantiating crate | |
| 154 | /// into the symbol name. | |
| 155 | fn compute_symbol_name<'tcx>( | |
| 152 | pub fn symbol_name_from_attrs<'tcx>( | |
| 156 | 153 | tcx: TyCtxt<'tcx>, |
| 157 | instance: Instance<'tcx>, | |
| 158 | compute_instantiating_crate: impl FnOnce() -> CrateNum, | |
| 159 | ) -> String { | |
| 160 | let def_id = instance.def_id(); | |
| 161 | let args = instance.args; | |
| 162 | ||
| 163 | debug!("symbol_name(def_id={:?}, args={:?})", def_id, args); | |
| 154 | instance_kind: InstanceKind<'tcx>, | |
| 155 | ) -> Option<String> { | |
| 156 | let def_id = instance_kind.def_id(); | |
| 164 | 157 | |
| 165 | 158 | if let Some(def_id) = def_id.as_local() { |
| 166 | 159 | if tcx.proc_macro_decls_static(()) == Some(def_id) { |
| 167 | 160 | let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE); |
| 168 | return rustc_session::generate_proc_macro_decls_symbol(stable_crate_id); | |
| 161 | return Some(rustc_session::generate_proc_macro_decls_symbol(stable_crate_id)); | |
| 169 | 162 | } |
| 170 | 163 | } |
| 171 | 164 | |
| 172 | 165 | // FIXME(eddyb) Precompute a custom symbol name based on attributes. |
| 173 | 166 | let attrs = if tcx.def_kind(def_id).has_codegen_attrs() { |
| 174 | &tcx.codegen_instance_attrs(instance.def) | |
| 167 | &tcx.codegen_instance_attrs(instance_kind) | |
| 175 | 168 | } else { |
| 176 | 169 | CodegenFnAttrs::EMPTY |
| 177 | 170 | }; |
| ... | ... | @@ -197,7 +190,7 @@ fn compute_symbol_name<'tcx>( |
| 197 | 190 | // legacy symbol mangling scheme. |
| 198 | 191 | let name = if let Some(name) = attrs.symbol_name { name } else { tcx.item_name(def_id) }; |
| 199 | 192 | |
| 200 | return v0::mangle_internal_symbol(tcx, name.as_str()); | |
| 193 | return Some(v0::mangle_internal_symbol(tcx, name.as_str())); | |
| 201 | 194 | } |
| 202 | 195 | |
| 203 | 196 | let wasm_import_module_exception_force_mangling = { |
| ... | ... | @@ -225,15 +218,35 @@ fn compute_symbol_name<'tcx>( |
| 225 | 218 | if !wasm_import_module_exception_force_mangling { |
| 226 | 219 | if let Some(name) = attrs.symbol_name { |
| 227 | 220 | // Use provided name |
| 228 | return name.to_string(); | |
| 221 | return Some(name.to_string()); | |
| 229 | 222 | } |
| 230 | 223 | |
| 231 | 224 | if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { |
| 232 | 225 | // Don't mangle |
| 233 | return tcx.item_name(def_id).to_string(); | |
| 226 | return Some(tcx.item_name(def_id).to_string()); | |
| 234 | 227 | } |
| 235 | 228 | } |
| 236 | 229 | |
| 230 | None | |
| 231 | } | |
| 232 | ||
| 233 | /// Computes the symbol name for the given instance. This function will call | |
| 234 | /// `compute_instantiating_crate` if it needs to factor the instantiating crate | |
| 235 | /// into the symbol name. | |
| 236 | fn compute_symbol_name<'tcx>( | |
| 237 | tcx: TyCtxt<'tcx>, | |
| 238 | instance: Instance<'tcx>, | |
| 239 | compute_instantiating_crate: impl FnOnce() -> CrateNum, | |
| 240 | ) -> String { | |
| 241 | let def_id = instance.def_id(); | |
| 242 | let args = instance.args; | |
| 243 | ||
| 244 | debug!("symbol_name(def_id={:?}, args={:?})", def_id, args); | |
| 245 | ||
| 246 | if let Some(symbol) = symbol_name_from_attrs(tcx, instance.def) { | |
| 247 | return symbol; | |
| 248 | } | |
| 249 | ||
| 237 | 250 | // If we're dealing with an instance of a function that's inlined from |
| 238 | 251 | // another crate but we're marking it as globally shared to our |
| 239 | 252 | // compilation (aka we're not making an internal copy in each of our |
library/compiler-builtins/compiler-builtins/src/arm.rs+50-14| ... | ... | @@ -84,7 +84,11 @@ intrinsics! { |
| 84 | 84 | /// |
| 85 | 85 | /// Usual `memcpy` requirements apply. |
| 86 | 86 | #[cfg(not(target_vendor = "apple"))] |
| 87 | pub unsafe extern "aapcs" fn __aeabi_memcpy(dst: *mut u8, src: *const u8, n: usize) { | |
| 87 | pub unsafe extern "aapcs" fn __aeabi_memcpy( | |
| 88 | dst: *mut core::ffi::c_void, | |
| 89 | src: *const core::ffi::c_void, | |
| 90 | n: usize | |
| 91 | ) { | |
| 88 | 92 | // SAFETY: memcpy preconditions apply. |
| 89 | 93 | unsafe { crate::mem::memcpy(dst, src, n) }; |
| 90 | 94 | } |
| ... | ... | @@ -96,7 +100,11 @@ intrinsics! { |
| 96 | 100 | /// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to |
| 97 | 101 | /// four bytes. |
| 98 | 102 | #[cfg(not(target_vendor = "apple"))] |
| 99 | pub unsafe extern "aapcs" fn __aeabi_memcpy4(dst: *mut u8, src: *const u8, n: usize) { | |
| 103 | pub unsafe extern "aapcs" fn __aeabi_memcpy4( | |
| 104 | dst: *mut core::ffi::c_void, | |
| 105 | src: *const core::ffi::c_void, | |
| 106 | n: usize | |
| 107 | ) { | |
| 100 | 108 | // We are guaranteed 4-alignment, so accessing at u32 is okay. |
| 101 | 109 | let mut dst = dst.cast::<u32>(); |
| 102 | 110 | let mut src = src.cast::<u32>(); |
| ... | ... | @@ -121,7 +129,7 @@ intrinsics! { |
| 121 | 129 | } |
| 122 | 130 | |
| 123 | 131 | // SAFETY: `dst` and `src` will still be valid for `n` bytes |
| 124 | unsafe { __aeabi_memcpy(dst.cast::<u8>(), src.cast::<u8>(), n) }; | |
| 132 | unsafe { __aeabi_memcpy(dst.cast::<core::ffi::c_void>(), src.cast::<core::ffi::c_void>(), n) }; | |
| 125 | 133 | } |
| 126 | 134 | |
| 127 | 135 | /// `memcpy` for 8-byte alignment. |
| ... | ... | @@ -131,7 +139,11 @@ intrinsics! { |
| 131 | 139 | /// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to |
| 132 | 140 | /// eight bytes. |
| 133 | 141 | #[cfg(not(target_vendor = "apple"))] |
| 134 | pub unsafe extern "aapcs" fn __aeabi_memcpy8(dst: *mut u8, src: *const u8, n: usize) { | |
| 142 | pub unsafe extern "aapcs" fn __aeabi_memcpy8( | |
| 143 | dst: *mut core::ffi::c_void, | |
| 144 | src: *const core::ffi::c_void, | |
| 145 | n: usize | |
| 146 | ) { | |
| 135 | 147 | debug_assert!(dst.addr().is_multiple_of(8)); |
| 136 | 148 | debug_assert!(src.addr().is_multiple_of(8)); |
| 137 | 149 | |
| ... | ... | @@ -145,7 +157,11 @@ intrinsics! { |
| 145 | 157 | /// |
| 146 | 158 | /// Usual `memmove` requirements apply. |
| 147 | 159 | #[cfg(not(target_vendor = "apple"))] |
| 148 | pub unsafe extern "aapcs" fn __aeabi_memmove(dst: *mut u8, src: *const u8, n: usize) { | |
| 160 | pub unsafe extern "aapcs" fn __aeabi_memmove( | |
| 161 | dst: *mut core::ffi::c_void, | |
| 162 | src: *const core::ffi::c_void, | |
| 163 | n: usize | |
| 164 | ) { | |
| 149 | 165 | // SAFETY: memmove preconditions apply. |
| 150 | 166 | unsafe { crate::mem::memmove(dst, src, n) }; |
| 151 | 167 | } |
| ... | ... | @@ -157,7 +173,11 @@ intrinsics! { |
| 157 | 173 | /// Usual `memmove` requirements apply. Additionally, `dest` and `src` must be aligned to |
| 158 | 174 | /// four bytes. |
| 159 | 175 | #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] |
| 160 | pub unsafe extern "aapcs" fn __aeabi_memmove4(dst: *mut u8, src: *const u8, n: usize) { | |
| 176 | pub unsafe extern "aapcs" fn __aeabi_memmove4( | |
| 177 | dst: *mut core::ffi::c_void, | |
| 178 | src: *const core::ffi::c_void, | |
| 179 | n: usize | |
| 180 | ) { | |
| 161 | 181 | debug_assert!(dst.addr().is_multiple_of(4)); |
| 162 | 182 | debug_assert!(src.addr().is_multiple_of(4)); |
| 163 | 183 | |
| ... | ... | @@ -172,7 +192,11 @@ intrinsics! { |
| 172 | 192 | /// Usual `memmove` requirements apply. Additionally, `dst` and `src` must be aligned to |
| 173 | 193 | /// eight bytes. |
| 174 | 194 | #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] |
| 175 | pub unsafe extern "aapcs" fn __aeabi_memmove8(dst: *mut u8, src: *const u8, n: usize) { | |
| 195 | pub unsafe extern "aapcs" fn __aeabi_memmove8( | |
| 196 | dst: *mut core::ffi::c_void, | |
| 197 | src: *const core::ffi::c_void, | |
| 198 | n: usize | |
| 199 | ) { | |
| 176 | 200 | debug_assert!(dst.addr().is_multiple_of(8)); |
| 177 | 201 | debug_assert!(src.addr().is_multiple_of(8)); |
| 178 | 202 | |
| ... | ... | @@ -186,7 +210,11 @@ intrinsics! { |
| 186 | 210 | /// |
| 187 | 211 | /// Usual `memset` requirements apply. |
| 188 | 212 | #[cfg(not(target_vendor = "apple"))] |
| 189 | pub unsafe extern "aapcs" fn __aeabi_memset(dst: *mut u8, n: usize, c: i32) { | |
| 213 | pub unsafe extern "aapcs" fn __aeabi_memset( | |
| 214 | dst: *mut core::ffi::c_void, | |
| 215 | n: usize, | |
| 216 | c: i32 | |
| 217 | ) { | |
| 190 | 218 | // Note the different argument order |
| 191 | 219 | // SAFETY: memset preconditions apply. |
| 192 | 220 | unsafe { crate::mem::memset(dst, c, n) }; |
| ... | ... | @@ -199,7 +227,11 @@ intrinsics! { |
| 199 | 227 | /// Usual `memset` requirements apply. Additionally, `dest` and `src` must be aligned to |
| 200 | 228 | /// four bytes. |
| 201 | 229 | #[cfg(not(target_vendor = "apple"))] |
| 202 | pub unsafe extern "aapcs" fn __aeabi_memset4(dst: *mut u8, n: usize, c: i32) { | |
| 230 | pub unsafe extern "aapcs" fn __aeabi_memset4( | |
| 231 | dst: *mut core::ffi::c_void, | |
| 232 | n: usize, | |
| 233 | c: i32 | |
| 234 | ) { | |
| 203 | 235 | let mut dst = dst.cast::<u32>(); |
| 204 | 236 | debug_assert!(dst.is_aligned()); |
| 205 | 237 | let mut n = n; |
| ... | ... | @@ -222,7 +254,7 @@ intrinsics! { |
| 222 | 254 | } |
| 223 | 255 | |
| 224 | 256 | // SAFETY: `dst` will still be valid for `n` bytes |
| 225 | unsafe { __aeabi_memset(dst.cast::<u8>(), n, byte as i32) }; | |
| 257 | unsafe { __aeabi_memset(dst.cast::<core::ffi::c_void>(), n, byte as i32) }; | |
| 226 | 258 | } |
| 227 | 259 | |
| 228 | 260 | /// `memset` for 8-byte alignment. |
| ... | ... | @@ -232,7 +264,11 @@ intrinsics! { |
| 232 | 264 | /// Usual `memset` requirements apply. Additionally, `dst` and `src` must be aligned to |
| 233 | 265 | /// eight bytes. |
| 234 | 266 | #[cfg(not(target_vendor = "apple"))] |
| 235 | pub unsafe extern "aapcs" fn __aeabi_memset8(dst: *mut u8, n: usize, c: i32) { | |
| 267 | pub unsafe extern "aapcs" fn __aeabi_memset8( | |
| 268 | dst: *mut core::ffi::c_void, | |
| 269 | n: usize, | |
| 270 | c: i32 | |
| 271 | ) { | |
| 236 | 272 | debug_assert!(dst.addr().is_multiple_of(8)); |
| 237 | 273 | |
| 238 | 274 | // SAFETY: memset preconditions apply, less strict alignment. |
| ... | ... | @@ -245,7 +281,7 @@ intrinsics! { |
| 245 | 281 | /// |
| 246 | 282 | /// Usual `memclr` requirements apply. |
| 247 | 283 | #[cfg(not(target_vendor = "apple"))] |
| 248 | pub unsafe extern "aapcs" fn __aeabi_memclr(dst: *mut u8, n: usize) { | |
| 284 | pub unsafe extern "aapcs" fn __aeabi_memclr(dst: *mut core::ffi::c_void, n: usize) { | |
| 249 | 285 | // SAFETY: memclr preconditions apply, less strict alignment. |
| 250 | 286 | unsafe { __aeabi_memset(dst, n, 0) }; |
| 251 | 287 | } |
| ... | ... | @@ -257,7 +293,7 @@ intrinsics! { |
| 257 | 293 | /// Usual `memclr` requirements apply. Additionally, `dest` and `src` must be aligned to |
| 258 | 294 | /// four bytes. |
| 259 | 295 | #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] |
| 260 | pub unsafe extern "aapcs" fn __aeabi_memclr4(dst: *mut u8, n: usize) { | |
| 296 | pub unsafe extern "aapcs" fn __aeabi_memclr4(dst: *mut core::ffi::c_void, n: usize) { | |
| 261 | 297 | debug_assert!(dst.addr().is_multiple_of(4)); |
| 262 | 298 | |
| 263 | 299 | // SAFETY: memclr preconditions apply, less strict alignment. |
| ... | ... | @@ -271,7 +307,7 @@ intrinsics! { |
| 271 | 307 | /// Usual `memclr` requirements apply. Additionally, `dst` and `src` must be aligned to |
| 272 | 308 | /// eight bytes. |
| 273 | 309 | #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] |
| 274 | pub unsafe extern "aapcs" fn __aeabi_memclr8(dst: *mut u8, n: usize) { | |
| 310 | pub unsafe extern "aapcs" fn __aeabi_memclr8(dst: *mut core::ffi::c_void, n: usize) { | |
| 275 | 311 | debug_assert!(dst.addr().is_multiple_of(8)); |
| 276 | 312 | |
| 277 | 313 | // SAFETY: memclr preconditions apply, less strict alignment. |
library/compiler-builtins/compiler-builtins/src/mem/mod.rs+30-10| ... | ... | @@ -9,37 +9,57 @@ mod impls; |
| 9 | 9 | |
| 10 | 10 | intrinsics! { |
| 11 | 11 | #[mem_builtin] |
| 12 | pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { | |
| 13 | impls::copy_forward(dest, src, n); | |
| 12 | pub unsafe extern "C" fn memcpy( | |
| 13 | dest: *mut core::ffi::c_void, | |
| 14 | src: *const core::ffi::c_void, | |
| 15 | n: usize | |
| 16 | ) -> *mut core::ffi::c_void { | |
| 17 | impls::copy_forward(dest.cast(), src.cast(), n); | |
| 14 | 18 | dest |
| 15 | 19 | } |
| 16 | 20 | |
| 17 | 21 | #[mem_builtin] |
| 18 | pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { | |
| 22 | pub unsafe extern "C" fn memmove( | |
| 23 | dest: *mut core::ffi::c_void, | |
| 24 | src: *const core::ffi::c_void, | |
| 25 | n: usize | |
| 26 | ) -> *mut core::ffi::c_void { | |
| 19 | 27 | let delta = (dest as usize).wrapping_sub(src as usize); |
| 20 | 28 | if delta >= n { |
| 21 | 29 | // We can copy forwards because either dest is far enough ahead of src, |
| 22 | 30 | // or src is ahead of dest (and delta overflowed). |
| 23 | impls::copy_forward(dest, src, n); | |
| 31 | impls::copy_forward(dest.cast(), src.cast(), n); | |
| 24 | 32 | } else { |
| 25 | impls::copy_backward(dest, src, n); | |
| 33 | impls::copy_backward(dest.cast(), src.cast(), n); | |
| 26 | 34 | } |
| 27 | 35 | dest |
| 28 | 36 | } |
| 29 | 37 | |
| 30 | 38 | #[mem_builtin] |
| 31 | pub unsafe extern "C" fn memset(s: *mut u8, c: core::ffi::c_int, n: usize) -> *mut u8 { | |
| 32 | impls::set_bytes(s, c as u8, n); | |
| 39 | pub unsafe extern "C" fn memset( | |
| 40 | s: *mut core::ffi::c_void, | |
| 41 | c: core::ffi::c_int, | |
| 42 | n: usize | |
| 43 | ) -> *mut core::ffi::c_void { | |
| 44 | impls::set_bytes(s.cast(), c as u8, n); | |
| 33 | 45 | s |
| 34 | 46 | } |
| 35 | 47 | |
| 36 | 48 | #[mem_builtin] |
| 37 | pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> core::ffi::c_int { | |
| 38 | impls::compare_bytes(s1, s2, n) | |
| 49 | pub unsafe extern "C" fn memcmp( | |
| 50 | s1: *const core::ffi::c_void, | |
| 51 | s2: *const core::ffi::c_void, | |
| 52 | n: usize | |
| 53 | ) -> core::ffi::c_int { | |
| 54 | impls::compare_bytes(s1.cast(), s2.cast(), n) | |
| 39 | 55 | } |
| 40 | 56 | |
| 41 | 57 | #[mem_builtin] |
| 42 | pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> core::ffi::c_int { | |
| 58 | pub unsafe extern "C" fn bcmp( | |
| 59 | s1: *const core::ffi::c_void, | |
| 60 | s2: *const core::ffi::c_void, | |
| 61 | n: usize | |
| 62 | ) -> core::ffi::c_int { | |
| 43 | 63 | memcmp(s1, s2, n) |
| 44 | 64 | } |
| 45 | 65 |
library/core/src/ffi/mod.rs+27| ... | ... | @@ -85,3 +85,30 @@ impl fmt::Debug for c_void { |
| 85 | 85 | )] |
| 86 | 86 | #[link(name = "/defaultlib:libcmt", modifiers = "+verbatim", cfg(target_feature = "crt-static"))] |
| 87 | 87 | unsafe extern "C" {} |
| 88 | ||
| 89 | // Used by rustc for checking the definitions of other function with the same symbol names | |
| 90 | // | |
| 91 | // See the `invalid_runtime_symbols_definitions` lint. | |
| 92 | mod runtime_symbols { | |
| 93 | use crate::ffi::{c_char, c_int, c_void}; | |
| 94 | ||
| 95 | unsafe extern "C" { | |
| 96 | #[lang = "memcpy_fn"] | |
| 97 | fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; | |
| 98 | ||
| 99 | #[lang = "memmove_fn"] | |
| 100 | fn memmove(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; | |
| 101 | ||
| 102 | #[lang = "memset_fn"] | |
| 103 | fn memset(s: *mut c_void, c: c_int, n: usize) -> *mut c_void; | |
| 104 | ||
| 105 | #[lang = "memcmp_fn"] | |
| 106 | fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int; | |
| 107 | ||
| 108 | #[lang = "bcmp_fn"] | |
| 109 | fn bcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int; | |
| 110 | ||
| 111 | #[lang = "strlen_fn"] | |
| 112 | fn strlen(s: *const c_char) -> usize; | |
| 113 | } | |
| 114 | } |
tests/codegen-llvm/no_builtins-at-crate.rs+4-2| ... | ... | @@ -3,11 +3,13 @@ |
| 3 | 3 | #![no_builtins] |
| 4 | 4 | #![crate_type = "lib"] |
| 5 | 5 | |
| 6 | use std::ffi::c_void; | |
| 7 | ||
| 6 | 8 | // CHECK: define |
| 7 | 9 | // CHECK-SAME: @__aeabi_memcpy |
| 8 | 10 | // CHECK-SAME: #0 |
| 9 | 11 | #[no_mangle] |
| 10 | pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usize) { | |
| 12 | pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut c_void, src: *const c_void, size: usize) { | |
| 11 | 13 | // CHECK: call |
| 12 | 14 | // CHECK-SAME: @memcpy( |
| 13 | 15 | memcpy(dest, src, size); |
| ... | ... | @@ -17,7 +19,7 @@ pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usi |
| 17 | 19 | // CHECK-SAME: @memcpy |
| 18 | 20 | // CHECK-SAME: #0 |
| 19 | 21 | extern "C" { |
| 20 | pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; | |
| 22 | pub fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; | |
| 21 | 23 | } |
| 22 | 24 | |
| 23 | 25 | // CHECK: attributes #0 |
tests/ui/foreign/foreign-int-types.rs+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | |
| 5 | 5 | mod xx { |
| 6 | 6 | extern "C" { |
| 7 | pub fn strlen(str: *const u8) -> usize; | |
| 7 | pub fn strlen2(str: *const u8) -> usize; | |
| 8 | 8 | pub fn foo(x: isize, y: usize); |
| 9 | 9 | } |
| 10 | 10 | } |
tests/ui/lint/runtime-symbols.rs created+95| ... | ... | @@ -0,0 +1,95 @@ |
| 1 | // This test checks the runtime symbols lint. | |
| 2 | ||
| 3 | //@ edition: 2021 | |
| 4 | //@ normalize-stderr: "\*const [iu]8" -> "*const U8" | |
| 5 | ||
| 6 | #![feature(c_variadic)] | |
| 7 | #![allow(clashing_extern_declarations)] // we are voluntarily testing different definitions | |
| 8 | ||
| 9 | use core::ffi::{c_char, c_int, c_void}; | |
| 10 | ||
| 11 | fn invalid() { | |
| 12 | #[no_mangle] | |
| 13 | pub fn memmove() {} | |
| 14 | //~^ ERROR invalid definition of the runtime `memmove` symbol | |
| 15 | ||
| 16 | extern "C" { | |
| 17 | pub fn memset(); | |
| 18 | //~^ ERROR invalid definition of the runtime `memset` symbol | |
| 19 | ||
| 20 | pub fn memcmp(); | |
| 21 | //~^ ERROR invalid definition of the runtime `memcmp` symbol | |
| 22 | } | |
| 23 | ||
| 24 | #[no_mangle] | |
| 25 | pub static strlen: () = (); | |
| 26 | //~^ ERROR invalid definition of the runtime `strlen` symbol | |
| 27 | ||
| 28 | // ABI mismatch: Rust ABI instead of C ABI | |
| 29 | #[no_mangle] | |
| 30 | pub fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void { | |
| 31 | dest | |
| 32 | } | |
| 33 | //~^^^ ERROR invalid definition of the runtime `memcpy` symbol | |
| 34 | ||
| 35 | // C-Variadic mismatch | |
| 36 | #[no_mangle] | |
| 37 | pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: usize, _: ...) -> c_int { | |
| 38 | 0 | |
| 39 | } | |
| 40 | //~^^^ ERROR invalid definition of the runtime `bcmp` symbol | |
| 41 | ||
| 42 | // Return type is missing | |
| 43 | #[export_name = "bcmp"] | |
| 44 | pub extern "C" fn bcmp_(s1: *const c_void, s2: *const c_void, n: usize) {} | |
| 45 | //~^ ERROR invalid definition of the runtime `bcmp` symbol | |
| 46 | } | |
| 47 | ||
| 48 | fn suspicious() { | |
| 49 | #[no_mangle] | |
| 50 | pub extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { | |
| 51 | std::ptr::null_mut() | |
| 52 | } | |
| 53 | //~^^^ WARN suspicious definition of the runtime `memcpy` symbol | |
| 54 | ||
| 55 | #[no_mangle] | |
| 56 | pub extern "C" fn memmove(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { | |
| 57 | std::ptr::null_mut() | |
| 58 | } | |
| 59 | //~^^^ WARN suspicious definition of the runtime `memmove` symbol | |
| 60 | ||
| 61 | extern "C" { | |
| 62 | fn memset(s: *mut c_void, c: c_int, n: usize) -> f64; | |
| 63 | //~^ WARN suspicious definition of the runtime `memset` symbol | |
| 64 | } | |
| 65 | ||
| 66 | #[export_name = "bcmp"] | |
| 67 | pub extern "C" fn bcmp_(s1: *const u8, s2: *const u8, n: usize) -> c_int { | |
| 68 | 0 | |
| 69 | } | |
| 70 | //~^^^ WARN suspicious definition of the runtime `bcmp` symbol | |
| 71 | ||
| 72 | #[no_mangle] | |
| 73 | pub extern "C" fn strlen(s: *const u64) -> usize { | |
| 74 | 0 | |
| 75 | } | |
| 76 | //~^^^ WARN suspicious definition of the runtime `strlen` symbol | |
| 77 | } | |
| 78 | ||
| 79 | fn valid() { | |
| 80 | extern "C" { | |
| 81 | fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; | |
| 82 | ||
| 83 | fn memmove(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; | |
| 84 | ||
| 85 | fn memset(s: *mut c_void, c: c_int, n: usize) -> *mut c_void; | |
| 86 | ||
| 87 | fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int; | |
| 88 | ||
| 89 | fn bcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int; | |
| 90 | ||
| 91 | static strlen: Option<unsafe extern "C" fn(s: *const c_char) -> usize>; | |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 95 | fn main() {} |
tests/ui/lint/runtime-symbols.stderr created+129| ... | ... | @@ -0,0 +1,129 @@ |
| 1 | error: invalid definition of the runtime `memmove` symbol used by the standard library | |
| 2 | --> $DIR/runtime-symbols.rs:13:5 | |
| 3 | | | |
| 4 | LL | pub fn memmove() {} | |
| 5 | | ^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: expected `unsafe extern "C" fn(*mut c_void, *const c_void, usize) -> *mut c_void` | |
| 8 | found `fn()` | |
| 9 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memmove")]`, or `#[link_name = "memmove"]` | |
| 10 | = note: `#[deny(invalid_runtime_symbol_definitions)]` on by default | |
| 11 | ||
| 12 | error: invalid definition of the runtime `memset` symbol used by the standard library | |
| 13 | --> $DIR/runtime-symbols.rs:17:9 | |
| 14 | | | |
| 15 | LL | pub fn memset(); | |
| 16 | | ^^^^^^^^^^^^^^^^ | |
| 17 | | | |
| 18 | = note: expected `unsafe extern "C" fn(*mut c_void, i32, usize) -> *mut c_void` | |
| 19 | found `unsafe extern "C" fn()` | |
| 20 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memset")]`, or `#[link_name = "memset"]` | |
| 21 | ||
| 22 | error: invalid definition of the runtime `memcmp` symbol used by the standard library | |
| 23 | --> $DIR/runtime-symbols.rs:20:9 | |
| 24 | | | |
| 25 | LL | pub fn memcmp(); | |
| 26 | | ^^^^^^^^^^^^^^^^ | |
| 27 | | | |
| 28 | = note: expected `unsafe extern "C" fn(*const c_void, *const c_void, usize) -> i32` | |
| 29 | found `unsafe extern "C" fn()` | |
| 30 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcmp")]`, or `#[link_name = "memcmp"]` | |
| 31 | ||
| 32 | error: invalid definition of the runtime `strlen` symbol used by the standard library | |
| 33 | --> $DIR/runtime-symbols.rs:25:5 | |
| 34 | | | |
| 35 | LL | pub static strlen: () = (); | |
| 36 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 37 | | | |
| 38 | = note: expected `unsafe extern "C" fn(*const U8) -> usize` | |
| 39 | found `static strlen: ()` | |
| 40 | = help: either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = "strlen")]` | |
| 41 | ||
| 42 | error: invalid definition of the runtime `memcpy` symbol used by the standard library | |
| 43 | --> $DIR/runtime-symbols.rs:30:5 | |
| 44 | | | |
| 45 | LL | pub fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void { | |
| 46 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 47 | | | |
| 48 | = note: expected `unsafe extern "C" fn(*mut c_void, *const c_void, usize) -> *mut c_void` | |
| 49 | found `fn(*mut c_void, *const c_void, usize) -> *mut c_void` | |
| 50 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcpy")]`, or `#[link_name = "memcpy"]` | |
| 51 | ||
| 52 | error: invalid definition of the runtime `bcmp` symbol used by the standard library | |
| 53 | --> $DIR/runtime-symbols.rs:37:5 | |
| 54 | | | |
| 55 | LL | pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: usize, _: ...) -> c_int { | |
| 56 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 57 | | | |
| 58 | = note: expected `unsafe extern "C" fn(*const c_void, *const c_void, usize) -> i32` | |
| 59 | found `unsafe extern "C" fn(*const c_void, *const c_void, usize, ...) -> i32` | |
| 60 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "bcmp")]`, or `#[link_name = "bcmp"]` | |
| 61 | ||
| 62 | error: invalid definition of the runtime `bcmp` symbol used by the standard library | |
| 63 | --> $DIR/runtime-symbols.rs:44:5 | |
| 64 | | | |
| 65 | LL | pub extern "C" fn bcmp_(s1: *const c_void, s2: *const c_void, n: usize) {} | |
| 66 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 67 | | | |
| 68 | = note: expected `unsafe extern "C" fn(*const c_void, *const c_void, usize) -> i32` | |
| 69 | found `extern "C" fn(*const c_void, *const c_void, usize)` | |
| 70 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "bcmp")]`, or `#[link_name = "bcmp"]` | |
| 71 | ||
| 72 | warning: suspicious definition of the runtime `memcpy` symbol used by the standard library | |
| 73 | --> $DIR/runtime-symbols.rs:50:5 | |
| 74 | | | |
| 75 | LL | pub extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { | |
| 76 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 77 | | | |
| 78 | = note: expected `unsafe extern "C" fn(*mut c_void, *const c_void, usize) -> *mut c_void` | |
| 79 | found `extern "C" fn(*mut c_void, *const c_void, i64) -> *mut c_void` | |
| 80 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcpy")]`, or `#[link_name = "memcpy"]` | |
| 81 | = help: allow this lint if the signature is compatible | |
| 82 | = note: `#[warn(suspicious_runtime_symbol_definitions)]` on by default | |
| 83 | ||
| 84 | warning: suspicious definition of the runtime `memmove` symbol used by the standard library | |
| 85 | --> $DIR/runtime-symbols.rs:56:5 | |
| 86 | | | |
| 87 | LL | pub extern "C" fn memmove(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { | |
| 88 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 89 | | | |
| 90 | = note: expected `unsafe extern "C" fn(*mut c_void, *const c_void, usize) -> *mut c_void` | |
| 91 | found `extern "C" fn(*mut c_void, *const c_void, i64) -> *mut c_void` | |
| 92 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memmove")]`, or `#[link_name = "memmove"]` | |
| 93 | = help: allow this lint if the signature is compatible | |
| 94 | ||
| 95 | warning: suspicious definition of the runtime `memset` symbol used by the standard library | |
| 96 | --> $DIR/runtime-symbols.rs:62:9 | |
| 97 | | | |
| 98 | LL | fn memset(s: *mut c_void, c: c_int, n: usize) -> f64; | |
| 99 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 100 | | | |
| 101 | = note: expected `unsafe extern "C" fn(*mut c_void, i32, usize) -> *mut c_void` | |
| 102 | found `unsafe extern "C" fn(*mut c_void, i32, usize) -> f64` | |
| 103 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memset")]`, or `#[link_name = "memset"]` | |
| 104 | = help: allow this lint if the signature is compatible | |
| 105 | ||
| 106 | warning: suspicious definition of the runtime `bcmp` symbol used by the standard library | |
| 107 | --> $DIR/runtime-symbols.rs:67:5 | |
| 108 | | | |
| 109 | LL | pub extern "C" fn bcmp_(s1: *const U8, s2: *const U8, n: usize) -> c_int { | |
| 110 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 111 | | | |
| 112 | = note: expected `unsafe extern "C" fn(*const c_void, *const c_void, usize) -> i32` | |
| 113 | found `extern "C" fn(*const U8, *const U8, usize) -> i32` | |
| 114 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "bcmp")]`, or `#[link_name = "bcmp"]` | |
| 115 | = help: allow this lint if the signature is compatible | |
| 116 | ||
| 117 | warning: suspicious definition of the runtime `strlen` symbol used by the standard library | |
| 118 | --> $DIR/runtime-symbols.rs:73:5 | |
| 119 | | | |
| 120 | LL | pub extern "C" fn strlen(s: *const u64) -> usize { | |
| 121 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 122 | | | |
| 123 | = note: expected `unsafe extern "C" fn(*const U8) -> usize` | |
| 124 | found `extern "C" fn(*const u64) -> usize` | |
| 125 | = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]` | |
| 126 | = help: allow this lint if the signature is compatible | |
| 127 | ||
| 128 | error: aborting due to 7 previous errors; 5 warnings emitted | |
| 129 |