From eac571b9d7dd8006d605124ff179fa786ce6fb65 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 7 Nov 2017 00:43:07 +0100 Subject: [PATCH] fix(vm): child_threads must be traversed for all threads Fixes a memory unsafety issue where a child thread could be freed if it only existed as a `RootedThread` --- vm/src/gc.rs | 4 ++++ vm/src/thread.rs | 2 +- vm/src/vm.rs | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/vm/src/gc.rs b/vm/src/gc.rs index d72d5f12c0..7dd5adb9e6 100644 --- a/vm/src/gc.rs +++ b/vm/src/gc.rs @@ -98,6 +98,10 @@ impl<'s> WriteOnly<'s, str> { pub struct Generation(i32); impl Generation { + pub fn is_root(self) -> bool { + self.0 == 0 + } + /// Returns a generation which compared to any normal generation is always younger. pub fn disjoint() -> Generation { Generation(-1) diff --git a/vm/src/thread.rs b/vm/src/thread.rs index 7c634d153c..4322c72a19 100644 --- a/vm/src/thread.rs +++ b/vm/src/thread.rs @@ -254,7 +254,6 @@ impl Traverseable for Thread { fn traverse(&self, gc: &mut Gc) { self.traverse_fields_except_stack(gc); self.context.lock().unwrap().stack.get_values().traverse(gc); - self.child_threads.read().unwrap().traverse(gc); } } @@ -553,6 +552,7 @@ impl Thread { self.global_state.traverse(gc); self.roots.read().unwrap().traverse(gc); self.rooted_values.read().unwrap().traverse(gc); + self.child_threads.read().unwrap().traverse(gc); } fn parent_threads(&self) -> RwLockWriteGuard>> { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index f0875d66ed..92709d669c 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -445,6 +445,7 @@ impl GlobalVmState { metadata: Metadata, value: Value, ) -> Result<()> { + assert!(value.generation().is_root()); let mut env = self.env.write().unwrap(); let globals = &mut env.globals; let global = Global {