You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
borrowck is unsound in the presence of &'static muts #27616
Maybe there should be a "strict outlives" requirement for reborrows for &mut T, effectively denying them for &'static mut T.
I wonder if that would break any code.
I think there are two ways of looking at this issue:
leak is not sound, because it mints a static reference to a value that is not actually statically allocate (i.e. it can be freed).
leak is fine in principal, but aliasing 'static borrows is not -- the attack @arielb1 points out seems to rely on aliasing, and tricking the compiler into thinking it's safe to drop the string's Vec, although maybe it's not the only attack vector...
@eddyb's suggestions seems reasonable as a general rule, but in this case, isn't the borrow happening from an unsafe pointer, which doesn't have a lifetime? How would it prevent @arielb1's attack?
So aliasing 'static references is just plain problematic, and clearly leak can't be done safely while aliasing is allowed. Does this raise a slightly broader question about whether 'static references should be aliasable from "safe" code? If aliasing 'static references is not allowed, can leak be safe?
My intuition (and I suspect that of other people) was that global static mut items must be unsafe to access due to the combination of two reasons: (a) &mut references must always be unaliased, but (b) due to their global scope, it is impossible to enforce this for references created to static mut items. With a function like Box::leak(), however, (b) is not the case, so the usual move-only semantics of &mutshould be sufficient to ensure uniqueness... except it's currently not due to the handling of reborrowing which this issue is about.
leak is not sound, because it mints a static reference to a value that is not actually statically allocate (i.e. it can be freed).
I believe &'static doesn't promise anything about how the referent was/is allocated, only that it will live forever, which is the case here. (It can't be freed according to the typesystem because there is no fn free(&'static T).)
I agree with @eddyb that it's the re-borrow of s that's the issue. I guess that the 'static lifetime on alias is what is throwing it off. It really should be moved, not reborrowed, in this case, as the borrow doesn't seem to prevent usage of s like it does with a non-static lifetime. If you wrap the &'static mut String in some struct so re-borrowing doesn't happen, the code fails to compile as expected.
@arielb1 I know. I was trying to respond to @alevy's suspicion that the problem lies somewhere around the (purported) fact that these &'static mut values obtained by leak()ing "can be freed", unlike "normal" ones which are actually references to static items somewhere in the program.
@arielb1 My intuition was that the resulting 'static lifetime carries no information that could associate it with a borrow, unlike other kinds of lifetimes.
So the reason for this is clear enough. There is this code in gather_loans/mod.rs:
ty::ReStatic => {// If we get here, an error must have been// reported in// `lifetime::guarantee_lifetime()`, because// the only legal ways to have a borrow with a// static lifetime should not require// restrictions. To avoid reporting derived// errors, we just return here without adding// any loans.return;}
I think the assumption here was that &'static mut could only occur with a static mut. Anyway this is false, particularly now. Should be easy enough to fix I believe.
@eddyb sorry for being slow to respond. The answer is that I think the resulting restrictions are enough, as long as we extend the loan out to the borders of the fn. I have a patch that does just this.
Activity
eddyb commentedon Aug 10, 2015
Maybe there should be a "strict outlives" requirement for reborrows for
&mut T, effectively denying them for&'static mut T.I wonder if that would break any code.
alevy commentedon Aug 10, 2015
I think there are two ways of looking at this issue:
leakis not sound, because it mints a static reference to a value that is not actually statically allocate (i.e. it can be freed).leakis fine in principal, but aliasing 'static borrows is not -- the attack @arielb1 points out seems to rely on aliasing, and tricking the compiler into thinking it's safe todropthe string'sVec, although maybe it's not the only attack vector...@eddyb's suggestions seems reasonable as a general rule, but in this case, isn't the borrow happening from an unsafe pointer, which doesn't have a lifetime? How would it prevent @arielb1's attack?
arielb1 commentedon Aug 10, 2015
@alevy
You can basically do that with every
&'static mutpointer to a non-trivial type (you can alias them and then reborrow to a shorter lifetime).It doesn't matter how you get them.
alevy commentedon Aug 10, 2015
@arielb1 Can you mount the attack on a variable that's actually statically allocated? i.e.:
Isn't this the reason static variables can't have
Dropable types?arielb1 commentedon Aug 10, 2015
Note that this would also make a
thread_localthat doesn't require Sync unsafe (because ofRefCell).alevy commentedon Aug 10, 2015
A counter example to my question/claim that @arielb1 came up with on IRC:
So aliasing 'static references is just plain problematic, and clearly
leakcan't be done safely while aliasing is allowed. Does this raise a slightly broader question about whether 'static references should be aliasable from "safe" code? If aliasing 'static references is not allowed, canleakbe safe?glaebhoerl commentedon Aug 11, 2015
My intuition (and I suspect that of other people) was that global
static mutitems must beunsafeto access due to the combination of two reasons: (a)&mutreferences must always be unaliased, but (b) due to their global scope, it is impossible to enforce this for references created tostatic mutitems. With a function likeBox::leak(), however, (b) is not the case, so the usual move-only semantics of&mutshould be sufficient to ensure uniqueness... except it's currently not due to the handling of reborrowing which this issue is about.I believe
&'staticdoesn't promise anything about how the referent was/is allocated, only that it will live forever, which is the case here. (It can't be freed according to the typesystem because there is nofn free(&'static T).)Aatch commentedon Aug 11, 2015
I agree with @eddyb that it's the re-borrow of
sthat's the issue. I guess that the'staticlifetime onaliasis what is throwing it off. It really should be moved, not reborrowed, in this case, as the borrow doesn't seem to prevent usage ofslike it does with a non-static lifetime. If you wrap the&'static mut Stringin some struct so re-borrowing doesn't happen, the code fails to compile as expected.arielb1 commentedon Aug 11, 2015
@Aatch
There's no problem with the reborrowing - it's just that borrowck ignores the borrow part of the reborrow for some reason - probably this line.
If no reborrow happens, the value is moved as it should.
arielb1 commentedon Aug 11, 2015
@glaebhoerl
There is no
free(&'a mut T)for any'a. It's just that'staticvalues are required to be valid for the rest of the program's execution.@alevy
static mutis known to be unsafe. I am worried about using some kind ofMutex/RefCell/IVarturning a&'static Mutex<T>into a&'static mut T.glaebhoerl commentedon Aug 11, 2015
@arielb1 I know. I was trying to respond to @alevy's suspicion that the problem lies somewhere around the (purported) fact that these
&'static mutvalues obtained byleak()ing "can be freed", unlike "normal" ones which are actually references tostaticitems somewhere in the program.eddyb commentedon Aug 11, 2015
@arielb1 My intuition was that the resulting
'staticlifetime carries no information that could associate it with a borrow, unlike other kinds of lifetimes.arielb1 commentedon Aug 11, 2015
@eddyb
You can always borrow for the outermost function's lifetime - all borrows must intersect it.
huonw commentedon Aug 13, 2015
A example of the core problem is:
i.e.
&'static muts can be aliased.nikomatsakis commentedon Aug 20, 2015
So the reason for this is clear enough. There is this code in
gather_loans/mod.rs:I think the assumption here was that
&'static mutcould only occur with astatic mut. Anyway this is false, particularly now. Should be easy enough to fix I believe.eddyb commentedon Aug 20, 2015
@nikomatsakis I'm curious what the effects of removing that early return would be.
What would get tracked? Would the resulting restrictions be enough?
Treat loans of 'static data as extending to the end of the enclosing
nikomatsakis commentedon Sep 9, 2015
@eddyb sorry for being slow to respond. The answer is that I think the resulting restrictions are enough, as long as we extend the loan out to the borders of the fn. I have a patch that does just this.
Auto merge of #28321 - nikomatsakis:issue-27616, r=pnkfelix
switch to returning mutable refs