Change:
} } <del> /// Sets the thread handle for the current thread. /// /// Aborts if the handle or the ID has been set already. pub(crate) fn set_current(thread: Thread) { if CURRENT.get() != NONE || id::get().is_some() { // Using `panic` here can add ~3kB to the binary size. We have complete // control over where this is called, so just abort if there is a bug. rtabort!("thread::set_current should only be called once per thread"); </del> <ins> /// Tries to set the thread handle for the current thread. Fails if a handle was /// already set or if the thread ID of `thread` would change an already-set ID. pub(crate) fn set_current(thread: Thread) -> Result<(), Thread> { if CURRENT.get() != NONE { return Err(thread); </ins> } <del> id::set(thread.id()); </del> <ins> match id::get() { Some(id) if id == thread.id() => {} None => id::set(thread.id()), _ => return Err(thread), } </ins> // Make sure that `crate::rt::thread_cleanup` will be run, which will // call `drop_current`. crate::sys::thread_local::guard::enable(); CURRENT.set(thread.into_raw().cast_mut()); <ins> Ok(()) </ins> } /// Gets the id of the thread that invokes it.

Discussion:
Hi! I have a project where I define a to use as by linking an function to . I was using Rust 1.80.1 and unit tests were working without issues. However, since bumping to 1.81.0, our CI (Linux runners) started failing though no significant changes had been to the code. The thing is, if you built the project with either version and passed the resulting as it seemed to work without issues. I have set up a minimal reproducer that you can inspect . It is just a "hello world" with a simple unit and integration test, though these tests can be removed and the output will be the same when running the steps below. The reproducer's includes sample commands ran through , as I wrote it from a different OS. the repository and check the code at . with Rust 1.80.1. Should work. with Rust 1.81.0. Should fail with . and call some command passing the resulting as , such as . Should work for Rust 1.80.1. and call some command passing the resulting as , such as . Should work for Rust 1.81.0. I have noticed that if I add to the that stores the function and is linked to the tests run without issues in both versions, but I'm not sure if this is a proper solution and the way to work with testing s or if I'm masking some other problem. I have opened the issue here because I think the failure might lie in how the "test runner executable" is built and ran. If you read the outputs I pasted on the reproducer's for the runs, you'll see that the behavior linked to is present in the test runner as the log line is shown at the beginning, in both Rust toolchain versions. Please let me know if this is not the proper place and point me to the appropriate one to open the report. While I am not very knowledgeable about the internals that might have caused this, I'd like to figure this out, particularly to make sure that this cannot happen on an eventual "production" usage with the compiled project and not only on tests, given the actual problem I'm working with would require performing more than just a and any crash during the preload prevents the actual process from running (placing it in could seemingly brick a host!).

I get that this kind of lower level, run-before-main behaviors can be pretty hard to do well, so I really want to be sure I'm doing things right.
Thanks for the report and the detailed reproduction! I have transferred this to rust-lang/rust since this isn't a cargo issue. I believe this was changed by . cc and
Thanks Yeah I was in doubt of where to put it, but since I imagined that managed how the test runner gets built I opened the issue there. Sorry for the inconvenience.
cc
Hi! From that linked thread that I opened we have had a bit of discussion. Just so I have it clear and see if it makes sense to have this bug report open or not: Given the above is true about the call, is this the expected behavior? This is the same doubt written in the Solutions section above: is a way to test code linked to to just make it conditional over not being in a test so it doesn't conflict with the test runner entry-point? I wonder if I might be masking something else that can bite me later. The answer by to the above question is probably_. Aside from the testing suggested, should I fear any other conflicts of this kind? Does the output type or make any difference here?
This falls in the . In short, we don't really guarantee anything in this environment. That said, is one of those features which we have tried to make universally available in the past (e.g. we ensure that the stdio buffer is flushed to ensure output after main is visible), so I think it makes sense to fix this. I have an idea for fixing this, it's just currently blocked on .
I can confirm this when trying to running a test binary compiled to WebAssembly, where I've overridden the methods for getting environment variables. I had some println! calls in there, which started failing in 1.81.0. Removing the println calls makes the test pass again.