-
Notifications
You must be signed in to change notification settings - Fork 13k
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
rustup-init 0.6.1 segfaults on x86_64 and armv7, 0.6.0 on OS X 10.10 #36023
Comments
@brson Do you know of a |
@eddyb looking for one now. |
rust-lang-deprecated/rustup.sh#68 looks like the exact same issue AFAICT. |
reproducing: commit c8cc167a0ab725e25dc49eda1ea9d71196def5d7
nightly results:
stable/beta results: |
Removing the two lifetime annotations from #35409 appears to make the crash go away. |
I am trying to minimize a test case next. |
Reduced case. This segfaults on x86_64-unknown-linux-gnu with use std::ops::Deref;
fn main() {
if env_var("FOOBAR").as_ref().map(Deref::deref).ok() == Some("yes") {
panic!()
}
let env_home: Result<String, ()> = Ok("foo-bar-baz".to_string());
let env_home = env_home.as_ref().map(Deref::deref).ok();
if env_home == Some("") { panic!() }
}
#[inline(never)]
fn env_var(s: &str) -> Result<String, VarError> {
Err(VarError::NotPresent)
}
pub enum VarError {
NotPresent,
NotUnicode(String),
} |
Normalized to: #[inline(never)]
fn err_none() -> Result<String, Option<String>> {
Err(None)
}
#[inline(never)]
fn panic() -> ! {
panic!()
}
#[inline(always)]
fn ok<T, E>(r: Result<T, E>) -> Option<T> {
match r {
Ok(x) => Some(x),
Err(_) => None
}
}
fn main() {
{
let a = err_none();
let b = match a {
Ok(ref x) => Ok(&**x),
Err(ref e) => Err(e)
};
if let Some("a") = ok(b) {
panic()
}
}
{
let a = err_none();
let b = match a {
Ok(ref x) => Ok(&**x),
Err(ref e) => Err(e)
};
if let Some("a") = ok(b) {
panic()
}
}
} Backtrace is: #0 je_rtree_get (rtree=<optimized out>, dependent=true, key=0) at /home/eddy/Projects/rust-2/src/liballoc_jemalloc/../jemalloc/include/jemalloc/internal/rtree.h:253
#1 je_chunk_lookup (dependent=true, ptr=0x0) at /home/eddy/Projects/rust-2/src/liballoc_jemalloc/../jemalloc/include/jemalloc/internal/chunk.h:91
#2 huge_node_get (ptr=0x0) at /home/eddy/Projects/rust-2/src/liballoc_jemalloc/../jemalloc/src/huge.c:11
#3 je_huge_dalloc (tsd=0x7ffff7ff1770, ptr=0x0, tcache=0x7ffff6a0c000) at /home/eddy/Projects/rust-2/src/liballoc_jemalloc/../jemalloc/src/huge.c:375
#4 0x000055555555b262 in alloc::heap::deallocate (align=1, ptr=<optimized out>, old_size=<optimized out>) at /home/eddy/Projects/rust-2/src/liballoc/heap.rs:113
#5 alloc::raw_vec::{{impl}}::drop<u8> (self=<optimized out>) at /home/eddy/Projects/rust-2/src/liballoc/raw_vec.rs:561
#6 test::main () at /home/eddy/Projects/rust-2/test.rs:21
#7 0x0000555555569997 in __rust_maybe_catch_panic ()
#8 0x000055555556241f in std::rt::lang_start::h5381d9388ae2d3b7 ()
#9 0x00007ffff7219770 in __libc_start_main () from /nix/store/qc1jm0rplpgkwcacnc03hs9w4c8v2m31-glibc-multi-2.23/lib/libc.so.6
#10 0x000055555555b059 in _start () at ../sysdeps/x86_64/start.S:108 Note the |
So far I've found that the drop glue for bb2.i: ; preds = %bb3
%4 = bitcast [3 x i64]* %3 to %"3.std::string::String"*
%5 = getelementptr inbounds %"3.std::string::String", %"3.std::string::String"* %4, i64 0, i32 0, i32 0, i32 0, i32 0, i32 0
%6 = load i8*, i8** %5, align 8, !alias.scope !2, !nonnull !9 That EDIT: Those 3 instructions are for the bb3:
%a = alloca %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", align 8
%a1 = alloca %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", align 8
%0 = bitcast %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* %a to i8*
call void @llvm.lifetime.start(i64 32, i8* %0)
call fastcc void @_ZN4test8err_none17h78cf98032df7f4e6E(%"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* noalias nocapture nonnull dereferenceable(32) %a)
%1 = getelementptr inbounds %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* %a, i64 0, i32 0
%2 = load i64, i64* %1, align 8, !range !1
%switch = icmp eq i64 %2, 1
%3 = getelementptr inbounds %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* %a, i64 0, i32 2
br i1 %switch, label %bb3.i, label %bb2.i
bb2.i: ; preds = %bb3
%4 = getelementptr inbounds [3 x i64], [3 x i64]* %3, i64 0, i64 0
%5 = load i64, i64* %4, align 8, !range !2, !alias.scope !3
%6 = getelementptr inbounds %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* %a, i64 0, i32 2, i64 2
%7 = load i64, i64* %6, align 8, !alias.scope !10
br label %bb8
bb3.i: ; preds = %bb3
br label %bb8 The But SimplifyCFG comes in and shoves the load into the entry block: bb3:
%a = alloca %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", align 8
%a1 = alloca %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", align 8
%0 = bitcast %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* %a to i8*
call void @llvm.lifetime.start(i64 32, i8* %0)
call fastcc void @_ZN4test8err_none17h78cf98032df7f4e6E(%"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* noalias nocapture nonnull dereferenceable(32) %a)
%1 = getelementptr inbounds %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* %a, i64 0, i32 0
%2 = load i64, i64* %1, align 8, !range !1
%switch = icmp eq i64 %2, 1
%3 = getelementptr inbounds %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* %a, i64 0, i32 2
%4 = getelementptr inbounds [3 x i64], [3 x i64]* %3, i64 0, i64 0
; This is the load for the Ok case specifically.
%5 = load i64, i64* %4, align 8, !range !2, !alias.scope !3
%6 = getelementptr inbounds %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>", %"2.std::result::Result<std::string::String, std::option::Option<std::string::String>>"* %a, i64 0, i32 2, i64 2
%7 = load i64, i64* %6, align 8, !alias.scope !10
%b.sroa.7.097 = select i1 %switch, i64 undef, i64 %7
%tmp6.sroa.0.0 = select i1 %switch, i64 0, i64 %5
%8 = inttoptr i64 %tmp6.sroa.0.0 to i8*
%switch5tmp = icmp ne i64 %tmp6.sroa.0.0, 0
%9 = icmp eq i64 %b.sroa.7.097, 1
%or.cond = and i1 %switch5tmp, %9
br i1 %or.cond, label %bb4.i.i.i.i.i, label %bb10 What does this mean?
|
Barebones reproduction: #![feature(start)]
use std::ptr;
extern {
fn abort() -> !;
}
struct S {
ptr: &'static mut u8,
cap: usize,
len: usize
}
struct OS {
ptr: *mut u8,
cap: usize,
len: usize
}
struct R {
is_err: bool,
buf: OS
}
#[inline(never)]
unsafe fn begin() -> R {
R {
is_err: true,
buf: OS { ptr: ptr::null_mut(), len: 0, cap: 0 }
}
}
unsafe fn end(r: &mut R) {
if r.is_err {
if r.buf.ptr != ptr::null_mut() {
*r.buf.ptr = 0;
}
} else {
*r.buf.ptr = 0;
}
}
unsafe fn ok(r: [usize; 3]) -> (*const u8, usize) {
let r: &(bool, (*const u8, usize)) = &*(&r as *const _ as *const _);
if r.0 {
(ptr::null(), std::mem::uninitialized())
} else {
r.1
}
}
macro_rules! twice {
($x:expr) => {$x; $x}
}
#[start]
fn start(_: isize, _: *const *const u8) -> isize {
twice!(unsafe {
let mut r = begin();
let a = if r.is_err {
[1usize, &r.buf as *const _ as usize, 0]
} else {
let s: &S = &*(&r.buf as *const _ as *const S);
[0usize, s.ptr as *const _ as usize, s.len]
};
let b = ok(a);
if b.0 != ptr::null() && b.1 == 1 && *b.0 == 1 {
abort()
}
end(&mut r);
});
0
} |
Found a LLVM commit should've fixed this (but apparently didn't fully?): llvm-mirror/llvm@a90859a. EDIT: Most likely |
Filed LLVM bug report: https://llvm.org/bugs/show_bug.cgi?id=29163. |
But I thought that bad-metadata loads only result in |
@arielb1 Just |
Fix is llvm-mirror/llvm@f94d4a7. Recommend backport to beta, too. |
Thanks a bunch @eddyb |
llvm: backport "[SimplifyCFG] Hoisting invalidates metadata". Fixes #36023 by backporting @majnemer's LLVM patch fixing [the LLVM bug](https://llvm.org/bugs/show_bug.cgi?id=29163.) where SimplifyCFG hoisted instructions andkept their metadata (conditional `!nonnull` loads could kill a null check later if hoisted). r? @alexcrichton
LLVM patch was merged to 3.9 stable branch in r288063 and will be included in 3.9.1 release. |
rustup reports of 0.6.1 crashes:
These were built with
rustc 1.13.0-nightly (3c5a0fa45 2016-08-22)
rustup 0.6.0 crashed on OS X 10.10+. Fixed with a strategic
#[inline(never)]
That was built with
rustc 1.13.0-nightly (1576de0ce 2016-08-21)
Reducing these has been very difficult and I have nothing for them right now.
cc @nikomatsakis @eddyb @alexcrichton
The text was updated successfully, but these errors were encountered: