From f0d85aaaa5a88aed884063fffa8931346d99fa3d Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 24 Sep 2024 03:29:49 +0200 Subject: [PATCH] No more (direct) mutable references to mutable statics (#2550) * No more (direct) mutable references to mutable statics * More * Fix build, but it's unsafe dude * more * fmt * More fix * more? --- libafl/src/events/mod.rs | 5 +-- libafl/src/observers/map/hitcount_map.rs | 20 ++++++++---- libafl/src/observers/mod.rs | 5 +-- libafl_bolts/src/lib.rs | 2 +- libafl_bolts/src/serdeany.rs | 17 ++++++---- libafl_qemu/src/breakpoint.rs | 5 ++- libafl_qemu/src/emu/systemmode.rs | 2 +- libafl_qemu/src/lib.rs | 1 + libafl_qemu/src/modules/calls.rs | 21 ++++++++---- libafl_qemu/src/modules/mod.rs | 7 ++-- libafl_qemu/src/qemu/mod.rs | 41 ++++++++++++++---------- libafl_qemu/src/qemu/usermode.rs | 4 +-- libafl_targets/src/call.rs | 16 ++++++--- libafl_targets/src/coverage.rs | 3 +- libafl_targets/src/sancov_8bit.rs | 22 +++++++++---- libafl_targets/src/sancov_pcguard.rs | 34 ++++++++++++-------- 16 files changed, 130 insertions(+), 75 deletions(-) diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 656d9fbdaf..2efe5b079e 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -938,7 +938,7 @@ pub trait AdaptiveSerializer { #[cfg(test)] mod tests { - use core::ptr::addr_of_mut; + use core::ptr::{addr_of, addr_of_mut}; use libafl_bolts::{current_time, tuples::tuple_list, Named}; use tuple_list::tuple_list_type; @@ -955,7 +955,8 @@ mod tests { #[test] fn test_event_serde() { let obv = unsafe { - StdMapObserver::from_mut_ptr("test", addr_of_mut!(MAP) as *mut u32, MAP.len()) + let len = (*addr_of!(MAP)).len(); + StdMapObserver::from_mut_ptr("test", addr_of_mut!(MAP) as *mut u32, len) }; let map = tuple_list!(obv); let observers_buf = postcard::to_allocvec(&map).unwrap(); diff --git a/libafl/src/observers/map/hitcount_map.rs b/libafl/src/observers/map/hitcount_map.rs index cd8f1f7193..b17379434f 100644 --- a/libafl/src/observers/map/hitcount_map.rs +++ b/libafl/src/observers/map/hitcount_map.rs @@ -1,6 +1,12 @@ //! Hitcount map observer is for implementing AFL's hit count bucket use alloc::{borrow::Cow, vec::Vec}; -use core::{fmt::Debug, hash::Hash, mem::size_of, slice}; +use core::{ + fmt::Debug, + hash::Hash, + mem::size_of, + ptr::{addr_of, addr_of_mut}, + slice, +}; use libafl_bolts::{AsIter, AsIterMut, AsSlice, AsSliceMut, HasLen, Named, Truncate}; use serde::{Deserialize, Serialize}; @@ -35,17 +41,19 @@ static mut COUNT_CLASS_LOOKUP_16: Vec = vec![]; /// /// # Safety /// -/// Calling this from multiple threads may be racey and hence leak 65k mem +/// Calling this from multiple threads may be racey and hence leak 65k mem or even create a broken lookup vec. fn init_count_class_16() { unsafe { - if !COUNT_CLASS_LOOKUP_16.is_empty() { + let count_class_lookup_16 = &mut *addr_of_mut!(COUNT_CLASS_LOOKUP_16); + + if !count_class_lookup_16.is_empty() { return; } - COUNT_CLASS_LOOKUP_16 = vec![0; 65536]; + *count_class_lookup_16 = vec![0; 65536]; for i in 0..256 { for j in 0..256 { - COUNT_CLASS_LOOKUP_16[(i << 8) + j] = + count_class_lookup_16[(i << 8) + j] = (u16::from(COUNT_CLASS_LOOKUP[i]) << 8) | u16::from(COUNT_CLASS_LOOKUP[j]); } } @@ -117,7 +125,7 @@ where #[allow(clippy::unused_enumerate_index)] for (_i, item) in map16[0..cnt].iter_mut().enumerate() { unsafe { - *item = *COUNT_CLASS_LOOKUP_16.get_unchecked(*item as usize); + *item = *(*addr_of!(COUNT_CLASS_LOOKUP_16)).get_unchecked(*item as usize); } } diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index d27ff4860a..80ac4f8eab 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -446,7 +446,7 @@ where #[cfg(test)] mod tests { - use core::ptr::addr_of_mut; + use core::ptr::{addr_of, addr_of_mut}; use libafl_bolts::{ ownedref::OwnedMutSlice, @@ -461,9 +461,10 @@ mod tests { #[test] fn test_observer_serde() { let obv = tuple_list!(TimeObserver::new("time"), unsafe { + let len = (*addr_of!(MAP)).len(); StdMapObserver::from_ownedref( "map", - OwnedMutSlice::from_raw_parts_mut(addr_of_mut!(MAP) as *mut u32, MAP.len()), + OwnedMutSlice::from_raw_parts_mut(addr_of_mut!(MAP) as *mut u32, len), ) }); let vec = postcard::to_allocvec(&obv).unwrap(); diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index adfded38df..014e911af0 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -992,7 +992,7 @@ impl SimpleFdLogger { // The passed-in `fd` has to be a legal file descriptor to log to. // We also access a shared variable here. unsafe { - LIBAFL_RAWFD_LOGGER.set_fd(log_fd); + (*ptr::addr_of_mut!(LIBAFL_RAWFD_LOGGER)).set_fd(log_fd); log::set_logger(&*ptr::addr_of!(LIBAFL_RAWFD_LOGGER))?; } Ok(()) diff --git a/libafl_bolts/src/serdeany.rs b/libafl_bolts/src/serdeany.rs index 5ac58f20c1..be5b956b92 100644 --- a/libafl_bolts/src/serdeany.rs +++ b/libafl_bolts/src/serdeany.rs @@ -118,7 +118,12 @@ pub mod serdeany_registry { boxed::Box, string::{String, ToString}, }; - use core::{any::TypeId, fmt, hash::BuildHasherDefault}; + use core::{ + any::TypeId, + fmt, + hash::BuildHasherDefault, + ptr::{addr_of, addr_of_mut}, + }; use hashbrown::{ hash_map::{Values, ValuesMut}, @@ -156,7 +161,7 @@ pub mod serdeany_registry { let id: TypeRepr = visitor.next_element()?.unwrap(); let cb = unsafe { - REGISTRY + (*addr_of!(REGISTRY)) .deserializers .as_ref() .ok_or_else(|| @@ -228,7 +233,7 @@ pub mod serdeany_registry { T: crate::serdeany::SerdeAny + Serialize + serde::de::DeserializeOwned, { unsafe { - REGISTRY.register::(); + (*addr_of_mut!(REGISTRY)).register::(); } } @@ -239,7 +244,7 @@ pub mod serdeany_registry { /// It dereferences the `REGISTRY` hashmap and adds the given type to it. pub fn finalize() { unsafe { - REGISTRY.finalize(); + (*addr_of_mut!(REGISTRY)).finalize(); } } } @@ -366,7 +371,7 @@ pub mod serdeany_registry { assert!( unsafe { - REGISTRY + (*addr_of!(REGISTRY)) .deserializers .as_ref() .expect(super::ERR_EMPTY_TYPES_REGISTER) @@ -629,7 +634,7 @@ pub mod serdeany_registry { assert!( unsafe { - REGISTRY + (*addr_of!(REGISTRY)) .deserializers .as_ref() .expect(super::ERR_EMPTY_TYPES_REGISTER) diff --git a/libafl_qemu/src/breakpoint.rs b/libafl_qemu/src/breakpoint.rs index 69e4e02ee1..e6c1c1ef2c 100644 --- a/libafl_qemu/src/breakpoint.rs +++ b/libafl_qemu/src/breakpoint.rs @@ -58,9 +58,8 @@ where impl BreakpointId { pub fn new() -> Self { - static mut BREAKPOINT_ID_COUNTER: OnceLock = OnceLock::new(); - - let counter = unsafe { BREAKPOINT_ID_COUNTER.get_or_init(|| AtomicU64::new(0)) }; + static BREAKPOINT_ID_COUNTER: OnceLock = OnceLock::new(); + let counter = BREAKPOINT_ID_COUNTER.get_or_init(|| AtomicU64::new(0)); BreakpointId(counter.fetch_add(1, Ordering::SeqCst)) } diff --git a/libafl_qemu/src/emu/systemmode.rs b/libafl_qemu/src/emu/systemmode.rs index 685f2eebed..e025ea9f49 100644 --- a/libafl_qemu/src/emu/systemmode.rs +++ b/libafl_qemu/src/emu/systemmode.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use hashbrown::HashMap; use libafl::{ inputs::{HasTargetBytes, UsesInput}, - prelude::{HasExecutions, State}, + state::{HasExecutions, State}, }; use libafl_qemu_sys::GuestPhysAddr; diff --git a/libafl_qemu/src/lib.rs b/libafl_qemu/src/lib.rs index 771eece838..6d3db6d30b 100644 --- a/libafl_qemu/src/lib.rs +++ b/libafl_qemu/src/lib.rs @@ -100,6 +100,7 @@ pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> { } m.add_submodule(&mmapm)?; + #[cfg(emulation_mode = "usermode")] m.add_class::()?; #[cfg(emulation_mode = "usermode")] diff --git a/libafl_qemu/src/modules/calls.rs b/libafl_qemu/src/modules/calls.rs index 5d4fd30ef4..56523c8c05 100644 --- a/libafl_qemu/src/modules/calls.rs +++ b/libafl_qemu/src/modules/calls.rs @@ -1,4 +1,4 @@ -use core::{cell::UnsafeCell, fmt::Debug}; +use core::{cell::UnsafeCell, fmt::Debug, ptr::addr_of_mut}; use capstone::prelude::*; use libafl::{ @@ -541,13 +541,13 @@ impl Default for FullBacktraceCollector { impl FullBacktraceCollector { pub fn new() -> Self { - unsafe { CALLSTACKS = Some(ThreadLocal::new()) }; + unsafe { *(&mut *addr_of_mut!(CALLSTACKS)) = Some(ThreadLocal::new()) }; Self {} } pub fn reset(&mut self) { unsafe { - for tls in CALLSTACKS.as_mut().unwrap().iter_mut() { + for tls in (*addr_of_mut!(CALLSTACKS)).as_mut().unwrap().iter_mut() { (*tls.get()).clear(); } } @@ -555,7 +555,7 @@ impl FullBacktraceCollector { pub fn backtrace() -> Option<&'static [GuestAddr]> { unsafe { - if let Some(c) = CALLSTACKS.as_mut() { + if let Some(c) = (*addr_of_mut!(CALLSTACKS)).as_mut() { Some(&*c.get_or_default().get()) } else { None @@ -578,7 +578,12 @@ impl CallTraceCollector for FullBacktraceCollector { { // TODO handle Thumb unsafe { - (*CALLSTACKS.as_mut().unwrap().get_or_default().get()).push(pc + call_len as GuestAddr); + (*(*addr_of_mut!(CALLSTACKS)) + .as_mut() + .unwrap() + .get_or_default() + .get()) + .push(pc + call_len as GuestAddr); } } @@ -594,7 +599,11 @@ impl CallTraceCollector for FullBacktraceCollector { S: Unpin + UsesInput, { unsafe { - let v = &mut *CALLSTACKS.as_mut().unwrap().get_or_default().get(); + let v = &mut *(*addr_of_mut!(CALLSTACKS)) + .as_mut() + .unwrap() + .get_or_default() + .get(); if !v.is_empty() { // if *v.last().unwrap() == ret_addr { // v.pop(); diff --git a/libafl_qemu/src/modules/mod.rs b/libafl_qemu/src/modules/mod.rs index 1ead41c795..700a02beb8 100644 --- a/libafl_qemu/src/modules/mod.rs +++ b/libafl_qemu/src/modules/mod.rs @@ -1,5 +1,4 @@ -use core::{fmt::Debug, ops::Range}; -use std::{cell::UnsafeCell, hash::BuildHasher}; +use core::{cell::UnsafeCell, fmt::Debug, hash::BuildHasher, ops::Range, ptr::addr_of_mut}; use hashbrown::HashSet; use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple}; @@ -311,7 +310,7 @@ impl HasInstrumentationFilter for () { } fn filter_mut(&mut self) -> &mut QemuInstrumentationAddressRangeFilter { - unsafe { EMPTY_ADDRESS_FILTER.get_mut() } + unsafe { (*addr_of_mut!(EMPTY_ADDRESS_FILTER)).get_mut() } } } @@ -321,7 +320,7 @@ impl HasInstrumentationFilter for () { } fn filter_mut(&mut self) -> &mut QemuInstrumentationPagingFilter { - unsafe { EMPTY_PAGING_FILTER.get_mut() } + unsafe { (*addr_of_mut!(EMPTY_PAGING_FILTER)).get_mut() } } } diff --git a/libafl_qemu/src/qemu/mod.rs b/libafl_qemu/src/qemu/mod.rs index e2195419c2..b3d6218734 100644 --- a/libafl_qemu/src/qemu/mod.rs +++ b/libafl_qemu/src/qemu/mod.rs @@ -3,16 +3,18 @@ //! This module exposes the low-level QEMU library through [`Qemu`]. //! To access higher-level features of QEMU, it is recommended to use [`crate::Emulator`] instead. -use core::fmt; -use std::{ +use core::{ cmp::{Ordering, PartialOrd}, + fmt, + ptr::{self, addr_of_mut}, +}; +use std::{ ffi::{c_void, CString}, fmt::{Display, Formatter}, intrinsics::{copy_nonoverlapping, transmute}, mem::MaybeUninit, ops::Range, pin::Pin, - ptr, }; use libafl_bolts::os::unix_signals::Signal; @@ -141,7 +143,7 @@ pub struct QemuMemoryChunk { } #[allow(clippy::vec_box)] -static mut GDB_COMMANDS: Vec> = vec![]; +static mut GDB_COMMANDS: Vec> = Vec::new(); unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool { unsafe { @@ -768,16 +770,16 @@ impl Qemu { id.remove(invalidate_block) } + // # Safety + // Calling this multiple times concurrently will access static variables and is unsafe. #[allow(clippy::type_complexity)] - pub fn add_gdb_cmd(&self, callback: Box bool>) { - unsafe { - let fat: Box = Box::new(transmute::< - Box FnMut(&'a Qemu, &'b str) -> bool>, - FatPtr, - >(callback)); - libafl_qemu_add_gdb_cmd(Some(gdb_cmd), ptr::from_ref(&*fat) as *mut c_void); - GDB_COMMANDS.push(fat); - } + pub unsafe fn add_gdb_cmd(&self, callback: Box bool>) { + let fat: Box = Box::new(transmute::< + Box FnMut(&'a Qemu, &'b str) -> bool>, + FatPtr, + >(callback)); + libafl_qemu_add_gdb_cmd(Some(gdb_cmd), ptr::from_ref(&*fat) as *mut c_void); + (*addr_of_mut!(GDB_COMMANDS)).push(fat); } pub fn gdb_reply(&self, output: &str) { @@ -956,7 +958,10 @@ pub mod pybind { static mut PY_GENERIC_HOOKS: Vec<(GuestAddr, PyObject)> = vec![]; extern "C" fn py_generic_hook_wrapper(idx: u64, _pc: GuestAddr) { - let obj = unsafe { &PY_GENERIC_HOOKS[idx as usize].1 }; + let obj = unsafe { + let hooks = &mut *core::ptr::addr_of_mut!(PY_GENERIC_HOOKS); + &hooks[idx as usize].1 + }; Python::with_gil(|py| { obj.call0(py).expect("Error in the hook"); }); @@ -1032,8 +1037,9 @@ pub mod pybind { fn set_hook(&self, addr: GuestAddr, hook: PyObject) { unsafe { - let idx = PY_GENERIC_HOOKS.len(); - PY_GENERIC_HOOKS.push((addr, hook)); + let hooks = &mut *core::ptr::addr_of_mut!(PY_GENERIC_HOOKS); + let idx = hooks.len(); + hooks.push((addr, hook)); self.qemu.hooks().add_instruction_hooks( idx as u64, addr, @@ -1045,7 +1051,8 @@ pub mod pybind { fn remove_hooks_at(&self, addr: GuestAddr) -> usize { unsafe { - PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr); + let hooks = &mut *core::ptr::addr_of_mut!(PY_GENERIC_HOOKS); + hooks.retain(|(a, _)| *a != addr); } self.qemu.hooks().remove_instruction_hooks_at(addr, true) } diff --git a/libafl_qemu/src/qemu/usermode.rs b/libafl_qemu/src/qemu/usermode.rs index c95763582a..3711d70f79 100644 --- a/libafl_qemu/src/qemu/usermode.rs +++ b/libafl_qemu/src/qemu/usermode.rs @@ -261,7 +261,7 @@ pub mod pybind { a6: u64, a7: u64, ) -> SyscallHookResult { - unsafe { PY_SYSCALL_HOOK.as_ref() }.map_or_else( + unsafe { (*core::ptr::addr_of!(PY_SYSCALL_HOOK)).as_ref() }.map_or_else( || SyscallHookResult::new(None), |obj| { let args = (sys_num, a0, a1, a2, a3, a4, a5, a6, a7); @@ -340,7 +340,7 @@ pub mod pybind { fn set_syscall_hook(&self, hook: PyObject) { unsafe { - PY_SYSCALL_HOOK = Some(hook); + *(&mut *core::ptr::addr_of_mut!(PY_SYSCALL_HOOK)) = Some(hook); } self.qemu .hooks() diff --git a/libafl_targets/src/call.rs b/libafl_targets/src/call.rs index 581a3f2fcd..38a20a7611 100644 --- a/libafl_targets/src/call.rs +++ b/libafl_targets/src/call.rs @@ -1,4 +1,4 @@ -use core::marker::PhantomData; +use core::{marker::PhantomData, ptr::addr_of_mut}; use hashbrown::HashMap; use libafl::{ @@ -12,9 +12,11 @@ pub static mut FUNCTION_LIST: Lazy> = Lazy::new(HashMap::n #[no_mangle] /// The runtime code inserted at every callinst invokation (if you used the function-logging.cc) /// # Safety -/// unsafe because it touches pub static mut +/// unsafe because it touches the pub static mut `FUNCTION_LIST`. +/// May not be called concurrently. pub unsafe extern "C" fn __libafl_target_call_hook(id: usize) { - *FUNCTION_LIST.entry(id).or_insert(0) += 1; + let function_list = &mut *addr_of_mut!(FUNCTION_LIST); + *function_list.entry(id).or_insert(0) += 1; } /// The empty struct to clear the `FUNCTION_LIST` before the execution @@ -41,7 +43,13 @@ where fn pre_exec(&mut self, _state: &mut S, _input: &::Input) { // clear it before the execution - unsafe { FUNCTION_LIST.clear() } + // # Safety + // This typically happens while no other execution happens. + // In theory there is a race, but we can ignore it _for this use case_. + unsafe { + let function_list = &mut *addr_of_mut!(FUNCTION_LIST); + function_list.clear(); + } } fn post_exec(&mut self, _state: &mut S, _input: &::Input) {} diff --git a/libafl_targets/src/coverage.rs b/libafl_targets/src/coverage.rs index d5293f3b34..a6dfad6453 100644 --- a/libafl_targets/src/coverage.rs +++ b/libafl_targets/src/coverage.rs @@ -7,6 +7,7 @@ feature = "sancov_ctx" ))] use alloc::borrow::Cow; +use core::ptr::addr_of_mut; #[cfg(any(target_os = "linux", target_vendor = "apple"))] use libafl::{mutators::Tokens, Error}; @@ -157,7 +158,7 @@ pub fn edges_map_mut_ptr() -> *mut u8 { assert!(!EDGES_MAP_PTR.is_null()); EDGES_MAP_PTR } else { - EDGES_MAP.as_mut_ptr() + addr_of_mut!(EDGES_MAP) as *mut u8 } } } diff --git a/libafl_targets/src/sancov_8bit.rs b/libafl_targets/src/sancov_8bit.rs index 4f2d3ed8d2..9d81828d29 100644 --- a/libafl_targets/src/sancov_8bit.rs +++ b/libafl_targets/src/sancov_8bit.rs @@ -1,6 +1,6 @@ //! [`LLVM` `8-bit-counters`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`. use alloc::vec::Vec; -use core::ptr::addr_of_mut; +use core::ptr::{addr_of, addr_of_mut}; use libafl_bolts::{ownedref::OwnedMutSlice, AsSlice, AsSliceMut}; @@ -14,7 +14,8 @@ pub static mut COUNTERS_MAPS: Vec> = Vec::new(); /// You are responsible for ensuring there is no multi-mutability! #[must_use] pub unsafe fn extra_counters() -> Vec> { - COUNTERS_MAPS + let counter_maps = &*addr_of!(COUNTERS_MAPS); + counter_maps .iter() .map(|counters| { OwnedMutSlice::from_raw_parts_mut( @@ -31,7 +32,8 @@ pub unsafe fn extra_counters() -> Vec> { #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn __sanitizer_cov_8bit_counters_init(start: *mut u8, stop: *mut u8) { unsafe { - for existing in &mut *addr_of_mut!(COUNTERS_MAPS) { + let counter_maps = &mut *addr_of_mut!(COUNTERS_MAPS); + for existing in counter_maps { let range = existing.as_slice_mut().as_mut_ptr() ..=existing .as_slice_mut() @@ -46,8 +48,10 @@ pub extern "C" fn __sanitizer_cov_8bit_counters_init(start: *mut u8, stop: *mut return; } } + + let counter_maps = &mut *addr_of_mut!(COUNTERS_MAPS); // we didn't overlap; keep going - COUNTERS_MAPS.push(OwnedMutSlice::from_raw_parts_mut( + counter_maps.push(OwnedMutSlice::from_raw_parts_mut( start, stop.offset_from(start) as usize, )); @@ -327,7 +331,10 @@ mod observers { type IntoIter = Flatten>>; fn as_iter(&'it self) -> Self::IntoIter { - unsafe { COUNTERS_MAPS.iter().flatten() } + unsafe { + let counters_maps = &*addr_of!(COUNTERS_MAPS); + counters_maps.iter().flatten() + } } } @@ -336,7 +343,10 @@ mod observers { type IntoIterMut = Flatten>>; fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { - unsafe { COUNTERS_MAPS.iter_mut().flatten() } + unsafe { + let counters_maps = &mut *addr_of_mut!(COUNTERS_MAPS); + counters_maps.iter_mut().flatten() + } } } diff --git a/libafl_targets/src/sancov_pcguard.rs b/libafl_targets/src/sancov_pcguard.rs index cf6348845f..de98ca2faf 100644 --- a/libafl_targets/src/sancov_pcguard.rs +++ b/libafl_targets/src/sancov_pcguard.rs @@ -65,6 +65,8 @@ pub static SHR_4: Ngram4 = Ngram4::from_array([1, 1, 1, 1]); #[rustversion::nightly] pub static SHR_8: Ngram8 = Ngram8::from_array([1, 1, 1, 1, 1, 1, 1, 1]); +static mut PC_TABLES: Vec<&'static [PcTableEntry]> = Vec::new(); + use alloc::vec::Vec; #[cfg(any( feature = "sancov_ngram4", @@ -184,17 +186,19 @@ unsafe fn update_ngram(pos: usize) -> usize { let mut reduced = pos; #[cfg(feature = "sancov_ngram4")] { - PREV_ARRAY_4 = PREV_ARRAY_4.rotate_elements_right::<1>(); - PREV_ARRAY_4.shl_assign(SHR_4); - PREV_ARRAY_4.as_mut_array()[0] = pos as u32; - reduced = PREV_ARRAY_4.reduce_xor() as usize; + let prev_array_4 = &mut *core::ptr::addr_of_mut!(PREV_ARRAY_4); + *prev_array_4 = prev_array_4.rotate_elements_right::<1>(); + prev_array_4.shl_assign(SHR_4); + prev_array_4.as_mut_array()[0] = pos as u32; + reduced = prev_array_4.reduce_xor() as usize; } #[cfg(feature = "sancov_ngram8")] { - PREV_ARRAY_8 = PREV_ARRAY_8.rotate_elements_right::<1>(); - PREV_ARRAY_8.shl_assign(SHR_8); - PREV_ARRAY_8.as_mut_array()[0] = pos as u32; - reduced = PREV_ARRAY_8.reduce_xor() as usize; + let prev_array_8 = &mut *core::ptr::addr_of_mut!(PREV_ARRAY_8); + *prev_array_8 = prev_array_8.rotate_elements_right::<1>(); + prev_array_8.shl_assign(SHR_8); + prev_array_8.as_mut_array()[0] = pos as u32; + reduced = prev_array_8.reduce_xor() as usize; } reduced %= EDGES_MAP_SIZE_IN_USE; reduced @@ -269,7 +273,7 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) { pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) { #[cfg(feature = "pointer_maps")] if EDGES_MAP_PTR.is_null() { - EDGES_MAP_PTR = EDGES_MAP.as_mut_ptr(); + EDGES_MAP_PTR = core::ptr::addr_of_mut!(EDGES_MAP) as *mut u8; } if start == stop || *start != 0 { @@ -292,8 +296,6 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32 } } -static mut PC_TABLES: Vec<&'static [PcTableEntry]> = Vec::new(); - #[no_mangle] unsafe extern "C" fn __sanitizer_cov_pcs_init(pcs_beg: *const usize, pcs_end: *const usize) { // "The Unsafe Code Guidelines also notably defines that usize and isize are respectively compatible with uintptr_t and intptr_t defined in C." @@ -312,7 +314,8 @@ unsafe extern "C" fn __sanitizer_cov_pcs_init(pcs_beg: *const usize, pcs_end: *c "Unaligned PC Table - start: {pcs_beg:x?} end: {pcs_end:x?}" ); - PC_TABLES.push(slice::from_raw_parts(pcs_beg as *const PcTableEntry, len)); + let pc_tables = &mut *core::ptr::addr_of_mut!(PC_TABLES); + pc_tables.push(slice::from_raw_parts(pcs_beg as *const PcTableEntry, len)); } /// An entry to the `sanitizer_cov` `pc_table` @@ -338,8 +341,11 @@ impl PcTableEntry { } /// Returns an iterator over the PC tables. If no tables were registered, this will be empty. -pub fn sanitizer_cov_pc_table() -> impl Iterator { +pub fn sanitizer_cov_pc_table<'a>() -> impl Iterator { // SAFETY: Once PCS_BEG and PCS_END have been initialized, will not be written to again. So // there's no TOCTOU issue. - unsafe { PC_TABLES.iter().copied() } + unsafe { + let pc_tables = &*core::ptr::addr_of!(PC_TABLES); + pc_tables.iter().copied() + } }