-
Notifications
You must be signed in to change notification settings - Fork 121
GC related safety and soundness issues #569
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
Comments
Proposed fixes (some of this I'm posting for the first time, other of this I'm copying in from previous discussions): GC using values while we have a
|
I missed that how we're construction |
NOTE-TO-SELF: Lines 194 to 196 in 3e8e9d3
where we create Handle from MutableHandle. I am not 100% sure how implicit lifetimes works, but I would feel safer if we explicitly return Handle<'a, T> (is that enough or should we also include lifetime of &self?). I think this should do it pub fn <'a: 'b> handle(&'b self) -> Handle<'b T> { .
|
We should only need the lifetime of We want the lifetime of Meanwhile in I think the implicit lifetimes are correct here, I agree it would be nice if they were explicit. |
I think it would still be worth to be explicit about this in function bounds, so having both (inner lifetime and |
So in the context of the outstanding PRs, you prefer impl<'a, T> HandleType<'a, T> {
/// Safety: GC must not run during the lifetime of the returned reference.
pub unsafe fn as_mut<'b>(&'b mut self) -> &'b mut T
where
'a: 'b
{
&mut *(self.as_ptr())
}
} I guess I have a weak preference against this (it feels like unnecessary information, that someone might read as "this isn't normal" when it is normal), but not a very strong one. I'll update the PRs to do this. |
Hello from out of nowhere! I thought I might have some potentially interesting suggestions / thoughts on GC safety and soundness, from the point of view of a person writing a JS engine in Rust which has... well, quite a different setup from SpiderMonkey, but still of course has GC and all the questions that come with it. In my/our engine we don't have direct pointers to GC data, instead using handles, so a lot of the problems you deal with are in some ways automatically dealt with. But, because we use unrooted handles by default we actually get a lot of the problems right back. The way I've "resolved" this issue is that I pass around an exclusive, non-clonable but reborrowable From an outside perspective (and from my personal philosophy on GC) I would think that you could and would want to use the fn as_mut<'gc>(&mut self, _: &'gc JSContext) -> &'gc mut T {
&mut *(self.as_ptr())
} (some additional lifetime bounds for Now assuming that From a philosophical standpoint, this also seems to make sense (to me anyway): The JSContext is the way to access the GC heap; that a My apologies if this is unnecessary chatter; I have somewhat of a vested interest in Servo's JS engine binding system and a highly vested interest in GC modeling in Rust, so wanted to chime in. If this is unwanted, please let me know or just hide the comment. If this is wanted/interesting/confusing, I'll be happy to exchange more messages here or elsewhere. Cheers! |
Something like this is considered, but this will require a lot of work, mainly passing JSContext everywhere in servo, see: #520 (comment). You might also be interested in https://github.com/asajeffrey/josephine, that has some interesting GC-rust ideas. nit: JSContext lifetime should be named |
Hi @aapoalas - speaking for myself super happy to have you here! I've read about and watched your talk on how you're implementing GC in nova, and it seems quite clever. I think we're ok on this issue, but taking this as an opportunity to record some thoughts: This API has been proposed, to my surprise I don't think we need it, at least for now. I managed to remove the (main) Some important context here - and I'm curious if anyone here will disagree with how I phrase this since this is the first time I'm writing it down - Servo's GC can be thought of as two nested GCs
As a result handles into servo's GC (what we actually call This has the interesting consequence, that servo frequently takes advantage of, that handles can be safely de-referenced into I don't think we can (or should) eliminate the Back to the proposed API, there is a related one that might help more. Servo makes use of interior mutability for things that it mutates (which explains why we don't need pub struct JSCell<T> { inner: UnsafeCell<T> }
impl<T> JSCell<T> {
fn new(val: T) -> Self;
fn into_inner(self) -> T;
fn as_mut(&mut self) -> &mut T;
fn get(&self, &JSContext<'_>) -> T where T: Copy;
fn set(&self, &mut JSContext<'_>, val: T);
fn borrow_mut<'a>(&'a self, &'a mut JSContext<'_>) -> &'a mut T;
fn borrow<'a>(&'a self, &'a JSContext<'_>) -> &'a T;
} (Which also relies on #554 for a context type that tracks lifetimes properly) I haven't thought about this deeply, or closely read the relevant code, but there might also be an opportunity for an Footnotes
|
While working on #520 other soundness and safety issues came up, this is something of an omnibus issue regarding them.
By "handle like types" I mean
RootedGuard
,RootedVec
,MutableHandle
, andJS::MutableHandle
, as well as potentiallyRootedTraceableBox
, andCustomAutoRooter
.Soundness - correct use of the public API results in undefined behavior
Traceable
modifies values behind a&T
reference (Traceable is unsound #560).RootedGuard
stores a&mut
reference to data the GC looks at and modifies over GC pauses (RootedGuard<T> construction related unsoundness #564).MutableHandle
is constructed via a&mut
reference, which will be invalidated by GC (Remove DerefMut impl for RootedGuard #572).Handle
stores an&
reference to data (not wrapped in aCell
type) that the GC modifies over GC pauses.Deref
implementations for handle like types allow for safe code to hold an&
reference to data (not wrapped in aCell
type) that the GC will modify at over GC pauses. (Arguably a safety issue not a soundness issue, but I think we'll end up allowing borrowing over GC pauses).Traceable
.Rooted
viaRootKind
.ForOfIteratorGuard::new
is suspicious, it likely has issues similar to those described in RootedGuard<T> construction related unsoundness #564.Safety - it's possible to use this improperly in safe code
DerefMut
implementations for handle like types allow for safe code to hold an&mut
reference to data the GC will look at and modify over GC pauses.JS::MutableHandle
#574JS::MutableHandle
#574JS::MutableHandle
allows mutating an&T
returned fromDeref
viaset
on an aliasing handle.JS::[Mutable]Handle
allows use after free in safe code viaDerefMut
Remove DerefMut impl forJS::MutableHandle
#574Deref
,get
, andset
Assumptions in comments on public APIs
as_ptr
method assumes that the GC will only read - i.e. writes will occur through interior mutability. If that ends up not being the case, the comment should be updated.The text was updated successfully, but these errors were encountered: