Skip to content

Commit d067b26

Browse files
committed
feat: Add lender feature to check if a pointer is valid
1 parent 224ad67 commit d067b26

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ std = []
1818
alloc = []
1919
# Allow to use some FFI for C types
2020
c-types = ["std"]
21+
lender = ["lazy_static"]
2122

2223
[dependencies]
2324
log = "^0"
25+
lazy_static = { version = "^1", optional = true }
2426

2527
[package.metadata.docs.rs]
2628
features = ["std", "c-types"]

src/lib.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,30 @@ extern crate std;
2121
#[cfg(feature = "std")]
2222
use std::boxed::Box;
2323

24+
#[cfg(all(feature = "std", feature = "lender"))]
25+
#[macro_use]
26+
extern crate lazy_static;
27+
#[cfg(all(feature = "std", feature = "lender"))]
28+
use std::collections::HashSet;
29+
#[cfg(all(feature = "std", feature = "lender"))]
30+
use std::sync::RwLock;
31+
2432
#[cfg(all(feature = "std", feature = "c-types"))]
2533
pub mod c;
2634

2735
pub mod error;
2836

37+
#[cfg(all(feature = "std", feature = "lender"))]
38+
lazy_static! {
39+
static ref LENT: RwLock<HashSet<usize>> = { RwLock::new(HashSet::new()) };
40+
}
41+
42+
#[cfg(all(feature = "std", feature = "lender"))]
43+
#[inline]
44+
fn is_lent<T>(pointer: *const T) -> bool {
45+
return LENT.read().unwrap().contains(&(pointer as usize));
46+
}
47+
2948
#[inline]
3049
fn null_error_check<T>(pointer: *const T) -> Result<(), crate::error::PointerError> {
3150
if pointer.is_null() {
@@ -41,7 +60,10 @@ fn null_error_check<T>(pointer: *const T) -> Result<(), crate::error::PointerErr
4160
#[cfg(any(feature = "alloc", feature = "std"))]
4261
#[inline]
4362
pub fn raw<T>(data: T) -> *mut T {
44-
return Box::into_raw(Box::new(data));
63+
let pointer = Box::into_raw(Box::new(data));
64+
#[cfg(all(feature = "std", feature = "lender"))]
65+
LENT.write().unwrap().insert(pointer as usize);
66+
return pointer;
4567
}
4668

4769
/// Call to [`own_back<T>()`] ignoring the result.
@@ -78,8 +100,13 @@ pub unsafe fn free<T>(pointer: *mut T) {
78100
#[inline]
79101
pub unsafe fn own_back<T>(pointer: *mut T) -> Result<T, crate::error::PointerError> {
80102
null_error_check(pointer)?;
81-
// CAUTION: this is the unsafe part of the function.
82-
let boxed = Box::from_raw(pointer);
103+
#[cfg(all(feature = "std", feature = "lender"))]
104+
if !is_lent(pointer) {
105+
return Err(crate::error::PointerError::Invalid);
106+
}
107+
let boxed = { Box::from_raw(pointer) };
108+
#[cfg(all(feature = "std", feature = "lender"))]
109+
LENT.write().unwrap().remove(&(pointer as usize));
83110
return Ok(*boxed);
84111
}
85112

@@ -98,7 +125,10 @@ pub unsafe fn own_back<T>(pointer: *mut T) -> Result<T, crate::error::PointerErr
98125
#[inline]
99126
pub unsafe fn object<'a, T>(pointer: *const T) -> Result<&'a T, crate::error::PointerError> {
100127
null_error_check(pointer)?;
101-
// CAUTION: this is unsafe
128+
#[cfg(all(feature = "std", feature = "lender"))]
129+
if !is_lent(pointer) {
130+
return Err(crate::error::PointerError::Invalid);
131+
}
102132
return Ok(&*pointer);
103133
}
104134

@@ -117,6 +147,9 @@ pub unsafe fn object<'a, T>(pointer: *const T) -> Result<&'a T, crate::error::Po
117147
#[inline]
118148
pub unsafe fn mut_object<'a, T>(pointer: *mut T) -> Result<&'a mut T, crate::error::PointerError> {
119149
null_error_check(pointer)?;
120-
// CAUTION: this is unsafe
150+
#[cfg(all(feature = "std", feature = "lender"))]
151+
if !is_lent(pointer) {
152+
return Err(crate::error::PointerError::Invalid);
153+
}
121154
return Ok(&mut *pointer);
122155
}

0 commit comments

Comments
 (0)