diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index f0d24d27e85a3..975bf1d18622a 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -721,11 +721,37 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result< } } + let current_session_directory_name = + session_directory.file_name().expect("session directory is not `..`"); + // Now garbage collect the valid session directories. let deletion_candidates = lock_file_to_session_dir.items().filter_map(|(lock_file_name, directory_name)| { debug!("garbage_collect_session_directories() - inspecting: {}", directory_name); + if directory_name.as_str() == current_session_directory_name { + // Skipping our own directory is, unfortunately, important for correctness. + // + // To summarize #147821: we will try to lock directories before deciding they can be + // garbage collected, but the ability of `flock::Lock` to detect a lock held *by the + // same process* varies across file locking APIs. Then, if our own session directory + // has become old enough to be eligible for GC, we are beholden to platform-specific + // details about detecting the our own lock on the session directory. + // + // POSIX `fcntl(F_SETLK)`-style file locks are maintained across a process. On + // systems where this is the mechanism for `flock::Lock`, there is no way to + // discover if an `flock::Lock` has been created in the same process on the same + // file. Attempting to set a lock on the lockfile again will succeed, even if the + // lock was set by another thread, on another file descriptor. Then we would + // garbage collect our own live directory, unable to tell it was locked perhaps by + // this same thread. + // + // It's not clear that `flock::Lock` can be fixed for this in general, and our own + // incremental session directory is the only one which this process may own, so skip + // it here and avoid the problem. We know it's not garbage anyway: we're using it. + return None; + } + let Ok(timestamp) = extract_timestamp_from_session_dir(directory_name) else { debug!( "found session-dir with malformed timestamp: {}",