Skip to content

Commit 209a9b9

Browse files
Lorak-mmkmuzarski
authored andcommitted
argconv: Define new traits for a bit safer FFI
The reasons behind the API (and this PR) are following: - reduce the lifetime of reference obtained from the pointer Current pointer-to-ref conversion API (ptr_to_ref_[mut]) returns a reference with a static lifetime. New API is parameterized by a lifetime, which is not 'static. - Ensure that IF the memory associated with the pointer was allocated a certain way, the raw pointer will be converted to the corresponding Rust pointer primitive i.e. Box or Arc (or reference if the pointer was not obtained from an explicit allocation). However, this does not give us any guarantees about the origin of the pointer. Consider following example: // Rust impl ArcFFI for Foo {} fn extern "C" f1() -> *const Foo { // a pointer to stack variable // Also applies to some valid pointer obtained from the reference // to the field of some already heap-allocated object. // Decided to go with a stack variable to keep the example simple. let foo = Foo; &foo } fn extern "C" f2(foo: *const Foo) { let foo = ArcFFI::cloned_from_ptr(foo); } // C Foo *foo = f1(); f2(foo); // Segfault. // Even if f1() returned a valid pointer, that points to some // heap-allocated memory. The pointer was not obtained from an Arc allocation. // I.e., it was not obtained via Arc::into_raw(). To guarantee this, we need to introduce a special type for pointer that would represent the pointer's properties. This will be done in a follow-up PR.
1 parent 7468390 commit 209a9b9

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed

scylla-rust-wrapper/src/argconv.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,77 @@ macro_rules! make_c_str {
9797

9898
#[cfg(test)]
9999
pub(crate) use make_c_str;
100+
101+
/// Defines a pointer manipulation API for non-shared heap-allocated data.
102+
///
103+
/// Implement this trait for types that are allocated by the driver via [`Box::new`],
104+
/// and then returned to the user as a pointer. The user is responsible for freeing
105+
/// the memory associated with the pointer using corresponding driver's API function.
106+
pub trait BoxFFI {
107+
fn into_ptr(self: Box<Self>) -> *mut Self {
108+
Box::into_raw(self)
109+
}
110+
unsafe fn from_ptr(ptr: *mut Self) -> Box<Self> {
111+
Box::from_raw(ptr)
112+
}
113+
unsafe fn as_maybe_ref<'a>(ptr: *const Self) -> Option<&'a Self> {
114+
ptr.as_ref()
115+
}
116+
unsafe fn as_ref<'a>(ptr: *const Self) -> &'a Self {
117+
ptr.as_ref().unwrap()
118+
}
119+
unsafe fn as_mut_ref<'a>(ptr: *mut Self) -> &'a mut Self {
120+
ptr.as_mut().unwrap()
121+
}
122+
unsafe fn free(ptr: *mut Self) {
123+
std::mem::drop(BoxFFI::from_ptr(ptr));
124+
}
125+
}
126+
127+
/// Defines a pointer manipulation API for shared heap-allocated data.
128+
///
129+
/// Implement this trait for types that require a shared ownership of data.
130+
/// The data should be allocated via [`Arc::new`], and then returned to the user as a pointer.
131+
/// The user is responsible for freeing the memory associated
132+
/// with the pointer using corresponding driver's API function.
133+
pub trait ArcFFI {
134+
fn as_ptr(self: &Arc<Self>) -> *const Self {
135+
Arc::as_ptr(self)
136+
}
137+
fn into_ptr(self: Arc<Self>) -> *const Self {
138+
Arc::into_raw(self)
139+
}
140+
unsafe fn from_ptr(ptr: *const Self) -> Arc<Self> {
141+
Arc::from_raw(ptr)
142+
}
143+
unsafe fn cloned_from_ptr(ptr: *const Self) -> Arc<Self> {
144+
Arc::increment_strong_count(ptr);
145+
Arc::from_raw(ptr)
146+
}
147+
unsafe fn as_maybe_ref<'a>(ptr: *const Self) -> Option<&'a Self> {
148+
ptr.as_ref()
149+
}
150+
unsafe fn as_ref<'a>(ptr: *const Self) -> &'a Self {
151+
ptr.as_ref().unwrap()
152+
}
153+
unsafe fn free(ptr: *const Self) {
154+
std::mem::drop(ArcFFI::from_ptr(ptr));
155+
}
156+
}
157+
158+
/// Defines a pointer manipulation API for data owned by some other object.
159+
///
160+
/// Implement this trait for the types that do not need to be freed (directly) by the user.
161+
/// The lifetime of the data is bound to some other object owning it.
162+
///
163+
/// For example: lifetime of CassRow is bound by the lifetime of CassResult.
164+
/// There is no API function that frees the CassRow. It should be automatically
165+
/// freed when user calls cass_result_free.
166+
pub trait RefFFI {
167+
fn as_ptr(&self) -> *const Self {
168+
self as *const Self
169+
}
170+
unsafe fn as_ref<'a>(ptr: *const Self) -> &'a Self {
171+
ptr.as_ref().unwrap()
172+
}
173+
}

0 commit comments

Comments
 (0)