From f24a34b6cf62d5ede45445065b432b4dff8d33df Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 8 Oct 2020 13:38:01 +0200 Subject: [PATCH] feat(c-api) Implement `Drop` for `wasm_exporttype_t`. `wasm_exporttype_t` has 2 fields: `name` and `extern_type`. Both are of kind `NonNull`. When `wasm_exporttype_t` is dropped, nor `name` nor `extern_type` are going to be dropped. To avoid leaking data, this patch adds a new field: `owns_fields`: * When `wasm_exporttype_t` is built from `wasm_exportype_new`, this field is set to `false` because `name` and `extern_type` are received by pointer, and its the responsibility of the caller to free them, * When `wasm_exporttype_t` is built from the `From<&ExportType>` implementation, _we_ create `name` and `extern_type` to then leak them. In this case, it is safe to reconstruct proper `Box`es to finally drop them. --- lib/c-api/src/wasm_c_api/types/export.rs | 27 ++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/types/export.rs b/lib/c-api/src/wasm_c_api/types/export.rs index 919e0927164..cd05ff6c63c 100644 --- a/lib/c-api/src/wasm_c_api/types/export.rs +++ b/lib/c-api/src/wasm_c_api/types/export.rs @@ -6,6 +6,7 @@ use wasmer::ExportType; pub struct wasm_exporttype_t { name: NonNull, extern_type: NonNull, + owns_fields: bool, } wasm_declare_boxed_vec!(exporttype); @@ -15,7 +16,11 @@ pub extern "C" fn wasm_exporttype_new( name: NonNull, extern_type: NonNull, ) -> Box { - Box::new(wasm_exporttype_t { name, extern_type }) + Box::new(wasm_exporttype_t { + name, + extern_type, + owns_fields: false, + }) } #[no_mangle] @@ -33,6 +38,20 @@ pub extern "C" fn wasm_exporttype_type( #[no_mangle] pub extern "C" fn wasm_exporttype_delete(_exporttype: Option>) {} +impl Drop for wasm_exporttype_t { + fn drop(&mut self) { + if self.owns_fields { + // SAFETY: `owns_fields` is set to `true` only in + // `wasm_exporttype_t.from(&ExportType)`, where the data + // are leaked properly and won't be freed somewhere else. + unsafe { + let _ = Box::from_raw(self.name.as_ptr()); + let _ = Box::from_raw(self.extern_type.as_ptr()); + } + } + } +} + impl From for wasm_exporttype_t { fn from(other: ExportType) -> Self { (&other).into() @@ -59,6 +78,10 @@ impl From<&ExportType> for wasm_exporttype_t { unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(extern_type))) } }; - wasm_exporttype_t { name, extern_type } + wasm_exporttype_t { + name, + extern_type, + owns_fields: true, + } } }