Skip to content
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

Fixed some memory leak issue with InstanceHandle #3493

Merged
merged 6 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/api/src/sys/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::sys::module::Module;
use crate::sys::{LinkError, RuntimeError};
use std::fmt;
use thiserror::Error;
use wasmer_vm::{InstanceHandle, StoreHandle};
use wasmer_vm::{StoreHandle, VMInstance};

#[cfg(feature = "compiler")]
use super::store::AsStoreMut;
Expand All @@ -20,7 +20,7 @@ use crate::sys::{externals::Extern, imports::Imports};
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#module-instances>
#[derive(Clone)]
pub struct Instance {
_handle: StoreHandle<InstanceHandle>,
_handle: StoreHandle<VMInstance>,
module: Module,
/// The exports for an instance.
pub exports: Exports,
Expand Down
4 changes: 2 additions & 2 deletions lib/api/src/sys/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use wasmer_types::{ExportType, ImportType};
#[cfg(feature = "compiler")]
use crate::{sys::InstantiationError, AsStoreMut, AsStoreRef, IntoBytes};
#[cfg(feature = "compiler")]
use wasmer_vm::InstanceHandle;
use wasmer_vm::VMInstance;

/// IO Error on a Module Compilation
#[derive(Error, Debug)]
Expand Down Expand Up @@ -316,7 +316,7 @@ impl Module {
&self,
store: &mut impl AsStoreMut,
imports: &[crate::Extern],
) -> Result<InstanceHandle, InstantiationError> {
) -> Result<VMInstance, InstantiationError> {
// Ensure all imports come from the same context.
for import in imports {
if !import.is_from_store(store) {
Expand Down
14 changes: 7 additions & 7 deletions lib/compiler/src/engine/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use wasmer_types::{
use wasmer_types::{CompileModuleInfo, Target};
use wasmer_types::{SerializableModule, SerializeError};
use wasmer_vm::{FunctionBodyPtr, MemoryStyle, TableStyle, VMSharedSignatureIndex, VMTrampoline};
use wasmer_vm::{InstanceAllocator, InstanceHandle, StoreObjects, TrapHandlerFn, VMExtern};
use wasmer_vm::{InstanceAllocator, StoreObjects, TrapHandlerFn, VMExtern, VMInstance};

/// A compiled wasm module, ready to be instantiated.
pub struct Artifact {
Expand Down Expand Up @@ -307,13 +307,13 @@ impl Artifact {
///
/// # Safety
///
/// See [`InstanceHandle::new`].
/// See [`VMInstance::new`].
pub unsafe fn instantiate(
&self,
tunables: &dyn Tunables,
imports: &[VMExtern],
context: &mut StoreObjects,
) -> Result<InstanceHandle, InstantiationError> {
) -> Result<VMInstance, InstantiationError> {
// Validate the CPU features this module was compiled with against the
// host CPU features.
let host_cpu_features = CpuFeature::for_host();
Expand Down Expand Up @@ -367,7 +367,7 @@ impl Artifact {

self.register_frame_info();

let handle = InstanceHandle::new(
let handle = VMInstance::new(
allocator,
module,
context,
Expand All @@ -383,15 +383,15 @@ impl Artifact {
Ok(handle)
}

/// Finishes the instantiation of a just created `InstanceHandle`.
/// Finishes the instantiation of a just created `VMInstance`.
///
/// # Safety
///
/// See [`InstanceHandle::finish_instantiation`].
/// See [`VMInstance::finish_instantiation`].
pub unsafe fn finish_instantiation(
&self,
trap_handler: Option<*const TrapHandlerFn<'static>>,
handle: &mut InstanceHandle,
handle: &mut VMInstance,
) -> Result<(), InstantiationError> {
let data_initializers = self
.data_initializers()
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub trait ArtifactCreate: Send + Sync + Upcastable {
/// Returns the table plans associated with this `Artifact`.
fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle>;

/// Returns data initializers to pass to `InstanceHandle::initialize`
/// Returns data initializers to pass to `VMInstance::initialize`
fn data_initializers(&self) -> &[OwnedDataInitializer];

/// Serializes an artifact into bytes
Expand Down
2 changes: 1 addition & 1 deletion lib/types/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl SerializableModule {
EnumSet::from_u64(self.cpu_features)
}

/// Returns data initializers to pass to `InstanceHandle::initialize`
/// Returns data initializers to pass to `VMInstance::initialize`
pub fn data_initializers(&self) -> &[OwnedDataInitializer] {
&self.data_initializers
}
Expand Down
14 changes: 7 additions & 7 deletions lib/vm/src/instance/allocator.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Instance, InstanceHandle};
use super::{Instance, VMInstance};
use crate::vmcontext::VMTableDefinition;
use crate::VMMemoryDefinition;
use std::alloc::{self, Layout};
Expand Down Expand Up @@ -59,15 +59,15 @@ impl Drop for InstanceAllocator {
}

impl InstanceAllocator {
/// Allocates instance data for use with [`InstanceHandle::new`].
/// Allocates instance data for use with [`VMInstance::new`].
///
/// Returns a wrapper type around the allocation and 2 vectors of
/// pointers into the allocated buffer. These lists of pointers
/// correspond to the location in memory for the local memories and
/// tables respectively. These pointers should be written to before
/// calling [`InstanceHandle::new`].
/// calling [`VMInstance::new`].
///
/// [`InstanceHandle::new`]: super::InstanceHandle::new
/// [`VMInstance::new`]: super::VMInstance::new
pub fn new(
module: &ModuleInfo,
) -> (
Expand Down Expand Up @@ -188,15 +188,15 @@ impl InstanceAllocator {

/// Finish preparing by writing the [`Instance`] into memory, and
/// consume this `InstanceAllocator`.
pub(crate) fn write_instance(mut self, instance: Instance) -> InstanceHandle {
pub(crate) fn into_vminstance(mut self, instance: Instance) -> VMInstance {
// Prevent the old state's drop logic from being called as we
// transition into the new state.
self.consumed = true;

unsafe {
// `instance` is moved at `Self.instance_ptr`. This
// pointer has been allocated by `Self::allocate_instance`
// (so by `InstanceHandle::allocate_instance`).
// (so by `VMInstance::allocate_instance`).
ptr::write(self.instance_ptr.as_ptr(), instance);
// Now `instance_ptr` is correctly initialized!
}
Expand All @@ -205,7 +205,7 @@ impl InstanceAllocator {

// This is correct because of the invariants of `Self` and
// because we write `Instance` to the pointer in this function.
InstanceHandle {
VMInstance {
instance,
instance_layout,
}
Expand Down
35 changes: 29 additions & 6 deletions lib/vm/src/instance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

//! An `Instance` contains all the runtime state used by execution of
//! a WebAssembly module (except its callstack and register state). An
//! `InstanceHandle` is a wrapper around `Instance` that manages
//! `VMInstance` is a wrapper around `Instance` that manages
//! how it is allocated and deallocated.

mod allocator;
Expand Down Expand Up @@ -1024,7 +1024,7 @@ impl Instance {
/// This is more or less a public facade of the private `Instance`,
/// providing useful higher-level API.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct InstanceHandle {
pub struct VMInstance {
/// The layout of `Instance` (which can vary).
instance_layout: Layout,

Expand All @@ -1040,8 +1040,24 @@ pub struct InstanceHandle {
instance: NonNull<Instance>,
}

impl InstanceHandle {
/// Create a new `InstanceHandle` pointing at a new [`InstanceRef`].
/// VMInstance are created with an InstanceAllocator
/// and it will "consume" the memory
/// So the Drop here actualy free it (else it would be leaked)
impl Drop for VMInstance {
fn drop(&mut self) {
let instance_ptr = self.instance.as_ptr();

unsafe {
// Need to drop all the actual Instance members
instance_ptr.drop_in_place();
// And then free the memory allocated for the Instance itself
std::alloc::dealloc(instance_ptr as *mut u8, self.instance_layout);
}
}
}

impl VMInstance {
/// Create a new `VMInstance` pointing at a new [`InstanceRef`].
///
/// # Safety
///
Expand All @@ -1051,7 +1067,7 @@ impl InstanceHandle {
/// method is a low-overhead way of saying “this is an extremely unsafe type
/// to work with”.
///
/// Extreme care must be taken when working with `InstanceHandle` and it's
/// Extreme care must be taken when working with `VMInstance` and it's
/// recommended to have relatively intimate knowledge of how it works
/// internally if you'd like to do so. If possible it's recommended to use
/// the `wasmer` crate API rather than this type since that is vetted for
Expand Down Expand Up @@ -1114,7 +1130,7 @@ impl InstanceHandle {
})),
};

let mut instance_handle = allocator.write_instance(instance);
let mut instance_handle = allocator.into_vminstance(instance);

// Set the funcrefs after we've built the instance
{
Expand Down Expand Up @@ -1586,3 +1602,10 @@ fn build_funcrefs(
imported_func_refs.into_boxed_slice(),
)
}

/// This type is deprecated, it has been replaced by VMinstance.
#[deprecated(
since = "3.2.0",
note = "InstanceHandle has been replaced by VMInstance"
)]
pub type InstanceHandle = VMInstance;
6 changes: 3 additions & 3 deletions lib/vm/src/instance/ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ unsafe impl Sync for InstanceInner {}
/// simplified version of `std::sync::Arc`.
///
/// Note for the curious reader: [`InstanceAllocator::new`]
/// and [`InstanceHandle::new`] will respectively allocate a proper
/// and [`VMInstance::new`] will respectively allocate a proper
/// `Instance` and will fill it correctly.
///
/// A little bit of background: The initial goal was to be able to
/// share an [`Instance`] between an [`InstanceHandle`] and the module
/// exports, so that one can drop a [`InstanceHandle`] but still being
/// share an [`Instance`] between an [`VMInstance`] and the module
/// exports, so that one can drop a [`VMInstance`] but still being
/// able to use the exports properly.
#[derive(Debug, PartialEq, Clone)]
pub struct InstanceRef(Arc<InstanceInner>);
Expand Down
3 changes: 2 additions & 1 deletion lib/vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ pub use crate::extern_ref::{VMExternObj, VMExternRef};
pub use crate::function_env::VMFunctionEnvironment;
pub use crate::global::*;
pub use crate::imports::Imports;
pub use crate::instance::{InstanceAllocator, InstanceHandle};
#[allow(deprecated)]
pub use crate::instance::{InstanceAllocator, InstanceHandle, VMInstance};
pub use crate::memory::{
initialize_memory_with_data, LinearMemory, VMMemory, VMOwnedMemory, VMSharedMemory,
};
Expand Down
2 changes: 1 addition & 1 deletion lib/vm/src/libcalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
//! function frame, we need to raise it. This involves some nasty and quite
//! unsafe code under the covers! Notable, after raising the trap, drops
//! **will not** be run for local variables! This can lead to things like
//! leaking `InstanceHandle`s which leads to never deallocating JIT code,
//! leaking `VMInstance`s which leads to never deallocating JIT code,
//! instances, and modules! Therefore, always use nested blocks to ensure
//! drops run before raising a trap:
//!
Expand Down
6 changes: 3 additions & 3 deletions lib/vm/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{
};

use crate::{
InstanceHandle, VMExternObj, VMFunction, VMFunctionEnvironment, VMGlobal, VMMemory, VMTable,
VMExternObj, VMFunction, VMFunctionEnvironment, VMGlobal, VMInstance, VMMemory, VMTable,
};

/// Unique ID to identify a context.
Expand Down Expand Up @@ -54,7 +54,7 @@ impl_context_object! {
functions => VMFunction,
tables => VMTable,
globals => VMGlobal,
instances => InstanceHandle,
instances => VMInstance,
memories => VMMemory,
extern_objs => VMExternObj,
function_environments => VMFunctionEnvironment,
Expand All @@ -68,7 +68,7 @@ pub struct StoreObjects {
tables: Vec<VMTable>,
globals: Vec<VMGlobal>,
functions: Vec<VMFunction>,
instances: Vec<InstanceHandle>,
instances: Vec<VMInstance>,
extern_objs: Vec<VMExternObj>,
function_environments: Vec<VMFunctionEnvironment>,
}
Expand Down