-
-
Notifications
You must be signed in to change notification settings - Fork 14.9k
#[no_mangle] is unsafe in the presence of name collisions #28179
Copy link
Copy link
Closed
Labels
A-linkageArea: linking into static, shared libraries and binariesArea: linking into static, shared libraries and binariesC-bugCategory: This is a bug.Category: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-lowLow priorityLow priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language teamRelevant to the language team
Metadata
Metadata
Assignees
Labels
A-linkageArea: linking into static, shared libraries and binariesArea: linking into static, shared libraries and binariesC-bugCategory: This is a bug.Category: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-lowLow priorityLow priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language teamRelevant to the language team
Type
Fields
Give feedbackNo fields configured for issues without a type.
On some platforms (at least GNU/Linux, but I hear Windows and several others too), if you link together two static libraries that both export a symbol of the same name, it's undefined which symbol actually gets linked. In practice on my machine, the first library seems to win. This lets you defeat type/memory safety without the
unsafekeyword, by having two crates export a#[no_mangle] pub fnwith different signatures but compatible calling conventions:Despite the stated call to
two::convert, it's actuallyone::convertthat gets called, which interprets the argument as a&'static i32. (It may be clearer to understand with this simpler example, which doesn't break type safety.)On at least GNU/Linux but not other platforms like Windows or Darwin, dynamically-linked symbols have the same ambiguity.
I don't know what the right response is here. The following options all seem pretty reasonable:
unsafekeyword.#[no_mangle]export both a mangled and un-mangled name, and have Rust crates call each other via mangled names only, on the grounds that#[no_mangle]is for external interfaces, not for crates linking to crates. ("External interfaces" includes other Rust code using FFI, but FFI is unsafe.) This is analogous to howextern "C" fns export both a Rust-ABI symbol as well as a C-ABI shim, and a direct, safe Rust call to those function happens through the Rust ABI, not through the C ABI. I'm pretty sure that all production uses of#[no_mangle]areextern "C", anyway (see e.g. Can't define unsafe extern "C" fn #10025).#[no_mangle]on safe functions and data, and introduce a new#[unsafe_no_mangle], so it substring-matchesunsafe. (#[no_mangle]on unsafe functions or mutable statics is fine, since you need theunsafekeyword to get at them.)All of these are, I think, backwards-compatible.