-
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
Regression from stable: pointer to usize conversion no longer compiles #54709
Comments
This check was added in #51361 so mentioning @oli-obk and @RalfJung. It looks quite intentional and justifiable to reject this code. The same code without the unsafe hack is already disallowed in 1.29.0. pub static ADDRESS: usize = &VALUE as *const usize as usize; error[E0018]: raw pointers cannot be cast to integers in statics
--> src/lib.rs:7:29
|
7 | pub static ADDRESS: usize = &VALUE as *const usize as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I would expect this to be reconsidered after stabilizing #51910. Here is the relevant message on nightly: error[E0658]: casting pointers to integers in statics is unstable (see issue #51910)
--> src/lib.rs:7:29
|
7 | pub static ADDRESS: usize = &VALUE as *const usize as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable |
Yea, this kind of constant is very dangerous. I personally don't think there can be a good enough use case to outweigh the problems with it. You can always use a |
Agreed, this was a deliberate change in behavior (and we cratered it, I assume?). The union hack was more of a loophole that we closed. Now, to be fair, this is a |
A static can refer to another static's value though. and then we have the same problem. |
And I don't think we want to make referring to other statics be dependent on the other static's validity checks succeeding |
Oh right, good point. Also, promoted code can refer to statics I assume. Same problem. So, I think this issue should be closed as "this regression is a bugfix". The work-around is to no longer lie about the actual type of the data stored in that static, and make it e.g. of type |
Can they? I thought a static could only refer to another static's address, not its value. Which is pretty different. |
Works just fine on stable: https://play.rust-lang.org/?gist=a07a6558a87a86b0ed2e23855f2b4c44&version=stable&mode=debug&edition=2015 This was implemented half a year ago by lifting a bunch of restrictions of the old const evaluator |
And here's an example of how the static it complains about can cause a problem. There's no reasonable way to implement "divide a pointer by 2" in CTFE. |
Interesting! I wasn't aware of those changes. Thanks for the demo.
I guess I don't really see what's wrong in that example. It fails to compile (which is correct) with a reasonable error message in a reasonable location. Seems okay to me. I don't see why this has to be preemptively prevented by disabling the union transmute hack. |
Things get more tricky if the static with the "bad" Also, if you write e.g. |
That only works for constants, I hope. Accessing a static's value only works in statics. But yes. Creating a bad constant and using it in runtime code can cause everything from weird errors to undefined behaviour if used in runtime places. |
Still this is probably sth. that some team should look at. AFAIK we do not have a team decision on this so far, and it seems prudent to get one. So maybe we should reopen and tag for, eh, T-lang? |
Yes, but |
It doesn't at run-time (except for |
So, @RalfJung, after going through the blog post (you definitely understand this better than I do, so let me know if I've misunderstood this), I'm still not sure why this has to be disallowed for CTFE. The expression |
Every expression you write in the initializer of a What is the problem with using a pointer type here? Pointers are not integers, and for CTFE this is apparent even by looking at what we send to LLVM (for pointers, we need relocations). This distinction is important to describe optimizing compilers even if you ignore constant evaluation, but it surfaces even more in const context. |
The problem is that you can already do let x: &'static u32 = &42; on stable Rust since a year or so. We need to keep supporting it, so we're very careful to not allow any oddball features like pointer values with integer types. Since It was an accident that we ever allwoed it. |
Some context about my use case: Objective-C type encoding uses different encodings for integers vs pointers. Some FFI-related data structures use I could use I'll stop pushing for this, though. |
Why can't you just use the |
It might also be an option to turn this into a deny-by-default lint for cases when people really are asking for a footgun? The interaction with promotion is ugly, though. |
That's what I would need to do. But storing the value in
I personally would love for this to be a lint. It can be a bit of a footgun, yes, but low level FFI programming is full of footguns. |
The footgun here, however, is of a different nature: If you ever write |
Forgive my ignorance, but why is that a problem? Failure to compile is exactly what I'd expect in that scenario. |
Do you really? This code compiles: union TransmuteHack<T: Copy> {
from: T,
to: usize,
}
pub static VALUE: usize = 42;
fn main() {
println!("{:?}", unsafe { TransmuteHack { from: &VALUE }.to } / 2);
} But with promotion, this would not: union TransmuteHack<T: Copy> {
from: T,
to: usize,
}
pub static VALUE: usize = 42;
pub static ADDRESS: usize = unsafe { TransmuteHack { from: &VALUE }.to };
fn main() {
println!("{:?}", ADDRESS / 2);
} Notice that @oli-obk Why does the last example compile on stable? Shouldn't it promote and then fail...? EDIT: Seems like we don't promote uses of a static. Interesting. |
For these I don't see the point in warning. If having a runtime local of reference type with |
Oh I see, you are saying if the info is any good we should make it a hard error. Makes sense. |
I didn't quite understand this part. You did say that "It seems that it is not possible to refer to statics in constants or promoteds", so I guess you mean that -- today -- everything should be fine, since the tainted value stays in "runtime land". (Also, since constants cannot refer to statics (e.g., But, if we accept these sorts of statics, then in the future we could not lift those restrictions without the results depending on the precise value of the static? |
It's an either or. Either we allow referring to statics in constants and promoteds or we allow creating statics with const-unsafe values. We can't have both.
|
Indeed. However, the bottom-left corner of that square has some other quirks -- we have to be very careful in what we let you do with the statics. Taking the address is always okay, but that remains the case even if we allow bad statics! So what remains is read-access to immutable statics (their type must be So we don't lose all that much here. |
Addresses are not ok if we ever want to allow dereferencing. or do we already do that? Dereferencing a reference to a static is just as bad as directly accessing it |
Ah right. I think it'd be fine to never allow dereferencing in promoteds, but for const that seems awfully restrictive. |
These comments have helped clarify some of my initial confusion as to why
I don't really understand why either of these things are the case. Item 1 would be taken care of if the compiler could "demote" something it had previously promoted and just fall back to evaluating it at run time. Item 2 seems to be unnecessary? The constant propagation optimization pass already exists, so I'm not sure what additional performance benefits are to be gained by doing item 2, and I can't see any additional non-performance benefits that come from constant promotion in regular I'm just a user of Rust, though, and obviously lack much of the big-picture design efforts and goals that are ongoing right now, so forgive me if my reply is super naive or outright wrong. |
Promotion is not at all about performance. It's about letting you write fn foo() -> &'static i32 { &42 } // note the lifetime! I suggest you have a look at the RFC for some further motivation. This also connects to item 1: The order of events is "we decide what to promote", "we do borrow checking", "we do const evaluation". Promoted things get the |
@rfcbot fcp close |
Team member @aturon has proposed to close this. The next step is review by the rest of the tagged teams:
No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
Just for context, the lang team is suggesting to close this because it got accidentally stabilized. This could still be a useful feature, but then it should go through the usual process for new features (i.e., an RFC), and not happen by accident. |
I see; that makes sense. Thank you. Sorry I kept missing the significance of this. Okay, well with that in mind I really can't argue against closing this. Thank you all (especially @RalfJung!) for looking into this thoroughly (and for your patience with me). |
discussed at compiler team meeting. FCP (to close) in process. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
closing ahead of actual release in a few hours. |
The following code works with Rust 1.29.0:
But it fails with the current beta (and nightly):
I think this code should still be valid. I don't see any reason for this to be undefined behavior. This is a hack, yes, but it's very useful for FFI-related work.
The text was updated successfully, but these errors were encountered: