From ccf68011407a24359bc5bb5e7ef1baebcf2eba00 Mon Sep 17 00:00:00 2001 From: Tzu Gwo Date: Tue, 8 Oct 2024 00:56:06 +0800 Subject: [PATCH] fix(bindings/c): use `ManuallyDrop` instead to make sure pointer is valid (#5166) fix: https://github.com/apache/opendal/issues/5165 --- bindings/c/include/opendal.h | 4 ++++ bindings/c/src/types.rs | 26 +++++++++++++++++++------- bindings/go/types.go | 11 +++++++---- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/bindings/c/include/opendal.h b/bindings/c/include/opendal.h index 2df3447d23db..4fba90916344 100644 --- a/bindings/c/include/opendal.h +++ b/bindings/c/include/opendal.h @@ -99,6 +99,10 @@ typedef struct opendal_bytes { * The length of the byte array */ uintptr_t len; + /** + * The capacity of the byte array + */ + uintptr_t capacity; } opendal_bytes; /** diff --git a/bindings/c/src/types.rs b/bindings/c/src/types.rs index 051724a671e3..795c7a73b5c1 100644 --- a/bindings/c/src/types.rs +++ b/bindings/c/src/types.rs @@ -34,25 +34,37 @@ pub struct opendal_bytes { pub data: *const u8, /// The length of the byte array pub len: usize, + /// The capacity of the byte array + pub capacity: usize, } impl opendal_bytes { /// Construct a [`opendal_bytes`] from the Rust [`Vec`] of bytes pub(crate) fn new(buf: Buffer) -> Self { let vec = buf.to_vec(); - let data = vec.as_ptr(); - let len = vec.len(); - std::mem::forget(vec); - Self { data, len } + let mut buf = std::mem::ManuallyDrop::new(vec); + let data = buf.as_mut_ptr(); + let len = buf.len(); + let capacity = buf.capacity(); + Self { + data, + len, + capacity, + } } /// \brief Frees the heap memory used by the opendal_bytes #[no_mangle] pub unsafe extern "C" fn opendal_bytes_free(ptr: *mut opendal_bytes) { if !ptr.is_null() { - let data_mut = (*ptr).data as *mut u8; - drop(Vec::from_raw_parts(data_mut, (*ptr).len, (*ptr).len)); - drop(Box::from_raw(ptr)); + // transmuting `*const u8` to `*mut u8` is undefined behavior in any cases + // however, fields type of `opendal_bytes` is already related to the zig binding + // it should be fixed later + let _ = Vec::from_raw_parts((*ptr).data as *mut u8, (*ptr).len, (*ptr).capacity); + // it is too weird that call `Box::new` outside `opendal_bytes::new` but dealloc it here + // also, boxing `opendal_bytes` might not be necessary + // `data` points to heap, so `opendal_bytes` could be passed as a stack value + let _ = Box::from_raw(ptr); } } } diff --git a/bindings/go/types.go b/bindings/go/types.go index 59583a94afd5..613825af5104 100644 --- a/bindings/go/types.go +++ b/bindings/go/types.go @@ -47,6 +47,7 @@ var ( typeBytes = ffi.Type{ Type: ffi.Struct, Elements: &[]*ffi.Type{ + &ffi.TypePointer, &ffi.TypePointer, &ffi.TypePointer, nil, @@ -257,8 +258,9 @@ type resultStat struct { type opendalMetadata struct{} type opendalBytes struct { - data *byte - len uintptr + data *byte + len uintptr + capacity uintptr } type opendalError struct { @@ -292,8 +294,9 @@ func toOpendalBytes(data []byte) opendalBytes { ptr = &b } return opendalBytes{ - data: ptr, - len: uintptr(l), + data: ptr, + len: uintptr(l), + capacity: uintptr(l), } }