pub const COVERAGE_MAP_SIZE: usize = 1024;
pub struct CoverageBitmap {
ptr: *mut u8,
}
impl CoverageBitmap {
pub unsafe fn new(ptr: *mut u8) -> Self {
Self { ptr }
}
pub fn set_bit(&self, index: usize) {
let bit_index = index % (COVERAGE_MAP_SIZE * 8);
let byte = bit_index / 8;
let bit = bit_index % 8;
unsafe {
*self.ptr.add(byte) |= 1 << bit;
}
}
pub fn clear(&self) {
unsafe {
std::ptr::write_bytes(self.ptr, 0, COVERAGE_MAP_SIZE);
}
}
pub fn as_ptr(&self) -> *const u8 {
self.ptr
}
}
pub struct ExploredMap {
ptr: *mut u8,
}
impl ExploredMap {
pub unsafe fn new(ptr: *mut u8) -> Self {
Self { ptr }
}
pub fn merge_from(&self, other: &CoverageBitmap) {
unsafe {
for i in 0..COVERAGE_MAP_SIZE {
*self.ptr.add(i) |= *other.as_ptr().add(i);
}
}
}
pub fn count_bits_set(&self) -> u32 {
let mut count: u32 = 0;
unsafe {
for i in 0..COVERAGE_MAP_SIZE {
count += (*self.ptr.add(i)).count_ones();
}
}
count
}
pub fn has_new_bits(&self, other: &CoverageBitmap) -> bool {
unsafe {
for i in 0..COVERAGE_MAP_SIZE {
let explored = *self.ptr.add(i);
let child = *other.as_ptr().add(i);
if (child & !explored) != 0 {
return true;
}
}
}
false
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::shared_mem;
#[test]
fn test_set_bit_and_check() {
let ptr = shared_mem::alloc_shared(COVERAGE_MAP_SIZE).expect("alloc failed");
let explored_ptr = shared_mem::alloc_shared(COVERAGE_MAP_SIZE).expect("alloc failed");
let bm = unsafe { CoverageBitmap::new(ptr) };
let vm = unsafe { ExploredMap::new(explored_ptr) };
assert!(!vm.has_new_bits(&bm));
bm.set_bit(42);
assert!(vm.has_new_bits(&bm));
vm.merge_from(&bm);
assert!(!vm.has_new_bits(&bm));
unsafe {
shared_mem::free_shared(ptr, COVERAGE_MAP_SIZE);
shared_mem::free_shared(explored_ptr, COVERAGE_MAP_SIZE);
}
}
#[test]
fn test_clear() {
let ptr = shared_mem::alloc_shared(COVERAGE_MAP_SIZE).expect("alloc failed");
let bm = unsafe { CoverageBitmap::new(ptr) };
bm.set_bit(0);
bm.set_bit(100);
bm.set_bit(8000);
bm.clear();
unsafe {
for i in 0..COVERAGE_MAP_SIZE {
assert_eq!(*ptr.add(i), 0);
}
shared_mem::free_shared(ptr, COVERAGE_MAP_SIZE);
}
}
#[test]
fn test_merge_accumulates() {
let bm1_ptr = shared_mem::alloc_shared(COVERAGE_MAP_SIZE).expect("alloc failed");
let bm2_ptr = shared_mem::alloc_shared(COVERAGE_MAP_SIZE).expect("alloc failed");
let vm_ptr = shared_mem::alloc_shared(COVERAGE_MAP_SIZE).expect("alloc failed");
let bm1 = unsafe { CoverageBitmap::new(bm1_ptr) };
let bm2 = unsafe { CoverageBitmap::new(bm2_ptr) };
let vm = unsafe { ExploredMap::new(vm_ptr) };
bm1.set_bit(10);
bm2.set_bit(20);
vm.merge_from(&bm1);
assert!(vm.has_new_bits(&bm2));
vm.merge_from(&bm2);
assert!(!vm.has_new_bits(&bm1));
assert!(!vm.has_new_bits(&bm2));
unsafe {
shared_mem::free_shared(bm1_ptr, COVERAGE_MAP_SIZE);
shared_mem::free_shared(bm2_ptr, COVERAGE_MAP_SIZE);
shared_mem::free_shared(vm_ptr, COVERAGE_MAP_SIZE);
}
}
#[test]
fn test_count_bits_set() {
let vm_ptr = shared_mem::alloc_shared(COVERAGE_MAP_SIZE).expect("alloc failed");
let bm_ptr = shared_mem::alloc_shared(COVERAGE_MAP_SIZE).expect("alloc failed");
let vm = unsafe { ExploredMap::new(vm_ptr) };
let bm = unsafe { CoverageBitmap::new(bm_ptr) };
assert_eq!(vm.count_bits_set(), 0);
bm.set_bit(0);
bm.set_bit(42);
bm.set_bit(8000);
vm.merge_from(&bm);
assert_eq!(vm.count_bits_set(), 3);
unsafe {
shared_mem::free_shared(vm_ptr, COVERAGE_MAP_SIZE);
shared_mem::free_shared(bm_ptr, COVERAGE_MAP_SIZE);
}
}
}