From 56fefe19bfcdc9a3ce631615859c7cc5cdd0ee58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 19:50:03 -0400 Subject: [PATCH] cargo-miri: write the Xargo project files atomically --- cargo-miri/bin.rs | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4c9f3aabaa..c4ed92d038 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -319,6 +319,23 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { } } +/// Writes the given content to the given file *cross-process atomically*, in the sense that another +/// process concurrently reading that file will see either the old content or the new content, but +/// not some intermediate (e.g., empty) state. +/// +/// We assume no other parts of this same process are trying to read or write that file. +fn write_to_file(filename: &Path, content: &str) { + // Create a temporary file with the desired contents. + let mut temp_filename = filename.as_os_str().to_os_string(); + temp_filename.push(&format!(".{}", std::process::id())); + let mut temp_file = File::create(&temp_filename).unwrap(); + temp_file.write_all(content.as_bytes()).unwrap(); + drop(temp_file); + + // Move file to the desired location. + fs::rename(temp_filename, filename).unwrap(); +} + /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. @@ -398,28 +415,25 @@ fn setup(subcommand: MiriCommand) { if !dir.exists() { fs::create_dir_all(&dir).unwrap(); } - let mut xargo_toml = File::create(dir.join("Xargo.toml")).unwrap(); - if std::env::var_os("MIRI_NO_STD").is_none() { - // The interesting bit: Xargo.toml (only needs content if we actually need std) - xargo_toml - .write_all( - br#" + // The interesting bit: Xargo.toml (only needs content if we actually need std) + let xargo_toml = if std::env::var_os("MIRI_NO_STD").is_some() { + "" + } else { + r#" [dependencies.std] default_features = false # We support unwinding, so enable that panic runtime. features = ["panic_unwind", "backtrace"] [dependencies.test] -"#, - ) - .unwrap(); - } +"# + }; + write_to_file(&dir.join("Xargo.toml"), xargo_toml); // The boring bits: a dummy project for xargo. // FIXME: With xargo-check, can we avoid doing this? - File::create(dir.join("Cargo.toml")) - .unwrap() - .write_all( - br#" + write_to_file( + &dir.join("Cargo.toml"), + r#" [package] name = "miri-xargo" description = "A dummy project for building libstd with xargo." @@ -428,9 +442,8 @@ version = "0.0.0" [lib] path = "lib.rs" "#, - ) - .unwrap(); - File::create(dir.join("lib.rs")).unwrap().write_all(b"#![no_std]").unwrap(); + ); + write_to_file(&dir.join("lib.rs"), "#![no_std]"); // Determine architectures. // We always need to set a target so rustc bootstrap can tell apart host from target crates.