From b6087492ed7b78096adbdba1e086cc987f46b32d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 27 Jun 2019 02:14:57 -0700 Subject: [PATCH] rustc: Retry SIGILL linker invocations We've seen quite a few issues with spurious illegal instructions getting executed on OSX on CI recently. For whatever reason `cc` itself is executing an illegal instruction and we're not really getting any other information about what's happening. Since we're already retrying the linker when it segfaults, let's just continue to retry everything and automatically reinvoke the linker when it fails with an illegal instruction. --- src/librustc_codegen_ssa/back/link.rs | 71 ++++++++++++++++++--------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 0ba5451bd72f5..618e8b8699fcc 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -29,7 +29,7 @@ use std::fmt; use std::fs; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Output, Stdio}; +use std::process::{Output, Stdio, ExitStatus}; use std::str; use std::env; @@ -510,21 +510,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, sess.abort_if_errors(); // Invoke the system linker - // - // Note that there's a terribly awful hack that really shouldn't be present - // in any compiler. Here an environment variable is supported to - // automatically retry the linker invocation if the linker looks like it - // segfaulted. - // - // Gee that seems odd, normally segfaults are things we want to know about! - // Unfortunately though in rust-lang/rust#38878 we're experiencing the - // linker segfaulting on Travis quite a bit which is causing quite a bit of - // pain to land PRs when they spuriously fail due to a segfault. - // - // The issue #38878 has some more debugging information on it as well, but - // this unfortunately looks like it's just a race condition in macOS's linker - // with some thread pool working in the background. It seems that no one - // currently knows a fix for this so in the meantime we're left with this... info!("{:?}", &cmd); let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok(); let mut prog; @@ -567,21 +552,59 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, info!("{:?}", &cmd); continue; } + + // Here's a terribly awful hack that really shouldn't be present in any + // compiler. Here an environment variable is supported to automatically + // retry the linker invocation if the linker looks like it segfaulted. + // + // Gee that seems odd, normally segfaults are things we want to know + // about! Unfortunately though in rust-lang/rust#38878 we're + // experiencing the linker segfaulting on Travis quite a bit which is + // causing quite a bit of pain to land PRs when they spuriously fail + // due to a segfault. + // + // The issue #38878 has some more debugging information on it as well, + // but this unfortunately looks like it's just a race condition in + // macOS's linker with some thread pool working in the background. It + // seems that no one currently knows a fix for this so in the meantime + // we're left with this... if !retry_on_segfault || i > 3 { break } let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11"; let msg_bus = "clang: error: unable to execute command: Bus error: 10"; - if !(out.contains(msg_segv) || out.contains(msg_bus)) { - break + if out.contains(msg_segv) || out.contains(msg_bus) { + warn!( + "looks like the linker segfaulted when we tried to call it, \ + automatically retrying again. cmd = {:?}, out = {}.", + cmd, + out, + ); + continue; } - warn!( - "looks like the linker segfaulted when we tried to call it, \ - automatically retrying again. cmd = {:?}, out = {}.", - cmd, - out, - ); + if is_illegal_instruction(&output.status) { + warn!( + "looks like the linker hit an illegal instruction when we \ + tried to call it, automatically retrying again. cmd = {:?}, ]\ + out = {}, status = {}.", + cmd, + out, + output.status, + ); + continue; + } + + #[cfg(unix)] + fn is_illegal_instruction(status: &ExitStatus) -> bool { + use std::os::unix::prelude::*; + status.signal() == Some(libc::SIGILL) + } + + #[cfg(windows)] + fn is_illegal_instruction(_status: &ExitStatus) -> bool { + false + } } match prog {