rust-analyser segfault with lto=thin, linker=lld-link

Created on 24 Apr 2020  路  20Comments  路  Source: rust-lang/rust

I was having fun compiling rust-analyser for maximizing performance on my machine.

Compiling commit ec645f2d75d2939a2f64959019dd916750f1ec00 of rust-analyser with lto=fat seems to work as expected.

But this configuration on windows:

[profile.release]
lto = "thin"
#incremental = true
debug = 0 # set this to 1 or 2 to get more useful backtraces in debugger

Result in rust-analyser segfaut:

Access violation executing location 0x0000000100785A4D.

Meta

rustc 1.43.0 (4fb7144ed 2020-04-20)
binary: rustc
commit-hash: 4fb7144ed159f94491249e86d5bbd033b5d60550
commit-date: 2020-04-20
host: x86_64-pc-windows-msvc
release: 1.43.0
LLVM version: 9.0

Backtrace

>   rust-analyzer.exe!_ZN7globset8pathutil9file_name17h08d0f1900ad67247E
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!_ZN7globset7GlobSet8is_match17hf1cf9a1f69ce8dd2E
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!_ZN77_$LT$rust_analyzer..vfs_glob..RustPackageFilter$u20$as$u20$ra_vfs..Filter$GT$11include_dir17ha6495721bf18fe0eE
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!_ZN6ra_vfs5roots16to_relative_path17hb9707874d497bdc4E
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!_ZN106_$LT$core..iter..adapters..chain..Chain$LT$A$C$B$GT$$u20$as$u20$core..iter..traits..iterator..Iterator$GT$8try_fold17hac44483bd652ee40E
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!_ZN108_$LT$walkdir..FilterEntry$LT$walkdir..IntoIter$C$P$GT$$u20$as$u20$core..iter..traits..iterator..Iterator$GT$4next17ha136f9b20c380477E
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!_ZN6ra_vfs2io13handle_change17h8a81e482afc2c09bE
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!_ZN6ra_vfs2io10watch_root17h425c73dcf2ce2dd1E
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17hb0fd61dddb6f5a20E.llvm.14564221459209632736
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!_ZN4core3mem4drop17hab46961f8567a42bE.llvm.1531302937598756963
()  Unknown Non-user code. Symbols loaded.
    rust-analyzer.exe!alloc::boxed::{{impl}}::call_once<(),FnOnce<()>>() Line 1017  Unknown Symbols loaded.
    [Inline Frame] rust-analyzer.exe!alloc::boxed::{{impl}}::call_once() Line 1017  Unknown Symbols loaded.
    [Inline Frame] rust-analyzer.exe!std::sys_common::thread::start_thread() Line 13    Unknown Symbols loaded.
    rust-analyzer.exe!std::sys::windows::thread::{{impl}}::new::thread_start() Line 51  Unknown Symbols loaded.

Frame 0 Assembly

_ZN7globset8pathutil9file_name17h08d0f1900ad67247E:
00007FF66A5D76B0  push        rbp  
00007FF66A5D76B1  push        r15  
00007FF66A5D76B3  push        r14  
00007FF66A5D76B5  push        r12  
00007FF66A5D76B7  push        rsi  
00007FF66A5D76B8  push        rdi  
00007FF66A5D76B9  push        rbx  
00007FF66A5D76BA  sub         rsp,60h  
00007FF66A5D76BE  lea         rbp,[rsp+60h]  
00007FF66A5D76C3  mov         qword ptr [rbp-8],0FFFFFFFFFFFFFFFEh  
00007FF66A5D76CB  mov         r12,rcx  
00007FF66A5D76CE  mov         rsi,qword ptr [rdx]  
00007FF66A5D76D1  mov         rdi,qword ptr [rdx+10h]  
00007FF66A5D76D5  cmp         rsi,1  
00007FF66A5D76D9  mov         rbx,qword ptr [rdx+18h]  
00007FF66A5D76DD  mov         r8,rdi  
00007FF66A5D76E0  cmove       r8,rbx  
00007FF66A5D76E4  test        r8,r8  
00007FF66A5D76E7  je          _ZN7globset8pathutil9file_name17h08d0f1900ad67247E+45h (07FF66A5D76F5h)  
00007FF66A5D76E9  mov         r15,qword ptr [rdx+8]  
00007FF66A5D76ED  cmp         byte ptr [r8+r15-1],2Eh  
00007FF66A5D76F3  jne         _ZN7globset8pathutil9file_name17h08d0f1900ad67247E+52h (07FF66A5D7702h)  
00007FF66A5D76F5  mov         qword ptr [r12],2  
00007FF66A5D76FD  jmp         _ZN7globset8pathutil9file_name17h08d0f1900ad67247E+14Fh (07FF66A5D77FFh)  
00007FF66A5D7702  mov         rax,qword ptr [__imp__ZN6memchr3x867memrchr2FN17h7699f2e42a7ae581E (07FF66BBC73B0h)]  
00007FF66A5D7709  mov         rax,qword ptr [rax]  
00007FF66A5D770C  mov         cl,2Fh  
00007FF66A5D770E  mov         rdx,r15  
00007FF66A5D7711  call        rax <<< rax is garbage
00007FF66A5D7713  mov         r14,rdx  
00007FF66A5D7716  add         r14,1  

Frame 0 Registers

RBX聽=聽00000238EB8D2FE0
RSI聽=聽0000000000000000
RDI聽=聽0000000000000005
R12聽=聽000000C631DFE620 
R13聽=聽000000C631DFE790
R14聽=聽0000000000000008
R15聽=聽00000238EB8D2FE0
RIP聽=聽00007FF66A5D7713
RSP聽=聽000000C631DFE540 
RBP聽=聽000000C631DFE5A0 

So this function seams to be miss compiled:

https://github.com/BurntSushi/ripgrep/blob/a2e6aec7a4d9382941932245e8854f0ae5703a5e/crates/globset/src/pathutil.rs#L9

pub fn file_name<'a>(path: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
    if path.is_empty() {
        return None;
    } else if path.last_byte() == Some(b'.') {
        return None;
    }
    let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
    Some(match *path {
        Cow::Borrowed(path) => Cow::Borrowed(&path[last_slash..]),
        Cow::Owned(ref path) => {
            let mut path = path.clone();
            path.drain_bytes(..last_slash);
            Cow::Owned(path)
        }
    })
}

In particular this line:

let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
00007FF66A5D7702  mov         rax,qword ptr [__imp__ZN6memchr3x867memrchr2FN17h7699f2e42a7ae581E (07FF66BBC73B0h)]  
00007FF66A5D7709  mov         rax,qword ptr [rax]
00007FF66A5D770C  mov         cl,2Fh  
00007FF66A5D770E  mov         rdx,r15  
00007FF66A5D7711  call        rax <<< rax is garbage
A-linkage C-bug E-needs-mcve I-unsound 馃挜 ICEBreaker-Cleanup-Crew ICEBreaker-LLVM P-high T-compiler

Most helpful comment

I was able to repro this with the following steps:

  1. rustup update nightly

  2. Install lld-link.exe. On Windows, the easiest thing I found was to install LLVM from their downloads page. I did not add LLVM to my system path.

  3. Setup the repro crate as described in https://github.com/rust-lang/rust/issues/71504#issuecomment-618941146

  4. Inside the root of the repro crate, create .cargo/config and put this in it:

[target.x86_64-pc-windows-msvc]
linker = "lld-link.exe"
  1. Run cargo with this invocation and observe the issue (note I use git-bash):
$ PATH=/c/Program\ Files/LLVM/bin/:$PATH cargo +nightly run --release
   Compiling memchr v2.3.3
   Compiling log v0.4.8
   Compiling regex-syntax v0.6.17
   Compiling aho-corasick v0.7.10
   Compiling bstr v0.2.12
   Compiling regex v1.3.7
   Compiling globset v0.4.5
   Compiling test_ice v0.1.0 (C:\projects\temp\test_ice)
    Finished release [optimized] target(s) in 16.54s
     Running `target\release\test_ice.exe`
error: process didn't exit successfully: `target\release\test_ice.exe` (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
Segmentation fault

I can confirm that this is lld specific, using the native Windows linker does not cause an issue.

All 20 comments

I managed to create a smaller reproducer:

[package]
name = "rust-71504"
version = "0.1.0"
authors = ["Vincent Rouill茅 <[email protected]>"]
edition = "2018"

[dependencies]
globset = "0.4.5"

[profile.release]
lto = "thin"
use globset::GlobSetBuilder;

fn main() {
    assert!(GlobSetBuilder::new().build().unwrap().is_match("src/tests"));
}

cargo run --release 
   Compiling rust-71504 v0.1.0 (C:\Development\GitHub\rust-71504)
    Finished release [optimized] target(s) in 4.19s
     Running `target\release\rust-71504.exe`
error: process didn't exit successfully: `target\release\rust-71504.exe` (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)

Does this reproduce on nightly?

Yes with rustc 1.44.0-nightly (b2e36e6c2 2020-04-22)

And the generated code that crash is the same:

00007FF694210542  mov         rax,qword ptr [__imp__ZN6memchr3x867memrchr2FN17h93ee2fcbd3a00cdaE (07FF6943143B0h)]  
00007FF694210549  mov         rax,qword ptr [rax]  
00007FF69421054C  mov         cl,2Fh  
00007FF69421054E  mov         rdx,r15  
00007FF694210551  call        rax 

globset::pathutil::file_name llvm-ir

@_ZN6memchr3x867memrchr2FN17h5bc0baf729fbe004E = external dllimport local_unnamed_addr global %"core::sync::atomic::AtomicPtr<()>"

; globset::pathutil::file_name
; Function Attrs: uwtable
define void @_ZN7globset8pathutil9file_name17hbcd7b89f83326b91E(%"core::option::Option<alloc::borrow::Cow<[u8]>>"* noalias nocapture sret dereferenceable(32), %"alloc::borrow::Cow<[u8]>"* noalias nocapture readonly align 8 dereferenceable(32) %path) unnamed_addr #0 personality i32 (...)* @__CxxFrameHandler3 {
start:
  %vector.i.i.i = alloca %"alloc::vec::Vec<u8>", align 8
  %path1 = alloca %"alloc::vec::Vec<u8>", align 8
  %1 = getelementptr inbounds %"alloc::borrow::Cow<[u8]>", %"alloc::borrow::Cow<[u8]>"* %path, i64 0, i32 0, i64 0
  %_3.i = load i64, i64* %1, align 8, !range !2, !alias.scope !5129
  %switch.i = icmp eq i64 %_3.i, 1
  %owned.i = getelementptr inbounds %"alloc::borrow::Cow<[u8]>", %"alloc::borrow::Cow<[u8]>"* %path, i64 0, i32 2
  %2 = getelementptr inbounds %"alloc::borrow::Cow<[u8]>", %"alloc::borrow::Cow<[u8]>"* %path, i64 0, i32 2, i64 1
  %3 = getelementptr inbounds %"alloc::borrow::Cow<[u8]>", %"alloc::borrow::Cow<[u8]>"* %path, i64 0, i32 2, i64 2
  %_2.sroa.0.0.in.i = bitcast [3 x i64]* %owned.i to [0 x i8]**
  %_2.sroa.0.0.i = load [0 x i8]*, [0 x i8]** %_2.sroa.0.0.in.i, align 8, !alias.scope !5129, !nonnull !1
  %.val.i = load i64, i64* %3, align 8, !alias.scope !5129
  %.val3.i = load i64, i64* %2, align 8, !alias.scope !5129
  %_2.sroa.5.0.i = select i1 %switch.i, i64 %.val.i, i64 %.val3.i
  %4 = icmp eq i64 %_2.sroa.5.0.i, 0
  br i1 %4, label %bb5, label %"_ZN70_$LT$core..option..Option$LT$T$GT$$u20$as$u20$core..cmp..PartialEq$GT$2eq17h38574dfda84b4f2cE.exit"

"_ZN70_$LT$core..option..Option$LT$T$GT$$u20$as$u20$core..cmp..PartialEq$GT$2eq17h38574dfda84b4f2cE.exit": ; preds = %start
  %5 = add i64 %_2.sroa.5.0.i, -1
  %6 = getelementptr inbounds [0 x i8], [0 x i8]* %_2.sroa.0.0.i, i64 0, i64 %5
  %.val.i.i = load i8, i8* %6, align 1, !alias.scope !5132
  %7 = icmp eq i8 %.val.i.i, 46
  br i1 %7, label %bb12, label %_ZN4bstr9ext_slice9ByteSlice10rfind_byte17h49aefeba57a625e8E.exit

bb5:                                              ; preds = %start
  %8 = getelementptr inbounds %"core::option::Option<alloc::borrow::Cow<[u8]>>", %"core::option::Option<alloc::borrow::Cow<[u8]>>"* %0, i64 0, i32 0, i64 0
  store i64 2, i64* %8, align 8
  br label %bb6

bb6:                                              ; preds = %bb5, %bb12, %bb25
  ret void

_ZN4bstr9ext_slice9ByteSlice10rfind_byte17h49aefeba57a625e8E.exit: ; preds = %"_ZN70_$LT$core..option..Option$LT$T$GT$$u20$as$u20$core..cmp..PartialEq$GT$2eq17h38574dfda84b4f2cE.exit"
  %9 = load atomic i64, i64* bitcast (i8** getelementptr inbounds (%"core::sync::atomic::AtomicPtr<()>", %"core::sync::atomic::AtomicPtr<()>"* @_ZN6memchr3x867memrchr2FN17h5bc0baf729fbe004E, i64 0, i32 1) to i64*) monotonic, align 8, !noalias !5137
  %10 = inttoptr i64 %9 to { i64, i64 } (i8, [0 x i8]*, i64)*
  %11 = icmp ne i64 %9, 0
  tail call void @llvm.assume(i1 %11), !noalias !5137
  %12 = tail call { i64, i64 } %10(i8 47, [0 x i8]* noalias nonnull readonly align 1 %_2.sroa.0.0.i, i64 %_2.sroa.5.0.i)
  %.fca.0.extract.i.i = extractvalue { i64, i64 } %12, 0
  %.fca.1.extract.i.i = extractvalue { i64, i64 } %12, 1
  %switch.i41 = icmp eq i64 %.fca.0.extract.i.i, 0
  %13 = add i64 %.fca.1.extract.i.i, 1
  %..i = select i1 %switch.i41, i64 0, i64 %13
  br i1 %switch.i, label %bb17, label %bb19

bb12:                                             ; preds = %"_ZN70_$LT$core..option..Option$LT$T$GT$$u20$as$u20$core..cmp..PartialEq$GT$2eq17h38574dfda84b4f2cE.exit"
  %14 = getelementptr inbounds %"core::option::Option<alloc::borrow::Cow<[u8]>>", %"core::option::Option<alloc::borrow::Cow<[u8]>>"* %0, i64 0, i32 0, i64 0
  store i64 2, i64* %14, align 8
  br label %bb6

bb17:                                             ; preds = %_ZN4bstr9ext_slice9ByteSlice10rfind_byte17h49aefeba57a625e8E.exit
  %15 = bitcast %"alloc::vec::Vec<u8>"* %path1 to i8*
  call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %15)
  %16 = bitcast %"alloc::vec::Vec<u8>"* %vector.i.i.i to i8*
  call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %16), !noalias !5146
  %_15.i.i.i.i.i.i = icmp eq i64 %.val.i, 0
  br i1 %_15.i.i.i.i.i.i, label %"_ZN5alloc3vec12Vec$LT$T$GT$13with_capacity17hc96a68e01ada40f4E.exit.i.i.i", label %"_ZN62_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..AllocRef$GT$5alloc17h2d3f07a62eac3ef8E.exit.i.i.i.i.i.i"

"_ZN62_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..AllocRef$GT$5alloc17h2d3f07a62eac3ef8E.exit.i.i.i.i.i.i": ; preds = %bb17
  %17 = tail call i8* @__rust_alloc(i64 %.val.i, i64 1) #16, !noalias !5156
  %18 = icmp eq i8* %17, null
  br i1 %18, label %bb18.i.i.i.i.i.i, label %"_ZN5alloc3vec12Vec$LT$T$GT$13with_capacity17hc96a68e01ada40f4E.exit.i.i.i"

bb18.i.i.i.i.i.i:                                 ; preds = %"_ZN62_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..AllocRef$GT$5alloc17h2d3f07a62eac3ef8E.exit.i.i.i.i.i.i"
; call alloc::alloc::handle_alloc_error
  tail call void @_ZN5alloc5alloc18handle_alloc_error17h31c2c94a892ecbd6E(i64 %.val.i, i64 1) #16, !noalias !5156
  unreachable

"_ZN5alloc3vec12Vec$LT$T$GT$13with_capacity17hc96a68e01ada40f4E.exit.i.i.i": ; preds = %"_ZN62_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..AllocRef$GT$5alloc17h2d3f07a62eac3ef8E.exit.i.i.i.i.i.i", %bb17
  %ptr.0.i.i.i.i.i.i = phi i8* [ inttoptr (i64 1 to i8*), %bb17 ], [ %17, %"_ZN62_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..AllocRef$GT$5alloc17h2d3f07a62eac3ef8E.exit.i.i.i.i.i.i" ]
  %19 = bitcast %"alloc::vec::Vec<u8>"* %vector.i.i.i to i8**
  store i8* %ptr.0.i.i.i.i.i.i, i8** %19, align 8, !alias.scope !5159, !noalias !5146
  %20 = getelementptr inbounds %"alloc::vec::Vec<u8>", %"alloc::vec::Vec<u8>"* %vector.i.i.i, i64 0, i32 1, i32 1
  store i64 %.val.i, i64* %20, align 8, !alias.scope !5159, !noalias !5146
  %21 = getelementptr inbounds %"alloc::vec::Vec<u8>", %"alloc::vec::Vec<u8>"* %vector.i.i.i, i64 0, i32 3
  store i64 0, i64* %21, align 8, !alias.scope !5159, !noalias !5146
; invoke alloc::vec::Vec<T>::reserve
  invoke fastcc void @"_ZN5alloc3vec12Vec$LT$T$GT$7reserve17h8328aa9ad9c26b4cE"(%"alloc::vec::Vec<u8>"* nonnull align 8 dereferenceable(24) %vector.i.i.i, i64 %.val.i)
          to label %"_ZN63_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$core..clone..Clone$GT$5clone17ha8687e9b953bbe67E.exit" unwind label %funclet_bb5.i.i.i, !noalias !5146

funclet_bb5.i.i.i:                                ; preds = %"_ZN5alloc3vec12Vec$LT$T$GT$13with_capacity17hc96a68e01ada40f4E.exit.i.i.i"
  %cleanuppad.i.i.i = cleanuppad within none []
  call fastcc void bitcast (void (%"alloc::string::String"*)* @_ZN4core3ptr13drop_in_place17h16849cb7958e75d3E to void (%"alloc::vec::Vec<u8>"*)*)(%"alloc::vec::Vec<u8>"* nonnull %vector.i.i.i) #22 [ "funclet"(token %cleanuppad.i.i.i) ], !noalias !5146
  cleanupret from %cleanuppad.i.i.i unwind to caller

"_ZN63_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$core..clone..Clone$GT$5clone17ha8687e9b953bbe67E.exit": ; preds = %"_ZN5alloc3vec12Vec$LT$T$GT$13with_capacity17hc96a68e01ada40f4E.exit.i.i.i"
  %22 = getelementptr inbounds [0 x i8], [0 x i8]* %_2.sroa.0.0.i, i64 0, i64 0
  %self.idx.val.i.i.i.i.i = load i64, i64* %21, align 8, !noalias !5160
  %_13.i.i.i.i.i = add i64 %self.idx.val.i.i.i.i.i, %.val.i
  store i64 %_13.i.i.i.i.i, i64* %21, align 8, !noalias !5160
  %23 = bitcast %"alloc::vec::Vec<u8>"* %vector.i.i.i to [0 x i8]**
  %_3.idx.val.i1.i.i.i.i.i.i = load [0 x i8]*, [0 x i8]** %23, align 8, !noalias !5160, !nonnull !1
  %24 = getelementptr inbounds [0 x i8], [0 x i8]* %_3.idx.val.i1.i.i.i.i.i.i, i64 0, i64 %self.idx.val.i.i.i.i.i
  tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 1 %24, i8* nonnull align 1 %22, i64 %.val.i, i1 false) #16, !noalias !5163
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 8 %15, i8* nonnull align 8 %16, i64 24, i1 false), !noalias !5164
  call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %16), !noalias !5146
  %self.idx.i.i = getelementptr inbounds %"alloc::vec::Vec<u8>", %"alloc::vec::Vec<u8>"* %path1, i64 0, i32 3
  %self.idx.val.i.i = load i64, i64* %self.idx.i.i, align 8, !noalias !5165
  %_26.i.i = icmp ult i64 %self.idx.val.i.i, %..i
  br i1 %_26.i.i, label %bb19.i.i, label %bb22

bb19.i.i:                                         ; preds = %"_ZN63_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$core..clone..Clone$GT$5clone17ha8687e9b953bbe67E.exit"
; invoke core::panicking::panic
  invoke void @_ZN4core9panicking5panic17h07bec01df8643458E([0 x i8]* noalias nonnull readonly align 1 bitcast (<{ [28 x i8] }>* @anon.aed952bceef054ab22098ec10f8b5504.48 to [0 x i8]*), i64 28, %"core::panic::Location"* noalias readonly align 8 dereferenceable(24) bitcast (<{ i8*, [16 x i8] }>* @anon.aed952bceef054ab22098ec10f8b5504.40 to %"core::panic::Location"*))
          to label %.noexc unwind label %funclet_bb23

.noexc:                                           ; preds = %bb19.i.i
  unreachable

bb19:                                             ; preds = %_ZN4bstr9ext_slice9ByteSlice10rfind_byte17h49aefeba57a625e8E.exit
  %_3.i.i.i = icmp ult i64 %.val3.i, %..i
  br i1 %_3.i.i.i, label %bb2.i.i.i, label %"_ZN4core5slice74_$LT$impl$u20$core..ops..index..Index$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$5index17h358af9de6dfcb22eE.exit"

bb2.i.i.i:                                        ; preds = %bb19
; call core::slice::slice_index_order_fail
  tail call void @_ZN4core5slice22slice_index_order_fail17h3334b3335c3bd3ecE(i64 %..i, i64 %.val3.i)
  unreachable

"_ZN4core5slice74_$LT$impl$u20$core..ops..index..Index$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$5index17h358af9de6dfcb22eE.exit": ; preds = %bb19
  %25 = getelementptr inbounds [0 x i8], [0 x i8]* %_2.sroa.0.0.i, i64 0, i64 %..i
  %_8.i.i.i.i = sub i64 %.val3.i, %..i
  %26 = bitcast i8* %25 to [0 x i8]*
  br label %bb25

bb22:                                             ; preds = %"_ZN63_$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$core..clone..Clone$GT$5clone17ha8687e9b953bbe67E.exit"
  store i64 0, i64* %self.idx.i.i, align 8, !noalias !5165
  %27 = bitcast %"alloc::vec::Vec<u8>"* %path1 to [0 x i8]**
  %_3.idx.val.i22.i.i = load [0 x i8]*, [0 x i8]** %27, align 8, !noalias !5165, !nonnull !1
  %_43.i.i = sub i64 %self.idx.val.i.i, %..i
  %_4.i.i.i.i.i = icmp eq i64 %_43.i.i, 0
  %28 = getelementptr inbounds [0 x i8], [0 x i8]* %_3.idx.val.i22.i.i, i64 0, i64 0
  br i1 %_4.i.i.i.i.i, label %bb24, label %bb2.i.i.i.i.i

bb2.i.i.i.i.i:                                    ; preds = %bb22
  %_11.i.i.i.i.i = icmp eq i64 %..i, 0
  br i1 %_11.i.i.i.i.i, label %bb11.i.i.i.i.i, label %bb5.i.i.i.i.i

bb5.i.i.i.i.i:                                    ; preds = %bb2.i.i.i.i.i
  %29 = getelementptr inbounds [0 x i8], [0 x i8]* %_3.idx.val.i22.i.i, i64 0, i64 %..i
  tail call void @llvm.memmove.p0i8.p0i8.i64(i8* nonnull align 1 %28, i8* nonnull align 1 %29, i64 %_43.i.i, i1 false) #16
  br label %bb11.i.i.i.i.i

bb11.i.i.i.i.i:                                   ; preds = %bb5.i.i.i.i.i, %bb2.i.i.i.i.i
  store i64 %_43.i.i, i64* %self.idx.i.i, align 8
  br label %bb24

bb24:                                             ; preds = %bb11.i.i.i.i.i, %bb22
  %_36.sroa.4.0..sroa_idx16 = getelementptr inbounds %"alloc::vec::Vec<u8>", %"alloc::vec::Vec<u8>"* %path1, i64 0, i32 1, i32 1
  %_36.sroa.4.0.copyload = load i64, i64* %_36.sroa.4.0..sroa_idx16, align 8
  call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %15)
  br label %bb25

bb25:                                             ; preds = %"_ZN4core5slice74_$LT$impl$u20$core..ops..index..Index$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$5index17h358af9de6dfcb22eE.exit", %bb24
  %_20.sroa.8.0 = phi i64 [ undef, %"_ZN4core5slice74_$LT$impl$u20$core..ops..index..Index$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$5index17h358af9de6dfcb22eE.exit" ], [ %_43.i.i, %bb24 ]
  %_20.sroa.7.0 = phi i64 [ %_8.i.i.i.i, %"_ZN4core5slice74_$LT$impl$u20$core..ops..index..Index$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$5index17h358af9de6dfcb22eE.exit" ], [ %_36.sroa.4.0.copyload, %bb24 ]
  %_20.sroa.5.0 = phi [0 x i8]* [ %26, %"_ZN4core5slice74_$LT$impl$u20$core..ops..index..Index$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$5index17h358af9de6dfcb22eE.exit" ], [ %_3.idx.val.i22.i.i, %bb24 ]
  %_20.sroa.0.0 = phi i64 [ 0, %"_ZN4core5slice74_$LT$impl$u20$core..ops..index..Index$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$5index17h358af9de6dfcb22eE.exit" ], [ 1, %bb24 ]
  %_20.sroa.0.0..sroa_idx = getelementptr inbounds %"core::option::Option<alloc::borrow::Cow<[u8]>>", %"core::option::Option<alloc::borrow::Cow<[u8]>>"* %0, i64 0, i32 0, i64 0
  store i64 %_20.sroa.0.0, i64* %_20.sroa.0.0..sroa_idx, align 8
  %_20.sroa.5.0..sroa_idx5 = getelementptr inbounds %"core::option::Option<alloc::borrow::Cow<[u8]>>", %"core::option::Option<alloc::borrow::Cow<[u8]>>"* %0, i64 0, i32 2
  %_20.sroa.5.0..sroa_cast = bitcast [3 x i64]* %_20.sroa.5.0..sroa_idx5 to [0 x i8]**
  store [0 x i8]* %_20.sroa.5.0, [0 x i8]** %_20.sroa.5.0..sroa_cast, align 8
  %30 = getelementptr inbounds %"core::option::Option<alloc::borrow::Cow<[u8]>>", %"core::option::Option<alloc::borrow::Cow<[u8]>>"* %0, i64 0, i32 2, i64 1
  store i64 %_20.sroa.7.0, i64* %30, align 8
  %31 = getelementptr inbounds %"core::option::Option<alloc::borrow::Cow<[u8]>>", %"core::option::Option<alloc::borrow::Cow<[u8]>>"* %0, i64 0, i32 2, i64 2
  store i64 %_20.sroa.8.0, i64* %31, align 8
  br label %bb6

funclet_bb23:                                     ; preds = %bb19.i.i
  %cleanuppad = cleanuppad within none []
  call fastcc void bitcast (void (%"alloc::string::String"*)* @_ZN4core3ptr13drop_in_place17h16849cb7958e75d3E to void (%"alloc::vec::Vec<u8>"*)*)(%"alloc::vec::Vec<u8>"* nonnull %path1) #22 [ "funclet"(token %cleanuppad) ]
  cleanupret from %cleanuppad unwind to caller
}

memchr::x86::memrchr::detect llvm-ir

@_ZN6memchr3x867memrchr2FN17h5bc0baf729fbe004E = local_unnamed_addr global <{ i8*, [0 x i8] }> <{ i8* bitcast ({ i64, i64 } (i8, [0 x i8]*, i64)* @_ZN6memchr3x867memrchr6detect17h517e20eb83e5ca39E to i8*), [0 x i8] zeroinitializer }>, align 8

@"\01__imp__ZN6memchr3x867memrchr2FN17h5bc0baf729fbe004E" = global i8* bitcast (<{ i8*, [0 x i8] }>* @_ZN6memchr3x867memrchr2FN17h5bc0baf729fbe004E to i8*)


; memchr::x86::memrchr::detect
; Function Attrs: uwtable
define internal { i64, i64 } @_ZN6memchr3x867memrchr6detect17h517e20eb83e5ca39E(i8 %n1, [0 x i8]* noalias nonnull readonly align 1 %haystack.0, i64 %haystack.1) unnamed_addr #2 personality i32 (...)* @__CxxFrameHandler3 {
start:
  %0 = load atomic i64, i64* getelementptr inbounds ([2 x %"std::std_detect::detect::cache::Cache"], [2 x %"std::std_detect::detect::cache::Cache"]* @_ZN3std10std_detect6detect5cache5CACHE17h36155bdd5a985257E, i64 0, i64 0, i32 1, i32 1) seq_cst, align 8
  %1 = icmp eq i64 %0, -1
  br i1 %1, label %bb7.i.i.i, label %_ZN3std10std_detect6detect4arch21__is_feature_detected4avx217hc0fbd12b9336552cE.exit

bb7.i.i.i:                                        ; preds = %start
; call std::std_detect::detect::os::detect_features
  %2 = tail call i64 @_ZN3std10std_detect6detect2os15detect_features17h30d1c684eca000e9E()
  %_6.i.i.i.i.i = and i64 %2, 9223372036854775807
  store atomic i64 %_6.i.i.i.i.i, i64* getelementptr inbounds ([2 x %"std::std_detect::detect::cache::Cache"], [2 x %"std::std_detect::detect::cache::Cache"]* @_ZN3std10std_detect6detect5cache5CACHE17h36155bdd5a985257E, i64 0, i64 0, i32 1, i32 1) seq_cst, align 8
  %_15.i.i.i.i.i = lshr i64 %2, 63
  store atomic i64 %_15.i.i.i.i.i, i64* getelementptr inbounds ([2 x %"std::std_detect::detect::cache::Cache"], [2 x %"std::std_detect::detect::cache::Cache"]* @_ZN3std10std_detect6detect5cache5CACHE17h36155bdd5a985257E, i64 0, i64 1, i32 1, i32 1) seq_cst, align 8
  br label %_ZN3std10std_detect6detect4arch21__is_feature_detected4avx217hc0fbd12b9336552cE.exit

_ZN3std10std_detect6detect4arch21__is_feature_detected4avx217hc0fbd12b9336552cE.exit: ; preds = %start, %bb7.i.i.i
  %3 = load atomic i64, i64* getelementptr inbounds ([2 x %"std::std_detect::detect::cache::Cache"], [2 x %"std::std_detect::detect::cache::Cache"]* @_ZN3std10std_detect6detect5cache5CACHE17h36155bdd5a985257E, i64 0, i64 0, i32 1, i32 1) seq_cst, align 8
  %4 = trunc i64 %3 to i16
  %5 = icmp slt i16 %4, 0
  %.sink = select i1 %5, i64 ptrtoint ({ i64, i64 } (i8, [0 x i8]*, i64)* @_ZN6memchr3x863avx7memrchr17h082fa08fb3cf7b05E to i64), i64 ptrtoint ({ i64, i64 } (i8, [0 x i8]*, i64)* @_ZN6memchr3x864sse27memrchr17h62035a598a168baeE to i64)
  %6 = select i1 %5, { i64, i64 } (i8, [0 x i8]*, i64)* @_ZN6memchr3x863avx7memrchr17h082fa08fb3cf7b05E, { i64, i64 } (i8, [0 x i8]*, i64)* @_ZN6memchr3x864sse27memrchr17h62035a598a168baeE
  store atomic i64 %.sink, i64* bitcast (<{ i8*, [0 x i8] }>* @_ZN6memchr3x867memrchr2FN17h5bc0baf729fbe004E to i64*) monotonic, align 8
  %7 = tail call { i64, i64 } %6(i8 %n1, [0 x i8]* noalias nonnull readonly align 1 %haystack.0, i64 %haystack.1)
  ret { i64, i64 } %7
}

Probable relevant part:

%9 = load atomic i64, i64* bitcast (i8** getelementptr inbounds (%"core::sync::atomic::AtomicPtr<()>", %"core::sync::atomic::AtomicPtr<()>"* @_ZN6memchr3x867memrchr2FN17h5bc0baf729fbe004E, i64 0, i32 1) to i64*) monotonic, align 8, !noalias !5137
  %10 = inttoptr i64 %9 to { i64, i64 } (i8, [0 x i8]*, i64)*
  %11 = icmp ne i64 %9, 0
  tail call void @llvm.assume(i1 %11), !noalias !5137

Assembly and llvm-ir files: deps.zip

Let's have more people to try and minimize that.
@rustbot ping cleanup
@rustbot ping llvm

Hey Cleanup Crew ICE-breakers! This bug has been identified as a good
"Cleanup ICE-breaking candidate". In case it's useful, here are some
[instructions] for tackling these sorts of bugs. Maybe take a look?
Thanks! <3

cc @AminArria @chrissimpkins @contrun @DutchGhost @elshize @ethanboxx @h-michael @HallerPatrick @hdhoang @hellow554 @imtsuki @jakevossen5 @kanru @KarlK90 @LeSeulArtichaut @MAdrianMattocks @matheus-consoli @mental32 @nmccarty @Noah-Kennedy @pard68 @PeytonT @pierreN @Redblueflame @RobbieClarken @RobertoSnap @robjtede @SarthakSingh31 @senden9 @shekohex @sinato @spastorino @turboladen @woshilapin @yerke

@rustbot ping llvm

Hey LLVM ICE-breakers! This bug has been identified as a good
"LLVM ICE-breaking candidate". In case it's useful, here are some
[instructions] for tackling these sorts of bugs. Maybe take a look?
Thanks! <3

cc @comex @CrazyDebugger @cuviper @DutchGhost @hanna-kruppe @hdhoang @heyrutvik @JOE1994 @jryans @mmilenko @nagisa @nikic @Noah-Kennedy @SiavoshZarrasvand @spastorino @vertexclique

Assigning P-critical as discussed as part of the Prioritization Working Group process and removing I-prioritize.

I've used the example code in https://github.com/rust-lang/rust/issues/71504#issuecomment-618941146, but can't reproduce. Neither in stable nor in nightly for windows and macOS.

$> cargo run --release
    Finished release [optimized] target(s) in 0.03s
     Running `target\release\i71504.exe`
thread 'main' panicked at 'assertion failed: GlobSetBuilder::new().build().unwrap().is_match("src/tests")', src\main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\release\i71504.exe` (exit code: 101)
$> rustc -vV
rustc 1.43.0 (4fb7144ed 2020-04-20)
binary: rustc
commit-hash: 4fb7144ed159f94491249e86d5bbd033b5d60550
commit-date: 2020-04-20
host: x86_64-pc-windows-msvc
release: 1.43.0
LLVM version: 9.0

I'm sorry, I forgot to unset my global linker setting, I was using "lld-link".

With the official link.exe, this bug doesn't occur.

So this is an lld (LLVM 10) bug, the first I encounter. So I guess this is out of rust-lang scope.

I there any target where lld is the official linker? Might be a COFF only bug tho.

Changing the linker back to the default one, also fixed the compilation of rust-analyser, lto=fat, target-cpu=native btw (52s total vs 100s with the official build, I'm happy).

cc @Gankra (relevant to the LLD-by-default plans)

Removing I-unsound as this is an upstream bug. Maybe it should be closed outright, since having an issue for every problem in LLVM isn't terribly helpful, but with the plans for using LLD by default this might be helpful.

I there any target where lld is the official linker?

Yes, embedded ARM targets use it by default. They're ELF targets though, and LLD's ELF backend is fairly reliable (I've only witnessed it corrupting debuginfo once, not cause crashes like this).

Well I'have been using lld-link as default rust linker on windows for about 2 years now: no issue.

PS: I was able to reproduce it with lld-link 9.0.1 and 10.0.0

After some discussion during triage meeting, we've decided to change the priority to P-high.

I was able to repro this with the following steps:

  1. rustup update nightly

  2. Install lld-link.exe. On Windows, the easiest thing I found was to install LLVM from their downloads page. I did not add LLVM to my system path.

  3. Setup the repro crate as described in https://github.com/rust-lang/rust/issues/71504#issuecomment-618941146

  4. Inside the root of the repro crate, create .cargo/config and put this in it:

[target.x86_64-pc-windows-msvc]
linker = "lld-link.exe"
  1. Run cargo with this invocation and observe the issue (note I use git-bash):
$ PATH=/c/Program\ Files/LLVM/bin/:$PATH cargo +nightly run --release
   Compiling memchr v2.3.3
   Compiling log v0.4.8
   Compiling regex-syntax v0.6.17
   Compiling aho-corasick v0.7.10
   Compiling bstr v0.2.12
   Compiling regex v1.3.7
   Compiling globset v0.4.5
   Compiling test_ice v0.1.0 (C:\projects\temp\test_ice)
    Finished release [optimized] target(s) in 16.54s
     Running `target\release\test_ice.exe`
error: process didn't exit successfully: `target\release\test_ice.exe` (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
Segmentation fault

I can confirm that this is lld specific, using the native Windows linker does not cause an issue.

This no longer occurs on the latest nightly. I bisected the fix to https://github.com/rust-lang/rust/commit/63d03779946a07d8c418a361278168a6d3a1f4d2 (in nightly-2020-05-08)

The relevant change seems to be https://github.com/rust-lang/cargo/pull/8192. Were the 'unused' object files somehow affecting LTO?

Minimized:

fn main() {
    memchr::memrchr(b'a', b"b");
}

given "memchr" = "2.1.2", and the setup described in https://github.com/rust-lang/rust/issues/71504#issuecomment-622422103

Minimized even further:

// 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();
}

These functions must be in two different crates, and be compiled with the setup described in https://github.com/rust-lang/rust/issues/71504#issuecomment-622422103

Was this page helpful?
0 / 5 - 0 ratings