detect and prevent² concurrent AtomTable use

²in the case of `#[cfg(not(test))]` there is still a toctou race as I am not sufficently familiar with Atomics
This commit is contained in:
Bennet Bleßmann
2023-07-27 23:35:57 +02:00
parent 31d17f135a
commit 4ef8c5c47d

View File

@@ -54,7 +54,12 @@ static mut ATOM_TABLE_BUF_BASE: *const u8 = ptr::null_mut();
#[cfg(test)] #[cfg(test)]
fn set_atom_tbl_buf_base(ptr: *const u8) { fn set_atom_tbl_buf_base(ptr: *const u8) {
ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| { ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| {
*atom_table_buf_base.borrow_mut() = ptr; let mut borrow = atom_table_buf_base.borrow_mut();
assert!(
borrow.is_null() || ptr.is_null(),
"Overwriting atom table base pointer!"
);
*borrow = ptr;
}); });
} }
@@ -66,6 +71,11 @@ pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
#[cfg(not(test))] #[cfg(not(test))]
fn set_atom_tbl_buf_base(ptr: *const u8) { fn set_atom_tbl_buf_base(ptr: *const u8) {
unsafe { unsafe {
// FIXME: to prevent a toctou race-condition an atomic compare_exchange or a global lock should be used
assert!(
ATOM_TABLE_BUF_BASE.is_null() || ptr.is_null(),
"Overwriting atom table base pointer!"
);
ATOM_TABLE_BUF_BASE = ptr; ATOM_TABLE_BUF_BASE = ptr;
} }
} }
@@ -75,6 +85,13 @@ pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
unsafe { ATOM_TABLE_BUF_BASE } unsafe { ATOM_TABLE_BUF_BASE }
} }
#[test]
#[should_panic(expected = "Overwriting atom table base pointer!")]
fn atomtable_is_not_concurrency_safe() {
let table_a = AtomTable::new();
let table_b = AtomTable::new();
}
impl RawBlockTraits for AtomTable { impl RawBlockTraits for AtomTable {
#[inline] #[inline]
fn init_size() -> usize { fn init_size() -> usize {
@@ -241,6 +258,7 @@ pub struct AtomTable {
impl Drop for AtomTable { impl Drop for AtomTable {
fn drop(&mut self) { fn drop(&mut self) {
set_atom_tbl_buf_base(ptr::null());
self.block.deallocate(); self.block.deallocate();
} }
} }