Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upRFC: Allow safe access to some `static mut` vars #177
Conversation
alexcrichton
referenced this pull request
Jul 22, 2014
Closed
rustc: Allow safe access of shareable static muts #14862
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
As described in great detail in the referenced issue, this is not even remotely safe. It's also a complete mis-use of the
The definition of The counterargument is that since a The general rule for Given this definition, since the mere ability to take a The only situation in which this RFC actually affects things is when the I believe that there are alternative approaches that we can use to solve the |
This comment has been minimized.
This comment has been minimized.
erickt
commented
Jul 23, 2014
|
@kballard: do you have an alternative you prefer? I also think we should also consider putting |
This comment has been minimized.
This comment has been minimized.
|
While CTFE will allow for nicer initializers, I don't think it will help with requiring |
This comment has been minimized.
This comment has been minimized.
The safe functions in the |
bharrisau
reviewed
Jul 23, 2014
|
|
||
| Requiring unsafe access to these types unnecessarily introduces `unsafe` blocks | ||
| in otherwise safe programs, and have the risk of leading to further unsafe | ||
| behaviors if it's unclear what exactly in the block is unsafe. |
This comment has been minimized.
This comment has been minimized.
bharrisau
Jul 23, 2014
Has there been an RFC or discussion on other ways to achieve this? We only have three sources of unsafety, could we mark up the unsafe {} with which we are intending on using?
unsafe<RawDeref + MutStatic + UnsafeFn> { }
Sorry it is a little off topic, I'm just not 100% across all the previous discussions and this seems like a similar solution.
This comment has been minimized.
This comment has been minimized.
alexcrichton
Jul 23, 2014
Author
Member
This has come up in the past before, although there haven't been any concrete proposals in the area, more of just ideas. For now though, the RFC is written with the assumption that this does not exist (but it would be quite nice!)
This comment has been minimized.
This comment has been minimized.
huonw
Jul 23, 2014
Member
FWIW, once rust-lang/rust#15701 is implemented it could be a lint, interpreting things like #[behaviour(raw_deref, mut_static)] unsafe { ... }.
This comment has been minimized.
This comment has been minimized.
I would imagine that the large portion of safety that most Rust users consider is only safe code considered as a whole. Can you concretely explain how you believe this proposal is unsafe assuming there is no unsafe code? |
This comment has been minimized.
This comment has been minimized.
erickt
commented
Jul 23, 2014
|
@alexcrichton: that's why I said "some" usages of Two thoughts off the top of my head without thinking about it too deeply:
|
This comment has been minimized.
This comment has been minimized.
I view the addition of a new kind of static to the language as more than it's worth given the problem that this RFC is trying to solve. The naming would also have to be quite different because otherwise we'll have a system where
This is certainly plausible! I personally believe that |
This comment has been minimized.
This comment has been minimized.
bharrisau
commented
Jul 23, 2014
|
Is there a potential that the If initialization isn't a problem, I don't see why reading a Storing |
This comment has been minimized.
This comment has been minimized.
Thankfully no, all static variables are required to have initializers, and initializers are always just bit patterns so there are no statics which are ever uninitialized at any time.
The borrow checker cannot guarantee this because it doesn't have total knowledge, but this is why |
This comment has been minimized.
This comment has been minimized.
|
One issue here is because statics are used in 2 contexts here - there are static VALUES (which are, for example, useful in initializers) and static VARIABLES (assignables, by Harper's nomelecture) which have an identity and can potentially be modified. Static values are values. changing them makes as much sense as executing 1+1 = 3. Note that sometimes (e.g. mutex static initializers) they need to contain an Unsafe. Being values, they still can't be mutated. Static assignables are accessible through the program. It seems that a decent way of handling them is to make them behave like a &'static T parameter passed to all functions in the program. Of course given multithreading they need to be Share. |
This comment has been minimized.
This comment has been minimized.
|
Thinking about it more, the initializers-can't-be-priv problem may be annoying: If one wants a manually-synchronized static (i.e. a static variable which can't be proven synchronized by the type-system), then with my proposal it would need to be wrapped withing a Share wrapper. Because of the initializer-can't-be-priv issue, you can't have an externally-safe wrapper in a library. For example struct MyDSWrapper {
// intentionally private
inner: Unsafe<ManuallySynchronizedDS>
}
impl share for MyDSWrapper;
static mut svar: MyDSWrapper = MyDSWrapper
{ inner: ManuallySynchronizedDS { ... }};
pub fn work() {
let x = external_lock();
do_something_with(&mut unsafe { *svar.get() });
}However, an inline wrapper wouldn't be much more dangerous than most other uses of unsafe (i.e. uncareful safe code in the same module can trigger undefined behaviour). I don't think this is a big problem but some don't like it. However, this isn't particularly related to static muts but it is rather the way Rust handles unsafe. |
This comment has been minimized.
This comment has been minimized.
Rust takes the same approach with
If you take a look at |
This comment has been minimized.
This comment has been minimized.
But the unsafety is limited to Furthermore, I think there's a fundamental difference between arguing that access to a struct field can produce unsafety vs
Yes. Make The issue here is that this then allows e.g. |
This comment has been minimized.
This comment has been minimized.
You cannot assume there is no unsafe code. That's the problem. You, the library author, do not have control over the Maybe we should just get rid of |
This comment has been minimized.
This comment has been minimized.
|
Regarding safety, I am of the opinion that this proposal does not introduce any new risks for unsafe code. It is always true that unsafe operations may interfere with safe operations (that is, indeed, why we call them unsafe). The rules that govern static mut are that when one writes to a static mut, one must ensure that this read is ordered with respect to all reads of that static mut. As @kballard notes, these reads may occur in safe code or in unsafe code. In practice, this probably means that privacy must be used to restrict the set of code where the static mut can be accessed. This is par for the course with unsafe code. The fact that the writes must be ordered with respect to "safe" reads is not unusual and occurs in many situations. For example, transmuting a pointer can easily violate Rust's aliasing rules, which would render otherwise safe code unsafe. The public field in |
This comment has been minimized.
This comment has been minimized.
|
Well the unsafety problem is slightly different from the Vec problem - actually it is the already-present problem with Unsafe (when one can take the value while the Unsafe is borrowed by unsafe code) - but this problem has nothing to do with statics. From some point of view, it can be said that this is different from the Vec problem - because in the Vec problem the undefined behaviour happens within unsafe code, while here the problem is that safe code can see aliasing & and an &mut. I would prefer that this problem is fixed (mostly because it would make the spurious write semantics simpler) but it (still) has nothing to do with statics. |
This comment has been minimized.
This comment has been minimized.
|
That said, I think there is an argument for using Conceivably we could have three kinds of declarations:
A
And then having
Under this scheme, the The downside is that there are three things, but in a sense those three things exist today, it's just that we use Worth thinking about. |
This comment has been minimized.
This comment has been minimized.
|
What's the difference in your proposal between static and static mut? |
This comment has been minimized.
This comment has been minimized.
|
I like This could also be coupled with my earlier suggestion to remove The difference is |
This comment has been minimized.
This comment has been minimized.
|
In this case I'm not sure why |
This comment has been minimized.
This comment has been minimized.
|
Not sure what you mean by a |
This comment has been minimized.
This comment has been minimized.
|
By "Share wrapper" I meant a wrapper around Unsafe that is Share. And I think unsafe fields are orthogonal to public-initialize-private-access fields. (For example, a public-initialize-private-access field would be rather bad on Vec). |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis Under the three-way distinction you propose, would (Premature bikeshedding: one small issue with the particular naming suggested here is that it would make IINM, it also wouldn't be possible to take an |
This comment has been minimized.
This comment has been minimized.
|
I think that it would be preferable to let only consts be "compile-time known" - you can always declare |
This comment has been minimized.
This comment has been minimized.
|
I think there's three big reasons why I view The first is that a The second is that the unsafety with Note here, again, that the only reason the This is why I very strongly favor the suggestions that allow for The third reason is that, with Ultimately, it just feels like library-provided invariants are things that are never expected to be checked by the compiler, whereas
The first one isn't important to this discussion, but the second is. Borrowck enforces it normally, so the only way to violate it is with The problem is, this RFC very explicitly breaks this otherwise-inviolate guarantee. It provides a mechanism to produce a |
This comment has been minimized.
This comment has been minimized.
|
Incidentally, I retract my suggestion to remove |
This comment has been minimized.
This comment has been minimized.
|
The Unsafe reference problem would still exist if we have By the way, could we talk on IRC? |
This comment has been minimized.
This comment has been minimized.
If
I don't think there would necessarily be a problem with allowing |
This comment has been minimized.
This comment has been minimized.
|
You can already write an My current viewpoint is:
|
This comment has been minimized.
This comment has been minimized.
|
@arielb1 Regarding
FWIW, with the If we can fix the |
This comment has been minimized.
This comment has been minimized.
|
@kballard I don't know why you say that a static mut is "expected" to be public. Indeed, I expect just the opposite. |
This comment has been minimized.
This comment has been minimized.
|
On Wed, Jul 23, 2014 at 09:08:55AM -0700, Gábor Lehel wrote:
No.
No.
Only consts.
Yes. |
This comment has been minimized.
This comment has been minimized.
Maybe that's the confusion here. Go look at |
This comment has been minimized.
This comment has been minimized.
|
On Thu, Jul 24, 2014 at 10:22:38AM -0700, Kevin Ballard wrote:
@kballard I guess I wasn't precise enough. I expect any static muts |
This comment has been minimized.
This comment has been minimized.
|
Ultimately, I still feel like this is a violation of I do get the argument that mutation is still unsafe and therefore the guarantee can be provided on the mutation side. But I just don't consider that persuasive. Generally, the approach Rust takes is to require Also, the more we talk about this, the more I'm convinced that requiring users to use |
nrc
assigned
alexcrichton
Sep 4, 2014
alexcrichton
force-pushed the
rust-lang:master
branch
from
6357402
to
e0acdf4
Sep 11, 2014
aturon
force-pushed the
rust-lang:master
branch
from
4c0bebf
to
b1d1bfd
Sep 16, 2014
This comment has been minimized.
This comment has been minimized.
|
Closing in favor of #246, which is now accepted. |
alexcrichton commentedJul 22, 2014
Rendered