Repository: wasmerio/wasmer (language: rust)

Issue:
wasmer-c-api: wasm_val_delete causes double free error
<!-- Thanks for the bug report! -->

### Describe the bug

<!--
A clear and concise description of what the bug is.

Copy and paste the result of executing the following in your shell, so we can know the version of wasmer, Rust (if available) and architecture of your environment.
-->

Calling `wasm_val_delete` on a dynamically allocated `wasm_val_t *` causes a double free error.

Environment info:

````
wasmer 4.4.0 (b2fa4b1 2024-10-05)
binary: wasmer-cli
commit-hash: b2fa4b19ff24f2facbe878b256c76d8e4bd6b25a
commit-date: 2024-10-05
host: x86_64-unknown-linux-gnu
compiler: singlepass,cranelift,llvm

rustc 1.54.0 (a178d0322 2021-07-26)
binary: rustc
commit-hash: a178d0322ce20e33eac124758e837cbd80a6f633
commit-date: 2021-07-26
host: x86_64-unknown-linux-gnu
release: 1.54.0
LLVM version: 12.0.1

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.4.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-11-XeT9lY/gcc-11-11.4.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-11-XeT9lY/gcc-11-11.4.0/debian/tmp-gcn/usr --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04) 
````


### Steps to reproduce
<!--
Include steps that will help us recreate the issue.
-->

`test.c` file :

````c
#include <stdio.h>
#include <stdlib.h>
#include "wasmer.h"

int main(int argc, const char* argv[]) {
  wasm_val_t *val;

  val = (wasm_val_t *)malloc(sizeof(wasm_val_t));

  val->kind = WASM_I32;
  val->of.i32 = 7;

  printf("val: %d\n", val->of.i32);

  wasm_val_delete(val);
  free(val);
  
  return 0;
}
````

Compiled with flags 

````
CFLAGS = -g -I$(shell $(WASMER_DIR)/bin/wasmer config --includedir)
LDFLAGS = -Wl,-rpath,$(shell $(WASMER_DIR)/bin/wasmer config --libdir)
LDLIBS = $(shell $(WASMER_DIR)/bin/wasmer config --libs)
````

### Expected behavior
<!-- A clear and concise description of what you expected to happen. -->

Calling `wasm_val_delete` then `free` on a dynamically allocated `wasm_val_t *` pointer should not result in a double free. 

`wasm_val_delete` should only de-allocate memory referenced within its argument (e.g. if `.of.ref` is set) and not the memory pointed to by its argument (i.e. the argument itself). Doing so makes allocating `wasm_val_t` on the stack unsafe.

### Actual behavior

<!--
A clear and concise description of what actually happened.

If applicable, add screenshots to help explain your problem.
-->

Running the above code results in 

This results in error

````
$ ./test
double free or corruption (out)
Aborted (core dumped)
````

### Additional context
<!-- Add any other context about the problem here. -->



Discussion / hints:
Thanks! I'll investigate this as soon as possible. 

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 721eaf6a9f3..2e716e90a9a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -597,20 +597,20 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cbindgen"
-version = "0.24.5"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b922faaf31122819ec80c4047cc684c6979a087366c069611e33649bf98e18d"
+checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb"
 dependencies = [
  "heck 0.4.1",
- "indexmap 1.9.3",
+ "indexmap 2.6.0",
  "log 0.4.22",
  "proc-macro2",
  "quote",
  "serde",
  "serde_json",
- "syn 1.0.109",
+ "syn 2.0.79",
  "tempfile",
- "toml 0.5.11",
+ "toml 0.8.19",
 ]
 
 [[package]]
diff --git a/lib/api/third_party/.gitignore b/lib/api/third_party/.gitignore
new file mode 100644
index 00000000000..b2e7e790c55
--- /dev/null
+++ b/lib/api/third_party/.gitignore
@@ -0,0 +1,1 @@
+wamr
diff --git a/lib/c-api/Cargo.toml b/lib/c-api/Cargo.toml
index dad2b23e7b0..ade9ac88870 100644
--- a/lib/c-api/Cargo.toml
+++ b/lib/c-api/Cargo.toml
@@ -111,4 +111,4 @@ jit = ["compiler"]
 #emscripten = ["wasmer-emscripten"]
 
 [build-dependencies]
-cbindgen = { version = "0.24", default-features = false }
+cbindgen = { version = "0.27", default-features = false }
diff --git a/lib/c-api/src/wasm_c_api/value.rs b/lib/c-api/src/wasm_c_api/value.rs
index 3be2f2a340b..5a5a6e67561 100644
--- a/lib/c-api/src/wasm_c_api/value.rs
+++ b/lib/c-api/src/wasm_c_api/value.rs
@@ -156,11 +156,24 @@ pub unsafe extern "C" fn wasm_val_copy(
     }); otherwise ());
 }
 
+impl Drop for wasm_val_t {
+    fn drop(&mut self) {
+        let kind: Result<wasm_valkind_enum, _> = self.kind.try_into();
+        match kind {
+            Ok(wasm_valkind_enum::WASM_EXTERNREF) | Ok(wasm_valkind_enum::WASM_FUNCREF) => unsafe {
+                if !self.of.wref.is_null() {
+                    drop(Box::from_raw(self.of.wref));
+                }
+            },
+            _ => {}
+        }
+    }
+}
+
 #[no_mangle]
-pub unsafe extern "C" fn wasm_val_delete(val: Option<Box<wasm_val_t>>) {
-    if let Some(val) = val {
-        // TODO: figure out where wasm_val is allocated first...
-        let _ = val;
+pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
+    if !val.is_null() {
+        std::ptr::drop_in_place(val);
     }
 }
 


Test patch: