t_rust_less_lib/memguard/
memory.rs1use std::ptr;
2
3#[inline(never)]
11pub unsafe fn memeq(b1: *const u8, b2: *const u8, len: usize) -> bool {
12 (0..len as isize)
13 .map(|i| ptr::read_volatile(b1.offset(i)) ^ ptr::read_volatile(b2.offset(i)))
14 .fold(0, |sum, next| sum | next)
15 .eq(&0)
16}
17
18#[inline(never)]
24#[allow(dead_code)]
25pub unsafe fn memcmp(b1: *const u8, b2: *const u8, len: usize) -> i32 {
26 let mut res = 0;
27 for i in (0..len as isize).rev() {
28 let diff = i32::from(ptr::read_volatile(b1.offset(i))) - i32::from(ptr::read_volatile(b2.offset(i)));
29 res = (res & (((diff - 1) & !diff) >> 8)) | diff;
30 }
31 ((res - 1) >> 8) + (res >> 8) + 1
32}
33
34#[cfg(feature = "nightly-features")]
42#[cfg(any(not(target_os = "macos"), not(feature = "use_os")))]
43#[inline(never)]
44pub unsafe fn memset(s: *mut u8, c: u8, n: usize) {
45 core::intrinsics::volatile_set_memory(s, c, n);
46}
47
48#[cfg(not(feature = "nightly-features"))]
54#[cfg(any(not(target_os = "macos"), not(feature = "use_os")))]
55#[inline(never)]
56pub unsafe fn memset(s: *mut u8, c: u8, n: usize) {
57 for i in 0..n {
58 ptr::write_volatile(s.add(i), c);
59 }
60}
61
62#[cfg(all(target_os = "macos", feature = "use_os"))]
64pub unsafe fn memset(s: *mut u8, c: u8, n: usize) {
65 use libc::{c_int, c_void};
66 use mach_o_sys::ranlib::{errno_t, rsize_t};
67
68 extern "C" {
69 fn memset_s(s: *mut c_void, smax: rsize_t, c: c_int, n: rsize_t) -> errno_t;
70 }
71
72 if n > 0 && memset_s(s as *mut c_void, n as _, c as _, n as _) != 0 {
73 std::process::abort()
74 }
75}
76
77#[cfg(any(
83 not(any(all(windows, not(target_env = "msvc")), target_os = "freebsd", target_os = "netbsd")),
84 not(feature = "use_os")
85))]
86#[inline]
87pub unsafe fn memzero(dest: *mut u8, n: usize) {
88 memset(dest, 0, n);
89}
90
91#[cfg(all(any(target_os = "freebsd", target_os = "netbsd"), feature = "use_os"))]
97pub unsafe fn memzero(dest: *mut u8, n: usize) {
98 extern "C" {
99 fn explicit_bzero(s: *mut libc::c_void, n: libc::size_t);
100 }
101 explicit_bzero(dest as *mut libc::c_void, n);
102}
103
104#[cfg(all(windows, not(target_env = "msvc"), feature = "use_os"))]
110pub unsafe fn memzero(s: *mut u8, n: usize) {
111 extern "system" {
112 fn RtlSecureZeroMemory(ptr: winapi::shared::ntdef::PVOID, cnt: winapi::shared::basetsd::SIZE_T);
113 }
114 RtlSecureZeroMemory(s as winapi::shared::ntdef::PVOID, n as winapi::shared::basetsd::SIZE_T);
115}
116
117#[cfg(unix)]
123pub unsafe fn mlock(addr: *mut u8, len: usize) -> bool {
124 #[cfg(target_os = "linux")]
125 libc::madvise(addr as *mut ::libc::c_void, len, ::libc::MADV_DONTDUMP);
126
127 #[cfg(target_os = "freebsd")]
128 libc::madvise(addr as *mut ::libc::c_void, len, ::libc::MADV_NOCORE);
129
130 libc::mlock(addr as *mut ::libc::c_void, len) == 0
131}
132
133#[cfg(windows)]
139pub unsafe fn mlock(addr: *mut u8, len: usize) -> bool {
140 winapi::um::memoryapi::VirtualLock(
141 addr as ::winapi::shared::minwindef::LPVOID,
142 len as ::winapi::shared::basetsd::SIZE_T,
143 ) != 0
144}
145
146#[cfg(unix)]
152pub unsafe fn munlock(addr: *mut u8, len: usize) -> bool {
153 memzero(addr, len);
154
155 #[cfg(target_os = "linux")]
156 libc::madvise(addr as *mut ::libc::c_void, len, ::libc::MADV_DODUMP);
157
158 #[cfg(target_os = "freebsd")]
159 libc::madvise(addr as *mut ::libc::c_void, len, ::libc::MADV_CORE);
160
161 libc::munlock(addr as *mut ::libc::c_void, len) == 0
162}
163
164#[cfg(windows)]
170pub unsafe fn munlock(addr: *mut u8, len: usize) -> bool {
171 memzero(addr, len);
172 winapi::um::memoryapi::VirtualUnlock(
173 addr as ::winapi::shared::minwindef::LPVOID,
174 len as ::winapi::shared::basetsd::SIZE_T,
175 ) != 0
176}
177
178#[cfg(test)]
179mod tests {
180 #[cfg(unix)]
181 use std::cmp;
182 use std::mem;
183
184 #[cfg(unix)]
185 use quickcheck::quickcheck;
186
187 use super::*;
188
189 #[test]
190 fn memzero_test() {
191 unsafe {
192 let mut x: [usize; 16] = [1; 16];
193 memzero(x.as_mut_ptr() as *mut u8, mem::size_of_val(&x));
194 assert_eq!(x, [0; 16]);
195 x.clone_from_slice(&[1; 16]);
196 assert_eq!(x, [1; 16]);
197 memzero(x[1..11].as_mut_ptr() as *mut u8, 10 * mem::size_of_val(&x[0]));
198 assert_eq!(x, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1]);
199 }
200 }
201
202 #[test]
203 #[cfg(unix)]
204 fn memeq_test() {
205 #[allow(clippy::needless_pass_by_value)]
206 fn check_memeq(x: Vec<u8>, y: Vec<u8>) -> bool {
207 unsafe {
208 let memsec_output = memeq(x.as_ptr(), y.as_ptr(), cmp::min(x.len(), y.len()));
209 let libc_output = libc::memcmp(
210 x.as_ptr() as *const libc::c_void,
211 y.as_ptr() as *const libc::c_void,
212 cmp::min(x.len(), y.len()),
213 ) == 0;
214 memsec_output == libc_output
215 }
216 }
217 quickcheck(check_memeq as fn(Vec<u8>, Vec<u8>) -> bool);
218 }
219
220 #[test]
221 #[cfg(unix)]
222 fn memcmp_test() {
223 #[allow(clippy::needless_pass_by_value)]
224 fn check_memcmp(x: Vec<u8>, y: Vec<u8>) -> bool {
225 unsafe {
226 let memsec_output = memcmp(x.as_ptr(), y.as_ptr(), cmp::min(x.len(), y.len()));
227 let libc_output = libc::memcmp(
228 x.as_ptr() as *const libc::c_void,
229 y.as_ptr() as *const libc::c_void,
230 cmp::min(x.len(), y.len()),
231 );
232 (memsec_output > 0) == (libc_output > 0)
233 && (memsec_output < 0) == (libc_output < 0)
234 && (memsec_output == 0) == (libc_output == 0)
235 }
236 }
237 quickcheck(check_memcmp as fn(Vec<u8>, Vec<u8>) -> bool);
238 }
239
240 #[test]
241 fn mlock_munlock_test() {
242 unsafe {
243 let mut x = [1; 16];
244
245 assert!(mlock(x.as_mut_ptr(), mem::size_of_val(&x)));
246 assert!(munlock(x.as_mut_ptr(), mem::size_of_val(&x)));
247 assert_eq!(x, [0; 16]);
248 }
249 }
250}