Question: target_os = "openbsd", target_arch = "aarch64", no_elf_tls)))] <ins> #[doc(hidden)] </ins> mod imp { use std::cell::Cell;

There is an  in the scoped TLS module, which allows for sharing of data that wasn't meant to be shared. An unqualified should only_ be used when provides some sort of threadsafe locking mechanism. and do not. This lets us, for example, clone an or between threads, in safe code: Here, we have clones from different threads being interleaved, which can cause unsafety if there's a race on the refcount. We could also cause unsafety with a , or any other non-Sync type. basically lets us share across threads even if . I put the sleeps in there because somehow without them the routines are run serially. Note that this is not a problem with the API. I'm using here because to exploit one needs to be able to share across threads, and has an additional bound which doesn't satisfy. Any usable API will probably have to make the assumption that . Nor is this a problem with , since it can be done with , too. Solution: Make it ... I think. I'm not familiar with this API, and I'm not sure why it's even in the first place.
cc
cc This seems concerning: this is designed to be thread-local, so that e.g. storing a works (which would be safe, if it were guaranteed to stay on one thread). However currently requires unconditionally, hence this overly-accepting impl.
Qualifying the impl with breaks scoped TLS for (see the associated PR); because becomes no longer and thus can't be stuffed inside a static.
I believe the only way statics can be safe is by requiring the absence of Sync. That may sound odd, but consider the following: - sending thread-local references across threads is memory unsafe even with no interior mutability a static with no interior mutability is almost entirely useless, certainly not a common case non- containers offering interior mutabilities are cheaper and preferred to ones, where they can be used The main issue is actually within the libstd TLS implementation: is a wrapper for getters so it's unaffected by it, but may live in a static or a global one, depending on whether the platform natively supports TLS or not. -ing a across threads is actually safe on the architectures which do not have native TLS support. However, allowing it on some architectures and not on others is undesirable. Should use an accessor model like ?


Question: target_os = "openbsd", target_arch = "aarch64", no_elf_tls)))] <ins> #[doc(hidden)] </ins> mod imp { use std::cell::Cell;

Then the actual borrow of a static is an implementation detail and happens on the thread where the key is used, not where it was itself borrowed.
"I believe the only way #[threadlocal] statics can be safe is by requiring the absence of ." This is wrong, I think. For example, one might use thread local data for intrusive linked lists of hazard pointers. They would be thread local but might still be (one can guarantee existence with scoped threads or in certain circumstances where threads are bound to cores). That said you can obviously come up with other representations. In any case, I've mostly come around to believing that we need a separate lifetime (not just for this, but for things like ensuring that can't catch an error in a thread that changes thread local data, violating exception safety).
Based on what wrote, it seems like the TLS interface requires a that only allows non- data and is still accessible like one. One idea I had of how to enable this in todays Rust is to make generate a unit like struct instead of a . That struct would be and have a impl: According to this could also help with , but I'm not familiar enough with the TLS API in general to really reason about this.
I was expecting the impl to target an intermediary type, not the contents themselves. and have their own APIs to deal with. You would still be about to use the TLS API provided by libstd with thread-safe data, it's just the low-level which would have the requirement. Ideas of thread-local lifetimes predate the removal of from , and I'm not sure how relevant they are anymore. I'm also conflating thread-safe data access and thread lifetime... but how long does a thread live? What would unify with? Actually, there's an... easy solution for this. Somehow we were blinded by language semantics, but their details are fluid. It is trivial to make borrows of behave like borrows of an arbitrary rvalue, allowing the resulting reference to be passed down, but not returned. That would ensure that the the thread is just as alive for such borrows as it is for stack ones. would still require a like has, because it may not be when native TLS is supported. But both their APIs are compatible with such a change.
Wouldn't that limit the usability of thread locals in some cases, though?


Question: target_os = "openbsd", target_arch = "aarch64", no_elf_tls)))] <ins> #[doc(hidden)] </ins> mod imp { use std::cell::Cell;

e.g., wouldn't that make it difficult to have a thread local point to another thread local? Maybe I just have to think about it. (BTW, I'm aware we're just talking about the low-level API :)).
in a , borrows are , I didn't even think of that. First off, a global static shouldn't be allowed to borrow a static. And in general, having borrows in a is going to be difficult to support, except for non- data, because they would be right now. We could disallow borrows or we could give some kind of scope to those borrows. Which makes me think, as a compromise between a lifetime and , there could be a pseudo-(rvalue)-scope. Combined with the ability to leave out in globals' type (or not having a type at all), the scope should bubble up into users of those statics. They would behave as if they were borrowed before everything else in the function where they're used, but still not (and they can't be returned from functions).
There's a few intertwined issues here at play, so I just want to quickly summarize the way I see things: This does not affect as it which has an , which while sound should be fixed, allowing removal of the block for . A borrow of a static should not yield something with the lifetime, as that is clearly not sound. I'm not sure I follow why we might require the types in a are not , I haven't quite followed that. Due the cross-platform requirements of std, however, I believe the best solution here is to use the same strategy as with an indirect accessor to ensure the semantics are the same across platforms that have and those that don't (where a normal is used).
triage: P-medium This is an unstable API so it's not super-high priority to fix, but we should defnitely fix!
requiring that a is not is an easy way to ensure that a borrow of it, while , cannot escape the current thread. I've changed my mind and prefer an rvalue borrow semantic for , but it still is the case that and use non- statics (ignoring the workarounds for ). If was supported everywhere, having rvalue borrow semantics wouldn't hurt the std TLS API (aside from stability issues with ), as the access patterns are already through anonymous lifetimes (references passed to closures).


Question: target_os = "openbsd", target_arch = "aarch64", no_elf_tls)))] <ins> #[doc(hidden)] </ins> mod imp { use std::cell::Cell;

Maybe a combined strategy, where borrows of statics are iff the data is not (and rvalue-like otherwise), might work better and would require fewer changes to the std TLS implementation.
Right, but returning a borrow with a lifetime for a global is unsafe for other reasons (the lifetime of the thread is not ).
how can it be abused without sending it to a different thread?
The actual values themselves do not have a lifetime, so it can be a source of unsafety to advertise otherwise. For example you could stick a into a TLS value with a destructor, but when the destructor runs that pointer could be invalid.


Question: None } }) <del> .filter(|feature| { RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature)) }) </del> <ins> .filter(|feature| features.contains(&Symbol::intern(feature))) </ins> .map(|feature| Symbol::intern(feature)) .collect() }

introduced what I think is a logic error: is now always on s390x targets, even if the feature gate is not set. I verified this with Miri, which shares the logic with rustc so it should be a correct test. This should print when built without (as the feature seems off-by-default), but prints instead: Cc
I believe this is intended. is an always-available code-generation option in LLVM disguised as a target feature. Also, enabling for a single function is useless due to how IBM Z's mechanism works.
By "always available" you mean that there is no difference between and ? But then why would one set this feature?
There are differences between the code generated with or without attribute. Still, unlike other processors, this is a platform-specific (potential) unwinding mechanism that does not require additional processor features when you don't have DWARF information or don't want to use it (profilers on IBM Z systems may use it).
The point of is to reflect whether the feature is enabled. It doesn't matter whether it could be enabled or anything like that. For example, is false unless you are building with . It's not about whether static builds are "available" (that's not even a meaningful question), it's about the flags used to build this code. Maybe you are confusing with . Those are not the same thing. If this is not actually a target feature, then it is not clear that we want this to be a target feature in Rust. Though I guess is (unfortunately) precedent here. What happens when I mix code built with and without ? Does anything go wrong?
No, it just means you won't be able to perform unwinding actions based purely on backchain information.
If you want to know how Clang passes attribute in this situation, you can take a look at this Godbolt playground: In this example, is specified (see ), so the compiler needs to generate backchain-enabled code.
Okay, thanks. I don't fully understand the consequences of that -- if this makes Rust panic catching go wrong, that still seems bad -- but :shrug: whatever. The point of the issue is that the behavior of is wrong. Are you still arguing against that or have my examples above been convincing?


Question: None } }) <del> .filter(|feature| { RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature)) }) </del> <ins> .filter(|feature| features.contains(&Symbol::intern(feature))) </ins> .map(|feature| Symbol::intern(feature)) .collect() }

It is currently inconsistent with how behaves, which is a similar kind of "target feature" that's really more like a boolean codegen toggle.
Hmm, I don't know what we should do here, if we need to fix this issue, how should we avoid passing the to in the current framework?
The logic that decides what to pass to LLVM and the logic that decides what is set in are completely independent. (That's fairly recent and might have happened after you implemented this feature.) I think all that needs to be done is change this to simply The feature will have been to in . But better add a test for this to be sure.
Yes, I believe the change was done after I . I will try to implement this change then.


Question: c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, ) }; <del> if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) } </del> <ins> if ret != 0 { fallback_rng() } else { v } </ins> } /// Generate random numbers using the fallback RNG function (RtlGenRandom) #[cfg(not(target_vendor = "uwp"))] <del> fn fallback_rng() -> Result<(u64, u64), io::Error> { </del> <ins> #[inline(never)] fn fallback_rng() -> (u64, u64) { </ins> let mut v = (0, 0); let ret = unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) }; <del> if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) } </del> <ins> if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) } </ins> } /// We can't use RtlGenRandom with UWP, so there is no fallback #[cfg(target_vendor = "uwp")] <del> fn fallback_rng() -> Result<(u64, u64), io::Error> { Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP")) </del> <ins> #[inline(never)] fn fallback_rng() -> (u64, u64) { panic!("fallback RNG broken: RtlGenRandom() not supported on UWP"); </ins> }

I tried this code: 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 calling ! 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 Latest working version: Earliest version that gets stuck:
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 from should suffice?) and the OS setup (does this occur on a fresh OS install? If not, what modifications are necessary for the reduced reproducer to start hanging)
The nightly that it first started failing under is the first nightly after was merged, which just happens to be directly related to ? That's really whack given that the stack trace above shows the hang taking place just before any of the changes that PR introduced are invoked.
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 . And calling directly seems pretty complicated :( It requires calling which still requires knowing which algorithm to chose, and what flags to use :( I also see this in the documentation: and this in the code: , but unfortunately I can not say how relevant that it.
It's unlikely to be a problem with itself as that works in the earlier version. Is this code being used in ? 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.


Question: c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, ) }; <del> if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) } </del> <ins> if ret != 0 { fallback_rng() } else { v } </ins> } /// Generate random numbers using the fallback RNG function (RtlGenRandom) #[cfg(not(target_vendor = "uwp"))] <del> fn fallback_rng() -> Result<(u64, u64), io::Error> { </del> <ins> #[inline(never)] fn fallback_rng() -> (u64, u64) { </ins> let mut v = (0, 0); let ret = unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) }; <del> if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) } </del> <ins> if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) } </ins> } /// We can't use RtlGenRandom with UWP, so there is no fallback #[cfg(target_vendor = "uwp")] <del> fn fallback_rng() -> Result<(u64, u64), io::Error> { Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP")) </del> <ins> #[inline(never)] fn fallback_rng() -> (u64, u64) { panic!("fallback RNG broken: RtlGenRandom() not supported on UWP"); </ins> }

It have something to do with initializing the logs in , but I have no clue what specific small detail it is that breaks it <details<summaryExe code (not much interesting)</summary<p</p</details<details<summaryDLL code</summary rust-toolchain </p</details
Ok, I've submitted a fix. See the PR linked above. is tricky because of the loader lock and other tricks the OS does while a dll is loading.
I know is tricky, but is there any better option to do initialization, if I do not control the exe? And I need to fix the exe (by doing memory patches) before it reaches its .
Possibly not, which is why I filed a fix. Using the std in only works on a "best effort" basis. We do try to support it as much as reasonably possible but there are always going to be limitations due to the OS.
I get maybe a bit crazy idea, but my DLL hooks functions anyway, so if I would limit to 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 ? Or is it not worth it?
Calling load_library in is susceptible to deadlocks unless the library is already loaded. I think you might just need to be very careful about the dependencies you use. Maybe there's a different or lighter weight logger you can use in place of log4js that doesn't use HashSet?
On further inspection it seems unlikely that 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 , this causes a deadlock. 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 (and/or on newer systems, which apparently works?). So I'm not sure what we can do about this.


Question: c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, ) }; <del> if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) } </del> <ins> if ret != 0 { fallback_rng() } else { v } </ins> } /// Generate random numbers using the fallback RNG function (RtlGenRandom) #[cfg(not(target_vendor = "uwp"))] <del> fn fallback_rng() -> Result<(u64, u64), io::Error> { </del> <ins> #[inline(never)] fn fallback_rng() -> (u64, u64) { </ins> let mut v = (0, 0); let ret = unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) }; <del> if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) } </del> <ins> if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) } </ins> } /// We can't use RtlGenRandom with UWP, so there is no fallback #[cfg(target_vendor = "uwp")] <del> fn fallback_rng() -> Result<(u64, u64), io::Error> { Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP")) </del> <ins> #[inline(never)] fn fallback_rng() -> (u64, u64) { panic!("fallback RNG broken: RtlGenRandom() not supported on UWP"); </ins> }

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 Win7[^1] 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 it uses in particular) is unlikely to be viable in DllMain (at least on win7), I think things from liballoc should be fine (so long as your allocator supports it), so my recommendation might be to switch to using /, which shouldn't have this issue. Another option would be to use a different hasher that doesn't need randomness, but be careful about that. [^1]: It may be worth reconsidering if this happens on newer Windows as well. There are some... unpleasant approaches we could consider, but I don't think they're worth it for Win7 given how close to EOL it is, and the fact that we don't really support use from DllMain anyway.
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 libstd support being a best-effort deal, but I'm guessing that something in how/what gets locked/attempted before the call into changes the state in some unsupported way that caused the bug to surface. I'd be curious what Application Verifier finds if you run it against a minimum repro.


Question: c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, ) }; <del> if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) } </del> <ins> if ret != 0 { fallback_rng() } else { v } </ins> } /// Generate random numbers using the fallback RNG function (RtlGenRandom) #[cfg(not(target_vendor = "uwp"))] <del> fn fallback_rng() -> Result<(u64, u64), io::Error> { </del> <ins> #[inline(never)] fn fallback_rng() -> (u64, u64) { </ins> let mut v = (0, 0); let ret = unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) }; <del> if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) } </del> <ins> if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) } </ins> } /// We can't use RtlGenRandom with UWP, so there is no fallback #[cfg(target_vendor = "uwp")] <del> fn fallback_rng() -> Result<(u64, u64), io::Error> { Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP")) </del> <ins> #[inline(never)] fn fallback_rng() -> (u64, u64) { panic!("fallback RNG broken: RtlGenRandom() not supported on UWP"); </ins> }

I tried Application Verifier, because I was wondering what it does. My code is in the dll, and it seems to not work for only dll, so I needed to enable the tests for the exe directly. did not catch anything. But what is bit more funny is that enabling causes the application to fail so early that none of my code is executed... (at least if I set it up correctly and understand what it is doing)


Question: # libcurl, instead it should compile its own. ENV LIBCURL_NO_PKG_CONFIG 1 <ins> # There was a bad interaction between "old" 32-bit binaries on current 64-bit # kernels with selinux enabled, where ASLR mmap would sometimes choose a low # address and then block it for being below `vm.mmap_min_addr` -> `EACCES`. # This is probably a kernel bug, but setting `ulimit -Hs` works around it. # See also `src/ci/run.sh` where this takes effect. ENV SET_HARD_RLIMIT_STACK 1 </ins> ENV DIST_REQUIRE_ALL_TOOLS 1

The docs currently claim that the minimum Linux kernel version for is 2.6.18 (released September 20th, 2006). This is because RHEL 5 used that kernel version. However, RHEL 5 entered ELS on March 31, 2017. Should we continue to support RHEL 5 for , or should we increase the minimum Linux Kernel version to 2.6.27 (2nd LTS) or 2.6.32 (RHEL 6, 3rd LTS)? . Even bumping the min-version to 2.6.27 would allow us to remove most of the Linux-specific hacks in . Example: .
Given that RHEL is the only reason we keep comically old kernel versions around, I would propose that Rust only support RHEL until Maintenance Support ends. This is (essentially) what we already did for RHEL 4. Rust never supported RHEL 4, and back when RHEL 5 still had maintenance support. It would be nice to get someone from Red Hat or a RHEL customer to comment. This policy would allow us to increment the minimum kernel from 2.6.18 to 2.6.32 (and remove a lot of Linux-specific hacks). Note that RHEL has a weird (and very long) support system for RHEL 4, 5, and 6 (sources: and ). It has 5 major steps: Full Support Normal support of the OS Maintenance Support 1 Bug/Security fixes Limited hardware refresh Maintenance Support 2 Bug/Security fixes The end of this phase is considered "Product retirement" Extended Life Cycle Support (ELS) Additional paid product from Red Hat Gives updates for a longer period of time No additional releases/images Extended Life Phase (ELP) No more updates Limited Technical Support End date not given by Red Hat Current status of RHEL versions: RHEL 4 Not supported by Rust Currently in ELP (no end date specified) ELS ended March 31, 2017 RHEL 5 Supported by Rust Currently in ELS Maintenance Support ended March 31, 2017 ELS ends November 30, 2020 RHEL 6 Supported by Rust Currently in Maintenance Support 2 Maintenance Support ends November 30, 2020
cc which I think they could be related.


Question: # libcurl, instead it should compile its own. ENV LIBCURL_NO_PKG_CONFIG 1 <ins> # There was a bad interaction between "old" 32-bit binaries on current 64-bit # kernels with selinux enabled, where ASLR mmap would sometimes choose a low # address and then block it for being below `vm.mmap_min_addr` -> `EACCES`. # This is probably a kernel bug, but setting `ulimit -Hs` works around it. # See also `src/ci/run.sh` where this takes effect. ENV SET_HARD_RLIMIT_STACK 1 </ins> ENV DIST_REQUIRE_ALL_TOOLS 1

It also may be worth to drop support of Windows XP and Vista (especially considering that panics are broken on XP since June 2016, see: ). Previously it was discussed . cc
Besides , which other things would we be able to clean up?
Good question! There are 6 workarounds in for older Linux versions (that I could find). Increasing the minimum version to 2.6.32 (aka 3rd Kernel LTS, aka RHEL 6) would fix 5 of them. Code links are inline: (mentioned above, in 2.6.23) ( in 2.6.24, there is also the mention of a bug occuring on "some linux kernel at some point") to atomically set the flag on the pipe fds ( in 2.6.27) ( in 2.6.27) to permit use of ( in 2.6.28) ( in 4.5, not fixed by this proposal) As you can see, the workarounds fixed by this proposal all have a similar flavor.
I am Red Hat's maintainer for Rust on RHEL -- thanks for the cc. I try to keep an eye on new issues, but this one slipped past me. Red Hat only ships the Rust toolchain to customers for RHEL 7 and RHEL 8. If our customers would like to use Rust on older RHEL, they can do so via , and we'll support them in the same way we would for any other third-party software. Internally we do also build and use on RHEL 6, mostly because it's needed to ship Firefox updates. This is where it gets a little hairy, because each RHEL N is bootstrapped on RHEL N-1 and often kept that way -- meaning a lot of our RHEL 6 builders are still running on a RHEL 5 kernel. I would have to apply local workarounds if upstream Rust loses the ability to run on 2.6.18 kernels. We prefer to keep fixes upstream as much as possible, both for open sharing and to avoid bitrot. Is there much of a benefit to removing the current workarounds? I agree all of that code is annoying and cumbersome, but it's already written, and as far as I know it hasn't been a maintenance burden. Do you see otherwise?


Question: # libcurl, instead it should compile its own. ENV LIBCURL_NO_PKG_CONFIG 1 <ins> # There was a bad interaction between "old" 32-bit binaries on current 64-bit # kernels with selinux enabled, where ASLR mmap would sometimes choose a low # address and then block it for being below `vm.mmap_min_addr` -> `EACCES`. # This is probably a kernel bug, but setting `ulimit -Hs` works around it. # See also `src/ci/run.sh` where this takes effect. ENV SET_HARD_RLIMIT_STACK 1 </ins> ENV DIST_REQUIRE_ALL_TOOLS 1

If there are any known issues with such Linux compatibility code, I am definitely willing to take assignment for fixing them.
(Not a Rust maintainer, but I'm a Rust user and maintain a lot of other OSS software so I have well-developed feelings around supporting Very Old Software :-)) Do you have any sense of on what timeline Rust would be able to drop support for 2.6.18 kernels without causing you pain? In general I don't think people mind supporting configurations that have users and are painful to work around, but needing to support them for forever is a bitter pill to swallow! Particularly as they get harder and harder to test over time (already I have no idea how to test on really old kernels besides building it myself). So if there was an estimate "we'd like to be able to support this until Q2 2020", even if it's not set in stone, I think that would be very helpful!
The other benefit would be that Rust wouldn't have to use CentOS 5 for CI, which means we don't have to patch LLVM (and Emscripten LLVM) to compile on those systems. Of course that's also fairly limited in scope.
As soon as we stop shipping Firefox and Thunderbird updates on RHEL 6, I won't need Rust there anymore. AFAIK this does correspond to the end of Maintenance Support, November 30, 2020. Then I'll be on to RHEL 7 builders as my minimum, probably still with some RHEL 6 2.6.32 kernels involved. It should be fine for me if we update CI to CentOS 6. This is mostly concerned with how the release binaries are linked to GLIBC symbol versions, which is all in userspace. It's a broader community question whether any other Rust users still care about running on RHEL or CentOS 5. (Small caveat - glibc support for a symbol can still return , .)
I noticed that Red Hat also has Extended Life Cycle Support (ELS) for RHEL 6 until June 30, 2024. Will you need RHEL 5 to work during this time? I don't know how ELS works with Firefox updates. Also, is there any reason RHEL 4 support wasn't an issue prior to March 31, 2017 (while RHEL 5 was still normally supported)?


Question: # libcurl, instead it should compile its own. ENV LIBCURL_NO_PKG_CONFIG 1 <ins> # There was a bad interaction between "old" 32-bit binaries on current 64-bit # kernels with selinux enabled, where ASLR mmap would sometimes choose a low # address and then block it for being below `vm.mmap_min_addr` -> `EACCES`. # This is probably a kernel bug, but setting `ulimit -Hs` works around it. # See also `src/ci/run.sh` where this takes effect. ENV SET_HARD_RLIMIT_STACK 1 </ins> ENV DIST_REQUIRE_ALL_TOOLS 1

This issue came up for me when dealing with opening files in , see for more info. No single RHEL 5 issue is that bad, it's mainly just the sum of a bunch of tiny issues.
I'm not on that team, but AFAIK we don't ship Firefox updates for ELS. The last build I see for RHEL 5 was . Maybe there could be an exception for a severe security issue, but I really doubt we'd rebase to newer Firefox for that, which means Rust requirements won't change. New Firefox ESR versions do require a newer Rust toolchain too, which is generally why we have to keep up. Otherwise we could just freeze some older compat rustc while upstream moves on. Rust wasn't required until Firefox 52.
that makes perfect sense to me, thanks for clarifying. So the proposed policy would be: Support RHEL until RHEL is retired (i.e. ends normal support). This would mean: Supporting RHEL 5 (v2.6.18) until November 30, 2020 Supporting RHEL 6 (v2.6.32) until June 30, 2024 Supporting RHEL 7 (v3.10) until May, 2029 This is a much longer support tail than any other Linux distros (that I know of), so it would also be the effective minimum kernel version of , , and their dependencies. How does that sound to people? EDIT: The alternative to this would be Support RHEL until it is retired, taking the table above and incrementing the RHEL versions by 1. It would also mean being able to drop RHEL 5 support now.
Sure, that's ideal for me. :smile: As mentioned, is just needed for kernel support, as far as I'm concerned. Userspace concerns like GLIBC symbol versions can stick to currently supported for my needs.
Red Hat should backport the features we need (CLOEXEC and getrandom, in particular) to whatever kernels that it wants Rust to support. I don't know any good reason why they don't do so, other than it's cheaper to convince the whole world to keep supporting older kernel versions than it is to do the backports. We should change that dynamic.


Question: # libcurl, instead it should compile its own. ENV LIBCURL_NO_PKG_CONFIG 1 <ins> # There was a bad interaction between "old" 32-bit binaries on current 64-bit # kernels with selinux enabled, where ASLR mmap would sometimes choose a low # address and then block it for being below `vm.mmap_min_addr` -> `EACCES`. # This is probably a kernel bug, but setting `ulimit -Hs` works around it. # See also `src/ci/run.sh` where this takes effect. ENV SET_HARD_RLIMIT_STACK 1 </ins> ENV DIST_REQUIRE_ALL_TOOLS 1

The alternative to this would be Support RHEL N until it is retired I think we should not officially support retired OS versions (well, maybe with some grace period), so I prefer this option. Supporting 14 year old kernels seems a bit too much to me. each RHEL N is bootstrapped on RHEL N-1 and often kept that way -- meaning a lot of our RHEL 6 builders are still running on a RHEL 5 kernel Is it possible to apply kernel patches to those builders to add support for functionality like CLOEXEC? Or build Firefox separately on RHEL 6?
I think it won't be fruitful for us to debate the merits of stable enterprise kernels, but no, this is not a possibility. An alternative take is "Red Hat should be responsible for the work in Rust to maintain the support they want" -- here I am, ready and willing. I definitely can't change those kernels. The ones that are stuck on N-1 are precisely to avoid rocking the boat, and backporting features is a big change. Some of our arches do eventually update the builders to their matching N kernel, but some don't, and I don't know all the reasons. If the workarounds are removed, then I will have to reapply them in our own builds. This assumes I keep using only our own binaries -- if I ever have to re-bootstrap from upstream binaries for stage0, I would also have to use some interception (like ) to hack in the workarounds. This is all possible, but much worse than the status quo of maintaining support here.
I think this sounds reasonable. We aren't going to be able to update these kernels, it's just a question of when we would drop support for these OSes. Especially given that we wont need RHEL 5 CI support, I think that leaving things as they are is fine. I opened this issue to verify two things: 1) That we weren't intending on supporting RHEL 5 "forever", and had a clear date when to drop support. 2) That someone from Red Hat actively cared about supporting these older kernels. It looks like both these things are true. We should remove RHEL 5 workarounds after November 30, 2020. This issue can be postponed until then.


Question: # libcurl, instead it should compile its own. ENV LIBCURL_NO_PKG_CONFIG 1 <ins> # There was a bad interaction between "old" 32-bit binaries on current 64-bit # kernels with selinux enabled, where ASLR mmap would sometimes choose a low # address and then block it for being below `vm.mmap_min_addr` -> `EACCES`. # This is probably a kernel bug, but setting `ulimit -Hs` works around it. # See also `src/ci/run.sh` where this takes effect. ENV SET_HARD_RLIMIT_STACK 1 </ins> ENV DIST_REQUIRE_ALL_TOOLS 1

EDIT: For our use case in , we were able to add compatibility for RHEL 5 .
See for a recent case where supporting such ancient kernels required extra manual work ( to the 2 lines mentioned by above). I am not sure how often that comes up, but probably the hardest part is to even notice that it happens -- and even then those codepaths will likely linger untested.
Yes, but this will still be true in general. If the CI kernel is newer than whatever kernel baseline we choose, it will be possible for newer syscalls to pass undetected. I don't know if we have any control over that -- can we choose a particular VM image? So that leaves us with a stated policy of support. The more that developers are aware of such issues, the better, but I'm the one most likely to notice when my build actually fails. If I come back with a fix, I at least need the project to be receptive. I haven't been in the habit of building nightly on our RHEL6 builders, but maybe I should! Catching this early is better for everyone involved...
That seems reasonable. How quick is the Rust related bootstrapping? Could it be run automatically (or more frequently)? This is an interesting point. If I hadn't made that change, would have kept working on RHEL 5, it just would have leaked an FD. I'm not sure how we would even test for this sort of thing. This isn't a RHEL 5 specific concern, I just don't know how Rust tests these types of resource leak issues in general.
About 2 hours. Automation is harder, since I believe our build system needs my credentials, but I'll look into what is possible here. Yeah, that's a lot more subtle than an !


Question: /// println!("last OS error: {:?}", Error::last_os_error()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] <ins> #[inline] </ins> pub fn last_os_error() -> Error { Error::from_raw_os_error(sys::os::errno() as i32) }

I am facing a problem while reading different kinds of binary formats. If you are going to read primitives like too often, then performance degrades. This is mainly due to the fact that returns box. Also it does boxing TWICE! doc link: I wrote simple bench to show pref problem. Use to get it We can clearly see that performance is degrading. The more calls it takes to read, the worse the results will be. The first very popular crate that comes to mind is . It mainly depends on the data format. But what if you need to receive data over the network? The attacker may abuse wrong data to make ton of pointless memory allocations. stdlib is also use often enough. Let's run a simple bash to make sure of this In many cases, you will see that it is used . stdlib sometimes create with macro, however it doesn't happen very often. Consider adding a new static method such as and new internal member of that's enum. How about using something like , but with static lifetime? : Update 07.03.2021: Benchmarks have been improved as per the comment. This should show the problem better.
The "std_err" bench is still pretty slow though
Yes, I probably made a mistake while copying the code for the benchmark of . It should be . However, this shows that not zero-cost.
This is fixed by
Turns out it was three times, if you also count the that the is copied into.
Running your benchmark (thanks!): Before: After: Looks like it isn't completely solved yet. Adding to now... :)
That fixed it.


Question: /// /// # Examples ///  /// Converts an Option<[String]> into an Option<[usize]>, consuming /// the original:   /// Calculates the length of an Option<[String]> as an /// Option<[usize]>, consuming the original:  /// /// [String]: ../../std/string/struct.String.html "String" /// ```

url: function: asref() Examples: Perhaps I'm just confused, but shouldn't that say: <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
Transferring to the rust-lang/rust repository, as that is where the standard library documentation is. I think it is trying to illustrate the conversion from → → . The text is just eliding the middle step, and explaining where it is starting from and where it is finishing.
No, that seems fine; what confuses you (or leads you to the &str conclusion)? I could follow but not . Perhaps you're thinking the impl on would make the contain or such?
I guess I'm extremely confused then. If I have an , what good does an do me? If I have &Some( "fubar" ), how does that translate to a usize? Is it giving me the length of the string or it's pointer in memory? Neither seems useful nor relevant to the description of "Converts from &Option<Tto Option<&T.".
You can call . just describes the example code's functionality, not 's. It's showing one of the ways you could use .
Okay, sorry, I understand now that comment is talking about the upcoming example instead of discussing as_ref() in general. In order to help others not experience the same confusion I did, perhaps I could suggest a tweak to the wording, such as: ?
memory address
claim


Question: &mut err, ); <ins> self.suggest_deref_unwrap_or( &mut err, error_span, callee_ty, call_ident, expected_ty, provided_ty, provided_args[*provided_idx], is_method, ); </ins> // Call out where the function is defined self.label_fn_like( &mut err,

Given : Current error, for the motivating use case above: It should be possible for rustc to suggest replacing this specific instantiation of with . Maybe similarly for some other common cases: . Originally posted by in label -T-rustdoc T-compiler


Question: } unsafe fn get_stackp() -> *mut libc::c_void { <del> let stackp = mmap(ptr::null_mut(), SIGSTKSZ, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); </del> <ins> let stackp = mmap( ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0, ); </ins> if stackp == MAP_FAILED { panic!("failed to allocate an alternative stack"); } <del> stackp </del> <ins> let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE); if guard_result != 0 { panic!("failed to set up alternative stack guard page"); } stackp.add(page_size()) </ins> } #[cfg(any(

Rust's runtime installs a signal handler to distinguish stack overflows from other faults. This requires using an alternate signal stack (), which we create with the default size . That's usually quite small, 8KB or so depending on the target, but it's still plenty for what the handler is doing. There's currently no guard page like we have on normal stacks. That alternate stack is shared by all signals for a thread, so if a user installs any other signal handler, and they opt in with the flag , they'll be limited to the same tiny stack. If their handler happens to be more involved and overflows that stack, it may silently clobber other memory. If we had a guard page on the signal stack, that would cause a process abort instead. This was reported to the Security Response WG with a reproducer in . However, after discussion we decided to treat this as a normal issue for a few reasons: Setting a custom signal handler requires code. Signal handlers already run in a quite constrained environment, e.g. . It's unusual to use for signals other than , and if you choose so, you also bear responsibility to make sure that stack suffices. Nevertheless, as a defensive measure, it's still a reasonable idea to map a guard page when Rust is creating its signal stack, so an unexpected overflow will abort rather than silently corrupting memory. For full protection, that would also depend on the guard page not being skipped, but not all targets have stack probes yet (). Thanks to for reporting this in accordance with our , even though we have decided not to treat this as a security issue at this time. cc
cc This is another reason we perhaps shouldn't be registering the signal handler... cc


Question: /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] <del> #[inline] </del> pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> { builders::debug_struct_new(self, name) }

After discussing it on the forums I bit I decided to look into what the optimizer spends time on, and inlining seems to be a significant part of it. There seems to be a lot of room for improvement here. Tested by compiling syntex in rustc-benchmarks (though the inlining time seem quite significant in other crates as well.). I counted which functions were inlined the most, and and to a lesser extent , which are when automatically deriving , and which simply wrap two other functions inside fmt::builder show up a lot. Maybe derive(debug) could output the wrapped functions instead, or the equivalent code, so llvm doesn't have to spend time inlining them (unless this causes problems for debug info). is also inlined a lot, and also plays a role in derive(Debug). Maybe something could be done about that one as well, as it's that creates a struct but doesn't do anything else. <details<summaryOutput from time-llvm-passes</summaryUsing in the syntex-0.42.2 directory in rustc-benchmarks. It's a bit hard to say which crate is which, as the output from llvm and cargo isn't synced, though these are the bottom three (excluding the benchmark dummy) in reverse order: </details<details<summaryMost inlined functions: </summaryRunning , and filtering the output using this: (Yeah it's a bit of a monstrosity, and takes a long time, maybe I could look into making some tool analyze this if it turns out to be useful.)


Question: /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] <del> #[inline] </del> pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> { builders::debug_struct_new(self, name) }

gives: <pre1865 ZN4core3ptr13dropinplace17hffb7ed55089717f8E inlined into 917 ZN50Tascore..convert..FromTGT$4from17h99c56b7d2123957eE inlined into <b677 ZN4core3fmt9Arguments6newv117h0a32116e8ade096aE inlined into</b549 ZN4core3ptr13dropinplace17h8905708a4bea3261E inlined into <b517 ZN4core3fmt9Formatter11debugtuple17h312acfb009988478E inlined into</b484 ZN50Tascore..convert..FromTGT$4from17hf6536c6dc214691bE inlined into 438 ZN5alloc9allocator6Layout4size17h278602cb6317171dE inlined into 402 ZN63alloc..allocator..LayoutasGT$5clone17hba86f6db001903cdE inlined into 381 ZN61u20u20GT$7dealloc17h3db9762b4fdfd21eE inlined into 344 ZN5alloc4heap15exchangemalloc17he9800f033a6330e4E inlined into 341 ZN4core3ptr13dropinplace17hb5325e51b98a161aE inlined into ... <b82 ZN4core3fmt9Formatter12debug_struct17h5cfb920e90696799E inlined into</b... </pre</details<details<summaryrustc --version</summary</details
We should just drop the from those functions - debug printing is something we want to be optimizing on code size/compile time rather than perf.
Yup, that's a good point. EDIT: Actually since they're just generic over lifetimes it looks like that's not an issue.


Question: use super::*; use crate::panic::{RefUnwindSafe, UnwindSafe}; <ins> use crate::sync::mpsc::sync_channel; </ins> use crate::thread; #[test]

Given the following code: The current output is: I think it's typical for a newcomer to want to get a iterator by chaining method calls like . There's no obvious reason why that shouldn't work. The examples in the documentation do typically show being assigned to a variable prior to calling its method, but don't explain why that's necessary. I think the "borrow" terminology is misleading, but there might not be a concise way to describe what's actually going on to the user. The "temporary value is freed at the end of this statement" is probably correct. The "creates a temporary which is freed while still in use" is probably more correctly "creates a temporary that is required to outlive (or live exactly as long as) the result of...", followed by a pointer to the method invocation, with text of " method call". Maybe it should also point out the lifetime argument in the return type. I tried and failed to find a satisfactory explanation of what exactly was borrowing from the temporary value produced by . When I looked through the library source code, the only references in were those created by locking a , and the in question is static. I'm guessing the existence of a borrow is assumed rather than inferred from analyzing the function body of . The assumption might be the result of the anonymous lifetime argument on the output type from , which imposes a requirement that the doesn't outlive (or has the same lifetime as?) the value that is the receiver of . The correct fix might be to change the locked stdin handles to all use lifetimes, but I will probably file that as a separate issue.
label +A-borrow-checker +A-lifetimes +D-confusing +D-incorrect +D-newcomer-roadblock
IMO the intent is clear here. Without changing the API, why exactly is Rust unable to lift 'a &'static X to 'static & 'static X, if X also contains only 'static lifetimes? I don't think raw references have a meaningful dropper; borrowck is able to freely resolve any derived lifetimes on impls that don't depend on anything else to 'static; I'm pretty sure under current rules we should be able to substitute latter for earlier and get exactly the same behaviour.
This is due to .


Question: use super::*; use crate::panic::{RefUnwindSafe, UnwindSafe}; <ins> use crate::sync::mpsc::sync_channel; </ins> use crate::thread; #[test]

is declared as follows: Because there is only one input lifetime (the elided lifetime of ), it is assigned to the output lifetime , which is why the lock can live at most as long as the temporary.
Thanks. I think this might be a bug in libstd (using instead of as the return type), but I'll file that separately. What I think is a diagnostic inaccuracy is that the error message refers to a borrow, when, by inspection of the library source code, no borrow is taking place in . (Unless I'm missing something?) What I think is happening is that the compiler is enforcing that lives no longer than the temporary produced by , and is misleadingly calling that a borrow in the error message.
As a simplified example: The error message refers to a borrow even when the output type of does not refer to at all!
that's because of the elision rules: on the declaration you're implicitly telling the compiler that the lifetime of the borrow matches the lifetime of the type. .
Thanks. I think the error messages could use a little more detail about how something that the borrow checker sees as a borrow may be an artifact of lifetime constraints in a function signature rather than an actual borrow in the function body. It certainly surprised me the first time I ran into it. (Maybe only in the explanatory text in the compiler error index. It looks like E0597 could also benefit from that detail, because it's a similar case, and an example in E0716 produces E0597.)
Shorter example, probably better suited for an example in the compiler error index:


Question: } fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { <ins> use rustc_errors::Applicability; </ins> if !sess.opts.unstable_features.is_nightly_build() { <ins> let lang_features = &sess.features_untracked().declared_lang_features; </ins> for attr in krate.attrs.iter().filter(|attr| sess.check_name(attr, sym::feature)) { <del> struct_span_err!( </del> <ins> let mut err = struct_span_err!( </ins> sess.parse_sess.span_diagnostic, attr.span, E0554, "`#![feature]` may not be used on the {} release channel", option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)") <del> ) .emit(); </del> <ins> ); let mut all_stable = true; for ident in attr.meta_item_list().into_iter().flatten().map(|nested| nested.ident()).flatten() { let name = ident.name; let stable_since = lang_features .iter() .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) .next(); if let Some(since) = stable_since { err.help(&format!( "the feature `{}` has been stable since {} and no longer requires  an attribute to enable", name, since )); } else { all_stable = false; } } if all_stable { err.span_suggestion( attr.span, "remove the attribute", String::new(), Applicability::MachineApplicable, ); } err.emit(); </ins> } } }

I was under the impression that should work on stable channel with version 1.51, however using the example code from I get rustc -Vv output (its the ):
attributes are used to enable unstable/gated features in the nightly compiler. Once a feature stabilizes, the attribute is no longer required.
I think the compiler should suggest removing the feature gate if it's been stabilized.
I see, I was unsure whether the error message was referring to the referred feature or the feature flag itself (since the example code of the stabilize PR was using it too I was assuming the former). And yes, removing the feature line from the example code makes it compile, thanks. Is there any way to make rustc ignore the feature flag and try to compile it anyway? The crate I want to use still has it included and I'd prefer not having to remove it manually until it gets removed upstream. (re-opening since seems to think its a valid issue/suggestion)
No, you'll need to either patch the crate or fix it upstream.


Question: -include ../tools.mk <ins> LOG := $(TMPDIR)/log.txt # FIXME(#46126) ThinLTO for libstd broke this test ifeq (1,0) </ins> all: ifeq ($(TARGET),x86_64-unknown-linux-gnu) ifdef SANITIZER_SUPPORT $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | grep -q librustc_lsan <del> $(TMPDIR)/leak 2>&1 | grep -q 'detected memory leaks' </del> <ins> $(TMPDIR)/leak 2>&1 | tee $(LOG) grep -q 'detected memory leaks' $(LOG) endif </ins> endif <ins> else all: </ins> endif

nightly-2017-10-24 contains a libtest with bad DWARF: I can reproduce this if I recompile libtest locally: The problem can be fixed by disabling thinlto (and keeping the codegen units is ok). I noticed this with nightly-2017-10-24 because it is the first nightly compiled with thinlto, but the problem also occurs if I compile libtest with thinlto enabled using earlier compilers (eg nightly-2017-10-17). Inspecting the DWARF, a DIE at that local ref offset does exist in another codegen unit, so the problem seems to be that we should be using a global ref instead.
cc'ing since he's been poking around in LLVM's DWARF generation code recently.
Sorta smells like an LLVM bug -- but hard to say. Who should investigate?
triage: P-medium if you are able to investigate as part of ThinLTO work would be great.
It's likely that this is the cause of , which even if the underlying segfault were fixed would likely prevent backtraces from happening on OSX.
This is unfortunately not "automagically fixed" if we upgrade to LLVM 5
Making progress. First up, minimized Rust source code via creduce to get: Next up let's see if we can reduce it to one object file: Ok looks like only one object file is invalid! Let's take a look the LLVM IR: Ok let's see what's happening by minimizing the LLVM IR: yielding which I . I checked out LLVM trunk, , and looks like the error is still on LLVM trunk.
I'm not sure at this point if this is an LLVM bug, a rustc bug, or a ThinLTO bug. I've managed to extract what I believe is a for this which reproduces the error. I'm hoping fixing that IR will fix all other related issues to this at this point in time. For those of you more familiar with debug information (probably everyone other than me!) mind taking a look at that IR? Does it look "obviously wrong"? If it's "obviously wrong" I can try to work backwards to figure out what piece of the pipeline introduced such a wrong piece, but if it looks correct I can open an LLVM bug saying that we think it may be broken (and maybe they'll say it's "obviously wrong"!)


Question: -include ../tools.mk <ins> LOG := $(TMPDIR)/log.txt # FIXME(#46126) ThinLTO for libstd broke this test ifeq (1,0) </ins> all: ifeq ($(TARGET),x86_64-unknown-linux-gnu) ifdef SANITIZER_SUPPORT $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | grep -q librustc_lsan <del> $(TMPDIR)/leak 2>&1 | grep -q 'detected memory leaks' </del> <ins> $(TMPDIR)/leak 2>&1 | tee $(LOG) grep -q 'detected memory leaks' $(LOG) endif </ins> endif <ins> else all: </ins> endif

cc
Er, I went ahead and to go ahead and broaden the search.
The DWARF is definitely badly formed: it's using a unit-relative offset to reference the parameter type, when it should be using a section-relative offset because the type is in a different unit. The bad offset is occurring for a parameter to subprogram in . The problem is that subprograms and share the same , but have different units ( and ). Based on some print debugging, it appears that LLVM doesn't handle this case. So and are constructed in unit , but when is constructed, it reuses the existing DIE as its parent, and so it also ends up in unit . So my guess is that when the parameter is constructed, it uses the unit that was specified to determine if the parameter and type are in the same unit, and thus gets it wrong.
thanks for the info! I know basically nothing about DWARF though and malformed whatnots, so the IR here is heavily edited by both machines (creduce/bugpoint) and me (to make it more readable). My assumption is that if LLVM accepts IR and generates an object file it shouldn't yield such a dwarfdump error, but are you thinking that given possibly valid LLVM IR the dwarfdump error is possible? If so that may make reduction far more difficult... Or do you think that this looks like upstream LLVM needs to get updated?
I don't think the editing of the IR caused the problem. I'll check later, but I think it's quite likely that the same problem occurs for the unedited IR. I don't know if the LLVM developers intend for this to be valid IR, or if they are missing a validation check somewhere. I think they may have never encountered this possibility. clang divides code into units based on files, so I don't think it ever splits code in the same scope across multiple units, whereas I think rust splits code into units quite differently. That's a bit of conjecture on my part though, it might be better to ask someone who knows more (I only know about DWARF, not LLVM or rustc). Reading the LLVM code a bit more, I think it will be possible to fix there by stopping it from sharing the scope (the scope creation is initiated and the sharing check is ). It's also worth reconsidering how rust splits code into units though.


Question: -include ../tools.mk <ins> LOG := $(TMPDIR)/log.txt # FIXME(#46126) ThinLTO for libstd broke this test ifeq (1,0) </ins> all: ifeq ($(TARGET),x86_64-unknown-linux-gnu) ifdef SANITIZER_SUPPORT $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | grep -q librustc_lsan <del> $(TMPDIR)/leak 2>&1 | grep -q 'detected memory leaks' </del> <ins> $(TMPDIR)/leak 2>&1 | tee $(LOG) grep -q 'detected memory leaks' $(LOG) endif </ins> endif <ins> else all: </ins> endif

It might make sense to ensure all code for a given type is kept in the same unit.
Ah ok that all makes sense. Note though that rustc is very much like clang when it comes to debuginfo/codegen units. The major difference here is that LLVM is doing inlining across codegen units via ThinLTO, and that's likely where these new situations are arising from.
I see, yep my understanding of how rust partitions units was wrong. So when using ThinLTO, the additional units by ThinLTO only contain information needed for the additional inlined functions? Do these inlined functions always share scopes/types with unit , or can we determine when they do? If so, it'd be nice to add them to unit instead of creating additonal units. I think this would get us DWARF that looks the same as that generated for . eg dwarfdump is happy if I run:
interesting! I'd have to look into the internals of ThinLTO to know for sure though. It seems like LLVM isn't ready (maybe?) for multiple codegen units in debug info in one LLVM module (a codegen unit), but it makes sense to me what you're thinking about having all inlined debug info share the same codegen unit information. Now where that change would go in LLVM I'm not entirely sure...
Does firefox use fat LTO? There's been a couple of bugs that have some similarities to this ( and maybe ). Also note that absence of dwarfdump errors doesn't mean the offsets are all okay. dwarfdump is only complaining if the offset is larger than the unit length, but even if it's less it may still incorrectly be a local ref. So there may be more instances that are unnoticed.
cc ^
I can reproduce using normal LTO. Library crate is: Binary crate is: Also here's a thin LTO version that gives smaller IR than the previous Vec test case:
Thanks It definitely sounds like at this point this is an existing bug we've just never hit before. My inclination would be to paper over this if we can. Unfortunately though I don't know how to fix this at the LLVM IR layer. My naive idea would be to just point everything at one codegen unit for each LLVM module (debug-info-wise) but I don't know how to change existing debuginfo of a module.


Question: -include ../tools.mk <ins> LOG := $(TMPDIR)/log.txt # FIXME(#46126) ThinLTO for libstd broke this test ifeq (1,0) </ins> all: ifeq ($(TARGET),x86_64-unknown-linux-gnu) ifdef SANITIZER_SUPPORT $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | grep -q librustc_lsan <del> $(TMPDIR)/leak 2>&1 | grep -q 'detected memory leaks' </del> <ins> $(TMPDIR)/leak 2>&1 | tee $(LOG) grep -q 'detected memory leaks' $(LOG) endif </ins> endif <ins> else all: </ins> endif

I'm not able to access currently, so not sure exactly what Adrian's suggestions were, but here's a that fixes LLVM to use a global ref when needed. It's not as simple as comparing parent DIEs, because the variable is initially , so the check . I don't have a lot of confidence in the patch, but maybe it's a useful starting point for someone who knows more about LLVM.
awesome thanks! I think LLVM's bugzilla is back now so indicating such.
I've confirmed that applying your patch to LLVM fixes having malformed debug information. Next up I'm confirming that it
Sure enough it fixes the issue! would you be interested in sending the patch upstream?
I prefer if someone who knows more about LLVM could upstream the patch.
Would this be something you could do, You can evaluate the changes to the generated DWARF best, I think.
We do use for Firefox builds, yes.
Sure, I will do this. I think the issue is more an LLVM thing than a DWARF thing, though; not certain I know enough there to say whether the patch is good, but I will at least do the shepherding. Also I wanted to point out that knows quite a bit about DWARF; he's one of the principals on
Actually maybe there's nothing to do here except merge this into rust-llvm?
Yes, I think so. I'll do that.
Cool, thanks!
oh no worries! I've tested it locally now and will submit a PR soon (with another change or two)
Ok, thanks
I've opened up which I think should close this out (and also re-enables ThinLTO in a few locations)
Hi, I get a Dwarf Error with GDB 8.0.1 on one of the files of Rust 1.23.0 that was built was Rust 1.23.0 on Fedora 27, in a build enabled with debuginfo. Is it related to this issue or should I open a new one? Relevant build flags:
yeah I believe that's this issue, it should be fixed in 1.24 though!


Question: <del> Subproject commit e57bd02999c9f40d52116e0beca7d1dccb0643de </del> <ins> Subproject commit bda50510d1daf6e9c53ad6ccf603da6e0fa8103f </ins>

Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool clippy-driver no longer builds. A follow-up PR to the repository is needed to fix the fallout. cc do you think you would have time to do the follow-up work? If so, that would be great! And nominating for compiler team prioritization.


Question: <ins> error: any use of this value will cause an error --> $DIR/const-external-macro-const-err.rs:12:5 | LL |     static_assert!(2 + 2 == 5); |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 | = note: `#[deny(const_err)]` on by default = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error </ins>

The following does not error locally / on the playground If I copy paste the macro into the same file, it errors as expected Checking other macros, error as expected.
This feels like it's related to a similar issue () I created a while back.
cc
This is probably because the "error" is just a lint. And we appear to silence it in external macros. We shouldn't do that. IIRC this is just a flag that needs to be set for the lint macro
Yes, we need to set reportinexternal_macro param on the lint I believe
Ah, that makes sense! Building locally with the parameter set to confirm. it does ^^ will check the samples in there too.


Question: <ins> // Non-regression test for issue #122674: a change in the format args visitor missed nested awaits. //@ edition: 2021 //@ check-pass pub fn f1() -> impl std::future::Future<Output = Result<(), String>> + Send { async { should_work().await?; Ok(()) } } async fn should_work() -> Result<String, String> { let x = 1; Err(format!("test: {}: {}", x, inner().await?)) } async fn inner() -> Result<String, String> { Ok("test".to_string()) } fn main() {} </ins>

searched nightlies: from nightly-2024-03-07 to nightly-2024-03-10 regressed nightly: nightly-2024-03-09 searched commit range: regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.8</summaryHost triple: aarch64-apple-darwin Reproduce with: </details modify labels: +regression-from-stable-to-nightly -regression-untriaged
I suspect caused this regression, but I don't know how to use to test this pr(I tried some times but all failed). Do you have any ideas about this?
if you use the latest version of cargo-bisect-rustc it will bisect the roll-up for you.
Hi, I'm using the latest version of , but seems that it fails to bisect the roll-up. Here's the complete log: bash cargo bisect-rustc --start 2024-03-08 --end 2024-03-09
It does bisect to for me. (With this visitor change in particular )
The fix has landed on master. Reopening to track beta backport.
Hi, 1.77.0 has been released, can this be backported to beta now?
I wasn’t at the weekly meeting and I don’t know for sure: is not yet marked as accepted for backport (it may just be an oversight in labeling, I’ll try to find out). Once that is done though, the release team, I believe, will backport it.
updated labels on (sorry for the delay)
That was backported in .


Question: version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ <del> "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", </del> <ins> "backtrace 0.3.29 (registry+https://github.com/rust-lang/crates.io-index)", </ins> ] [[package]]

Every since a recent nightly update, both distributed nightlies and locally built produce backtraces where every level of the stack is represented only by their memory address and the label : Sadly I don't have a more specific repro case, but I can consistently reproduce locally. Older distributed nightlies do not present this behavior.
This happens consistently for me as well (also macOS).
I've been seeing this on Linux too, though it's been at least a week. (It also may have been fixed in a rustc newer than the one servo uses)
We should have tests for backtraces, so they don't regress again in the future.
this is certainly happening on master, and it's been happening for a while, but I assumed it was my env.
It just occurred to me that this might be related to the new symbol mangling (although I doubt it).
I've been experiencing this for about a week now (also on macOS). It definitely started prior to being merged. I also have the following in my :
has absolutely no changes if you don't use the flag, so it's not from there.
It's definitely , I tried before and after. It works if you enable the "coresymbolication" feature, though that's obviously not an option for distribution. I tried the latest master of , but it didn't help.
To confirm, is everyone only experiencing problems on OSX for rustc itself? Are there problems with other projects on OSX? can you please confirm or deny your experience from Linux? Throwing in a new platform here changes this quite a lot
Ok I believe I've found the issue for OSX, but if other platforms are still an issue that would be good to know
I've only experienced this with rustc itself on OSX. Things it builds seem ok, and linux/windows seem to be ok.
No, it's still happening on Linux as of yesterday (I can try again today). I also assumed it was my env.
I think the Linux issue is separate since it's been happening much longer than the OSX one
Hey, this seems to an issue on nightly for Windows (msvc) as well: This uses backtrace via :
if that's only using the crate and not using libstd, can you open an issue on the repository? The OSX issue should be fixed in , which I'd like to finish testing and then I'll send an update to libstd.


Question: version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ <del> "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", </del> <ins> "backtrace 0.3.29 (registry+https://github.com/rust-lang/crates.io-index)", </ins> ] [[package]]

That could affect Linux as well but I doubt it, so if there are persisting Linux/Windows issues please feel free to let me know. If you can create an isolated problem which uses the crate rather than libstd that's even better!
Done: rust-lang/backtrace-rs


Question: Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast, }; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; <del> use rustc_middle::ty::{self, AdtKind, Ty}; </del> <ins> use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable}; </ins> use rustc_span::Span; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr<'tcx> {

The following ICE's on stable, beta and nightly: (notice the was NOT closed) <details<summaryBacktrace:</summary</details
Oh, this works with other types as well, except the messages are different ICE's with:
ICE's with:
Its worth nothing explicitly that: these ICE's are happening after we do issue a diagnostic for the parsing error If you address the parsing error (presumably in the same manner that the parser is auto-correcting to make further progress), the ICE goes away
triage: P-medium. Removing nomination.
Triage: The first example still ICEs in MIR building The second and third examples don't ICE anymore and need tests (without closing this issue!).
cc


Question: } } <ins> const LOADERS: &Vec<&'static u8> = &Vec::new(); pub fn break_code() -> Option<&'static u8> { for loader in *LOADERS { //~ ERROR cannot move out of a shared reference return Some(loader); } None } </ins> fn main() {}

<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --Haven't minimized the code yet, but the exact code is up here: It's a kind of search algorithm. I think the problematic code is the function in . Will report back if I figure out anything more. <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</detailsI just switched to the stable toolchain, and the compilar gave me two errors: Apparently these were not caught by the nightly compiler.
This is probably a duplicate of You're using the nightly compiler though, so working as intended
Assigning priority as discussed in the of the Prioritization Working Group. label -I-prioritize +P-medium


Question: } } <ins> const LOADERS: &Vec<&'static u8> = &Vec::new(); pub fn break_code() -> Option<&'static u8> { for loader in *LOADERS { //~ ERROR cannot move out of a shared reference return Some(loader); } None } </ins> fn main() {}

<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --Compiles with replaced for <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
I got the same issue on the latest nightly and on , without using rustc-private The commented out block was used originally and triggers the ICE as well.
searched nightlies: from nightly-2021-07-29 to nightly-2021-08-02 regressed nightly: nightly-2021-07-31 searched commits: from to regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.0</summaryHost triple: x8664-pc-windows-msvc Reproduce with: </detailsI think this might have been introduced by , in particular this piece of code:
If that's indeed caused by then we should let its author know:
Just checked and thankfully .
claim
Assigning priority as discussed in the of the Prioritization Working Group. label -I-prioritize +P-high


Question: let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?; let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?; let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?; <del> si.hStdInput = stdin.as_raw_handle(); si.hStdOutput = stdout.as_raw_handle(); si.hStdError = stderr.as_raw_handle(); </del> <ins> let mut si = zeroed_startupinfo(); si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD; // If at least one of stdin, stdout or stderr are set (i.e. are non null) // then set the `hStd` fields in `STARTUPINFO`. // Otherwise skip this and allow the OS to apply its default behaviour. // This provides more consistent behaviour between Win7 and Win8+. let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null(); if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) { si.dwFlags |= c::STARTF_USESTDHANDLES; si.hStdInput = stdin.as_raw_handle(); si.hStdOutput = stdout.as_raw_handle(); si.hStdError = stderr.as_raw_handle(); } </ins> unsafe { cvt(c::CreateProcessW(

<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: App P: App C: Build this in Windows. Since has "windows" subsystem, it will create no console window (i.e. no process). Since is a console app, when the process is created, I expect to see one console window that prints "Hello World" infinitely. App creates its console window but no text is printed. In Windows, spawn() eventually calls to with a , whose  is hard coded to . Additionally, it also with , and set them to the . Since app uses "windows" subsystem, it does not have console. stdout is always . Combining with in causes the unexpected behavior. If I make a call to with same parameters except a "zeroed" , it exhibits the correct behavior. spawn() should only conditionally set the flag if it can obtain those device handles, and never set any of those handles . Like this (pseudo code): <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --:
I think this will need a T-libs-api decision as the current documentation for  (and stdin/stderr) is: I would guess that this "inherit by default" is why it's implemented the way it is. But perhaps there's some wiggle room with what it means to inherit handles that don't exist so we can change it. In either case it would be good to have some way to use platform default behaviour here. label -T-libs +T-libs-api
That's exactly my point. If there is nothing to inherit in the first place, just inherit nothing. The current behavior () is simply wrong. I believe fixing it doesn't violate the current specification.
Basically, currently there are only two options when handling the stdout/stderr: inherit or pipe. I think there should be a third option: isolated - make the child handle its console by itself. For example, if user calls and , he basically says "the parent process doesn't care about the child's output". It is the same as the "windows" subsystem case above. In this case, the flag should never be set, regardless if or is called.


Question: let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?; let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?; let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?; <del> si.hStdInput = stdin.as_raw_handle(); si.hStdOutput = stdout.as_raw_handle(); si.hStdError = stderr.as_raw_handle(); </del> <ins> let mut si = zeroed_startupinfo(); si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD; // If at least one of stdin, stdout or stderr are set (i.e. are non null) // then set the `hStd` fields in `STARTUPINFO`. // Otherwise skip this and allow the OS to apply its default behaviour. // This provides more consistent behaviour between Win7 and Win8+. let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null(); if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) { si.dwFlags |= c::STARTF_USESTDHANDLES; si.hStdInput = stdin.as_raw_handle(); si.hStdOutput = stdout.as_raw_handle(); si.hStdError = stderr.as_raw_handle(); } </ins> unsafe { cvt(c::CreateProcessW(

More importantly, this is de facto the default way of how a process is created in Windows. Defaulting to really makes me confused before reading the internal source code.
Not always. Parent process can still set those handles to something other than . For example, if you launch App P from IntelliJ it actually prints "Hello World!" in a loop but not in the spawned console which is empty, but in IntelliJ internal terminal. returns non invalid handle. This solution would make behaviour different depending on how you launch your app. Also, you can explicitly ask to create new console with even if your app already uses console subsystem. In this case you also likely want to avoid inheriting handles because you want output of the spawned process to be displayed in the new console, not in the existing one. This solution doesn't help with this.
I can't verify your statements since I don't have IntelliJ atm, but even it's true, isn't it IntelliJ setting up the console with maybe some special debugging API? How to you modify the code of P to achieve the same? And realistically speaking, do people actually do that with GUI apps? I think in this case, it's impossible to be 100% sure where the user wants the output at. New option might be the way to go.
Your prediction was dead-on, as it came true in While we can do this, as is proposing, it seems best here that we create a function, or set of functions, that explicitly handle this kind of situation rather than guessing.
Even with new APIs, we still need reasonable default behaviour. And the Command API is documented as inheriting handles by default. However, currently the API neglects the "no handle set" case entirely as that's not really a thing in POSIX or ISO C (well, you can close stdio but that's usually considered a Bad Thing unless you're being very very careful).


Question: return None } None => { <del> if !tcx.sess.has_errors() { </del> <ins> if !tcx.sess.has_errors_or_delayed_span_bugs() { </ins> bug!("try_mark_previous_green() - Forcing the DepNode  should have set its color") } else { <del> // If the query we just forced has resulted // in some kind of compilation error, we // don't expect that the corresponding // dep-node color has been updated. </del> <ins> // If the query we just forced has resulted in // some kind of compilation error, we cannot rely on // the dep-node color having been properly updated. // This means that the query system has reached an // invalid state. We let the compiler continue (by // returning `None`) so it can emit error messages // and wind down, but rely on the fact that this // invalid state will not be persisted to the // incremental compilation cache because of // compilation errors being present. debug!("try_mark_previous_green({:?}) - END -  dependency {:?} resulted in compilation error", dep_node, dep_dep_node); return None </ins> } } }

Creating a recursive type with infinite size by removing a leads to an internal compiler error. Might be the same issue as . To reproduce this bug, run on this code: Replace by and run again: I expected to see this happen: Instead, this happened: :
triage: P-high. Removing nomination.
assigning to with expectation that they will delegate.
nominating to try to find someone to investigate this.
well spotted ;) Because this issue has the tag and the other doesn't I will post the incremental test here:
triage: Reassigning to self and in hopes that one of us will find time to investigate, since it seems to be an issue with the dep-graph/incr-comp infrastructure.
triage: Downgrading to P-medium. I still want to resolve this, but it simply does not warrant revisiting every week during T-compiler triage.
I encountered the same bug. I starting to create a new issue, but it's exactly the same than this one. In case it's needed, I uploaded the code on on the branch (there is two commits, the first is fine, the second generate the ICE) in case you want to validate your patch when you will eventually have time to fix it.
I am running into this issue as well. Since the corresponding pr has been merged 24 days ago and the latest version was tagged 14 days ago, I am not sure, if this error should have been fixed with . (I did not find the commit on the master but I am also unsure if it was squashed with other commits.) Therefore, I thought I would at least post my error as well, just in case this is supposed to work. In my case I have an enum which holds a struct which in turn references that enum. I know that this can't work and I know how the correct way of handling this scenario is, I just wanted to let you know that this crashes the compiler. If you need a more detailed code sample, let me know and I will try to reproduce the error outside of my project.


Question: <ins> // Checks that `SimplifyArmIdentity` is not applied if enums have incompatible layouts. // Regression test for issue #66856. // // compile-flags: -Zmir-opt-level=2 enum Src { Foo(u8), Bar, } enum Dst { Foo(u8), } fn main() { let e: Src = Src::Foo(0); let _: Dst = match e { Src::Foo(x) => Dst::Foo(x), Src::Bar => Dst::Foo(0), }; } // END RUST SOURCE // START rustc.main.SimplifyArmIdentity.before.mir // fn main() -> () { //     ... //     bb0: { //         StorageLive(_1); //         ((_1 as Foo).0: u8) = const 0u8; //         discriminant(_1) = 0; //         StorageLive(_2); //         _3 = discriminant(_1); //         switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; //     } //     bb1: { //         ((_2 as Foo).0: u8) = const 0u8; //         discriminant(_2) = 0; //         goto -> bb4; //     } //     ... //     bb3: { //         _4 = ((_1 as Foo).0: u8); //         ((_2 as Foo).0: u8) = move _4; //         discriminant(_2) = 0; //         goto -> bb4; //     } //     ... // } // END rustc.main.SimplifyArmIdentity.before.mir // START rustc.main.SimplifyArmIdentity.after.mir // fn main() -> () { //     ... //     bb0: { //         StorageLive(_1); //         ((_1 as Foo).0: u8) = const 0u8; //         discriminant(_1) = 0; //         StorageLive(_2); //         _3 = discriminant(_1); //         switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; //     } //     bb1: { //         ((_2 as Foo).0: u8) = const 0u8; //         discriminant(_2) = 0; //         goto -> bb4; //     } //     ... //     bb3: { //         _4 = ((_1 as Foo).0: u8); //         ((_2 as Foo).0: u8) = move _4; //         discriminant(_2) = 0; //         goto -> bb4; //     } //     ... // } // END rustc.main.SimplifyArmIdentity.after.mir </ins>

PR introduced an ICE in the following code with :
cc with mir-opt-level=1: with mir-opt-level=2: Where the types are


Question: <ins> // Checks that `SimplifyArmIdentity` is not applied if enums have incompatible layouts. // Regression test for issue #66856. // // compile-flags: -Zmir-opt-level=2 enum Src { Foo(u8), Bar, } enum Dst { Foo(u8), } fn main() { let e: Src = Src::Foo(0); let _: Dst = match e { Src::Foo(x) => Dst::Foo(x), Src::Bar => Dst::Foo(0), }; } // END RUST SOURCE // START rustc.main.SimplifyArmIdentity.before.mir // fn main() -> () { //     ... //     bb0: { //         StorageLive(_1); //         ((_1 as Foo).0: u8) = const 0u8; //         discriminant(_1) = 0; //         StorageLive(_2); //         _3 = discriminant(_1); //         switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; //     } //     bb1: { //         ((_2 as Foo).0: u8) = const 0u8; //         discriminant(_2) = 0; //         goto -> bb4; //     } //     ... //     bb3: { //         _4 = ((_1 as Foo).0: u8); //         ((_2 as Foo).0: u8) = move _4; //         discriminant(_2) = 0; //         goto -> bb4; //     } //     ... // } // END rustc.main.SimplifyArmIdentity.before.mir // START rustc.main.SimplifyArmIdentity.after.mir // fn main() -> () { //     ... //     bb0: { //         StorageLive(_1); //         ((_1 as Foo).0: u8) = const 0u8; //         discriminant(_1) = 0; //         StorageLive(_2); //         _3 = discriminant(_1); //         switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; //     } //     bb1: { //         ((_2 as Foo).0: u8) = const 0u8; //         discriminant(_2) = 0; //         goto -> bb4; //     } //     ... //     bb3: { //         _4 = ((_1 as Foo).0: u8); //         ((_2 as Foo).0: u8) = move _4; //         discriminant(_2) = 0; //         goto -> bb4; //     } //     ... // } // END rustc.main.SimplifyArmIdentity.after.mir </ins>

Since few Rustc nightly versions I see a miscompilation problem with the code below. I am using: If I compile with: The code:
NB: this is because it needs an unstable CLI flag to reproduce.
cc since this might have something to do with recent const-eval work (apologies if I left anyone out)
I've managed to minify it to
Bisected it to , most probably the same issue as


Question: traits_in_scope: DefIdMap<Vec<TraitCandidate>>, all_traits: Vec<DefId>, all_trait_impls: Vec<DefId>, <ins> document_private_items: bool, </ins> } impl IntraLinkCrateLoader<'_, '_> {

The ICE appears with and , but not . Beta: <details<summary<strongBacktrace</strong</summary<p</p</details
this is a regression affecting the release that is being prepared today.
I'll take a look.


Question: pub fn has_errors(&self) -> bool { self.inner.borrow().has_errors() } <ins> pub fn has_errors_or_delayed_span_bugs(&self) -> bool { self.inner.borrow().has_errors_or_delayed_span_bugs() } </ins> pub fn print_error_count(&self, registry: &Registry) { self.inner.borrow_mut().print_error_count(registry)

When compiling a testcase (e.g. the last snippet in on the current nightly, or any of the other examples in that issue on older compilers) with (or Cargo which does that by default), only the initial run will ICE. Subsequent runs will succeed without an ICE, in the absence of any regular errors. However, changing the relevant code (e.g. adding a space) can cause the query that calls to be recomputed and bring the ICE back. IIUC, incremental compilation stores diagnostics and replays them on subsequent runs, but that appears to not apply to ICEs. cc
It looks like without incremental we output artifacts (like ). Do we do this in case of errors too? It seems bad to produce artifacts after an ICE.
Nominating and proposing P-high (mostly because of potential annoyance factor). This should possibly also be labeled I-unsound under the assumption that under the general case of this issue, we might produce artifacts under subsequent runs that may produce UB traces. (However, it is probable that the user will notice the ICE at some other point in time and therefore discard the artifact.)
The current expected behavior of the compiler is to not save any incremental state if an error occurs. may slip through the cracks here.
In that case, it seems to me like it's a matter of recording the fact that we did a (which we already do, ) and then have this mean "there was an error" in terms of "should we save incremental state?".
Yep, the following check should also take into account: While we are at it, we could also add a similar check to and , as not to waste time producing values that will then be discarded anyway:
I'd like to start contributing to rustc and I wanted to ask if this is a good issue to start on (I have read the rustc book)
Sure, this is a decently good issue to start on and should be pretty interesting in terms of learning the infrastructure. If you get stuck, need help, and want to talk synchronously you can hop into https://rust- and we'll try to help out.
fixes this issue. It would still be good to have a test case for it.
I have started to write the code making this test possible, I'll open a PR shortly


Question: <del> Subproject commit 5f28fda13efeb85097fe082af4b4827a58b0ecf6 </del> <ins> Subproject commit 58e01ea4d7df69e658c034afbfa6d0abd90808ed </ins>

Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool clippy-driver no longer builds. A follow-up PR to the repository is needed to fix the fallout. cc do you think you would have time to do the follow-up work? If so, that would be great! cc the PR reviewer, and -- nominating for prioritization.
I suspect the or-pattern PR, , is to blame.
Fix for Clippy repo:


Question: <ins> //! This is a regression test for #129020 //! It ensures we can use `/WHOLEARCHIVE` to link a rust staticlib into DLL //! using the MSVC linker //@ only-msvc // Reason: this is testing the MSVC linker use std::path::PathBuf; use run_make_support::{cc, cmd, env_var, extra_c_flags, rustc}; fn main() { // Build the staticlib rustc().crate_type("staticlib").input("static.rs").output("static.lib").run(); // Build an empty object to pass to the linker. cc().input("c.c").output("c.obj").args(["-c"]).run(); // Find the C toolchain's linker. let mut linker = PathBuf::from(env_var("CC")); let linker_flavour = if linker.file_stem().is_some_and(|s| s == "cl") { linker.set_file_name("link.exe"); "msvc" } else if linker.file_stem().is_some_and(|s| s == "clang-cl") { linker.set_file_name("lld-link.exe"); "llvm" } else { panic!("unknown C toolchain"); }; // As a sanity check, make sure this works without /WHOLEARCHIVE. // Otherwise the actual test failure may be caused by something else. cmd(&linker) .args(["c.obj", "./static.lib", "-dll", "-def:dll.def", "-out:dll.dll"]) .args(extra_c_flags()) .run(); // FIXME(@ChrisDenton): this doesn't currently work with llvm's lld-link for other reasons. // May need LLVM patches. if linker_flavour == "msvc" { // Link in the staticlib using `/WHOLEARCHIVE` and produce a DLL. cmd(&linker) .args([ "c.obj", "-WHOLEARCHIVE:./static.lib", "-dll", "-def:dll.def", "-out:dll_whole_archive.dll", ]) .args(extra_c_flags()) .run(); } } </ins>

<!-- Thank you for filing a regression report! A regression is something that changed between versions of Rust but was not supposed to. Please provide a short summary of the regression, along with any information you feel is relevant to replicate it. --I tried to build using a simple then . I expected to see this happen: linking success. Instead, this happened: MSVC link returns LNK2005 and fails to the static library. It most recently worked on: 1.77.2 <!-- Provide the version you are using that has the regression. --: This is caused by both and When creating stdlibs, each MR causes the Rust compiler to add an export of ; one comes from api-ms-win-core-synch-l1-2-0.dll and the other from This error will not be found until one consumes the Rust-generated library. I am filing this report to consolidate the ones in and <!-- Did the compiler crash? If so, please provide a backtrace. --<!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summaryBacktrace</summary<p</p</details modify labels: +regression-from-stable-to-stable -regression-untriaged
cc
Using for a rust staticlib seems weird to me but cc
The purpose is to allow reexporting a subset of symbols on MSVC. This can be achieved with partial linking elsewhere, but this is not doable on Windows. I wrote about a specific application here:
Sorry, I'm confused, are you trying to create a dynamic or static library? The article that you linked to talks about static libraries, but the backtrace in the OP shows that you are creating a dynamic library.
Both: I'm using the Rust-produced static library through , plus a module definition file, to create a dynamic library. This is because (apart from size considerations) GNOME's gobject-introspection needs a shared library, and Meson will only accept targets that are generated by itself. Further context is here:
In this particular case, because of the imports present in the stdlib, linking something against the Rust-produced static librsvg is enough to trigger the issue.
I am still struggling to understand why is needed, at least for MSVC.


Question: <ins> //! This is a regression test for #129020 //! It ensures we can use `/WHOLEARCHIVE` to link a rust staticlib into DLL //! using the MSVC linker //@ only-msvc // Reason: this is testing the MSVC linker use std::path::PathBuf; use run_make_support::{cc, cmd, env_var, extra_c_flags, rustc}; fn main() { // Build the staticlib rustc().crate_type("staticlib").input("static.rs").output("static.lib").run(); // Build an empty object to pass to the linker. cc().input("c.c").output("c.obj").args(["-c"]).run(); // Find the C toolchain's linker. let mut linker = PathBuf::from(env_var("CC")); let linker_flavour = if linker.file_stem().is_some_and(|s| s == "cl") { linker.set_file_name("link.exe"); "msvc" } else if linker.file_stem().is_some_and(|s| s == "clang-cl") { linker.set_file_name("lld-link.exe"); "llvm" } else { panic!("unknown C toolchain"); }; // As a sanity check, make sure this works without /WHOLEARCHIVE. // Otherwise the actual test failure may be caused by something else. cmd(&linker) .args(["c.obj", "./static.lib", "-dll", "-def:dll.def", "-out:dll.dll"]) .args(extra_c_flags()) .run(); // FIXME(@ChrisDenton): this doesn't currently work with llvm's lld-link for other reasons. // May need LLVM patches. if linker_flavour == "msvc" { // Link in the staticlib using `/WHOLEARCHIVE` and produce a DLL. cmd(&linker) .args([ "c.obj", "-WHOLEARCHIVE:./static.lib", "-dll", "-def:dll.def", "-out:dll_whole_archive.dll", ]) .args(extra_c_flags()) .run(); } } </ins>

So the DLL is created here: is used so that the DLL includes every single object in the staticlib, even if it's unneeded or indeed causes conflicts. But then is used to add a which presumably defines what actually gets exported from the DLL. What I'm not understanding is what would be different if, for MSVC, it just linked normally without ? I.e. using instead.
On MSVC, static linking doesn't let you reexport dependencies' symbols automatically, they're subject to DCE. . However, PE-COFF static libraries don't support symbol visibility, so the is there to make all Rust symbols private and keep only the librsvg ones. See e.g. and for consequences of not blocking out symbols like .
Sure but the should work regardless of if is used or not because using the export will force the linker to go looking for the symbol(s) listed in the file. E.g. as a test I have the following static lib (using to make symbols easier to find): Which I compile into a static lib using: rustc -O --crate-type=staticlib And I have the following file: Which for simplicity I compile via rustc but I'm using an empty file and also raw linker arguments: rustc -O --crate-type=cdylib -C link-args=" " This compiles and if I see the two functions I wanted: No std symbols are exported.
Independent of whether whole-archive is necessary for this specific use case, we should support linking rust staticlibs with whole-archive, even if because of the fact that not linking with whole-archive can mask linker errors, which will later show up when any change to the cgu partitioning is made, which often causes people to report a regression even though their crate is at fault.
If I repeat the above using even in this simple case I get a bunch of errors, not just : I'm not really sure if rustc can currently guarantee that whole archive will work without doing some of the work of a linker. Which sounds like a new feature and not specific to MSVC.
All duplicate symbol errors for are caused by That it works without is by accident and likely to break in case of cgu partitioning changes.


Question: <ins> //! This is a regression test for #129020 //! It ensures we can use `/WHOLEARCHIVE` to link a rust staticlib into DLL //! using the MSVC linker //@ only-msvc // Reason: this is testing the MSVC linker use std::path::PathBuf; use run_make_support::{cc, cmd, env_var, extra_c_flags, rustc}; fn main() { // Build the staticlib rustc().crate_type("staticlib").input("static.rs").output("static.lib").run(); // Build an empty object to pass to the linker. cc().input("c.c").output("c.obj").args(["-c"]).run(); // Find the C toolchain's linker. let mut linker = PathBuf::from(env_var("CC")); let linker_flavour = if linker.file_stem().is_some_and(|s| s == "cl") { linker.set_file_name("link.exe"); "msvc" } else if linker.file_stem().is_some_and(|s| s == "clang-cl") { linker.set_file_name("lld-link.exe"); "llvm" } else { panic!("unknown C toolchain"); }; // As a sanity check, make sure this works without /WHOLEARCHIVE. // Otherwise the actual test failure may be caused by something else. cmd(&linker) .args(["c.obj", "./static.lib", "-dll", "-def:dll.def", "-out:dll.dll"]) .args(extra_c_flags()) .run(); // FIXME(@ChrisDenton): this doesn't currently work with llvm's lld-link for other reasons. // May need LLVM patches. if linker_flavour == "msvc" { // Link in the staticlib using `/WHOLEARCHIVE` and produce a DLL. cmd(&linker) .args([ "c.obj", "-WHOLEARCHIVE:./static.lib", "-dll", "-def:dll.def", "-out:dll_whole_archive.dll", ]) .args(extra_c_flags()) .run(); } } </ins>

Sure, and then if I compile the static library with and use whole archive then I get a whole slew of errors, which I'll spoiler for length <details<summarylinker errors</summary</details
There are also some technical details in that kleisauke linked. windows-gnu is unaffected because it uses legacy import libraries format.
To get back to address case we could either: Filter symbols when building a staticlib Try using COMDAT in generated raw-dylibs (might not work in this situation)
Filter in what way?
When linking raw dylibs into a staticlib we could exclude the objects containing . Except for one.