0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-12-23 15:50:11 -05:00

Add new terminate_execution test (#288)

This commit is contained in:
Ryan Dahl 2020-02-19 22:55:44 -05:00 committed by GitHub
parent 2aeb4e0cef
commit d3bbd05634
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 43 deletions

View file

@ -235,7 +235,8 @@ impl Isolate {
assert!(existing.is_none());
// ptr is still stored in Isolate's embedder slot.
let _ptr = Box::into_raw(states);
let ptr2 = Box::into_raw(states);
assert_eq!(ptr, ptr2);
}
pub fn state_get<S>(&self) -> Rc<RefCell<S>>
@ -251,7 +252,8 @@ impl Isolate {
// Rc<RefCell<S>> without transmute?
#[allow(clippy::transmute_ptr_to_ptr)]
let state = unsafe { std::mem::transmute::<_, &Rc<RefCell<S>>>(state) };
let _ptr = Box::into_raw(states); // because isolate slot 0 still has ptr.
let ptr2 = Box::into_raw(states); // because isolate slot still has ptr.
assert_eq!(ptr, ptr2);
state.clone()
}
@ -355,6 +357,10 @@ impl Isolate {
/// Disposes the isolate. The isolate must not be entered by any
/// thread to be disposable.
unsafe fn dispose(&mut self) {
IsolateHandle::dispose_isolate(self);
// No test case in rusty_v8 show this, but there have been situations in
// deno where dropping Annex before the states causes a segfault.
let ptr = self.get_data_int(InternalSlots::States as _) as *mut States;
if !ptr.is_null() {
let states = Box::from_raw(ptr);
@ -362,7 +368,6 @@ impl Isolate {
drop(states);
}
IsolateHandle::dispose_isolate(self);
v8__Isolate__Dispose(self)
}
}
@ -520,6 +525,9 @@ pub(crate) unsafe fn new_owned_isolate(
/// Same as Isolate but gets disposed when it goes out of scope.
pub struct OwnedIsolate(NonNull<Isolate>);
// TODO(ry) unsafe impl Send for OwnedIsolate {}
// TODO(ry) impl !Sync for OwnedIsolate {}
impl InIsolate for OwnedIsolate {
fn isolate(&mut self) -> &mut Isolate {
self.deref_mut()

View file

@ -532,53 +532,41 @@ fn thread_safe_handle_drop_after_isolate() {
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 0);
}
// TODO(ry) This test should use threads
#[test]
fn terminate_execution() {
let _setup_guard = setup();
let mut params = v8::Isolate::create_params();
params.set_array_buffer_allocator(v8::new_default_allocator());
let mut isolate = v8::Isolate::new(params);
let (tx, rx) = std::sync::mpsc::channel::<bool>();
let handle = isolate.thread_safe_handle();
// Originally run fine.
{
let mut hs = v8::HandleScope::new(&mut isolate);
let scope = hs.enter();
let context = v8::Context::new(scope);
let mut cs = v8::ContextScope::new(scope, context);
let scope = cs.enter();
let result = eval(scope, context, "true").unwrap();
let true_val = v8::Boolean::new(scope, true).into();
assert!(result.same_value(true_val));
}
// Terminate.
handle.terminate_execution();
// Below run should fail with terminated knowledge.
{
let mut hs = v8::HandleScope::new(&mut isolate);
let scope = hs.enter();
let context = v8::Context::new(scope);
let mut cs = v8::ContextScope::new(scope, context);
let scope = cs.enter();
let mut try_catch = v8::TryCatch::new(scope);
let tc = try_catch.enter();
let _ = eval(scope, context, "true");
assert!(tc.has_caught());
assert!(tc.has_terminated());
}
// Cancel termination.
handle.cancel_terminate_execution();
// Works again.
{
let mut hs = v8::HandleScope::new(&mut isolate);
let scope = hs.enter();
let context = v8::Context::new(scope);
let mut cs = v8::ContextScope::new(scope, context);
let scope = cs.enter();
let result = eval(scope, context, "true").unwrap();
let true_val = v8::Boolean::new(scope, true).into();
assert!(result.same_value(true_val));
}
let t = std::thread::spawn(move || {
// allow deno to boot and run
std::thread::sleep(std::time::Duration::from_millis(300));
handle.terminate_execution();
// allow shutdown
std::thread::sleep(std::time::Duration::from_millis(200));
// unless reported otherwise the test should fail after this point
tx.send(false).ok();
});
let mut hs = v8::HandleScope::new(&mut isolate);
let scope = hs.enter();
let context = v8::Context::new(scope);
let mut cs = v8::ContextScope::new(scope, context);
let scope = cs.enter();
// Rn an infinite loop, which should be terminated.
let source = v8_str(scope, "for(;;) {}");
let r = v8::Script::compile(scope, context, source, None);
let mut script = r.unwrap();
let result = script.run(scope, context);
assert!(result.is_none());
// TODO assert_eq!(e.to_string(), "Uncaught Error: execution terminated")
let msg = rx.recv().expect("execution should be terminated");
assert!(!msg);
// Make sure the isolate unusable again.
eval(scope, context, "1+1").expect("execution should be possible again");
t.join().expect("join t");
}
// TODO(ry) This test should use threads