-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
const-eval: loading or overwriting parts of a pointer is not supported #87184
Comments
I prefer the status quo over this, even if it would make debugging easier. We could consider emitting a lint though.
That seems like we're treating this as UB or at least unspecified behaviour and doing something random that we can change in the future. I don't like it much. It will also cause differences between the runtime and compile-time behaviour of const fns
preferrable, but yea, a perf problem. If we want per-byte provenance, we either can't do ByRef->ByVal conversion based on types anymore, but need to also consider the value's representability. That could be ok, but makes things more complex in various places. In addition, as you noted, we'd need to adjust the That said... I think we should at least wait until someone has a use case for such things. It is quite some work to implement and the benefits are unclear without having a use case |
Well, we already treat it as UB to overwrite some bytes of a pointer and then inspect the remaining bytes. So we already have a difference between runtime and compile-time behavior of
One step after the other. :) For now I am just talking about what can be represented inside So, let's focus just on what happens on a write now in this issue, I'd say.
This is not enough. If we overwrite the first byte of a pointer, we need to be able to represent "bytes 2-7 of this pointer are stored here". I was thinking of implementing this by adding a second "relocation" table for single-byte relocations: so a relocation at position x with value 8 adjacent bytes with single-byte relocations
My usecase is: I want Miri to be a faithful implementation of the Rust semantics. |
well... we can keep CTFE doing simple things and give Miri the ability to go crazy via more |
Propagating the |
don't we already do that with |
I removed that with my previous PR. ;) (And I am glad I did.) |
We could just always have that new fine-grained relocation table, and have a boolean flag in But honestly I think there's no good reason CTFE shouldn't implement this the right way (if we have the code anyway for Miri) -- as long as that doesn't cause slowdown for code not needing this feature. |
yea that's true. I'm not going to stop you from pursuing this, it just seems like quite a bit of work and lots of performance tuning |
…i-obk CTFE: throw unsupported error when partially overwriting a pointer Currently, during CTFE, when a write to memory would overwrite parts of a pointer, we make the remaining parts of that pointer "uninitialized". This is probably not what users expect, so if this ever happens they will be quite confused about why some of the data just vanishes for seemingly no good reason. So I propose we change this to abort CTFE when that happens, to at last avoid silently doing the wrong thing. Cc rust-lang#87184 Our CTFE test suite still seems to pass. However, we should probably crater this, and I want to do some tests with Miri as well.
FWIW, even with #94527 landed this issue means #94371 is not fully resolved, but the remaining problem causes an error rather than silent data corruption: #![feature(const_swap)]
#![feature(const_mut_refs)]
#[repr(C, packed)]
struct Demo(u32, &'static i32, u32, i64, i64);
const C: (Demo, Demo) = {
let mut x = Demo(0, &1, 2, -1, -1);
let mut y = Demo(3, &4, 5, -1, -1);
std::mem::swap(&mut x, &mut y);
(x, y)
};
fn main() {
let (d1, d2) = C;
} says
|
This affects |
My plans for how I want to implement this in Miri changed, but that new plan I think cannot work in CTFE. For Miri, I mentioned using the However, for CTFE, we don't know the actual byte on the real machine, so the We also have the problem that I don't think LLVM supports 'partial relocations', so if the final value of a constant contains some partial pointers we have to throw an error. All put together, I no longer have plans to fix this for CTFE -- no support for partial pointers is just an inherent limitation of compile-time evaluation. We could mitigate it with a lot of work but it'll always remain half-baked. I will hence close this issue, and open new issues for partial pointer support in Miri and for the |
The Miri core engine can only represent "full" pointers in memory, no parts of a pointer. This leads to strange behavior on code like
If overwriting a part of a pointer happens during CTFE, we halt execution (since #87248). In Miri, instead we de-initialize the entire pointer, so a write will affect the bytes "next to it". (Halting execution is not an option here.)
If loading a part of a pointer (including as the source of a mem-to-mem copy) happens during CTFE or Miri, we halt execution.
Long-term, it would be great to implement support for having just a few bytes of a pointer in a Miri core engine
Allocation
. However, this might be hard to do without a perf regression.Cc @rust-lang/wg-const-eval
The text was updated successfully, but these errors were encountered: