From 551f29499a3ca9c5b15692ac7877730808dda8cb Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Tue, 24 Nov 2020 10:45:29 +0100 Subject: openpgp: Make serialize::stream::Message Send + Sync. - See #615. --- openpgp-ffi/include/sequoia/io.h | 13 +++++++++++ openpgp-ffi/src/io.rs | 49 +++++++++++++++++++++++++++++----------- openpgp-ffi/src/serialize.rs | 4 ++-- 3 files changed, 51 insertions(+), 15 deletions(-) (limited to 'openpgp-ffi') diff --git a/openpgp-ffi/include/sequoia/io.h b/openpgp-ffi/include/sequoia/io.h index 81d0093a..e574aefb 100644 --- a/openpgp-ffi/include/sequoia/io.h +++ b/openpgp-ffi/include/sequoia/io.h @@ -92,6 +92,13 @@ pgp_writer_t pgp_writer_from_bytes (uint8_t *buf, size_t len); /// reference a chunk of memory allocated using libc's heap allocator. /// The caller is responsible to `free` it once the writer has been /// destroyed. +/// +/// # Sending objects across thread boundaries +/// +/// If you send a Sequoia object (like a pgp_writer_stack_t) that +/// serializes to an allocating writer across thread boundaries, you +/// must make sure that the system's allocator (i.e. `realloc (3)`) +/// supports reallocating memory allocated by another thread. /*/ pgp_writer_t pgp_writer_alloc (void **buf, size_t *len); @@ -104,6 +111,12 @@ typedef ssize_t (*pgp_writer_cb_t) (void *cookie, const void *buf, size_t len); /// Creates an writer from a callback and cookie. /// /// This writer calls the given callback to write data. +/// +/// # Sending objects across thread boundaries +/// +/// If you send a Sequoia object (like a pgp_writer_stack_t) that +/// serializes to a callback-based writer across thread boundaries, +/// you must make sure that the callback and cookie also support this. /*/ pgp_writer_t pgp_writer_from_callback (pgp_writer_cb_t, void *); diff --git a/openpgp-ffi/src/io.rs b/openpgp-ffi/src/io.rs index 35e80c47..484615cf 100644 --- a/openpgp-ffi/src/io.rs +++ b/openpgp-ffi/src/io.rs @@ -4,6 +4,7 @@ use std::fs::File; use std::io::{self, Read, Write, Cursor}; use std::path::Path; use std::slice; +use std::sync::Mutex; use libc::{c_void, c_char, size_t, ssize_t, realloc}; #[cfg(unix)] @@ -181,7 +182,7 @@ pub struct Writer(WriterKind); /// In some cases, we want to call functions on concrete types. To /// avoid nasty hacks, we have specialized variants for that. pub(crate) enum WriterKind { - Generic(Box), + Generic(Box), Armored(openpgp::armor::Writer<&'static mut WriterKind>), } @@ -247,6 +248,13 @@ fn pgp_writer_from_bytes(buf: *mut u8, len: size_t) -> *mut Writer { /// The caller is responsible to `free` it once the writer has been /// destroyed. /// +/// # Sending objects across thread boundaries +/// +/// If you send a Sequoia object (like a pgp_writer_stack_t) that +/// serializes to an allocating writer across thread boundaries, you +/// must make sure that the system's allocator (i.e. `realloc (3)`) +/// supports reallocating memory allocated by another thread. +/// /// # Examples /// /// ```c @@ -302,32 +310,36 @@ fn pgp_writer_alloc(buf: *mut *mut c_void, len: *mut size_t) let buf = ffi_param_ref_mut!(buf); let len = ffi_param_ref_mut!(len); - let w = WriterKind::Generic(Box::new(WriterAlloc { + let w = WriterKind::Generic(Box::new(WriterAlloc(Mutex::new(Buffer { buf: buf, len: len, - })); + })))); w.move_into_raw() } -struct WriterAlloc { +struct WriterAlloc(Mutex); +struct Buffer { buf: &'static mut *mut c_void, len: &'static mut size_t, } +unsafe impl Send for Buffer {} + impl Write for WriterAlloc { fn write(&mut self, buf: &[u8]) -> io::Result { - let old_len = *self.len; + let buffer = self.0.get_mut().expect("Mutex not to be poisoned"); + let old_len = *buffer.len; let new_len = old_len + buf.len(); let new = unsafe { - realloc(*self.buf, new_len) + realloc(*buffer.buf, new_len) }; if new.is_null() { return Err(io::Error::new(io::ErrorKind::Other, "out of memory")); } - *self.buf = new; - *self.len = new_len; + *buffer.buf = new; + *buffer.len = new_len; let sl = unsafe { slice::from_raw_parts_mut(new as *mut u8, new_len) @@ -348,26 +360,37 @@ type WriterCallbackFn = extern fn(*mut c_void, *const c_void, size_t) -> ssize_t /// Creates an writer from a callback and cookie. /// /// This writer calls the given callback to write data. +/// +/// # Sending objects across thread boundaries +/// +/// If you send a Sequoia object (like a pgp_writer_stack_t) that +/// serializes to a callback-based writer across thread boundaries, +/// you must make sure that the callback and cookie also support this. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_writer_from_callback(cb: WriterCallbackFn, cookie: *mut c_void) -> *mut Writer { - let w = WriterKind::Generic(Box::new(WriterCallback { - cb, cookie, - })); + let w = WriterKind::Generic(Box::new(WriterCallback(Mutex::new( + WriterClosure { cb, cookie, })))); w.move_into_raw() } /// A generic callback-based writer implementation. -struct WriterCallback { +struct WriterCallback(Mutex); + +struct WriterClosure { cb: WriterCallbackFn, cookie: *mut c_void, } +unsafe impl Send for WriterClosure {} + impl Write for WriterCallback { fn write(&mut self, buf: &[u8]) -> io::Result { + let closure = self.0.get_mut().expect("Mutex not to be poisoned"); let r = - (self.cb)(self.cookie, buf.as_ptr() as *const c_void, buf.len()); + (closure.cb)(closure.cookie, + buf.as_ptr() as *const c_void, buf.len()); if r < 0 { use std::io as stdio; Err(stdio::Error::new(stdio::ErrorKind::Other, diff --git a/openpgp-ffi/src/serialize.rs b/openpgp-ffi/src/serialize.rs index aecf1a0a..053fedbb 100644 --- a/openpgp-ffi/src/serialize.rs +++ b/openpgp-ffi/src/serialize.rs @@ -152,7 +152,7 @@ pub extern "C" fn pgp_arbitrary_writer_new pub extern "C" fn pgp_signer_new (errp: Option<&mut *mut crate::error::Error>, inner: *mut Message<'static>, - signers: *const *mut Box, + signers: *const *mut Box, signers_len: size_t, hash_algo: u8) -> *mut Message<'static> @@ -189,7 +189,7 @@ pub extern "C" fn pgp_signer_new pub extern "C" fn pgp_signer_new_detached (errp: Option<&mut *mut crate::error::Error>, inner: *mut Message<'static>, - signers: *const *mut Box, + signers: *const *mut Box, signers_len: size_t, hash_algo: u8) -> *mut Message<'static> -- cgit v1.2.3