From 6f21b9843b85ba232b8bbb8aa13acd21111eb3c9 Mon Sep 17 00:00:00 2001 From: Lukasz Anforowicz Date: Mon, 18 May 2026 17:25:58 +0000 Subject: [PATCH] Use `no_std`-friendly `spin::Mutex` to avoid `unsafe` for `static mut`. --- Cargo.toml | 1 + crates/serde_anymap/Cargo.toml | 1 + crates/serde_anymap/src/serdeany.rs | 98 +++++++++++------------------ 3 files changed, 37 insertions(+), 63 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 10aa5ed93de..2e04ef37b5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -152,6 +152,7 @@ serde = { version = "1.0.228", default-features = false } # serialization lib serde_json = { version = "1.0.149", default-features = false } serde_yaml = { version = "0.9.34" } # For parsing the injections yaml file serial_test = { version = "3.2.0", default-features = false } +spin = "0.11.0" static_assertions = "1.1.0" strum = "0.28.0" strum_macros = "0.28.0" diff --git a/crates/serde_anymap/Cargo.toml b/crates/serde_anymap/Cargo.toml index a7a6ee12e81..0dfe521714f 100644 --- a/crates/serde_anymap/Cargo.toml +++ b/crates/serde_anymap/Cargo.toml @@ -56,6 +56,7 @@ libafl_core = { workspace = true } postcard = { workspace = true } serde = { workspace = true, features = ["derive"] } static_assertions = { workspace = true } +spin = { workspace = true, features = ["mutex"] } [lints] workspace = true diff --git a/crates/serde_anymap/src/serdeany.rs b/crates/serde_anymap/src/serdeany.rs index 9f6d6cb11dc..1df8e17437a 100644 --- a/crates/serde_anymap/src/serdeany.rs +++ b/crates/serde_anymap/src/serdeany.rs @@ -113,12 +113,11 @@ where /// Creates the [`serde`] registry for serialization and deserialization of [`SerdeAny`]. /// Each element needs to be registered so that it can be deserialized. pub mod serdeany_registry { - use alloc::{ boxed::Box, string::{String, ToString}, }; - use core::{any::TypeId, fmt}; + use core::{any::TypeId, cell::RefCell, fmt}; use hashbrown::{ DefaultHashBuilder, HashMap, @@ -126,6 +125,7 @@ pub mod serdeany_registry { }; use libafl_core::{Error, format}; use serde::{Deserialize, Serialize, de}; + use spin::Mutex; use crate::serdeany::{ DeserializeCallback, DeserializeCallbackSeed, SerdeAny, TypeRepr, type_repr, @@ -153,17 +153,16 @@ pub mod serdeany_registry { { let id: TypeRepr = visitor.next_element()?.unwrap(); - let registry = &raw const REGISTRY; - let cb = unsafe { - (*registry) + let cb = REGISTRY + .lock() + .borrow() .deserializers .as_ref() .ok_or_else(|| de::Error::custom(super::ERR_EMPTY_TYPES_REGISTER))? .get(&id) .ok_or_else(|| de::Error::custom(format_args!("Cannot deserialize the unregistered type with id {id}. Enable the `serde_autoreg` feature in libafl_bolts or register all requried types manually.")))? - .0 - }; + .0; let seed = DeserializeCallbackSeed:: { cb }; let obj: Self::Value = visitor.next_element_seed(seed)?.unwrap(); Ok(obj) @@ -208,10 +207,10 @@ pub mod serdeany_registry { } } - static mut REGISTRY: Registry = Registry { + static REGISTRY: Mutex> = Mutex::new(RefCell::new(Registry { deserializers: None, finalized: false, - }; + })); /// This sugar must be used to register all the structs which /// have trait objects that can be serialized and deserialized in the program @@ -221,30 +220,16 @@ pub mod serdeany_registry { #[expect(unused_qualifications)] impl RegistryBuilder { /// Register a given struct type for trait object (de)serialization - /// - /// # Safety - /// This may never be called concurrently or at the same time as `finalize`. - /// It dereferences the `REGISTRY` hashmap and adds the given type to it. - pub unsafe fn register() + pub fn register() where T: crate::serdeany::SerdeAny + Serialize + serde::de::DeserializeOwned, { - let registry = &raw mut REGISTRY; - unsafe { - (*registry).register::(); - } + REGISTRY.lock().borrow_mut().register::(); } /// Finalize the registry, no more registrations are allowed after this call - /// - /// # Safety - /// This may never be called concurrently or at the same time as `register`. - /// It dereferences the `REGISTRY` hashmap and adds the given type to it. - pub unsafe fn finalize() { - let registry = &raw mut REGISTRY; - unsafe { - (*registry).finalize(); - } + pub fn finalize() { + REGISTRY.lock().borrow_mut().finalize(); } } @@ -380,16 +365,15 @@ pub mod serdeany_registry { #[cfg(not(feature = "stable_anymap"))] let type_repr = &type_repr; - let registry = &raw const REGISTRY; assert!( - unsafe { - (*registry) - .deserializers - .as_ref() - .expect(super::ERR_EMPTY_TYPES_REGISTER) - .get(type_repr) - .is_some() - }, + REGISTRY + .lock() + .borrow() + .deserializers + .as_ref() + .expect(super::ERR_EMPTY_TYPES_REGISTER) + .get(type_repr) + .is_some(), "Type {} was inserted without registration! Call RegistryBuilder::register::<{}>() or use serdeany_autoreg.", core::any::type_name::(), core::any::type_name::() @@ -667,16 +651,15 @@ pub mod serdeany_registry { let type_repr = type_repr::(); #[cfg(not(feature = "stable_anymap"))] let type_repr = &type_repr; - let registry = &raw const REGISTRY; assert!( - unsafe { - (*registry) - .deserializers - .as_ref() - .expect(super::ERR_EMPTY_TYPES_REGISTER) - .get(type_repr) - .is_some() - }, + REGISTRY + .lock() + .borrow() + .deserializers + .as_ref() + .expect(super::ERR_EMPTY_TYPES_REGISTER) + .get(type_repr) + .is_some(), "Type {} was inserted without registration! Call RegistryBuilder::register::<{}>() or use serdeany_autoreg.", core::any::type_name::(), core::any::type_name::() @@ -852,12 +835,8 @@ macro_rules! create_register { $crate::ctor::declarative::ctor! { /// Automatically register this type #[ctor(anonymous)] - unsafe fn register() { - // # Safety - // This `register` call will always run at startup and never in parallel. - unsafe { - $crate::serdeany::RegistryBuilder::register::<$struct_type>(); - } + fn register() { + $crate::serdeany::RegistryBuilder::register::<$struct_type>(); } } }; @@ -889,9 +868,7 @@ macro_rules! create_manual_register { #[macro_export] macro_rules! create_manual_register { ($struct_type:ty) => { - unsafe { - $crate::serdeany::RegistryBuilder::register::<$struct_type>(); - } + $crate::serdeany::RegistryBuilder::register::<$struct_type>(); }; } @@ -926,10 +903,7 @@ macro_rules! impl_serdeany { impl< $( $lt $( : $clt $(+ $dlt )* )? ),+ > $struct_name < $( $lt ),+ > { /// Manually register this type at a later point in time - /// - /// # Safety - /// This may never be called concurrently as it dereferences the `RegistryBuilder` without acquiring a lock. - pub unsafe fn register() { + pub fn register() { $( $crate::create_manual_register!($struct_name < $( $opt ),+ >); )* @@ -971,7 +945,7 @@ macro_rules! impl_serdeany { /// # Safety /// This may never be called concurrently as it dereferences the `RegistryBuilder` without acquiring a lock. #[expect(unused)] - pub unsafe fn register() { + pub fn register() { $crate::create_manual_register!($struct_name); } } @@ -1000,10 +974,8 @@ mod tests { #[test] fn test_deserialize_serialize() { - unsafe { - RegistryBuilder::register::(); - RegistryBuilder::register::(); - } + RegistryBuilder::register::(); + RegistryBuilder::register::(); let val = MyType(1); let serialized = postcard::to_allocvec(&val).unwrap();