-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
ACCESS_VIOLATION when dereferencing once_cell::Lazy in closure with LTO #81408
Comments
The reproducer::CHANNEL symbol gets mislinked. Here's where the symbol's address gets loaded into the register: If you check what's at that address, you find it's the beginning of the binary that is loaded as read only into the RAM: which later segfaults as that is interpreted as the Lazy's internal AtomicUsize, at which point everything goes wrong: The +crt-static is not necessary btw. It's a problem involving the fact that there's multiple crates, rust-lld and thin-lto. |
@rustbot ping windows |
Hey Windows Group! This bug has been identified as a good "Windows candidate". cc @arlosi @danielframpton @gdr-at-ms @kennykerr @luqmana @lzybkr @nico-abram @retep998 @rylev @sivadeilra |
We think this warrants a Could be interesting checking since when we have this behaviour |
With nearly the same set-up ( windows-msvc, rust-lld, thinlto, but without +crt-static), I also experienced After seeing this issue, I swapped Rather than an access violation, the program panicked with the following
rust/library/std/src/sync/once.rs Lines 423 to 425 in 19dae7b
The following example minimizes the main.rs: fn main() {
example::run()();
} lib.rs:use std::{cell::Cell, marker::PhantomData, sync::Once};
static X: SyncLazy<()> = SyncLazy::new(|| ());
pub fn run() -> impl FnOnce() {
|| {
let _ = SyncLazy::force(&X);
}
}
struct SyncOnceCell<T> {
once: Once,
_phantom: PhantomData<T>,
}
impl<T> SyncOnceCell<T> {
const fn new() -> Self {
SyncOnceCell {
once: Once::new(),
_phantom: PhantomData,
}
}
fn get_or_init<F>(&self, _f: F) -> &T
where
F: FnOnce() -> T,
{
self.once.call_once(|| unimplemented!());
unimplemented!()
}
}
struct SyncLazy<T, F = fn() -> T> {
cell: SyncOnceCell<T>,
_init: Cell<Option<F>>,
}
unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {}
impl<T, F> SyncLazy<T, F> {
const fn new(f: F) -> Self {
SyncLazy {
cell: SyncOnceCell::new(),
_init: Cell::new(Some(f)),
}
}
fn force(this: &Self) -> &T {
this.cell.get_or_init(|| unimplemented!())
}
}
backtrace
meta
|
It looks like some variation of this issue was reported in #71504, but eventually went away. Guess some form of the issue returned, or this issue is finding another way to trigger the underlying issue. A similar set-up was required to trigger the access violation #71504 (comment) edit: I am able to produce // lib.rs
use std::sync::atomic::{AtomicPtr, Ordering};
#[inline(always)]
pub fn memrchr() {
fn detect() {}
static FN: AtomicPtr<()> = AtomicPtr::new(detect as *mut ());
unsafe {
let fun = FN.load(Ordering::SeqCst);
std::mem::transmute::<*mut (), fn()>(fun)()
}
}
// main.rs
fn main() {
badlld::memrchr();
} |
To avoid duplicated work: Is anyone working on a concise bug report for the LLVM project? |
That is unfortunately still an issue with LLD from LLVM 13. |
So, this LLVM issue definitively needs to be reported upstream along with an LLVM-IR reproducible. Seems that no on has yet owned this upstream bug report, so it's open for grab (and if you @hkratz want to own it, as suggested here please feel free to do so - thanks). @rustbot label -I-nominated |
- Disable thin LTO due to rust-lang/rust#81408 - Pin shaderc to 0.7.3 due to linker errors with newer version. - Update dependencies.
Bumping. It's this bug's one-year anniversary 🎉. I've tried to create a more minimal reproducer, but I don't have a whole lot of experience with LLVM stuff, so please forgive any blunders I might have made 😅 . The reproducer can be found here, and is essentially a reduction of this reproducer using The binary is very, very simple here. This is essentially the entire binary: At the bottom, we see the |
This still reproduces with lld 14.0.0 (and therefore the current nightly's |
It does not reproduce with |
ok, probably the situation has changed compared to this comment. @rustbot label -O-windows-msvc |
Oh sorry, I just put it in the wrong order 🤦🏻♂️ @rustbot label +O-windows-msvc -O-windows |
Has any progress been made here? We just ran into this issue too on rust 1.64. |
…r=michaelwoerister Fix Access Violation when using lld & ThinLTO on windows-msvc Users report an AV at runtime of the compiled binary when using lld and ThinLTO on windows-msvc. The AV occurs when accessing a static value which is defined in one crate but used in another. Based on the disassembly of the cross-crate use, it appears that the use is not correctly linked with the definition and is instead assigned a garbage pointer value. If we look at the symbol tables for each crates' obj file, we can see what is happening: *lib.obj*: ``` COFF SYMBOL TABLE ... 00E 00000000 SECT2 notype External | _ZN10reproducer7memrchr2FN17h612b61ca0e168901E ... ``` *bin.obj*: ``` COFF SYMBOL TABLE ... 010 00000000 UNDEF notype External | __imp__ZN10reproducer7memrchr2FN17h612b61ca0e168901E ... ``` The use of the symbol has the "import" style symbol name but the declaration doesn't generate any symbol with the same name. As a result, linking the files generates a warning from lld: > rust-lld: warning: bin.obj: locally defined symbol imported: reproducer::memrchr::FN::h612b61ca0e168901 (defined in lib.obj) [LNK4217] and the symbol reference remains undefined at runtime leading to the AV. To fix this, we just need to detect that we are performing ThinLTO (and thus, static linking) and omit the `dllimport` attribute on the extern item in LLVM IR. Fixes rust-lang#81408
…r=michaelwoerister Fix Access Violation when using lld & ThinLTO on windows-msvc Users report an AV at runtime of the compiled binary when using lld and ThinLTO on windows-msvc. The AV occurs when accessing a static value which is defined in one crate but used in another. Based on the disassembly of the cross-crate use, it appears that the use is not correctly linked with the definition and is instead assigned a garbage pointer value. If we look at the symbol tables for each crates' obj file, we can see what is happening: *lib.obj*: ``` COFF SYMBOL TABLE ... 00E 00000000 SECT2 notype External | _ZN10reproducer7memrchr2FN17h612b61ca0e168901E ... ``` *bin.obj*: ``` COFF SYMBOL TABLE ... 010 00000000 UNDEF notype External | __imp__ZN10reproducer7memrchr2FN17h612b61ca0e168901E ... ``` The use of the symbol has the "import" style symbol name but the declaration doesn't generate any symbol with the same name. As a result, linking the files generates a warning from lld: > rust-lld: warning: bin.obj: locally defined symbol imported: reproducer::memrchr::FN::h612b61ca0e168901 (defined in lib.obj) [LNK4217] and the symbol reference remains undefined at runtime leading to the AV. To fix this, we just need to detect that we are performing ThinLTO (and thus, static linking) and omit the `dllimport` attribute on the extern item in LLVM IR. Fixes rust-lang#81408
…r=michaelwoerister Fix Access Violation when using lld & ThinLTO on windows-msvc Users report an AV at runtime of the compiled binary when using lld and ThinLTO on windows-msvc. The AV occurs when accessing a static value which is defined in one crate but used in another. Based on the disassembly of the cross-crate use, it appears that the use is not correctly linked with the definition and is instead assigned a garbage pointer value. If we look at the symbol tables for each crates' obj file, we can see what is happening: *lib.obj*: ``` COFF SYMBOL TABLE ... 00E 00000000 SECT2 notype External | _ZN10reproducer7memrchr2FN17h612b61ca0e168901E ... ``` *bin.obj*: ``` COFF SYMBOL TABLE ... 010 00000000 UNDEF notype External | __imp__ZN10reproducer7memrchr2FN17h612b61ca0e168901E ... ``` The use of the symbol has the "import" style symbol name but the declaration doesn't generate any symbol with the same name. As a result, linking the files generates a warning from lld: > rust-lld: warning: bin.obj: locally defined symbol imported: reproducer::memrchr::FN::h612b61ca0e168901 (defined in lib.obj) [LNK4217] and the symbol reference remains undefined at runtime leading to the AV. To fix this, we just need to detect that we are performing ThinLTO (and thus, static linking) and omit the `dllimport` attribute on the extern item in LLVM IR. Fixes rust-lang#81408
I did some investigating on why ThinLTO is required to reproduce this. It turns out ThinLTO is not generating Another fix for this issue could be to also generate these for ThinLTO, though I don't know where these are generated. They don't appear in the LLVM bitcode at least. |
…wiser Create `_imp__` symbols also when doing ThinLTO When generating a rlib crate on Windows we create `dllimport` / `_imp__` symbols for each global. This effectively makes the rlib contain an import library for itself and allows them to both be dynamically and statically linked. However when doing ThinLTO we do not generate these and thus we end up with missing symbols. Microsoft's `link` can fix these up (and emits warnings), but `lld` seems to currently be unable to. This PR also does this generation for ThinLTO avoiding those issues with `lld` and also avoids the warnings on `link`. This is an workaround for rust-lang#81408. cc `@lqd`
Rollup merge of rust-lang#129079 - Zoxc:thinlto_imp_symbols, r=wesleywiser Create `_imp__` symbols also when doing ThinLTO When generating a rlib crate on Windows we create `dllimport` / `_imp__` symbols for each global. This effectively makes the rlib contain an import library for itself and allows them to both be dynamically and statically linked. However when doing ThinLTO we do not generate these and thus we end up with missing symbols. Microsoft's `link` can fix these up (and emits warnings), but `lld` seems to currently be unable to. This PR also does this generation for ThinLTO avoiding those issues with `lld` and also avoids the warnings on `link`. This is an workaround for rust-lang#81408. cc `@lqd`
The code in the following repository crashes with an ACCESS_VIOLATION on Windows: https://github.com/roblabla/reproduce-boom/
To reproduce, four things are needed:
EDIT: Better reproducer can be found here.
The main.rs file:
The lib.rs file:
Running
cargo run --release
will trigger the following output:This issue seems related to ThinLTO. It only occurs on windows.
Meta
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: