#![no_main] use libfuzzer_sys::fuzz_target; use announcement::Announcement; use std::sync::{Arc, Barrier}; use std::thread; fuzz_target!(|data: &[u8]| { if data.len() < 4 { return; } // Extract test parameters from fuzz data let num_threads = (data[0] % 8) as usize + 2; // 2-9 threads let announce_delay = data[1] % 3; // 0-2 delay pattern let pattern = data[2] % 4; match pattern { 0 => { // Test concurrent listeners let (announcer, announcement) = Announcement::new(); let barrier = Arc::new(Barrier::new(num_threads + 1)); let handles: Vec<_> = (0..num_threads) .map(|i| { let listener = announcement.listener(); let barrier = barrier.clone(); thread::spawn(move || { // Synchronize start barrier.wait(); // All threads try to listen let value = listener.try_listen(); // Return thread id and value (i, value) }) }) .collect(); // Start all threads together barrier.wait(); // Announce after threads are started match announce_delay { 0 => { // Immediate announce let _ = announcer.announce(42u32); } 1 => { // Short delay thread::sleep(std::time::Duration::from_micros(10)); let _ = announcer.announce(42u32); } _ => { // Drop without announcing drop(announcer); } } // Collect results for handle in handles { let (id, value) = handle.join().unwrap(); if announce_delay < 2 { // Should get value if we announced // (might be None if thread checked before announce) if let Some(v) = value { assert_eq!(v, 42u32, "Thread {} got wrong value", id); } } } } 1 => { // Test concurrent clone and listener creation let (announcer, announcement) = Announcement::new(); let handles: Vec<_> = (0..num_threads) .map(|_| { let ann_clone = announcement.clone(); thread::spawn(move || { // Create listener from clone let listener = ann_clone.listener(); // Try to read listener.try_listen() }) }) .collect(); // Announce while threads are creating listeners let _ = announcer.announce(42u32); // All should eventually see the value for handle in handles { let value = handle.join().unwrap(); // May or may not have seen the value depending on timing if let Some(v) = value { assert_eq!(v, 42u32); } } } 2 => { // Test concurrent is_announced checks let (announcer, announcement) = Announcement::new(); let handles: Vec<_> = (0..num_threads) .map(|_| { let ann_clone = announcement.clone(); thread::spawn(move || { // Check announced state multiple times let mut states = vec![]; for _ in 0..10 { states.push(ann_clone.is_announced()); } states }) }) .collect(); // Announce in the middle thread::sleep(std::time::Duration::from_micros(5)); let _ = announcer.announce(42u32); // Collect all state observations for handle in handles { let states = handle.join().unwrap(); // States should only transition from false to true, never back let mut seen_true = false; for state in states { if seen_true { assert!(state, "is_announced went from true to false"); } if state { seen_true = true; } } } } _ => { // Test concurrent close checks let (announcer, announcement) = Announcement::::new(); let handles: Vec<_> = (0..num_threads) .map(|_| { let ann_clone = announcement.clone(); thread::spawn(move || { // Check closed state multiple times let mut states = vec![]; for _ in 0..10 { states.push(ann_clone.is_closed()); } states }) }) .collect(); // Close in the middle thread::sleep(std::time::Duration::from_micros(5)); announcer.close(); // Collect all state observations for handle in handles { let states = handle.join().unwrap(); // States should only transition from false to true, never back let mut seen_true = false; for state in states { if seen_true { assert!(state, "is_closed went from true to false"); } if state { seen_true = true; } } } } } });