-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std::collections::hash::map::new
stuck on Windows 7
#99341
Comments
#94098 seems possibly relevant, but since this is just hanging, I’m not sure we can blame it all on snake oil this time. Though maybe? Wouldn’t be the first time it breaks the system in incomprehensible ways. First and foremost – could you minimize the reproducer? Both from the perspective of the Rust code (sounds like simply calling |
The nightly that it first started failing under is the first nightly after #96917 was merged, which just happens to be directly related to |
I personally do not have Windows 7, and would prefer not not bother players with more testing unless really necessary. But I can confirm that at least one of the systems was clean Windows 7 Home Premium from here.
and this in the code: c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, but unfortunately I can not say how relevant that it. |
It's unlikely to be a problem with In any case, I think the fix here is to simplify the rng code so it's as close to the old version as possible. |
Yes logging is initialized in DllMain, I will soon post a very small example |
So it is related to it being library. Exe code (not much interesting)
const TOOLCHAIN : &str = include_str!("../rust-toolchain");
fn main() {
println!("does not matter in exe, but toolchain is: {}", TOOLCHAIN);
println!("In exe `std::collections::HashSet::new()` works");
let mut has_set = std::collections::HashSet::new();
println!("No issue on Windows 7");
has_set.insert(0);
unsafe{is_dll_ok()};
println!("dll called");
}
#[link(name = "test_dll")]
extern "cdecl" {
pub fn is_dll_ok();
} DLL code
lib.rs pub const DLL_PROCESS_ATTACH: u32 = 1;
pub const DLL_PROCESS_DETACH: u32 = 0;
const TOOLCHAIN : &str = include_str!("../rust-toolchain");
#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern "system" fn DllMain(
_module: *mut (),
call_reason: u32,
_reserved: *mut std::os::raw::c_void,
) -> i32 {
if call_reason == DLL_PROCESS_ATTACH {
println!("test toolchain: {}", TOOLCHAIN);
println!("going to hang on Windows 7 in std::collections::HashSet::new()");
let mut has_set = std::collections::HashSet::new();
println!("Unreachable on Windows 7");
has_set.insert(0);
1
} else if call_reason == DLL_PROCESS_ATTACH {
1
} else {
1
}
}
#[no_mangle]
pub extern "cdecl" fn is_dll_ok() {
if TOOLCHAIN.contains("nightly-2022-05-19-i686-pc-windows-msvc") {
println!("under Windows 7 we can not get here, because it hangs in DllMain");
} else if TOOLCHAIN.contains("nightly-2022-05-18-i686-pc-windows-msvc") {
println!("on old version the dll is OK")
} else {
println!("sorry did not bother to parse the toolchain version to say if this one works")
}
} Cargo.toml [package]
name = "test_dll"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] rust-toolchain
|
Ok, I've submitted a fix. See the PR linked above. |
I know |
Possibly not, which is why I filed a fix. Using the std in |
std::collections::hash::map::new
stuck on Windows 7
🤔 @ChrisDenton I get maybe a bit crazy idea, but my DLL hooks functions anyway, so if I would limit if call_reason == win_api::DLL_PROCESS_ATTACH {
if let Some(arg) = std::env::args().find(|a| a.starts_with(PROXY_OVERRIDE)) {
let override_path = arg.split_at(PROXY_OVERRIDE.len()).1.to_lowercase();
if !win_api::get_dylib_path(module).unwrap()
.to_str().unwrap().to_lowercase().ends_with(&override_path) {
return win_api::load_library(&override_path) as i32
}
}
}
let path = process_path::get_executable_path().unwrap();
let file_name = path.file_name().unwrap().to_str().unwrap();
match file_name.to_lowercase() {
// ... hook main function of the application
} and before the hooked main do my initialization. (for my use case any time before main is good enough) Would that eliminate wast majority of potential breaks related to |
Calling load_library in |
On further inspection it seems unlikely that #99371 fixes the issue although I still think it's a good cleanup and simplification (so I stand by my r+). That is, looking at your back trace... the deadlock you're hitting is from inside BCryptGenRandom itself, not from our code that synchronizes while calling it. It looks like BCryptGenRandom does some synchronizing when getting the preferred RNG (I guess). My hunch is for whatever reason this ends up needing to take the loader lock, and because the loader lock is already held inside If this is the case, I don't think there's a way for us to solve it... we can't detect it this in advance, nor is there a good alternative approach we can take that doesn't make things worse when outside To be clear, we (at least at the moment) don't really support calling into libstd from initialization contexts like DllMain. We sometimes fix bugs from this it, but mostly on a best-effort basis, which depending on stuff like severity/impact/maintance burden/hackiness/the weather/etc, all of which is mostly judged on an ad-hoc basis. Even when we fix it, there's no guarantee it'd going to keep working in the future. Given that it's only broken on Win71 and there doesn't seem to be a great approach that wouldn't make things worse outside of it (and/or for on newer windows), I'm inclined to just say... sorry, it's not really supported. Anyway, while things from libstd like HashMap (well, the Footnotes
|
😮 I am loading an dll from DLL main for years now, and you just told me that Microsoft can screw me over at any time 😮 Well thanks for warning. I will keep doing that and hope Microsoft will never change that. |
If you scroll down this page it has a list of things Microsoft says you should never do in DllMain: |
This is what I was saying before about the stack trace not actually reflecting the changes -- but I also mentioned the bizarre coincidence that this hang bisects to exactly the same nightly as the one with the patch. I agree with keeping the revised changes in all cases and @xNxExOx I'd be curious what Application Verifier finds if you run it against a minimum repro. |
@mqudsi I tried Application Verifier, because I was wondering what it does. |
I tried this code:
log4rs = "1.1.1"
HashSet::new called here
I expected it to work on Windows 7 the same as it works on other platforms.
Instead, this happened:
the code get stuck in the initialization of logging, we acquired same-ish stack from multiple people using Windows 7
It was always
[Inline Frame] pcre3.dll!std::collections::hash::map::impl$81::new::KEYS::__getit::closure$0() Line 353
callingbcrypt.dll!_BCryptGenRandom@16�()
On Windows 10 as under Wine the application starts normally
My rust code produces DLL that is loaded by C++ application from 10 years ago
Meta
Latest working version:
nightly-2022-05-18-i686-pc-windows-msvc
Earliest version that gets stuck:
nightly-2022-05-19-i686-pc-windows-msvc
The text was updated successfully, but these errors were encountered: