added descriptions to llmp
This commit is contained in:
parent
004c3e3233
commit
567f981f5f
@ -57,6 +57,7 @@ use core::{
|
|||||||
sync::atomic::{compiler_fence, Ordering},
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
@ -65,7 +66,7 @@ use std::{
|
|||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::shmem::ShMem;
|
use super::shmem::{ShMem, ShMemDescription};
|
||||||
use crate::utils::next_pow2;
|
use crate::utils::next_pow2;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
@ -217,6 +218,16 @@ unsafe fn _llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg {
|
|||||||
.offset((*last_msg).buf_len_padded as isize) as *mut LlmpMsg;
|
.offset((*last_msg).buf_len_padded as isize) as *mut LlmpMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Description of a shared map.
|
||||||
|
/// May be used to restore the map by id.
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct LlmpDescription {
|
||||||
|
/// Info about the SharedMap in use
|
||||||
|
shmem: ShMemDescription,
|
||||||
|
/// The last message sent or received, depnding on page type
|
||||||
|
last_message_offset: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
/// Result of an LLMP Mesasge hook
|
/// Result of an LLMP Mesasge hook
|
||||||
pub enum LlmpMsgHookResult {
|
pub enum LlmpMsgHookResult {
|
||||||
@ -327,6 +338,23 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describe this in a reproducable fashion, if it's a client
|
||||||
|
pub fn describe(&self) -> Result<LlmpClientDescription, AflError> {
|
||||||
|
Ok(match self {
|
||||||
|
LlmpConnection::IsClient { client } => client.describe()?,
|
||||||
|
_ => todo!("Only client can be described atm."),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recreate an existing client from the stored description
|
||||||
|
pub fn existing_client_from_description(
|
||||||
|
description: &LlmpClientDescription,
|
||||||
|
) -> Result<LlmpConnection<SH>, AflError> {
|
||||||
|
Ok(LlmpConnection::IsClient {
|
||||||
|
client: LlmpClient::existing_client_from_description(description)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Sends the given buffer over this connection, no matter if client or broker.
|
/// Sends the given buffer over this connection, no matter if client or broker.
|
||||||
pub fn send_buf(&mut self, tag: Tag, buf: &[u8]) -> Result<(), AflError> {
|
pub fn send_buf(&mut self, tag: Tag, buf: &[u8]) -> Result<(), AflError> {
|
||||||
match self {
|
match self {
|
||||||
@ -432,9 +460,6 @@ where
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn to_env(&self, env_name: &str) -> Result<(), AflError> {
|
pub fn to_env(&self, env_name: &str) -> Result<(), AflError> {
|
||||||
let current_out_map = self.out_maps.last().unwrap();
|
let current_out_map = self.out_maps.last().unwrap();
|
||||||
// TODO: Make sure somebody else has mapped this
|
|
||||||
// current_out_map.await_read_blocking();
|
|
||||||
|
|
||||||
current_out_map.shmem.write_to_env(env_name)?;
|
current_out_map.shmem.write_to_env(env_name)?;
|
||||||
current_out_map.msg_to_env(self.last_msg_sent, env_name)
|
current_out_map.msg_to_env(self.last_msg_sent, env_name)
|
||||||
}
|
}
|
||||||
@ -731,6 +756,28 @@ where
|
|||||||
self.send(msg)
|
self.send(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe this cient in a way, that it can be restored later with `Self::on_existing_from_description`
|
||||||
|
pub fn describe(&self) -> Result<LlmpDescription, AflError> {
|
||||||
|
let map = self.out_maps.last().unwrap();
|
||||||
|
let last_message_offset = if self.last_msg_sent.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(map.msg_to_offset(self.last_msg_sent)?)
|
||||||
|
};
|
||||||
|
Ok(LlmpDescription {
|
||||||
|
shmem: map.shmem.description(),
|
||||||
|
last_message_offset,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create this client on an existing map from the given description. acquired with `self.describe`
|
||||||
|
pub fn on_existing_from_description(description: &LlmpDescription) -> Result<Self, AflError> {
|
||||||
|
Self::on_existing_map(
|
||||||
|
SH::existing_from_description(&description.shmem)?,
|
||||||
|
description.last_message_offset,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receiving end on a (unidirectional) sharedmap channel
|
/// Receiving end on a (unidirectional) sharedmap channel
|
||||||
@ -922,6 +969,28 @@ where
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe this cient in a way, that it can be restored later with `Self::on_existing_from_description`
|
||||||
|
pub fn describe(&self) -> Result<LlmpDescription, AflError> {
|
||||||
|
let map = &self.current_recv_map;
|
||||||
|
let last_message_offset = if self.last_msg_recvd.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(map.msg_to_offset(self.last_msg_recvd)?)
|
||||||
|
};
|
||||||
|
Ok(LlmpDescription {
|
||||||
|
shmem: map.shmem.description(),
|
||||||
|
last_message_offset,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create this client on an existing map from the given description. acquired with `self.describe`
|
||||||
|
pub fn on_existing_from_description(description: &LlmpDescription) -> Result<Self, AflError> {
|
||||||
|
Self::on_existing_map(
|
||||||
|
SH::existing_from_description(&description.shmem)?,
|
||||||
|
description.last_message_offset,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A page wrapper
|
/// A page wrapper
|
||||||
@ -1330,6 +1399,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A restorable client description
|
||||||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct LlmpClientDescription {
|
||||||
|
/// Description of the sender
|
||||||
|
sender: LlmpDescription,
|
||||||
|
/// Description of the receiver
|
||||||
|
receiver: LlmpDescription,
|
||||||
|
}
|
||||||
|
|
||||||
/// Client side of LLMP
|
/// Client side of LLMP
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct LlmpClient<SH>
|
pub struct LlmpClient<SH>
|
||||||
@ -1380,6 +1458,24 @@ where
|
|||||||
self.receiver.to_env(&format!("{}_RECEIVER", env_name))
|
self.receiver.to_env(&format!("{}_RECEIVER", env_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describe this client in a way that it can be recreated, for example after crash
|
||||||
|
fn describe(&self) -> Result<LlmpClientDescription, AflError> {
|
||||||
|
Ok(LlmpClientDescription {
|
||||||
|
sender: self.sender.describe()?,
|
||||||
|
receiver: self.receiver.describe()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an existing client from description
|
||||||
|
fn existing_client_from_description(
|
||||||
|
description: &LlmpClientDescription,
|
||||||
|
) -> Result<Self, AflError> {
|
||||||
|
Ok(Self {
|
||||||
|
sender: LlmpSender::on_existing_from_description(&description.sender)?,
|
||||||
|
receiver: LlmpReceiver::on_existing_from_description(&description.receiver)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Waits for the sender to be save to unmap.
|
/// Waits for the sender to be save to unmap.
|
||||||
/// If a receiver is involved on the other side, this function should always be called.
|
/// If a receiver is involved on the other side, this function should always be called.
|
||||||
pub fn await_save_to_unmap_blocking(&self) {
|
pub fn await_save_to_unmap_blocking(&self) {
|
||||||
|
@ -12,7 +12,7 @@ use core::{
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
llmp::{LlmpClient, Tag},
|
llmp::{LlmpClient, LlmpClientDescription, Tag},
|
||||||
shmem::ShMem,
|
shmem::ShMem,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -800,6 +800,25 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describe the client event mgr's llmp parts in a restorable fashion
|
||||||
|
pub fn describe(&self) -> Result<LlmpClientDescription, AflError> {
|
||||||
|
self.llmp.describe()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an existing client from description
|
||||||
|
pub fn existing_client_from_description(
|
||||||
|
description: &LlmpClientDescription,
|
||||||
|
stats: ST,
|
||||||
|
) -> Result<Self, AflError> {
|
||||||
|
Ok(Self {
|
||||||
|
llmp: llmp::LlmpConnection::existing_client_from_description(description)?,
|
||||||
|
// Inserting a nop-stats element here so rust won't complain.
|
||||||
|
// In any case, the client won't currently use it.
|
||||||
|
stats: stats,
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// A client on an existing map
|
/// A client on an existing map
|
||||||
pub fn for_client(client: LlmpClient<SH>, stats: ST) -> Self {
|
pub fn for_client(client: LlmpClient<SH>, stats: ST) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -860,6 +879,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send an event kind via llmp
|
||||||
#[inline]
|
#[inline]
|
||||||
fn send_event_kind<'a>(&mut self, event: LLMPEventKind<'a, I>) -> Result<(), AflError> {
|
fn send_event_kind<'a>(&mut self, event: LLMPEventKind<'a, I>) -> Result<(), AflError> {
|
||||||
let serialized = postcard::to_allocvec(&event)?;
|
let serialized = postcard::to_allocvec(&event)?;
|
||||||
|
@ -6,11 +6,22 @@ pub use shmem::AflShmem;
|
|||||||
|
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
|
/// Description of a shared map.
|
||||||
|
/// May be used to restore the map by id.
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct ShMemDescription {
|
||||||
|
/// Size of this map
|
||||||
|
size: usize,
|
||||||
|
/// of name of this map, as fixed 20 bytes c-string
|
||||||
|
str_bytes: [u8; 20],
|
||||||
|
}
|
||||||
|
|
||||||
/// A Shared map
|
/// A Shared map
|
||||||
pub trait ShMem: Sized + Debug {
|
pub trait ShMem: Sized + Debug {
|
||||||
/// Creates a new map with the given size
|
/// Creates a new map with the given size
|
||||||
@ -52,6 +63,19 @@ pub trait ShMem: Sized + Debug {
|
|||||||
/// The actual shared map, mutable
|
/// The actual shared map, mutable
|
||||||
fn map_mut(&mut self) -> &mut [u8];
|
fn map_mut(&mut self) -> &mut [u8];
|
||||||
|
|
||||||
|
/// Describe this shared map in a recreatable fashion
|
||||||
|
fn description(&self) -> ShMemDescription {
|
||||||
|
ShMemDescription {
|
||||||
|
size: self.map().len(),
|
||||||
|
str_bytes: self.shm_slice().clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a map from a map description
|
||||||
|
fn existing_from_description(description: &ShMemDescription) -> Result<Self, AflError> {
|
||||||
|
Self::existing_from_shm_slice(&description.str_bytes, description.size)
|
||||||
|
}
|
||||||
|
|
||||||
/// Write this map's config to env
|
/// Write this map's config to env
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
fn write_to_env(&self, env_name: &str) -> Result<(), AflError> {
|
fn write_to_env(&self, env_name: &str) -> Result<(), AflError> {
|
||||||
|
@ -8,10 +8,65 @@ use xxhash_rust::xxh3::xxh3_64_with_seed;
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use crate::{corpus::Corpus, engines::State, feedbacks::FeedbacksTuple, inputs::Input, AflError};
|
use crate::{
|
||||||
|
corpus::Corpus,
|
||||||
|
engines::State,
|
||||||
|
events::{shmem::ShMem, LlmpEventManager, Stats},
|
||||||
|
feedbacks::FeedbacksTuple,
|
||||||
|
inputs::Input,
|
||||||
|
AflError,
|
||||||
|
};
|
||||||
|
|
||||||
pub type StdRand = RomuTrioRand;
|
pub type StdRand = RomuTrioRand;
|
||||||
|
|
||||||
|
/// Serialize the current state and corpus during an executiont to bytes.
|
||||||
|
/// On top, add the current llmp event manager instance to be restored
|
||||||
|
/// This method is needed when the fuzzer run crashes and has to restart.
|
||||||
|
pub fn serialize_state_corpus_mgr<C, FT, I, R, SH, ST>(
|
||||||
|
state: &State<I, R, FT>,
|
||||||
|
corpus: &C,
|
||||||
|
mgr: &LlmpEventManager<I, SH, ST>,
|
||||||
|
) -> Result<Vec<u8>, AflError>
|
||||||
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
SH: ShMem,
|
||||||
|
ST: Stats,
|
||||||
|
{
|
||||||
|
let mgr_bytes = postcard::to_allocvec(&mgr.describe()?)?;
|
||||||
|
let state_bytes = postcard::to_allocvec(&state)?;
|
||||||
|
let corpus_bytes = postcard::to_allocvec(&corpus)?;
|
||||||
|
Ok(postcard::to_allocvec(&(
|
||||||
|
state_bytes,
|
||||||
|
corpus_bytes,
|
||||||
|
mgr_bytes,
|
||||||
|
))?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)`
|
||||||
|
pub fn deserialize_state_corpus_mgr<C, FT, I, R, SH, ST>(
|
||||||
|
state_corpus_serialized: &[u8],
|
||||||
|
stats: ST,
|
||||||
|
) -> Result<(State<I, R, FT>, C, LlmpEventManager<I, SH, ST>), AflError>
|
||||||
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
SH: ShMem,
|
||||||
|
ST: Stats,
|
||||||
|
{
|
||||||
|
let tuple: (Vec<u8>, Vec<u8>, Vec<u8>) = postcard::from_bytes(&state_corpus_serialized)?;
|
||||||
|
let client_description = postcard::from_bytes(&tuple.2)?;
|
||||||
|
Ok((
|
||||||
|
postcard::from_bytes(&tuple.0)?,
|
||||||
|
postcard::from_bytes(&tuple.1)?,
|
||||||
|
LlmpEventManager::existing_client_from_description(&client_description, stats)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
/// Serialize the current state and corpus during an executiont to bytes.
|
/// Serialize the current state and corpus during an executiont to bytes.
|
||||||
/// This method is needed when the fuzzer run crashes and has to restart.
|
/// This method is needed when the fuzzer run crashes and has to restart.
|
||||||
pub fn serialize_state_corpus<C, FT, I, R>(
|
pub fn serialize_state_corpus<C, FT, I, R>(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user