-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cross-crate inlining breaks compare of functions passed between crates #117047
Comments
This may be related to rust-lang/unsafe-code-guidelines#239 but here are some points on this case:
|
This probably isn't a bug, but deserves some extra docs and maybe a lint. |
Agree, it's not a bug, but it really does look like one without a lint when it breaks in release.. // src/lib.rs
static INNER: fn() = inner;
fn inner() {}
pub fn create() -> fn() { INNER }
pub fn verify(value: fn()) { assert_eq!(value, INNER) } In this code we are using On the other hand, making |
As for a possible place to document such a thing I see Advanced Functions and Closures section of the book and I guess Items/Functions page of the reference |
Briefly looking at LLVM IR (
This seems reasonable, albeit a bit surprising |
One way to stop this surprising behavior might be to not inline functions that take address of other functions? Might be too strict though, forfeiting inlining just because somebody might want to compare function pointers doesn't seem reasonable |
Another way to stop this behavior is to not inline functions when their addresses are taken and only inline in case of a call. It is more complicated I guess but seems more sensible. There is no point in inlining a function that is referenced by address (because it needs to be separate) or duplicating it (it will be the same) |
I'm commenting here because I want to be helpful. I'm afraid that the way this issue leaves off without the comment I'm writing makes it sound like the compiler might be changed in order to preserve the previous behavior. I am glad to see that you promptly updated embassy in embassy-rs/embassy#2112. I do not expect anyone to implement the suggestions you both made; I'll admit I am not the most experienced compiler contributor but they both sound difficult/impossible for rustc-specific reasons. One problem is that "cross-crate-inlining" is not actual inlining, it is a change to the code generation strategy for a function. A function which is cross-crate-inlinable gets the behavior of The other problem is that cross-crate-inlinability is determined early in compilation, because it needs to inform whether other functions and static get internal or external linkage. A function which is cross-crate-inlinable exposes any static or function that it references. Since this whole process happens early, in rustc it happens before monomorphization. Disabling cross-crate-inlining for functions that reference other functions wouldn't just shut it off for all functions with a call, it would also turn it off for any function that takes the address of a generic which we can't prove is not a function. |
That's completely fair, I don't know that much about rustc, so my suggestions were more like guesses how I thought this could potentially be implemented. Thanks for taking time to point out why is this infeasible, it's definitely helpful For the problem at hand though, I guess this just means that we shouldn't rely on function address, which has been true already. Just that there's now more optimizations that can lead to problems. |
Would you consider this to be fixed by #120880? That adds a note on the |
Maybe also add a similar note to |
Oh you mean, because it has |
Yeah, this is how the issue has started: embassy compares AFAIU, what it does now is still not guaranteed to work, but replacing |
Rollup merge of rust-lang#120880 - RalfJung:vtable-fnptr-partialeq, r=cuviper add note on comparing vtables / function pointers Fixes rust-lang#99388 Fixes rust-lang#117047
This code panics when compiled with #116505 with cross-crate inlining being turned on:
cargo +nightly-2023-10-18 run --release
- okcargo +nightly-2023-10-19 run --release
- panicscargo +nightly-2023-10-19 run
- ok (opt-level = 2
incremental = false
to panic)It is clearly caused by #116505 because:
opt-level = 2
,incremental = false
and not-Zcross-crate-inline-threshold=0
(feature to be enabled)Ways to fix this minimal example:
create()
inline(never)
- probably this is not a root cause fix-Zcross-crate-inline-threshold=0
Originally I found this problem in Embassy (embedded framework using async). They are using such a comparison to ensure that passed
Waker
was created by the Embassy executor. In Embassy it is possible to fix it by either:from_task()
inline(never)
VTABLE
static
Meta
rustc +nightly --version --verbose
(bug still here):Precise versions (just skip, too much extra info)
rustup build - ok
custom build - ok
custom build - panics
rustup build - panics
Backtrace
Example more like in Embassy
The text was updated successfully, but these errors were encountered: