CI: Run miri tests (#1130)
* Fixes/ignores for miri support * linux * fix doctest for miri * fix docs * fix UB in baby_fuzzer * no custom allocator in miri
This commit is contained in:
parent
e8838ebebe
commit
2ed6583041
6
.github/workflows/build_and_test.yml
vendored
6
.github/workflows/build_and_test.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
||||
- name: get clang version
|
||||
run: command -v llvm-config && clang -v
|
||||
- name: Add nightly rustfmt and clippy
|
||||
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
||||
run: rustup toolchain install nightly --component rustfmt --component clippy --component miri --allow-downgrade
|
||||
- uses: actions/checkout@v3
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
@ -99,6 +99,10 @@ jobs:
|
||||
- name: Build examples
|
||||
run: cargo build --examples --verbose
|
||||
|
||||
# --- miri undefined behavior test --
|
||||
- name: Run miri tests
|
||||
run: RUST_BACKTRACE=1 MIRIFLAGS="-Zmiri-disable-isolation" cargo +nightly miri test
|
||||
|
||||
ubuntu-check:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -21,6 +21,7 @@ vendor
|
||||
*.obj
|
||||
|
||||
.cur_input
|
||||
.cur_input_*
|
||||
.venv
|
||||
|
||||
crashes
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
#[cfg(windows)]
|
||||
use std::ptr::write_volatile;
|
||||
use std::{path::PathBuf, ptr::write};
|
||||
|
||||
#[cfg(feature = "tui")]
|
||||
use libafl::monitors::tui::TuiMonitor;
|
||||
@ -24,10 +24,11 @@ use libafl::{
|
||||
|
||||
/// Coverage map with explicit assignments due to the lack of instrumentation
|
||||
static mut SIGNALS: [u8; 16] = [0; 16];
|
||||
static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() };
|
||||
|
||||
/// Assign a signal to the signals map
|
||||
fn signals_set(idx: usize) {
|
||||
unsafe { SIGNALS[idx] = 1 };
|
||||
unsafe { write(SIGNALS_PTR.add(idx), 1) };
|
||||
}
|
||||
|
||||
#[allow(clippy::similar_names, clippy::manual_assert)]
|
||||
@ -60,8 +61,7 @@ pub fn main() {
|
||||
};
|
||||
|
||||
// Create an observation channel using the signals map
|
||||
let observer =
|
||||
unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS.as_mut_ptr(), SIGNALS.len()) };
|
||||
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) };
|
||||
|
||||
// Feedback to rate the interestingness of an input
|
||||
let mut feedback = MaxMapFeedback::new(&observer);
|
||||
|
@ -25,9 +25,11 @@ use libafl::{
|
||||
state::{HasSolutions, StdState},
|
||||
};
|
||||
use libafl_targets::{DifferentialAFLMapSwapObserver, MAX_EDGES_NUM};
|
||||
#[cfg(not(miri))]
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[global_allocator]
|
||||
#[cfg(not(miri))]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
// bindings to the functions defined in the target
|
||||
|
@ -5,14 +5,15 @@
|
||||
//! This example shows how create a thread for each available processor and pin each thread to its corresponding processor.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use std::thread;
|
||||
//! use libafl::bolts::core_affinity;
|
||||
//!
|
||||
//! use std::thread;
|
||||
//!
|
||||
//! // Retrieve the IDs of all active CPU cores.
|
||||
//! # #[cfg(not(miri))]
|
||||
//! let core_ids = core_affinity::get_core_ids().unwrap();
|
||||
//!
|
||||
//! // Create a thread for each active CPU core.
|
||||
//! # #[cfg(not(miri))]
|
||||
//! let handles = core_ids.into_iter().map(|id| {
|
||||
//! thread::spawn(move || {
|
||||
//! // Pin this thread to a single CPU core.
|
||||
@ -21,6 +22,7 @@
|
||||
//! })
|
||||
//! }).collect::<Vec<_>>();
|
||||
//!
|
||||
//! # #[cfg(not(miri))]
|
||||
//! for handle in handles.into_iter() {
|
||||
//! handle.join().unwrap();
|
||||
//! }
|
||||
@ -307,11 +309,13 @@ mod linux {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_linux_get_affinity_mask() {
|
||||
get_affinity_mask().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_linux_set_for_current() {
|
||||
let ids = get_core_ids().unwrap();
|
||||
|
||||
@ -558,7 +562,7 @@ mod apple {
|
||||
thread_policy_flavor_t, thread_policy_t, thread_t, KERN_SUCCESS, THREAD_AFFINITY_POLICY,
|
||||
THREAD_AFFINITY_POLICY_COUNT,
|
||||
};
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[cfg(all(target_arch = "aarch64", not(miri)))]
|
||||
use libc::{pthread_set_qos_class_self_np, qos_class_t::QOS_CLASS_USER_INITIATED};
|
||||
|
||||
use super::CoreId;
|
||||
@ -622,6 +626,7 @@ mod apple {
|
||||
//
|
||||
// Furthermore, this seems to fail on background threads, so we ignore errors (result != 0).
|
||||
|
||||
#[cfg(not(miri))]
|
||||
unsafe {
|
||||
let _result = pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, 0);
|
||||
}
|
||||
@ -902,12 +907,14 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_get_core_ids() {
|
||||
let set = get_core_ids().unwrap();
|
||||
assert_eq!(set.len(), usize::from(available_parallelism().unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_set_affinity() {
|
||||
let ids = get_core_ids().unwrap();
|
||||
|
||||
|
@ -96,10 +96,10 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::bolts::current_time;
|
||||
#[cfg(all(unix, not(miri)))]
|
||||
use crate::bolts::os::unix_signals::setup_signal_handler;
|
||||
#[cfg(unix)]
|
||||
use crate::bolts::os::unix_signals::{
|
||||
setup_signal_handler, siginfo_t, ucontext_t, Handler, Signal,
|
||||
};
|
||||
use crate::bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal};
|
||||
use crate::{
|
||||
bolts::{
|
||||
shmem::{ShMem, ShMemDescription, ShMemId, ShMemProvider},
|
||||
@ -2190,7 +2190,7 @@ where
|
||||
{
|
||||
use super::current_milliseconds;
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(miri)))]
|
||||
if let Err(_e) = unsafe { setup_signal_handler(&mut LLMP_SIGHANDLER_STATE) } {
|
||||
// We can live without a proper ctrl+c signal handler. Print and ignore.
|
||||
log::info!("Failed to setup signal handlers: {_e}");
|
||||
@ -2254,7 +2254,7 @@ where
|
||||
where
|
||||
F: FnMut(ClientId, Tag, Flags, &[u8]) -> Result<LlmpMsgHookResult, Error>,
|
||||
{
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(miri)))]
|
||||
if let Err(_e) = unsafe { setup_signal_handler(&mut LLMP_SIGHANDLER_STATE) } {
|
||||
// We can live without a proper ctrl+c signal handler. Print and ignore.
|
||||
log::info!("Failed to setup signal handlers: {_e}");
|
||||
@ -3100,6 +3100,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
pub fn test_llmp_connection() {
|
||||
#[allow(unused_variables)]
|
||||
let shmem_provider = StdShMemProvider::new().unwrap();
|
||||
|
@ -635,6 +635,7 @@ mod tests {
|
||||
use crate::bolts::{minibsod::dump_registers, os::unix_signals::ucontext};
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
pub fn test_dump_registers() {
|
||||
let ucontext = ucontext().unwrap();
|
||||
let mut writer = BufWriter::new(stdout());
|
||||
|
@ -380,7 +380,9 @@ unsafe fn handle_signal(sig: c_int, info: siginfo_t, void: *mut c_void) {
|
||||
/// This will allocate a signal stack and set the signal handlers accordingly.
|
||||
/// It is, for example, used in the [`type@crate::executors::InProcessExecutor`] to restart the fuzzer in case of a crash,
|
||||
/// or to handle `SIGINT` in the broker process.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The signal handlers will be called on any signal. They should (tm) be async safe.
|
||||
/// A lot can go south in signal handling. Be sure you know what you are doing.
|
||||
pub unsafe fn setup_signal_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> {
|
||||
|
@ -1472,6 +1472,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_shmem_service() {
|
||||
let mut provider = StdShMemProvider::new().unwrap();
|
||||
let mut map = provider.new_shmem(1024).unwrap();
|
||||
|
@ -301,6 +301,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_state_restore() {
|
||||
const TESTMAP_SIZE: usize = 1024;
|
||||
|
||||
|
@ -22,6 +22,8 @@ use super::{CustomBufEventResult, CustomBufHandlerFn};
|
||||
use crate::bolts::core_affinity::CoreId;
|
||||
#[cfg(all(feature = "std", any(windows, not(feature = "fork"))))]
|
||||
use crate::bolts::os::startable_self;
|
||||
#[cfg(all(unix, feature = "std", not(miri)))]
|
||||
use crate::bolts::os::unix_signals::setup_signal_handler;
|
||||
#[cfg(all(feature = "std", feature = "fork", unix))]
|
||||
use crate::bolts::os::{fork, ForkResult};
|
||||
#[cfg(feature = "llmp_compression")]
|
||||
@ -32,10 +34,7 @@ use crate::bolts::{
|
||||
#[cfg(feature = "std")]
|
||||
use crate::bolts::{llmp::LlmpConnection, shmem::StdShMemProvider, staterestore::StateRestorer};
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
use crate::{
|
||||
bolts::os::unix_signals::setup_signal_handler,
|
||||
events::{shutdown_handler, SHUTDOWN_SIGHANDLER_DATA},
|
||||
};
|
||||
use crate::events::{shutdown_handler, SHUTDOWN_SIGHANDLER_DATA};
|
||||
use crate::{
|
||||
bolts::{
|
||||
llmp::{self, LlmpClient, LlmpClientDescription, Tag},
|
||||
@ -992,7 +991,7 @@ where
|
||||
}
|
||||
|
||||
// We setup signal handlers to clean up shmem segments used by state restorer
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(miri)))]
|
||||
if let Err(_e) = unsafe { setup_signal_handler(&mut SHUTDOWN_SIGHANDLER_DATA) } {
|
||||
// We can live without a proper ctrl+c signal handler. Print and ignore.
|
||||
log::error!("Failed to setup signal handlers: {_e}");
|
||||
@ -1474,6 +1473,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_mgr_state_restore() {
|
||||
let rand = StdRand::with_seed(0);
|
||||
|
||||
|
@ -19,13 +19,12 @@ use serde::{de::DeserializeOwned, Serialize};
|
||||
use super::{CustomBufEventResult, CustomBufHandlerFn, HasCustomBufHandlers, ProgressReporter};
|
||||
#[cfg(all(feature = "std", any(windows, not(feature = "fork"))))]
|
||||
use crate::bolts::os::startable_self;
|
||||
#[cfg(all(unix, feature = "std", not(miri)))]
|
||||
use crate::bolts::os::unix_signals::setup_signal_handler;
|
||||
#[cfg(all(feature = "std", feature = "fork", unix))]
|
||||
use crate::bolts::os::{fork, ForkResult};
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
use crate::{
|
||||
bolts::os::unix_signals::setup_signal_handler,
|
||||
events::{shutdown_handler, SHUTDOWN_SIGHANDLER_DATA},
|
||||
};
|
||||
use crate::events::{shutdown_handler, SHUTDOWN_SIGHANDLER_DATA};
|
||||
use crate::{
|
||||
bolts::ClientId,
|
||||
events::{
|
||||
@ -472,7 +471,7 @@ where
|
||||
}
|
||||
|
||||
// We setup signal handlers to clean up shmem segments used by state restorer
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(miri)))]
|
||||
if let Err(_e) = unsafe { setup_signal_handler(&mut SHUTDOWN_SIGHANDLER_DATA) } {
|
||||
// We can live without a proper ctrl+c signal handler. Print and ignore.
|
||||
log::error!("Failed to setup signal handlers: {_e}");
|
||||
|
@ -656,6 +656,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_builder() {
|
||||
let mut mgr = SimpleEventManager::new(SimpleMonitor::new(|status| {
|
||||
log::info!("{status}");
|
||||
@ -680,6 +681,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_parse_afl_cmdline() {
|
||||
use alloc::string::ToString;
|
||||
|
||||
|
@ -1283,6 +1283,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_forkserver() {
|
||||
const MAP_SIZE: usize = 65536;
|
||||
let bin = OsString::from("echo");
|
||||
|
@ -35,7 +35,7 @@ use nix::{
|
||||
#[cfg(windows)]
|
||||
use windows::Win32::System::Threading::SetThreadStackGuarantee;
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(miri)))]
|
||||
use crate::bolts::os::unix_signals::setup_signal_handler;
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
use crate::bolts::os::unix_signals::{ucontext_t, Handler, Signal};
|
||||
@ -348,10 +348,12 @@ impl InProcessHandlers {
|
||||
Z: HasObjective<Objective = OF, State = E::State>,
|
||||
{
|
||||
#[cfg(unix)]
|
||||
#[cfg_attr(miri, allow(unused_variables))]
|
||||
unsafe {
|
||||
let data = &mut GLOBAL_STATE;
|
||||
#[cfg(feature = "std")]
|
||||
unix_signal_handler::setup_panic_hook::<E, EM, OF, Z>();
|
||||
#[cfg(not(miri))]
|
||||
setup_signal_handler(data)?;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
Ok(Self {
|
||||
@ -1284,9 +1286,11 @@ impl InChildProcessHandlers {
|
||||
where
|
||||
E: HasObservers,
|
||||
{
|
||||
#[cfg_attr(miri, allow(unused_variables))]
|
||||
unsafe {
|
||||
let data = &mut FORK_EXECUTOR_GLOBAL_DATA;
|
||||
// child_signal_handlers::setup_child_panic_hook::<E, I, OT, S>();
|
||||
#[cfg(not(miri))]
|
||||
setup_signal_handler(data)?;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
Ok(Self {
|
||||
@ -1301,9 +1305,11 @@ impl InChildProcessHandlers {
|
||||
where
|
||||
E: HasObservers,
|
||||
{
|
||||
#[cfg_attr(miri, allow(unused_variables))]
|
||||
unsafe {
|
||||
let data = &mut FORK_EXECUTOR_GLOBAL_DATA;
|
||||
// child_signal_handlers::setup_child_panic_hook::<E, I, OT, S>();
|
||||
#[cfg(not(miri))]
|
||||
setup_signal_handler(data)?;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
Ok(Self {
|
||||
@ -2075,6 +2081,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
#[cfg(all(feature = "std", feature = "fork", unix))]
|
||||
fn test_inprocessfork_exec() {
|
||||
use crate::{
|
||||
|
@ -519,6 +519,9 @@ mod tests {
|
||||
fuzzer
|
||||
.fuzz_one(&mut stages, &mut executor, &mut state, &mut event_manager)
|
||||
.unwrap_or_else(|_| panic!("Error in iter {i}"));
|
||||
if cfg!(miri) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let state_serialized = postcard::to_allocvec(&state).unwrap();
|
||||
|
@ -1253,6 +1253,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // testing all mutators would be good but is way too slow. :/
|
||||
fn test_mutators() {
|
||||
let mut inputs = vec![
|
||||
BytesInput::new(vec![0x13, 0x37]),
|
||||
@ -1267,6 +1268,7 @@ mod tests {
|
||||
let mut state = test_state();
|
||||
|
||||
let mut mutations = test_mutations();
|
||||
|
||||
for _ in 0..2 {
|
||||
let mut new_testcases = vec![];
|
||||
for idx in 0..(mutations.len()) {
|
||||
@ -1294,7 +1296,10 @@ mod tests {
|
||||
let mut state = test_state();
|
||||
let mut mutator = BytesDeleteMutator::new();
|
||||
|
||||
for _ in 0..100000 {
|
||||
// If we're running in miri, we have to make this test a _lot_ shorter.
|
||||
let iters = if cfg!(miri) { 100 } else { 100_000 };
|
||||
|
||||
for _ in 0..iters {
|
||||
let mut mutated = base.clone();
|
||||
if mutator.mutate(&mut state, &mut mutated, 0)? == MutationResult::Skipped {
|
||||
continue;
|
||||
@ -1345,7 +1350,10 @@ mod tests {
|
||||
let mut state = test_state();
|
||||
let mut mutator = BytesExpandMutator::new();
|
||||
|
||||
for _ in 0..100000 {
|
||||
// If we're running in miri, we have to make this test a _lot_ shorter.
|
||||
let iters = if cfg!(miri) { 100 } else { 100_000 };
|
||||
|
||||
for _ in 0..iters {
|
||||
let mut mutated = base.clone();
|
||||
if mutator.mutate(&mut state, &mut mutated, 0)? == MutationResult::Skipped {
|
||||
continue;
|
||||
@ -1390,7 +1398,10 @@ mod tests {
|
||||
let mut state = test_state();
|
||||
let mut mutator = BytesInsertMutator::new();
|
||||
|
||||
for _ in 0..100000 {
|
||||
// If we're running in miri, we have to make this test a _lot_ shorter.
|
||||
let iters = if cfg!(miri) { 100 } else { 100_000 };
|
||||
|
||||
for _ in 0..iters {
|
||||
let mut mutated = base.clone();
|
||||
if mutator.mutate(&mut state, &mut mutated, 0)? == MutationResult::Skipped {
|
||||
continue;
|
||||
@ -1436,7 +1447,10 @@ mod tests {
|
||||
let mut state = test_state();
|
||||
let mut mutator = BytesRandInsertMutator::new();
|
||||
|
||||
for _ in 0..100000 {
|
||||
// If we're running in miri, we have to make this test a _lot_ shorter.
|
||||
let iters = if cfg!(miri) { 100 } else { 100_000 };
|
||||
|
||||
for _ in 0..iters {
|
||||
let mut mutated = base.clone();
|
||||
if mutator.mutate(&mut state, &mut mutated, 0)? == MutationResult::Skipped {
|
||||
continue;
|
||||
|
@ -362,6 +362,7 @@ mod tests {
|
||||
const TEST_GRAPH_STR: &str = "$$main+41864\n$$_ZN7MyClass1VEi+50306\n%%_ZN7MyClass1VEi+50306\n->19123\n%%main+41864\n->52706\n->26911\n%%main+52706\n%%main+26911\n->52706\n->41925\n";
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Testcase takes long in miri.
|
||||
fn test_basic_cfg_from_str() {
|
||||
let cfg: ControlFlowGraph<TestMetaData> = ControlFlowGraph::from_content(TEST_GRAPH_STR);
|
||||
let entry = cfg.get_entry("main").unwrap();
|
||||
@ -391,6 +392,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Testcase takes too long in miri. :/
|
||||
fn test_shortest_path() {
|
||||
let cfg: ControlFlowGraph<TestMetaData> = ControlFlowGraph::from_content(TEST_GRAPH_STR);
|
||||
let distances = cfg.calculate_distances_to_all_edges((41864 >> 1) ^ 26911);
|
||||
|
@ -470,6 +470,7 @@ mod tests {
|
||||
use crate::{ClangWrapper, CompilerWrapper};
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_clang_version() {
|
||||
if let Err(res) = ClangWrapper::new()
|
||||
.parse_args(&["my-clang", "-v"])
|
||||
|
Loading…
x
Reference in New Issue
Block a user