From ab568ccafbfccb65cca176dee04da7bfbb11f584 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Tue, 15 Sep 2020 19:13:31 -0500 Subject: [PATCH] Fix destructor during initialization --- vm/src/import.rs | 66 ++++++++++++++++++++++++++++-------------------- vm/src/vm.rs | 51 +++++++++++++++++++++++-------------- 2 files changed, 71 insertions(+), 46 deletions(-) diff --git a/vm/src/import.rs b/vm/src/import.rs index f5c1faeac..7f2a0542f 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -14,45 +14,57 @@ use crate::vm::{InitParameter, VirtualMachine}; #[cfg(feature = "rustpython-compiler")] use rustpython_compiler::compile; -pub fn init_importlib(vm: &mut VirtualMachine, initialize_parameter: InitParameter) -> PyResult { +pub fn init_importlib( + vm: &mut VirtualMachine, + initialize_parameter: InitParameter, +) -> PyResult<()> { + use crate::vm::thread::enter_vm; flame_guard!("init importlib"); - let importlib = import_frozen(vm, "_frozen_importlib")?; - let impmod = import_builtin(vm, "_imp")?; - let install = vm.get_attribute(importlib.clone(), "_install")?; - vm.invoke(&install, vec![vm.sys_module.clone(), impmod])?; + + let importlib = enter_vm(vm, || { + let importlib = import_frozen(vm, "_frozen_importlib")?; + let impmod = import_builtin(vm, "_imp")?; + let install = vm.get_attribute(importlib.clone(), "_install")?; + vm.invoke(&install, vec![vm.sys_module.clone(), impmod])?; + Ok(importlib) + })?; vm.import_func = vm.get_attribute(importlib.clone(), "__import__")?; match initialize_parameter { InitParameter::InitializeExternal if cfg!(feature = "rustpython-compiler") => { - flame_guard!("install_external"); - let install_external = vm.get_attribute(importlib, "_install_external_importers")?; - vm.invoke(&install_external, vec![])?; - // Set pyc magic number to commit hash. Should be changed when bytecode will be more stable. - let importlib_external = vm.import("_frozen_importlib_external", &[], 0)?; - let mut magic = get_git_revision().into_bytes(); - magic.truncate(4); - if magic.len() != 4 { - magic = rand::thread_rng().gen::<[u8; 4]>().to_vec(); - } - vm.set_attr(&importlib_external, "MAGIC_NUMBER", vm.ctx.new_bytes(magic))?; - let zipimport_res = (|| -> PyResult<()> { - let zipimport = vm.import("zipimport", &[], 0)?; - let zipimporter = vm.get_attribute(zipimport, "zipimporter")?; - let path_hooks = vm.get_attribute(vm.sys_module.clone(), "path_hooks")?; - let path_hooks = objlist::PyListRef::try_from_object(vm, path_hooks)?; - path_hooks.insert(0, zipimporter); + enter_vm(vm, || { + flame_guard!("install_external"); + let install_external = + vm.get_attribute(importlib, "_install_external_importers")?; + vm.invoke(&install_external, vec![])?; + // Set pyc magic number to commit hash. Should be changed when bytecode will be more stable. + let importlib_external = vm.import("_frozen_importlib_external", &[], 0)?; + let mut magic = get_git_revision().into_bytes(); + magic.truncate(4); + if magic.len() != 4 { + magic = rand::thread_rng().gen::<[u8; 4]>().to_vec(); + } + vm.set_attr(&importlib_external, "MAGIC_NUMBER", vm.ctx.new_bytes(magic))?; + let zipimport_res = (|| -> PyResult<()> { + let zipimport = vm.import("zipimport", &[], 0)?; + let zipimporter = vm.get_attribute(zipimport, "zipimporter")?; + let path_hooks = vm.get_attribute(vm.sys_module.clone(), "path_hooks")?; + let path_hooks = objlist::PyListRef::try_from_object(vm, path_hooks)?; + path_hooks.insert(0, zipimporter); + Ok(()) + })(); + if zipimport_res.is_err() { + warn!("couldn't init zipimport") + } Ok(()) - })(); - if zipimport_res.is_err() { - warn!("couldn't init zipimport") - } + })? } InitParameter::NoInitialize => { panic!("Import library initialize should be InitializeInternal or InitializeExternal"); } _ => {} } - Ok(vm.get_none()) + Ok(()) } pub fn import_frozen(vm: &VirtualMachine, module_name: &str) -> PyResult { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 54ae4a1af..ff0c0bf3b 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -69,23 +69,32 @@ pub struct VirtualMachine { } pub(crate) mod thread { - use super::{Interpreter, PyObjectRef, VirtualMachine}; + use super::{PyObjectRef, VirtualMachine}; use itertools::Itertools; use std::cell::RefCell; use std::ptr::NonNull; use std::thread_local; thread_local! { - pub(super) static VM_STACK: RefCell>> = Vec::with_capacity(1).into(); + pub(super) static VM_STACK: RefCell>> = Vec::with_capacity(1).into(); } - pub(crate) fn with_vm(obj: &PyObjectRef, f: F) -> R + pub fn enter_vm(vm: &VirtualMachine, f: impl FnOnce() -> R) -> R { + VM_STACK.with(|vms| { + vms.borrow_mut().push(vm.into()); + let ret = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)); + vms.borrow_mut().pop(); + ret.unwrap_or_else(|e| std::panic::resume_unwind(e)) + }) + } + + pub fn with_vm(obj: &PyObjectRef, f: F) -> R where F: Fn(&VirtualMachine) -> R, { - let vm_owns_obj = |intp: NonNull| { + let vm_owns_obj = |intp: NonNull| { // SAFETY: all references in VM_STACK should be valid - let vm = unsafe { &intp.as_ref().vm }; + let vm = unsafe { intp.as_ref() }; crate::obj::objtype::isinstance(obj, &vm.ctx.types.object_type) }; VM_STACK.with(|vms| { @@ -96,12 +105,12 @@ pub(crate) mod thread { } Err(mut others) => others .find(|x| vm_owns_obj(*x)) - .expect("can't get a vm; none on stack"), + .unwrap_or_else(|| panic!("can't get a vm for {:?}; none on stack", obj)), }; // SAFETY: all references in VM_STACK should be valid, and should not be changed or moved - // at least until this function returns and the stack unwinds to an Interpreter::enter call - let intp = unsafe { intp.as_ref() }; - f(&intp.vm) + // at least until this function returns and the stack unwinds to an enter_vm() call + let vm = unsafe { intp.as_ref() }; + f(vm) }) } } @@ -225,7 +234,6 @@ impl VirtualMachine { let profile_func = RefCell::new(ctx.none()); let trace_func = RefCell::new(ctx.none()); let signal_handlers = RefCell::new(arr![ctx.none(); 64]); - let initialize_parameter = settings.initialization_parameter; let stdlib_inits = stdlib::get_module_inits(); let frozen = frozen::get_module_inits(); @@ -235,7 +243,7 @@ impl VirtualMachine { None => rand::random(), }; - let mut vm = VirtualMachine { + let vm = VirtualMachine { builtins, sys_module: sysmod, ctx: PyRc::new(ctx), @@ -267,7 +275,6 @@ impl VirtualMachine { vm.get_none(), ); objmodule::init_module_dict(&vm, &sysmod_dict, vm.ctx.new_str("sys"), vm.get_none()); - vm.initialize(initialize_parameter); vm } @@ -1576,9 +1583,8 @@ pub struct Interpreter { impl Interpreter { pub fn new(settings: PySettings) -> Self { - Self { - vm: VirtualMachine::new(settings), - } + let init = settings.initialization_parameter; + Self::new_with_init(settings, |_| init) } pub fn new_with_init(settings: PySettings, init: F) -> Self @@ -1595,11 +1601,18 @@ impl Interpreter { where F: FnOnce(&VirtualMachine) -> R, { - thread::VM_STACK.with(|vms| vms.borrow_mut().push(self.into())); - let ret = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&self.vm))); - thread::VM_STACK.with(|vms| vms.borrow_mut().pop()); - ret.unwrap_or_else(|e| std::panic::resume_unwind(e)) + thread::enter_vm(&self.vm, || f(&self.vm)) } + + pub fn run(self, f: F) + where + F: FnOnce(&VirtualMachine), + { + self.enter(f); + self.shutdown(); + } + + pub fn shutdown(self) {} } impl Default for Interpreter {