-
Notifications
You must be signed in to change notification settings - Fork 15
Compiler optimizations considered harmful in safe function in "unsafe module" #40
Comments
@RalfJung that's undefined behavior - you're aliasing mutably with a reference. The subobject is referenced by |
At least, that's my opinion of it. |
That's one possible answer, but I feel that could actually rule out real-world unsafe code. Also, specifying exactly when "I stop being used" is happening doesn't seem an easy task. Once you are saying that it matters which of multiple "identical" pointers you are using to access a given location, that opens a whole can of worms. |
Also, saying just "from this point forward" would not permit moving loads/stores up across function calls. Seems like an access should have an effect "backwards in time"? |
@RalfJung I need to re-write down the wording that I used. Basically, in this case, since neither pointer is derived-from the other, it is known that they do not alias. |
and yes, it does open a can of worms - it's very important to open this can of worms. What about this example is different from the (definitely UB) example following?
|
The fact that my example involves an "unsafe type" that has its own invariant attached to it -- an invariant that makes a naive interpretation of my code work fine -- could make a difference. Imagine some form of tree where every node has a raw pointer back to the root. Some public method in this library could take the entire data structure via |
@RalfJung it may have to be a special case - pointers that live inside the object you have a reference to. |
(FWIW, I've written code that is very close to this in Rayon -- but not the same. In particular, the code had a "self-link" of this kind, but that self-link is an |
This is a good example though that gets right at the question of what the boundary for unsafe ought to be. I really feel like we need a way to make that boundary clearer -- this might be unsafe fields, I'm not sure -- and that it is inevitable that such boundaries will play a role in optimization. I still favor the idea that the boundary for unsafety follows the privacy rules, and that we add some sort of level ( |
@nikomatsakis I still disagree that |
But it won't even compile in safe -- the compiler will complain that you are performing unsafe operations. |
@RalfJung I'm talking about stuff that's in your example above. |
So am I. If we say that |
@RalfJung that both seems like a massive pessimization, and only moves the problem. Now it's "if someone creates an implementation module". |
It's not "just" moving the problem -- being in a separate module makes the privacy rules kick in. |
@RalfJung that doesn't really matter for internal modules? You can have intermodule invariants. |
Hm, yeah, you can. Maybe we require some annotation if that's what you do? Not sure. I don't claim I have all the answers. ;) Do you have an example of a real crate doing something like this? |
@RalfJung no, but I don't write very much unsafe code. Maybe something like |
Consider the following contrived module:
Playpen
What is strange or troublesome about this?
do_sth
looks like a perfectly safe function -- it's not marked unsafe and doesn't contain an unsafe block -- so we may think that we can do the usual optimizations that we think we can do in safe functions. However, if the compiler decides to move the store of42
down below the function call, the module's invariant is violated in a way that the module can observe. That's bad.One may say the actual cause of the trouble here is the fact that
check
is not marked as unsafe -- after all, that function doesn't actually work with any odd raw pointer. However,check
is internal, and it seems to be a long stretch to rely on everyone annotating their purely internal helper functions properly.Cc @nikomatsakis @arielb1
The text was updated successfully, but these errors were encountered: