Skip to content

Commit 469a3f4

Browse files
author
bors-servo
authored
Auto merge of #15118 - jdm:reflector-barrier-crash, r=<try>
Use Heap instead of UnsafeCell in DOM reflectors The previous `Reflector` implementation did not use post barriers, so we could crash when storing nursery objects in a `Reflector` structure that were later moved out of the nursery. - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #15085 - [X] There are tests for these changes <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15118) <!-- Reviewable:end -->
2 parents be3f358 + e5eaab3 commit 469a3f4

File tree

4 files changed

+19
-26
lines changed

4 files changed

+19
-26
lines changed

components/script/dom/bindings/reflector.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
use dom::bindings::conversions::DerivedFrom;
88
use dom::bindings::js::Root;
99
use dom::globalscope::GlobalScope;
10-
use js::jsapi::{HandleObject, JSContext, JSObject};
11-
use std::cell::UnsafeCell;
12-
use std::ptr;
10+
use js::jsapi::{HandleObject, JSContext, JSObject, Heap};
11+
use std::default::Default;
1312

1413
/// Create the reflector for a new DOM object and yield ownership to the
1514
/// reflector.
@@ -34,44 +33,41 @@ pub fn reflect_dom_object<T, U>(
3433
// If you're renaming or moving this field, update the path in plugins::reflector as well
3534
pub struct Reflector {
3635
#[ignore_heap_size_of = "defined and measured in rust-mozjs"]
37-
object: UnsafeCell<*mut JSObject>,
36+
object: Heap<*mut JSObject>,
3837
}
3938

4039
#[allow(unrooted_must_root)]
4140
impl PartialEq for Reflector {
4241
fn eq(&self, other: &Reflector) -> bool {
43-
unsafe { *self.object.get() == *other.object.get() }
42+
self.object.get() == other.object.get()
4443
}
4544
}
4645

4746
impl Reflector {
4847
/// Get the reflector.
4948
#[inline]
5049
pub fn get_jsobject(&self) -> HandleObject {
51-
unsafe { HandleObject::from_marked_location(self.object.get()) }
50+
self.object.handle()
5251
}
5352

5453
/// Initialize the reflector. (May be called only once.)
5554
pub fn set_jsobject(&mut self, object: *mut JSObject) {
56-
unsafe {
57-
let obj = self.object.get();
58-
assert!((*obj).is_null());
59-
assert!(!object.is_null());
60-
*obj = object;
61-
}
55+
assert!(self.object.get().is_null());
56+
assert!(!object.is_null());
57+
self.object.set(object);
6258
}
6359

6460
/// Return a pointer to the memory location at which the JS reflector
6561
/// object is stored. Used to root the reflector, as
6662
/// required by the JSAPI rooting APIs.
67-
pub fn rootable(&self) -> *mut *mut JSObject {
68-
self.object.get()
63+
pub fn rootable(&self) -> &Heap<*mut JSObject> {
64+
&self.object
6965
}
7066

7167
/// Create an uninitialized `Reflector`.
7268
pub fn new() -> Reflector {
7369
Reflector {
74-
object: UnsafeCell::new(ptr::null_mut()),
70+
object: Heap::default(),
7571
}
7672
}
7773
}

components/script/dom/bindings/trace.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//! calls `trace()` on the field.
2121
//! For example, for fields of type `JS<T>`, `JS<T>::trace()` calls
2222
//! `trace_reflector()`.
23-
//! 4. `trace_reflector()` calls `JS_CallUnbarrieredObjectTracer()` with a
23+
//! 4. `trace_reflector()` calls `JS::TraceEdge()` with a
2424
//! pointer to the `JSObject` for the reflector. This notifies the GC, which
2525
//! will add the object to the graph, and will trace that object as well.
2626
//! 5. When the GC finishes tracing, it [`finalizes`](../index.html#destruction)
@@ -54,7 +54,7 @@ use hyper::method::Method;
5454
use hyper::mime::Mime;
5555
use hyper::status::StatusCode;
5656
use ipc_channel::ipc::{IpcReceiver, IpcSender};
57-
use js::glue::{CallObjectTracer, CallUnbarrieredObjectTracer, CallValueTracer};
57+
use js::glue::{CallObjectTracer, CallValueTracer};
5858
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind};
5959
use js::jsval::JSVal;
6060
use js::rust::Runtime;
@@ -139,12 +139,8 @@ pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>)
139139
/// Trace the `JSObject` held by `reflector`.
140140
#[allow(unrooted_must_root)]
141141
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
142-
unsafe {
143-
trace!("tracing reflector {}", description);
144-
CallUnbarrieredObjectTracer(tracer,
145-
reflector.rootable(),
146-
GCTraceKindToAscii(TraceKind::Object));
147-
}
142+
trace!("tracing reflector {}", description);
143+
trace_object(tracer, description, reflector.rootable())
148144
}
149145

150146
/// Trace a `JSObject`.

components/script/dom/promise.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,12 @@ impl Promise {
9090
#[allow(unsafe_code, unrooted_must_root)]
9191
unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc<Promise> {
9292
assert!(IsPromiseObject(obj));
93-
let mut promise = Promise {
93+
let promise = Promise {
9494
reflector: Reflector::new(),
9595
permanent_js_root: MutHeapJSVal::new(),
9696
};
97-
promise.init_reflector(obj.get());
98-
let promise = Rc::new(promise);
97+
let mut promise = Rc::new(promise);
98+
Rc::get_mut(&mut promise).unwrap().init_reflector(obj.get());
9999
promise.initialize(cx);
100100
promise
101101
}

tests/wpt/mozilla/tests/mozilla/promise.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
var p = new Promise(function() {});
5959
var start = Date.now();
6060
t.resolvePromiseDelayed(p, 'success', 100);
61+
test.step_timeout(function() { window.gc() }, 0);
6162
return p.then(function(v) {
6263
var end = Date.now();
6364
assert_greater_than_equal(end - start, 100);

0 commit comments

Comments
 (0)