From 074d667cf507b55f74a721709cdfdf476102fbbe Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 25 May 2021 11:48:59 -0700 Subject: [PATCH 1/4] Don't panic when failing to initialize incremental directory. --- Cargo.lock | 1 + compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_data_structures/src/flock.rs | 13 +++++ compiler/rustc_incremental/Cargo.toml | 1 + compiler/rustc_incremental/src/persist/fs.rs | 53 +++++++++++--------- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_interface/src/queries.rs | 4 +- 7 files changed, 49 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 62734bfaf629f..5d5083277d322 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3876,6 +3876,7 @@ dependencies = [ "rand 0.7.3", "rustc_ast", "rustc_data_structures", + "rustc_errors", "rustc_fs_util", "rustc_graphviz", "rustc_hir", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index aa95ecbdaf932..c35a164bb3342 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -34,7 +34,7 @@ tempfile = "3.2" version = "0.11" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["fileapi", "psapi"] } +winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] memmap2 = "0.2.1" diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 9383be474fd5a..4f5d8d7ea48ba 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -54,6 +54,10 @@ cfg_if! { Ok(Lock { _file: file }) } } + + pub fn error_unsupported(err: &io::Error) -> bool { + matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS)) + } } // Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by @@ -103,6 +107,10 @@ cfg_if! { Ok(Lock { file }) } } + + pub fn error_unsupported(err: &io::Error) -> bool { + matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS)) + } } impl Drop for Lock { @@ -122,6 +130,7 @@ cfg_if! { use std::mem; use std::os::windows::prelude::*; + use winapi::shared::winerror::ERROR_INVALID_FUNCTION; use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK}; use winapi::um::fileapi::LockFileEx; use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE}; @@ -194,6 +203,10 @@ cfg_if! { Ok(Lock { _file: file }) } } + + pub fn error_unsupported(err: &io::Error) -> bool { + err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32) + } } // Note that we don't need a Drop impl on the Windows: The file is unlocked diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index 049e5b8b72284..85bf4dc176bd1 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -20,3 +20,4 @@ rustc_macros = { path = "../rustc_macros" } rustc_span = { path = "../rustc_span" } rustc_fs_util = { path = "../rustc_fs_util" } rustc_session = { path = "../rustc_session" } +rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 30c6c408bc7c0..a9925832fd879 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -106,6 +106,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::{base_n, flock}; +use rustc_errors::ErrorReported; use rustc_fs_util::{link_or_copy, LinkOrCopy}; use rustc_session::{CrateDisambiguator, Session}; @@ -189,9 +190,9 @@ pub fn prepare_session_directory( sess: &Session, crate_name: &str, crate_disambiguator: CrateDisambiguator, -) { +) -> Result<(), ErrorReported> { if sess.opts.incremental.is_none() { - return; + return Ok(()); } let _timer = sess.timer("incr_comp_prepare_session_directory"); @@ -201,9 +202,7 @@ pub fn prepare_session_directory( // {incr-comp-dir}/{crate-name-and-disambiguator} let crate_dir = crate_path(sess, crate_name, crate_disambiguator); debug!("crate-dir: {}", crate_dir.display()); - if create_dir(sess, &crate_dir, "crate").is_err() { - return; - } + create_dir(sess, &crate_dir, "crate")?; // Hack: canonicalize the path *after creating the directory* // because, on windows, long paths can cause problems; @@ -217,7 +216,7 @@ pub fn prepare_session_directory( crate_dir.display(), err )); - return; + return Err(ErrorReported); } }; @@ -232,16 +231,11 @@ pub fn prepare_session_directory( // Lock the new session directory. If this fails, return an // error without retrying - let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) { - Ok(e) => e, - Err(_) => return, - }; + let (directory_lock, lock_file_path) = lock_directory(sess, &session_dir)?; // Now that we have the lock, we can actually create the session // directory - if create_dir(sess, &session_dir, "session").is_err() { - return; - } + create_dir(sess, &session_dir, "session")?; // Find a suitable source directory to copy from. Ignore those that we // have already tried before. @@ -257,7 +251,7 @@ pub fn prepare_session_directory( ); sess.init_incr_comp_session(session_dir, directory_lock, false); - return; + return Ok(()); }; debug!("attempting to copy data from source: {}", source_directory.display()); @@ -278,7 +272,7 @@ pub fn prepare_session_directory( } sess.init_incr_comp_session(session_dir, directory_lock, true); - return; + return Ok(()); } else { debug!("copying failed - trying next directory"); @@ -478,7 +472,7 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { directory_path } -fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> { +fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorReported> { match std_fs::create_dir_all(path) { Ok(()) => { debug!("{} directory created successfully", dir_tag); @@ -492,13 +486,16 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> { path.display(), err )); - Err(()) + Err(ErrorReported) } } } /// Allocate the lock-file and lock it. -fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, PathBuf), ()> { +fn lock_directory( + sess: &Session, + session_dir: &Path, +) -> Result<(flock::Lock, PathBuf), ErrorReported> { let lock_file_path = lock_file_path(session_dir); debug!("lock_directory() - lock_file: {}", lock_file_path.display()); @@ -510,13 +507,23 @@ fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, Pa ) { // the lock should be exclusive Ok(lock) => Ok((lock, lock_file_path)), - Err(err) => { - sess.err(&format!( + Err(lock_err) => { + let mut err = sess.struct_err(&format!( "incremental compilation: could not create \ - session directory lock file: {}", - err + session directory lock file: {}", + lock_err )); - Err(()) + if flock::Lock::error_unsupported(&lock_err) { + err.note(&format!( + "the filesystem for the incremental path at {} \ + does not appear to support locking, consider changing the \ + incremental path to a filesystem that supports locking \ + or disable incremental compilation", + session_dir.display() + )); + } + err.emit(); + Err(ErrorReported) } } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 70ffff1ab9980..f99d929023852 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -172,7 +172,7 @@ pub fn register_plugins<'a>( let disambiguator = util::compute_crate_disambiguator(sess); sess.crate_disambiguator.set(disambiguator).expect("not yet initialized"); - rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); + rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator)?; if sess.opts.incremental.is_some() { sess.time("incr_comp_garbage_collect_session_directories", || { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 92d05e4806871..969b526235bb2 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -148,7 +148,7 @@ impl<'tcx> Queries<'tcx> { self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), krate, &crate_name, - ); + )?; // Compute the dependency graph (in the background). We want to do // this as early as possible, to give the DepGraph maximum time to @@ -157,7 +157,7 @@ impl<'tcx> Queries<'tcx> { // called, which happens within passes::register_plugins(). self.dep_graph_future().ok(); - result + Ok(result) }) } From 834ec68821b0d911d1ba095518bc7763236216dc Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 26 May 2021 17:44:03 -0700 Subject: [PATCH 2/4] Add test to check behavior when incremental session init fails. --- .../run-make/incremental-session-fail/Makefile | 15 +++++++++++++++ src/test/run-make/incremental-session-fail/foo.rs | 1 + 2 files changed, 16 insertions(+) create mode 100644 src/test/run-make/incremental-session-fail/Makefile create mode 100644 src/test/run-make/incremental-session-fail/foo.rs diff --git a/src/test/run-make/incremental-session-fail/Makefile b/src/test/run-make/incremental-session-fail/Makefile new file mode 100644 index 0000000000000..208a1b13a6d23 --- /dev/null +++ b/src/test/run-make/incremental-session-fail/Makefile @@ -0,0 +1,15 @@ +include ../../run-make-fulldeps/tools.mk + +SESSION_DIR := $(TMPDIR)/session +OUTPUT_FILE := $(TMPDIR)/build-output + +all: + echo $(TMPDIR) + mkdir $(SESSION_DIR) + # Make it so that rustc will fail to create a session directory. + chmod a-w $(SESSION_DIR) + # Check exit code is 1 for an error, and not 101 for ICE. + $(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ] + $(CGREP) "Could not create incremental compilation crate directory" < $(OUTPUT_FILE) + # -v tests are fragile, hopefully this text won't change + $(CGREP) -v "internal compiler error" < $(OUTPUT_FILE) diff --git a/src/test/run-make/incremental-session-fail/foo.rs b/src/test/run-make/incremental-session-fail/foo.rs new file mode 100644 index 0000000000000..d11c69f812a8d --- /dev/null +++ b/src/test/run-make/incremental-session-fail/foo.rs @@ -0,0 +1 @@ +// intentionally empty From e7411a26e4a247c86bb14ab37443bbad35c970b0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 28 May 2021 16:40:22 -0700 Subject: [PATCH 3/4] Add specific help for *how* to fix an incremental lock error. --- compiler/rustc_incremental/src/persist/fs.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index a9925832fd879..83e80b55daec1 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -521,6 +521,19 @@ fn lock_directory( or disable incremental compilation", session_dir.display() )); + if std::env::var_os("CARGO").is_some() { + err.help( + "incremental compilation can be disabled by setting the \ + environment variable CARGO_INCREMENTAL=0 (see \ + https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)", + ); + err.help( + "the entire build directory can be changed to a different \ + filesystem by setting the environment variable CARGO_TARGET_DIR \ + to a different path (see \ + https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)", + ); + } } err.emit(); Err(ErrorReported) From 4c550bc014cae30a3f0e8a7eb14f216ec26c345e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 29 May 2021 08:54:51 -0700 Subject: [PATCH 4/4] Fix incremental-session-fail to work when run as root. --- src/test/run-make/incremental-session-fail/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/run-make/incremental-session-fail/Makefile b/src/test/run-make/incremental-session-fail/Makefile index 208a1b13a6d23..0461bb926e76e 100644 --- a/src/test/run-make/incremental-session-fail/Makefile +++ b/src/test/run-make/incremental-session-fail/Makefile @@ -5,9 +5,8 @@ OUTPUT_FILE := $(TMPDIR)/build-output all: echo $(TMPDIR) - mkdir $(SESSION_DIR) # Make it so that rustc will fail to create a session directory. - chmod a-w $(SESSION_DIR) + touch $(SESSION_DIR) # Check exit code is 1 for an error, and not 101 for ICE. $(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ] $(CGREP) "Could not create incremental compilation crate directory" < $(OUTPUT_FILE)