Skip to content

Commit 1594b58

Browse files
Rollup merge of #107595 - michaelwoerister:retry_proc_macro_loading, r=petrochenkov
Retry opening proc-macro DLLs a few times on Windows. On Windows, the compiler [sometimes](https://users.rust-lang.org/t/error-loadlibraryexw-failed/77603) fails with the message `error: LoadLibraryExW failed` when trying to load a proc-macro crate. The error seems to occur intermittently, similar to #86929, however, it seems to be almost impossible to reproduce outside of CI environments and thus very hard to debug. The fact that the error only occurs intermittently makes me think that this is a timing related issue. This PR is an attempt to mitigate the issue by letting the compiler retry a few times when encountering this specific error (which resolved the issue described in #86929).
2 parents e99e05d + 227b285 commit 1594b58

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

Diff for: compiler/rustc_metadata/src/creader.rs

+40-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
3333
use proc_macro::bridge::client::ProcMacro;
3434
use std::ops::Fn;
3535
use std::path::Path;
36+
use std::time::Duration;
3637
use std::{cmp, env};
3738

3839
#[derive(Clone)]
@@ -689,8 +690,7 @@ impl<'a> CrateLoader<'a> {
689690
) -> Result<&'static [ProcMacro], CrateError> {
690691
// Make sure the path contains a / or the linker will search for it.
691692
let path = env::current_dir().unwrap().join(path);
692-
let lib = unsafe { libloading::Library::new(path) }
693-
.map_err(|err| CrateError::DlOpen(err.to_string()))?;
693+
let lib = load_dylib(&path, 5).map_err(|err| CrateError::DlOpen(err))?;
694694

695695
let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
696696
let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) }
@@ -1093,3 +1093,41 @@ fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
10931093
visit::walk_crate(&mut f, krate);
10941094
f.spans
10951095
}
1096+
1097+
// On Windows the compiler would sometimes intermittently fail to open the
1098+
// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
1099+
// system still holds a lock on the file, so we retry a few times before calling it
1100+
// an error.
1101+
fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> {
1102+
assert!(max_attempts > 0);
1103+
1104+
let mut last_error = None;
1105+
1106+
for attempt in 0..max_attempts {
1107+
match unsafe { libloading::Library::new(&path) } {
1108+
Ok(lib) => {
1109+
if attempt > 0 {
1110+
debug!(
1111+
"Loaded proc-macro `{}` after {} attempts.",
1112+
path.display(),
1113+
attempt + 1
1114+
);
1115+
}
1116+
return Ok(lib);
1117+
}
1118+
Err(err) => {
1119+
// Only try to recover from this specific error.
1120+
if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {
1121+
return Err(err.to_string());
1122+
}
1123+
1124+
last_error = Some(err);
1125+
std::thread::sleep(Duration::from_millis(100));
1126+
debug!("Failed to load proc-macro `{}`. Retrying.", path.display());
1127+
}
1128+
}
1129+
}
1130+
1131+
debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
1132+
Err(format!("{} (retried {} times)", last_error.unwrap(), max_attempts))
1133+
}

0 commit comments

Comments
 (0)