From 5438be891b80567de2fb142d4a6dec15ac9582a1 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Thu, 8 Aug 2019 23:55:42 +0200 Subject: [PATCH] Remove dc_context_unref from Rust API This removes the dc_context_unref function from the Rust API which was just an alias for dc_close. It still exists on the C API where it makes sure to free the memory. It also implements Drop for the context which just calls dc_close to make sure all the memory is freed. Since you can call dc_close as many times as you like this ensures that at the Rust level you can't Drop the struct without releasing the memory. Finally since memory is now freed by dropping the struct this removes the #[repr(C)] for the struct. This struct is fully opaque to the C API. --- deltachat-ffi/src/lib.rs | 5 ++++- examples/repl/main.rs | 6 ------ src/context.rs | 46 +++++++++++++++++++++++++--------------- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index ae4a0b337..6dfb27002 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -44,11 +44,14 @@ pub unsafe extern "C" fn dc_context_new( Box::into_raw(Box::new(ctx)) } +/// Release the context structure. +/// +/// This function releases the memory of the `dc_context_t` structure. #[no_mangle] pub unsafe extern "C" fn dc_context_unref(context: *mut dc_context_t) { assert!(!context.is_null()); let context = &mut *context; - context::dc_context_unref(context); + context::dc_close(context); Box::from_raw(context); } diff --git a/examples/repl/main.rs b/examples/repl/main.rs index c3a47ccec..c89ce9104 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -456,12 +456,6 @@ fn main_0(args: Vec) -> Result<(), failure::Error> { println!("history saved"); { stop_threads(&ctx.read().unwrap()); - - unsafe { - let mut ctx = ctx.write().unwrap(); - dc_close(&mut ctx); - dc_context_unref(&mut ctx); - } } Ok(()) diff --git a/src/context.rs b/src/context.rs index 3f2944e5a..619d26355 100644 --- a/src/context.rs +++ b/src/context.rs @@ -20,7 +20,6 @@ use crate::sql::Sql; use crate::types::*; use crate::x::*; -#[repr(C)] pub struct Context { pub userdata: *mut libc::c_void, pub dbfile: Arc>, @@ -77,6 +76,14 @@ impl Context { } } +impl Drop for Context { + fn drop(&mut self) { + unsafe { + dc_close(&self); + } + } +} + impl Default for RunningState { fn default() -> Self { RunningState { @@ -165,16 +172,6 @@ pub fn dc_context_new( } } -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn no_crashes_on_context_deref() { - let mut ctx = dc_context_new(None, std::ptr::null_mut(), Some("Test OS".into())); - unsafe { dc_context_unref(&mut ctx) }; - } -} - unsafe fn cb_receive_imf( context: &Context, imf_raw_not_terminated: *const libc::c_char, @@ -258,12 +255,6 @@ fn cb_get_config(context: &Context, key: &str) -> Option { context.sql.get_config(context, key) } -pub unsafe fn dc_context_unref(context: &mut Context) { - if 0 != dc_is_open(context) { - dc_close(context); - } -} - pub unsafe fn dc_close(context: &Context) { info!(context, 0, "disconnecting INBOX-watch",); context.inbox.read().unwrap().disconnect(context); @@ -591,3 +582,24 @@ pub fn dc_is_mvbox(context: &Context, folder_name: impl AsRef) -> bool { false } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn no_crashes_on_context_deref() { + let ctx = dc_context_new(None, std::ptr::null_mut(), Some("Test OS".into())); + std::mem::drop(ctx); + } + + #[test] + fn test_context_double_close() { + let ctx = dc_context_new(None, std::ptr::null_mut(), None); + unsafe { + dc_close(&ctx); + dc_close(&ctx); + } + std::mem::drop(ctx); + } +}