So in Servo we can have &mut references to stuff on the stack,
(let's assume said stuff on the stack doesn't move ever)
and the thing on the stack is also stored as a pointer to a trait object somewhere else in the program, as part of root lists for the JS GC,
is that unsound?
centril
nox: and by "doesn't move ever" I infer that it never gets popped from the stack frame either, so data is morally &'static mut ?
nox
?
No it does get popped from the stack when the function exits.
Not sure how that relates though.
Basically, you have a &mut T somewhere,
you call a JS function that triggers a GC,
the JS engine traverses the root list and traces it to not free stuff that is still used,
that root list ultimately will traverse that &mut T through the pointer in its root list, while you still have your &mut T in scope.
Is that unsound?
I know that using *some* methods are definitely unsound (Vec::drain for example, because some elements are "hidden" from the Vec while the draining iterator exists), but I don't know if it's always unsound.
If it is indeed unsound, we need some pretty drastic changes.
eddyb
nox: the rooting list thing is immutable-only, right?
nox
eddyb: What do you mean?
eddyb
nox: I mean the GC only does immutable accesses
nox
Yes.
eddyb: Well, JS itself will mutate stuff, but that stuff is properly behind UnsafeCell<T> on the Rust side.
eddyb
nox: well if you had &T and interior mutability instead of &mut it's sound I'm pretty sure
nox: because it's basically the same pattern as scoped thread-locals
nox
eddyb: And having a &mut T around while the GC stuff does immutable access is ok too?
eddyb
nox: I don't think so
nox: or rather, if it's okay, it's *nowhere* near as simple of a reason
nox
Ok.
nox still needs to rewrite half the things anyway.
eddyb: We have RootedVec<T> which stores a Vec<T> and puts a pointer to it in some root list,
eddyb
nox: wait you can send the &mut T to another thread
nox
and it DerefMut to Vec<T>,
eddyb
(if you can get *any* &mut)
(to any field)
mutation is fine, &mut isn't
nox
and I've just realised it is pretty bad, because draining and other stuff.
Not sure what you mean by that.
eddyb
yeah and there's probably worse things than draining
nox: if I can get a &mut u8 or something within that Vec
nox
Mmh…
eddyb
nox: I can pass that to another thread
so I think having &mut at all is pretty bad
nox
MMMMH
I kinda want to go back to bed and forget everything now.
centril also has to rewrite some stuff
centril
but not as much
nox
Wait, why is sending &mut u8 an issue?
eddyb
nox: because now you can data race
nox
Why?
eddyb
nox: with the shared reference
in the original thread
nox
I don't follow.
eddyb
there's no way to say that an &mut (of an arbitrary type) must be used in a certain way
so I can do things to it that aren't valid if you can also access that memory through any other way
and by not valid I mean UB
(well u8 isn't enough to cause UB trivially, but still)
nox
I think I see the issue.
eddyb
nox: &mut being unaliased is still important even in side-channel cases like these
so UnsafeCell and &self methods it is :P
centril
eddyb: `let PAT = EXPR;` is classified as a statement atm, right?
oln joined the channel
eddyb
centril: yes
centril
great
centril is fixing the if-while-or-patterns per nmatsakis's proviso
eddyb: hmm... what would the proper desugaring of `let A(x) | B(x) = expr;` be? My naive approach is `let x = match expr { A(x) | B(x) => x };`. Idk if that might be problematic tho
eddyb
centril: uhm
centril: you wouldn't desugar a let pattern
centril: wait so are we adding | to patterns?
I don't want an interpretation which requires | to be at the top-most level at any point in the implementation