mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
f8ef7c65d1
This gives an indication in the log that Tor was built with Rust support, as well as laying some groundwork for further string-returning APIs to be converted to Rust
102 lines
2.9 KiB
Rust
102 lines
2.9 KiB
Rust
use std::ffi::CString;
|
|
use std::mem::forget;
|
|
use libc;
|
|
|
|
/// Compatibility wrapper for strings allocated in Rust and passed to C.
|
|
///
|
|
/// Rust doesn't ensure the safety of freeing memory across an FFI boundary, so
|
|
/// we need to take special care to ensure we're not accidentally calling
|
|
/// `tor_free`() on any string allocated in Rust. To more easily differentiate
|
|
/// between strings that possibly (if Rust support is enabled) were allocated
|
|
/// in Rust, C has the `rust_str_t` helper type. The equivalent on the Rust
|
|
/// side is `RustString`.
|
|
///
|
|
/// Note: This type must not be used for strings allocated in C.
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
pub struct RustString(*mut libc::c_char);
|
|
|
|
impl RustString {
|
|
/// Returns a pointer to the underlying NUL-terminated byte array.
|
|
///
|
|
/// Note that this function is not typically useful for Rust callers,
|
|
/// except in a direct FFI context.
|
|
///
|
|
/// # Examples
|
|
/// ```
|
|
/// # use tor_util::RustString;
|
|
/// use std::ffi::CString;
|
|
///
|
|
/// let r = RustString::from(CString::new("asdf").unwrap());
|
|
/// let c_str = r.as_ptr();
|
|
/// assert_eq!(b'a', unsafe { *c_str as u8});
|
|
/// ```
|
|
pub fn as_ptr(&self) -> *const libc::c_char {
|
|
self.0 as *const libc::c_char
|
|
}
|
|
}
|
|
|
|
impl From<CString> for RustString {
|
|
/// Constructs a new `RustString`
|
|
///
|
|
/// # Examples
|
|
/// ```
|
|
/// # use tor_util::RustString;
|
|
/// use std::ffi::CString;
|
|
///
|
|
/// let r = RustString::from(CString::new("asdf").unwrap());
|
|
/// ```
|
|
fn from(str: CString) -> RustString {
|
|
RustString(str.into_raw())
|
|
}
|
|
}
|
|
|
|
impl Into<CString> for RustString {
|
|
/// Reconstructs a `CString` from this `RustString`.
|
|
///
|
|
/// Useful to take ownership back from a `RustString` that was given to C
|
|
/// code.
|
|
///
|
|
/// # Examples
|
|
/// ```
|
|
/// # use tor_util::RustString;
|
|
/// use std::ffi::CString;
|
|
///
|
|
/// let cs = CString::new("asdf").unwrap();
|
|
/// let r = RustString::from(cs.clone());
|
|
/// let cs2 = r.into();
|
|
/// assert_eq!(cs, cs2);
|
|
/// ```
|
|
fn into(self) -> CString {
|
|
// Calling from_raw is always OK here: We only construct self using
|
|
// valid CStrings and don't expose anything that could mutate it
|
|
let ret = unsafe { CString::from_raw(self.0) };
|
|
forget(self);
|
|
ret
|
|
}
|
|
}
|
|
|
|
impl Drop for RustString {
|
|
fn drop(&mut self) {
|
|
// Don't use into() here, because we would need to move out of
|
|
// self. Same safety consideration. Immediately drop the created
|
|
// CString, which takes care of freeing the wrapped string.
|
|
unsafe { CString::from_raw(self.0) };
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use std::mem;
|
|
use super::*;
|
|
|
|
use libc;
|
|
|
|
/// Ensures we're not adding overhead by using RustString.
|
|
#[test]
|
|
fn size_of() {
|
|
assert_eq!(mem::size_of::<*mut libc::c_char>(),
|
|
mem::size_of::<RustString>())
|
|
}
|
|
}
|