rtoolbox/
safe_string.rs

1use std::convert::Into;
2use std::ops::{Deref, DerefMut, Drop};
3use std::{ptr, sync::atomic};
4
5/// String that is zeroed when dropped
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct SafeString {
8    inner: String,
9}
10
11impl SafeString {
12    pub fn new() -> SafeString {
13        SafeString {
14            inner: String::new(),
15        }
16    }
17
18    pub fn from_string(inner: String) -> SafeString {
19        SafeString { inner }
20    }
21
22    pub fn into_inner(mut self) -> String {
23        std::mem::replace(&mut self.inner, String::new())
24    }
25}
26
27impl Drop for SafeString {
28    fn drop(&mut self) {
29        let default = u8::default();
30
31        for c in unsafe { self.inner.as_bytes_mut() } {
32            unsafe { ptr::write_volatile(c, default) };
33        }
34
35        atomic::fence(atomic::Ordering::SeqCst);
36        atomic::compiler_fence(atomic::Ordering::SeqCst);
37    }
38}
39
40impl Deref for SafeString {
41    type Target = String;
42
43    fn deref(&self) -> &String {
44        &self.inner
45    }
46}
47
48impl DerefMut for SafeString {
49    fn deref_mut(&mut self) -> &mut Self::Target {
50        &mut self.inner
51    }
52}
53
54impl Into<SafeString> for String {
55    fn into(self) -> SafeString {
56        SafeString::from_string(self)
57    }
58}
59
60impl<'a> Into<SafeString> for &'a str {
61    fn into(self) -> SafeString {
62        self.to_string().into()
63    }
64}