1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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::*;

    /// 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>())
    }
}