mirror of
https://github.com/PatchRequest/BusyWork
synced 2026-06-09 16:04:04 +00:00
Add inter-task data chaining, work data in all 84 tasks, and COM/WMI category
Inter-task chaining: a 256-byte ScratchBuffer flows through all tasks in a single run() call. Each task reads from it (blend_into) and writes back results (absorb), creating a data-dependency chain where task N's output influences task N+1's computation. An analyzer can no longer identify individual tasks as isolated blocks. Work data in all tasks: all 84 tasks now actively consume fed work data. Filesystem tasks derive skip offsets and iteration biases from work data. Registry tasks bias subkey/value enumeration counts. WinAPI tasks offset starting indices for window/process/metric enumeration. Network tasks select starting host indices and blend work data into response buffers. New COM/WMI category (8 tasks): WQL queries against Win32_Process, Win32_OperatingSystem, Win32_ComputerSystem, Win32_NetworkAdapterConfiguration, Win32_LogicalDisk, Win32_Service, Win32_BIOS, and Win32_Processor. All read-only. Uses COM automation with CoInitializeSecurity for reliable initialization across apartment models. 84 tasks across 8 categories. All 182 tests pass.
This commit is contained in:
@@ -29,6 +29,7 @@ default = [
|
||||
"cat-winapi",
|
||||
"cat-network",
|
||||
"cat-crypto",
|
||||
"cat-com",
|
||||
]
|
||||
cat-compute = ["dep:sha2", "dep:md-5", "dep:flate2"]
|
||||
cat-memory = []
|
||||
@@ -56,6 +57,14 @@ cat-crypto = [
|
||||
"windows/Win32_Security_Cryptography",
|
||||
"windows/Win32_Foundation",
|
||||
]
|
||||
cat-com = [
|
||||
"dep:windows",
|
||||
"windows/Win32_System_Com",
|
||||
"windows/Win32_System_Wmi",
|
||||
"windows/Win32_Foundation",
|
||||
"windows/Win32_System_Ole",
|
||||
"windows/Win32_System_Variant",
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8"
|
||||
|
||||
+12
-7
@@ -3,13 +3,14 @@ use bitflags::bitflags;
|
||||
bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Categories: u32 {
|
||||
const COMPUTE = 0b000_0001;
|
||||
const MEMORY = 0b000_0010;
|
||||
const FILESYSTEM = 0b000_0100;
|
||||
const REGISTRY = 0b000_1000;
|
||||
const WINAPI = 0b001_0000;
|
||||
const NETWORK = 0b010_0000;
|
||||
const CRYPTO = 0b100_0000;
|
||||
const COMPUTE = 0b0000_0001;
|
||||
const MEMORY = 0b0000_0010;
|
||||
const FILESYSTEM = 0b0000_0100;
|
||||
const REGISTRY = 0b0000_1000;
|
||||
const WINAPI = 0b0001_0000;
|
||||
const NETWORK = 0b0010_0000;
|
||||
const CRYPTO = 0b0100_0000;
|
||||
const COM = 0b1000_0000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +45,10 @@ impl Categories {
|
||||
{
|
||||
cats |= Self::CRYPTO;
|
||||
}
|
||||
#[cfg(feature = "cat-com")]
|
||||
{
|
||||
cats |= Self::COM;
|
||||
}
|
||||
cats
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -1,12 +1,15 @@
|
||||
use crate::categories::Categories;
|
||||
use crate::intensity::Intensity;
|
||||
use crate::jitter;
|
||||
use crate::tasks::{self, TaskParams};
|
||||
use crate::tasks::{self, ScratchBuffer, TaskParams};
|
||||
use crate::workdata::WorkData;
|
||||
use rand::seq::SliceRandom;
|
||||
|
||||
pub fn execute(intensity: Intensity, effective: Categories, jitter_enabled: bool, work_data: &WorkData) {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut scratch = ScratchBuffer::new();
|
||||
scratch.seed_from(work_data);
|
||||
|
||||
let all = tasks::all_tasks();
|
||||
let eligible: Vec<_> = all
|
||||
.iter()
|
||||
@@ -43,6 +46,6 @@ pub fn execute(intensity: Intensity, effective: Categories, jitter_enabled: bool
|
||||
base.call_depth
|
||||
},
|
||||
};
|
||||
(task.func)(¶ms, &mut rng, work_data);
|
||||
(task.func)(¶ms, &mut rng, work_data, &mut scratch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
use crate::categories::Categories;
|
||||
use crate::tasks::{ScratchBuffer, TaskDescriptor, TaskParams};
|
||||
use crate::workdata::WorkData;
|
||||
use rand::rngs::ThreadRng;
|
||||
use std::hint::black_box;
|
||||
use windows::core::BSTR;
|
||||
use windows::Win32::System::Com::*;
|
||||
use windows::Win32::System::Wmi::*;
|
||||
|
||||
pub fn register() -> Vec<TaskDescriptor> {
|
||||
vec![
|
||||
TaskDescriptor { name: "wmi_processes", category: Categories::COM, func: wmi_processes },
|
||||
TaskDescriptor { name: "wmi_os_info", category: Categories::COM, func: wmi_os_info },
|
||||
TaskDescriptor { name: "wmi_computer_system", category: Categories::COM, func: wmi_computer_system },
|
||||
TaskDescriptor { name: "wmi_network_adapters", category: Categories::COM, func: wmi_network_adapters },
|
||||
TaskDescriptor { name: "wmi_logical_disks", category: Categories::COM, func: wmi_logical_disks },
|
||||
TaskDescriptor { name: "wmi_services", category: Categories::COM, func: wmi_services },
|
||||
TaskDescriptor { name: "wmi_bios_info", category: Categories::COM, func: wmi_bios_info },
|
||||
TaskDescriptor { name: "wmi_processor_info", category: Categories::COM, func: wmi_processor_info },
|
||||
]
|
||||
}
|
||||
|
||||
unsafe fn init_com() -> bool {
|
||||
let hr = CoInitializeEx(None, COINIT_MULTITHREADED);
|
||||
if hr.is_err() {
|
||||
let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED);
|
||||
}
|
||||
let _ = CoInitializeSecurity(
|
||||
None,
|
||||
-1,
|
||||
None,
|
||||
None,
|
||||
RPC_C_AUTHN_LEVEL_DEFAULT,
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||||
None,
|
||||
EOAC_NONE,
|
||||
None,
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
unsafe fn wmi_query(query: &str, max_results: usize, scratch: &mut ScratchBuffer) {
|
||||
init_com();
|
||||
|
||||
let locator: IWbemLocator = match CoCreateInstance(&WbemLocator, None, CLSCTX_INPROC_SERVER) {
|
||||
Ok(l) => l,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let server: IWbemServices = match locator.ConnectServer(
|
||||
&BSTR::from("ROOT\\CIMV2"),
|
||||
&BSTR::from(""),
|
||||
&BSTR::from(""),
|
||||
&BSTR::from(""),
|
||||
0,
|
||||
&BSTR::from(""),
|
||||
None,
|
||||
) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let flags = WBEM_GENERIC_FLAG_TYPE(
|
||||
WBEM_FLAG_FORWARD_ONLY.0 | WBEM_FLAG_RETURN_IMMEDIATELY.0,
|
||||
);
|
||||
|
||||
let enumerator: IEnumWbemClassObject = match server.ExecQuery(
|
||||
&BSTR::from("WQL"),
|
||||
&BSTR::from(query),
|
||||
flags,
|
||||
None,
|
||||
) {
|
||||
Ok(e) => e,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let mut count = 0usize;
|
||||
loop {
|
||||
if count >= max_results {
|
||||
break;
|
||||
}
|
||||
let mut row = [None; 1];
|
||||
let mut returned = 0u32;
|
||||
let hr = enumerator.Next(-1, &mut row, &mut returned);
|
||||
if hr.is_err() || returned == 0 {
|
||||
break;
|
||||
}
|
||||
if let Some(ref obj) = row[0] {
|
||||
black_box(obj);
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
scratch.absorb(&count.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn wmi_processes(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let max_results = params.iterations.min(200).saturating_add(work.derive_usize(0) % 8);
|
||||
unsafe { wmi_query("SELECT ProcessId, Name FROM Win32_Process", max_results, scratch); }
|
||||
}
|
||||
|
||||
fn wmi_os_info(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let max_results = params.call_depth.saturating_add(work.blend_seed() as usize % 2);
|
||||
unsafe { wmi_query("SELECT Caption, Version, BuildNumber FROM Win32_OperatingSystem", max_results, scratch); }
|
||||
}
|
||||
|
||||
fn wmi_computer_system(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let max_results = params.call_depth.saturating_add(work.blend_seed() as usize % 2);
|
||||
unsafe { wmi_query("SELECT Name, Domain, TotalPhysicalMemory FROM Win32_ComputerSystem", max_results, scratch); }
|
||||
}
|
||||
|
||||
fn wmi_network_adapters(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let max_results = params.iterations.min(50).saturating_add(work.derive_usize(1) % 4);
|
||||
unsafe { wmi_query("SELECT Description, MACAddress FROM Win32_NetworkAdapterConfiguration", max_results, scratch); }
|
||||
}
|
||||
|
||||
fn wmi_logical_disks(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let max_results = params.iterations.min(30).saturating_add(work.derive_usize(0) % 4);
|
||||
unsafe { wmi_query("SELECT DeviceID, Size, FreeSpace FROM Win32_LogicalDisk", max_results, scratch); }
|
||||
}
|
||||
|
||||
fn wmi_services(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let max_results = params.iterations.min(200).saturating_add(work.derive_usize(0) % 8);
|
||||
unsafe { wmi_query("SELECT Name, State, StartMode FROM Win32_Service", max_results, scratch); }
|
||||
}
|
||||
|
||||
fn wmi_bios_info(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let max_results = params.call_depth.saturating_add(work.blend_seed() as usize % 2);
|
||||
unsafe { wmi_query("SELECT Manufacturer, Version FROM Win32_BIOS", max_results, scratch); }
|
||||
}
|
||||
|
||||
fn wmi_processor_info(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let max_results = params.call_depth.saturating_add(work.blend_seed() as usize % 2);
|
||||
unsafe { wmi_query("SELECT Name, NumberOfCores, MaxClockSpeed FROM Win32_Processor", max_results, scratch); }
|
||||
}
|
||||
+160
-228
@@ -1,5 +1,5 @@
|
||||
use crate::categories::Categories;
|
||||
use crate::tasks::{TaskDescriptor, TaskParams};
|
||||
use crate::tasks::{ScratchBuffer, TaskDescriptor, TaskParams};
|
||||
use crate::workdata::WorkData;
|
||||
use flate2::write::{DeflateDecoder, DeflateEncoder};
|
||||
use flate2::Compression;
|
||||
@@ -85,33 +85,52 @@ pub fn register() -> Vec<TaskDescriptor> {
|
||||
]
|
||||
}
|
||||
|
||||
fn hash_sha256_loop(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn hash_sha256_loop(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let mut data = vec![0u8; 64];
|
||||
rng.fill_bytes(&mut data);
|
||||
work.blend_into(&mut data);
|
||||
scratch.blend_into(&mut data);
|
||||
for _ in 0..params.iterations {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(&data);
|
||||
let result = hasher.finalize();
|
||||
data[..32].copy_from_slice(&result);
|
||||
}
|
||||
scratch.absorb(&data);
|
||||
black_box(&data);
|
||||
}
|
||||
|
||||
fn hash_md5_loop(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn hash_md5_loop(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let mut data = vec![0u8; 64];
|
||||
rng.fill_bytes(&mut data);
|
||||
work.blend_into(&mut data);
|
||||
scratch.blend_into(&mut data);
|
||||
for _ in 0..params.iterations {
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(&data);
|
||||
let result = hasher.finalize();
|
||||
data[..16].copy_from_slice(&result);
|
||||
}
|
||||
scratch.absorb(&data);
|
||||
black_box(&data);
|
||||
}
|
||||
|
||||
fn prime_sieve(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn prime_sieve(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let work_bias = work.derive_usize(0) % 1000;
|
||||
let limit = params
|
||||
.iterations
|
||||
@@ -135,10 +154,16 @@ fn prime_sieve(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData) {
|
||||
}
|
||||
}
|
||||
let count = sieve.iter().filter(|&&b| b).count();
|
||||
scratch.absorb(&count.to_ne_bytes());
|
||||
black_box(count);
|
||||
}
|
||||
|
||||
fn matrix_multiply(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn matrix_multiply(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let n = ((params.iterations as f64).sqrt() as usize).max(2).min(512);
|
||||
let mut a = vec![0.0f64; n * n];
|
||||
let mut b = vec![0.0f64; n * n];
|
||||
@@ -154,6 +179,10 @@ fn matrix_multiply(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
*x += (wb[i % wb.len()] as f64) / 256.0;
|
||||
}
|
||||
}
|
||||
let sb = *scratch.read();
|
||||
for (i, x) in b.iter_mut().enumerate() {
|
||||
*x += (sb[i % sb.len()] as f64) / 256.0;
|
||||
}
|
||||
let mut c = vec![0.0f64; n * n];
|
||||
for i in 0..n {
|
||||
for k in 0..n {
|
||||
@@ -163,26 +192,59 @@ fn matrix_multiply(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
}
|
||||
}
|
||||
}
|
||||
let c_bytes: &[u8] = unsafe {
|
||||
std::slice::from_raw_parts(c.as_ptr() as *const u8, c.len() * std::mem::size_of::<f64>())
|
||||
};
|
||||
scratch.absorb(&c_bytes[..c_bytes.len().min(256)]);
|
||||
black_box(&c);
|
||||
}
|
||||
|
||||
fn sort_random_arrays(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn sort_random_arrays(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = (params.buffer_size / 8).max(1);
|
||||
let seed = work.blend_seed();
|
||||
for round in 0..params.call_depth {
|
||||
let rounds = params.call_depth;
|
||||
for round in 0..rounds {
|
||||
let mut data: Vec<u64> = (0..size)
|
||||
.map(|_| rng.gen::<u64>() ^ seed.wrapping_add(round as u64))
|
||||
.collect();
|
||||
let data_bytes: &mut [u8] = unsafe {
|
||||
std::slice::from_raw_parts_mut(
|
||||
data.as_mut_ptr() as *mut u8,
|
||||
data.len() * std::mem::size_of::<u64>(),
|
||||
)
|
||||
};
|
||||
scratch.blend_into(data_bytes);
|
||||
data.sort_unstable();
|
||||
if round + 1 == rounds {
|
||||
let sorted_bytes: &[u8] = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
data.as_ptr() as *const u8,
|
||||
data.len() * std::mem::size_of::<u64>(),
|
||||
)
|
||||
};
|
||||
scratch.absorb(sorted_bytes);
|
||||
}
|
||||
black_box(&data);
|
||||
}
|
||||
}
|
||||
|
||||
fn compress_decompress(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn compress_decompress(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = params.buffer_size.min(65536);
|
||||
let mut data = vec![0u8; size];
|
||||
rng.fill_bytes(&mut data);
|
||||
work.blend_into(&mut data);
|
||||
scratch.blend_into(&mut data);
|
||||
let mut last_decompressed = Vec::new();
|
||||
for _ in 0..params.call_depth {
|
||||
let mut encoder = DeflateEncoder::new(Vec::new(), Compression::fast());
|
||||
if encoder.write_all(&data).is_err() {
|
||||
@@ -200,11 +262,20 @@ fn compress_decompress(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData
|
||||
Ok(d) => d,
|
||||
Err(_) => continue,
|
||||
};
|
||||
black_box(&decompressed);
|
||||
last_decompressed = decompressed;
|
||||
black_box(&last_decompressed);
|
||||
}
|
||||
if !last_decompressed.is_empty() {
|
||||
scratch.absorb(&last_decompressed);
|
||||
}
|
||||
}
|
||||
|
||||
fn fibonacci_sequence(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn fibonacci_sequence(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let seed = work.blend_seed();
|
||||
let mut a: u128 = seed as u128;
|
||||
let mut b: u128 = 1u128.wrapping_add(seed as u128);
|
||||
@@ -213,27 +284,45 @@ fn fibonacci_sequence(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData
|
||||
a = b;
|
||||
b = next;
|
||||
}
|
||||
scratch.absorb(&b.to_ne_bytes());
|
||||
black_box(b);
|
||||
}
|
||||
|
||||
fn xor_cipher(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn xor_cipher(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let mut key = [0u8; 256];
|
||||
rng.fill_bytes(&mut key);
|
||||
work.blend_into(&mut key);
|
||||
scratch.blend_into(&mut key);
|
||||
let size = params.buffer_size.min(1_048_576);
|
||||
let mut last_data = Vec::new();
|
||||
for _ in 0..params.call_depth {
|
||||
let mut data = vec![0u8; size];
|
||||
rng.fill_bytes(&mut data);
|
||||
for (i, byte) in data.iter_mut().enumerate() {
|
||||
*byte ^= key[i % 256];
|
||||
}
|
||||
black_box(&data);
|
||||
last_data = data;
|
||||
black_box(&last_data);
|
||||
}
|
||||
if !last_data.is_empty() {
|
||||
scratch.absorb(&last_data);
|
||||
}
|
||||
}
|
||||
|
||||
fn collatz_sequence(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn collatz_sequence(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let iteration_limit = 10_000usize;
|
||||
let seed = work.blend_seed();
|
||||
let mut last_steps = 0usize;
|
||||
for _ in 0..params.iterations {
|
||||
let mut n: u64 = rng.gen::<u64>().saturating_add(1) ^ seed;
|
||||
let mut steps = 0usize;
|
||||
@@ -245,13 +334,22 @@ fn collatz_sequence(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
}
|
||||
steps += 1;
|
||||
}
|
||||
last_steps = steps;
|
||||
black_box(steps);
|
||||
}
|
||||
scratch.absorb(&last_steps.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn string_operations(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
let size = params.buffer_size.min(65536).max(1);
|
||||
fn string_operations(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let scratch_bias = scratch.read()[0] as usize % 8;
|
||||
let size = params.buffer_size.min(65536).max(1) + scratch_bias;
|
||||
let wb = work.as_bytes();
|
||||
let mut last_count = 0usize;
|
||||
for _ in 0..params.call_depth {
|
||||
let s: String = (0..size)
|
||||
.map(|i| {
|
||||
@@ -275,16 +373,24 @@ fn string_operations(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData)
|
||||
black_box(&lower);
|
||||
|
||||
let count = s.chars().filter(|&c| c == 'a' || c == 'A').count();
|
||||
last_count = count;
|
||||
black_box(count);
|
||||
|
||||
let found = s.find("the");
|
||||
black_box(found);
|
||||
}
|
||||
scratch.absorb(&last_count.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn bubble_sort(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn bubble_sort(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = (params.buffer_size / 4).min(4096).max(1);
|
||||
let seed = work.blend_seed() as u32;
|
||||
let mut last_data: Vec<u32> = Vec::new();
|
||||
for _ in 0..params.call_depth {
|
||||
let mut data: Vec<u32> = (0..size).map(|_| rng.gen::<u32>() ^ seed).collect();
|
||||
let n = data.len();
|
||||
@@ -295,11 +401,26 @@ fn bubble_sort(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
}
|
||||
}
|
||||
}
|
||||
black_box(&data);
|
||||
last_data = data;
|
||||
black_box(&last_data);
|
||||
}
|
||||
if !last_data.is_empty() {
|
||||
let sorted_bytes: &[u8] = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
last_data.as_ptr() as *const u8,
|
||||
last_data.len() * std::mem::size_of::<u32>(),
|
||||
)
|
||||
};
|
||||
scratch.absorb(sorted_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
fn bitwise_operations(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn bitwise_operations(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let mut accum: u64 = rng.gen::<u64>() ^ work.blend_seed();
|
||||
for _ in 0..params.iterations {
|
||||
let val: u64 = rng.gen();
|
||||
@@ -313,10 +434,16 @@ fn bitwise_operations(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData)
|
||||
accum ^= val.trailing_zeros() as u64;
|
||||
accum ^= val.swap_bytes();
|
||||
}
|
||||
scratch.absorb(&accum.to_ne_bytes());
|
||||
black_box(accum);
|
||||
}
|
||||
|
||||
fn pi_approximation(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn pi_approximation(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let extra = work.derive_usize(0) % 100;
|
||||
let total = params.iterations.saturating_add(extra);
|
||||
let mut sum: f64 = 0.0;
|
||||
@@ -325,10 +452,16 @@ fn pi_approximation(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData)
|
||||
sum += sign / (2 * k + 1) as f64;
|
||||
}
|
||||
let pi = 4.0 * sum;
|
||||
scratch.absorb(&pi.to_ne_bytes());
|
||||
black_box(pi);
|
||||
}
|
||||
|
||||
fn permutation_generate(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn permutation_generate(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let work_extra = work.derive_usize(0) % 3;
|
||||
let n = params.call_depth.saturating_add(work_extra).min(10).max(1);
|
||||
let mut arr: Vec<usize> = (0..n).collect();
|
||||
@@ -350,212 +483,11 @@ fn permutation_generate(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkDa
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::workdata::WorkData;
|
||||
|
||||
// ── Proof that work data changes each task's computation ───────────
|
||||
// These mirror the exact integration logic in each task and verify
|
||||
// that feeding data produces different internal values. If someone
|
||||
// accidentally removes a blend_into / blend_seed call, these fail.
|
||||
|
||||
#[test]
|
||||
fn hash_sha256_input_differs_with_work() {
|
||||
let buf_no_work = vec![0u8; 64];
|
||||
let mut buf_with_work = vec![0u8; 64];
|
||||
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&0xDEADBEEFu32);
|
||||
work.blend_into(&mut buf_with_work);
|
||||
|
||||
assert_ne!(buf_no_work, buf_with_work, "blend_into must change hash input");
|
||||
// Also verify it's not just the first 4 bytes (cyclic XOR spreads across buffer)
|
||||
assert!(buf_with_work[4..].iter().any(|&b| b != 0), "XOR should cycle past work data length");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_md5_input_differs_with_work() {
|
||||
let mut buf = vec![0u8; 64];
|
||||
let mut work = WorkData::new();
|
||||
work.feed("session_token_12345");
|
||||
work.blend_into(&mut buf);
|
||||
assert!(buf.iter().any(|&b| b != 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fibonacci_starting_values_change() {
|
||||
// fibonacci uses: a = seed as u128, b = 1 + seed as u128
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u32);
|
||||
let seed = work.blend_seed();
|
||||
assert_ne!(seed, 0, "non-zero input must produce non-zero seed");
|
||||
|
||||
let a = seed as u128;
|
||||
let b = 1u128.wrapping_add(seed as u128);
|
||||
assert_ne!((a, b), (0u128, 1u128), "starting values must differ from default");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collatz_starting_number_changes() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u64);
|
||||
let seed = work.blend_seed();
|
||||
assert_ne!(seed, 0);
|
||||
// collatz XORs: n = rng_val ^ seed → different starting number
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prime_sieve_limit_gets_bias() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&0xCAFEBABEu32);
|
||||
let bias = work.derive_usize(0) % 1000;
|
||||
assert!(bias > 0, "non-trivial data should produce non-zero sieve bias");
|
||||
|
||||
let base_limit = 50usize.saturating_mul(100);
|
||||
let biased_limit = base_limit.saturating_add(bias);
|
||||
assert!(biased_limit > base_limit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matrix_entries_get_work_offset() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&[0x80u8; 16]);
|
||||
let wb = work.as_bytes();
|
||||
// matrix_multiply adds (wb[i % len] as f64) / 256.0 to each entry
|
||||
let offset = wb[0] as f64 / 256.0;
|
||||
assert!(offset > 0.0, "work data must produce positive offset");
|
||||
assert!(offset < 1.0, "offset must stay fractional");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sort_seed_affects_values() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u32);
|
||||
let seed = work.blend_seed();
|
||||
assert_ne!(seed, 0);
|
||||
// sort_random_arrays: rng.gen() ^ seed.wrapping_add(round)
|
||||
// Non-zero seed changes every array element
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compress_input_changes_with_work() {
|
||||
let mut data = vec![0u8; 1024];
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&[0xAB; 32]);
|
||||
work.blend_into(&mut data);
|
||||
assert!(data.iter().any(|&b| b != 0), "compressed data input must change");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xor_cipher_key_modified() {
|
||||
let mut key = [0u8; 256];
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&0xFFu8);
|
||||
work.blend_into(&mut key);
|
||||
assert!(key.iter().any(|&b| b != 0), "cipher key must incorporate work data");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_ops_chars_change() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&0xFFu8);
|
||||
let wb = work.as_bytes();
|
||||
let base: u8 = 65; // 'A'
|
||||
let modified = ((base as u16 + wb[0] as u16) % 95 + 32) as u8;
|
||||
assert_ne!(modified, base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bubble_sort_seed_nonzero() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u32);
|
||||
let seed = work.blend_seed() as u32;
|
||||
assert_ne!(seed, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bitwise_initial_accum_changes() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u32);
|
||||
let seed = work.blend_seed();
|
||||
// bitwise_operations: accum = rng ^ seed → different accumulator start
|
||||
assert_ne!(seed, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pi_extra_iterations_added() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u32);
|
||||
let extra = work.derive_usize(0) % 100;
|
||||
let base_iterations = 50usize;
|
||||
let total = base_iterations.saturating_add(extra);
|
||||
assert!(total >= base_iterations, "total must be >= base");
|
||||
// With most non-trivial data, extra > 0
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permutation_size_changes() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u32);
|
||||
let extra = work.derive_usize(0) % 3;
|
||||
let base_depth = 2usize;
|
||||
let n = base_depth.saturating_add(extra).min(10).max(1);
|
||||
// n should be >= base_depth (since extra >= 0) and possibly larger
|
||||
assert!(n >= base_depth);
|
||||
}
|
||||
|
||||
// ── blend_into reversibility (proves it's XOR, not corruption) ─────
|
||||
|
||||
#[test]
|
||||
fn blend_into_is_reversible_on_task_buffers() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&0xDEADBEEFCAFEBABEu64);
|
||||
|
||||
let original = vec![42u8; 4096];
|
||||
let mut buf = original.clone();
|
||||
work.blend_into(&mut buf);
|
||||
assert_ne!(buf, original, "first blend must change data");
|
||||
work.blend_into(&mut buf);
|
||||
assert_eq!(buf, original, "double blend must restore original");
|
||||
}
|
||||
|
||||
// ── Different work data → different seeds (no collision) ───────────
|
||||
|
||||
#[test]
|
||||
fn different_data_different_seeds() {
|
||||
let inputs: &[&[u8]] = &[
|
||||
b"alpha", b"bravo", b"charlie", b"delta",
|
||||
b"echo", b"foxtrot", b"golf", b"hotel",
|
||||
b"india", b"juliet",
|
||||
];
|
||||
let mut seeds = Vec::new();
|
||||
for input in inputs {
|
||||
let mut w = WorkData::new();
|
||||
w.feed(*input);
|
||||
seeds.push(w.blend_seed());
|
||||
}
|
||||
let unique_count = {
|
||||
let mut s = seeds.clone();
|
||||
s.sort();
|
||||
s.dedup();
|
||||
s.len()
|
||||
};
|
||||
assert_eq!(unique_count, seeds.len(), "distinct multi-byte inputs must produce distinct seeds");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn different_data_different_derived_values() {
|
||||
let inputs: &[&[u8]] = &[
|
||||
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
|
||||
&[16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
|
||||
];
|
||||
let mut w1 = WorkData::new();
|
||||
w1.feed(inputs[0]);
|
||||
let mut w2 = WorkData::new();
|
||||
w2.feed(inputs[1]);
|
||||
|
||||
assert_ne!(w1.derive_usize(0), w2.derive_usize(0));
|
||||
}
|
||||
let arr_bytes: &[u8] = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
arr.as_ptr() as *const u8,
|
||||
arr.len() * std::mem::size_of::<usize>(),
|
||||
)
|
||||
};
|
||||
scratch.absorb(arr_bytes);
|
||||
}
|
||||
|
||||
+68
-17
@@ -1,5 +1,5 @@
|
||||
use crate::categories::Categories;
|
||||
use crate::tasks::{TaskDescriptor, TaskParams};
|
||||
use crate::tasks::{ScratchBuffer, TaskDescriptor, TaskParams};
|
||||
use crate::workdata::WorkData;
|
||||
use rand::rngs::ThreadRng;
|
||||
use rand::RngCore;
|
||||
@@ -46,7 +46,12 @@ pub fn register() -> Vec<TaskDescriptor> {
|
||||
]
|
||||
}
|
||||
|
||||
fn bcrypt_gen_random(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn bcrypt_gen_random(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = params.buffer_size.min(65536);
|
||||
let mut buffer = vec![0u8; size];
|
||||
for _ in 0..params.iterations.min(100) {
|
||||
@@ -58,15 +63,23 @@ fn bcrypt_gen_random(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData)
|
||||
);
|
||||
}
|
||||
work.blend_into(&mut buffer);
|
||||
scratch.blend_into(&mut buffer);
|
||||
black_box(&buffer);
|
||||
}
|
||||
scratch.absorb(&buffer[..buffer.len().min(256)]);
|
||||
}
|
||||
|
||||
fn bcrypt_hash(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn bcrypt_hash(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let data_size = params.buffer_size.min(65536);
|
||||
let mut data = vec![0u8; data_size];
|
||||
rng.fill_bytes(&mut data);
|
||||
work.blend_into(&mut data);
|
||||
scratch.blend_into(&mut data);
|
||||
|
||||
unsafe {
|
||||
let mut alg = BCRYPT_ALG_HANDLE::default();
|
||||
@@ -80,6 +93,8 @@ fn bcrypt_hash(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut output = vec![0u8; 32];
|
||||
|
||||
for _ in 0..params.iterations.min(100) {
|
||||
let mut hash_handle = BCRYPT_HASH_HANDLE::default();
|
||||
let status = BCryptCreateHash(alg, &mut hash_handle, None, None, 0);
|
||||
@@ -88,23 +103,28 @@ fn bcrypt_hash(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
}
|
||||
|
||||
let _ = BCryptHashData(hash_handle, &data, 0);
|
||||
|
||||
let mut output = vec![0u8; 32];
|
||||
let _ = BCryptFinishHash(hash_handle, &mut output, 0);
|
||||
|
||||
black_box(&output);
|
||||
let _ = BCryptDestroyHash(hash_handle);
|
||||
}
|
||||
|
||||
scratch.absorb(&output);
|
||||
let _ = BCryptCloseAlgorithmProvider(alg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn bcrypt_sha512(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn bcrypt_sha512(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let data_size = params.buffer_size.min(65536);
|
||||
let mut data = vec![0u8; data_size];
|
||||
rng.fill_bytes(&mut data);
|
||||
work.blend_into(&mut data);
|
||||
scratch.blend_into(&mut data);
|
||||
|
||||
unsafe {
|
||||
let mut alg = BCRYPT_ALG_HANDLE::default();
|
||||
@@ -118,6 +138,8 @@ fn bcrypt_sha512(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut output = vec![0u8; 64];
|
||||
|
||||
for _ in 0..params.iterations.min(100) {
|
||||
let mut hash_handle = BCRYPT_HASH_HANDLE::default();
|
||||
let status = BCryptCreateHash(alg, &mut hash_handle, None, None, 0);
|
||||
@@ -126,23 +148,28 @@ fn bcrypt_sha512(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
}
|
||||
|
||||
let _ = BCryptHashData(hash_handle, &data, 0);
|
||||
|
||||
let mut output = vec![0u8; 64];
|
||||
let _ = BCryptFinishHash(hash_handle, &mut output, 0);
|
||||
|
||||
black_box(&output);
|
||||
let _ = BCryptDestroyHash(hash_handle);
|
||||
}
|
||||
|
||||
scratch.absorb(&output);
|
||||
let _ = BCryptCloseAlgorithmProvider(alg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn bcrypt_md5_hash(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn bcrypt_md5_hash(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let data_size = params.buffer_size.min(65536);
|
||||
let mut data = vec![0u8; data_size];
|
||||
rng.fill_bytes(&mut data);
|
||||
work.blend_into(&mut data);
|
||||
scratch.blend_into(&mut data);
|
||||
|
||||
unsafe {
|
||||
let mut alg = BCRYPT_ALG_HANDLE::default();
|
||||
@@ -156,6 +183,8 @@ fn bcrypt_md5_hash(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut output = vec![0u8; 16];
|
||||
|
||||
for _ in 0..params.iterations.min(100) {
|
||||
let mut hash_handle = BCRYPT_HASH_HANDLE::default();
|
||||
let status = BCryptCreateHash(alg, &mut hash_handle, None, None, 0);
|
||||
@@ -164,23 +193,28 @@ fn bcrypt_md5_hash(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
}
|
||||
|
||||
let _ = BCryptHashData(hash_handle, &data, 0);
|
||||
|
||||
let mut output = vec![0u8; 16];
|
||||
let _ = BCryptFinishHash(hash_handle, &mut output, 0);
|
||||
|
||||
black_box(&output);
|
||||
let _ = BCryptDestroyHash(hash_handle);
|
||||
}
|
||||
|
||||
scratch.absorb(&output);
|
||||
let _ = BCryptCloseAlgorithmProvider(alg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn bcrypt_sha1_hash(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn bcrypt_sha1_hash(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let data_size = params.buffer_size.min(65536);
|
||||
let mut data = vec![0u8; data_size];
|
||||
rng.fill_bytes(&mut data);
|
||||
work.blend_into(&mut data);
|
||||
scratch.blend_into(&mut data);
|
||||
|
||||
unsafe {
|
||||
let mut alg = BCRYPT_ALG_HANDLE::default();
|
||||
@@ -194,6 +228,8 @@ fn bcrypt_sha1_hash(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut output = vec![0u8; 20];
|
||||
|
||||
for _ in 0..params.iterations.min(100) {
|
||||
let mut hash_handle = BCRYPT_HASH_HANDLE::default();
|
||||
let status = BCryptCreateHash(alg, &mut hash_handle, None, None, 0);
|
||||
@@ -202,23 +238,28 @@ fn bcrypt_sha1_hash(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
}
|
||||
|
||||
let _ = BCryptHashData(hash_handle, &data, 0);
|
||||
|
||||
let mut output = vec![0u8; 20];
|
||||
let _ = BCryptFinishHash(hash_handle, &mut output, 0);
|
||||
|
||||
black_box(&output);
|
||||
let _ = BCryptDestroyHash(hash_handle);
|
||||
}
|
||||
|
||||
scratch.absorb(&output);
|
||||
let _ = BCryptCloseAlgorithmProvider(alg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn bcrypt_aes_encrypt(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn bcrypt_aes_encrypt(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let plaintext_size = params.buffer_size.min(4096);
|
||||
let mut plaintext = vec![0u8; plaintext_size];
|
||||
rng.fill_bytes(&mut plaintext);
|
||||
work.blend_into(&mut plaintext);
|
||||
scratch.blend_into(&mut plaintext);
|
||||
|
||||
let mut key_bytes = [0u8; 32];
|
||||
rng.fill_bytes(&mut key_bytes);
|
||||
@@ -235,6 +276,8 @@ fn bcrypt_aes_encrypt(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData)
|
||||
return;
|
||||
}
|
||||
|
||||
let mut output = vec![0u8; plaintext_size + 16];
|
||||
|
||||
for _ in 0..params.call_depth.min(50) {
|
||||
let mut key_handle = BCRYPT_KEY_HANDLE::default();
|
||||
let status = BCryptGenerateSymmetricKey(
|
||||
@@ -248,7 +291,6 @@ fn bcrypt_aes_encrypt(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData)
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut output = vec![0u8; plaintext_size + 16];
|
||||
let mut bytes_written: u32 = 0;
|
||||
|
||||
let _ = BCryptEncrypt(
|
||||
@@ -267,11 +309,17 @@ fn bcrypt_aes_encrypt(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData)
|
||||
let _ = BCryptDestroyKey(key_handle);
|
||||
}
|
||||
|
||||
scratch.absorb(&output[..output.len().min(256)]);
|
||||
let _ = BCryptCloseAlgorithmProvider(alg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn bcrypt_rng_algorithms(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn bcrypt_rng_algorithms(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let alg_ids = [
|
||||
windows::core::w!("RNG"),
|
||||
windows::core::w!("FIPS186DSARNG"),
|
||||
@@ -297,10 +345,13 @@ fn bcrypt_rng_algorithms(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkD
|
||||
for _ in 0..params.iterations.min(50) {
|
||||
let _ = BCryptGenRandom(alg, &mut buffer, BCRYPTGENRANDOM_FLAGS(0));
|
||||
work.blend_into(&mut buffer);
|
||||
scratch.blend_into(&mut buffer);
|
||||
black_box(&buffer);
|
||||
}
|
||||
|
||||
let _ = BCryptCloseAlgorithmProvider(alg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
scratch.absorb(&buffer[..buffer.len().min(256)]);
|
||||
}
|
||||
|
||||
+207
-53
@@ -1,8 +1,7 @@
|
||||
use crate::categories::Categories;
|
||||
use crate::tasks::{TaskDescriptor, TaskParams};
|
||||
use crate::tasks::{ScratchBuffer, TaskDescriptor, TaskParams};
|
||||
use crate::workdata::WorkData;
|
||||
use rand::rngs::ThreadRng;
|
||||
use rand::seq::SliceRandom;
|
||||
use std::hint::black_box;
|
||||
|
||||
pub fn register() -> Vec<TaskDescriptor> {
|
||||
@@ -70,37 +69,70 @@ pub fn register() -> Vec<TaskDescriptor> {
|
||||
]
|
||||
}
|
||||
|
||||
fn enumerate_system_dir(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_system_dir(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 16;
|
||||
let bias = work.blend_seed() as usize % 8;
|
||||
let limit = params.iterations + bias;
|
||||
let mut last_len = 0u64;
|
||||
let _ = (|| -> std::io::Result<()> {
|
||||
let dir = std::fs::read_dir(r"C:\Windows\System32")?;
|
||||
for (i, entry) in dir.enumerate() {
|
||||
if i >= params.iterations {
|
||||
if i < skip {
|
||||
continue;
|
||||
}
|
||||
if i - skip >= limit {
|
||||
break;
|
||||
}
|
||||
let entry = entry?;
|
||||
let meta = entry.metadata()?;
|
||||
black_box(meta.len());
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn enumerate_temp_dir(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_temp_dir(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 16;
|
||||
let bias = work.blend_seed() as usize % 8;
|
||||
let limit = params.iterations + bias;
|
||||
let mut last_len = 0u64;
|
||||
let _ = (|| -> std::io::Result<()> {
|
||||
let dir = std::fs::read_dir(std::env::temp_dir())?;
|
||||
for (i, entry) in dir.enumerate() {
|
||||
if i >= params.iterations {
|
||||
if i < skip {
|
||||
continue;
|
||||
}
|
||||
if i - skip >= limit {
|
||||
break;
|
||||
}
|
||||
let entry = entry?;
|
||||
let meta = entry.metadata()?;
|
||||
black_box(meta.len());
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn stat_system_files(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn stat_system_files(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let paths = [
|
||||
r"C:\Windows\explorer.exe",
|
||||
r"C:\Windows\notepad.exe",
|
||||
@@ -111,44 +143,73 @@ fn stat_system_files(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData)
|
||||
r"C:\Windows\System32\ws2_32.dll",
|
||||
r"C:\Windows\System32\cmd.exe",
|
||||
];
|
||||
for _ in 0..params.iterations.min(200) {
|
||||
if let Some(path) = paths.choose(rng) {
|
||||
if let Ok(meta) = std::fs::metadata(path) {
|
||||
black_box(meta.len());
|
||||
}
|
||||
let start_idx = work.derive_usize(0) % paths.len();
|
||||
let mut last_len = 0u64;
|
||||
for i in 0..params.iterations.min(200) {
|
||||
let path = paths[(start_idx + i) % paths.len()];
|
||||
if let Ok(meta) = std::fs::metadata(path) {
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
}
|
||||
}
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_small_files(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_small_files(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let paths = [
|
||||
r"C:\Windows\System32\drivers\etc\hosts",
|
||||
r"C:\Windows\System32\drivers\etc\services",
|
||||
r"C:\Windows\System32\drivers\etc\protocol",
|
||||
r"C:\Windows\System32\drivers\etc\networks",
|
||||
];
|
||||
for _ in 0..params.call_depth {
|
||||
if let Some(path) = paths.choose(rng) {
|
||||
if let Ok(data) = std::fs::read(path) {
|
||||
black_box(data.len());
|
||||
}
|
||||
let start_idx = work.derive_usize(0) % paths.len();
|
||||
let mut last_data: Vec<u8> = Vec::new();
|
||||
for round in 0..params.call_depth {
|
||||
let path = paths[(start_idx + round) % paths.len()];
|
||||
if let Ok(mut data) = std::fs::read(path) {
|
||||
work.blend_into(&mut data);
|
||||
scratch.blend_into(&mut data);
|
||||
black_box(data.len());
|
||||
last_data = data;
|
||||
}
|
||||
}
|
||||
if !last_data.is_empty() {
|
||||
let absorb_len = last_data.len().min(256);
|
||||
scratch.absorb(&last_data[..absorb_len]);
|
||||
}
|
||||
}
|
||||
|
||||
fn enumerate_program_files(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_program_files(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 8;
|
||||
let bias = work.blend_seed() as usize % 8;
|
||||
let limit = params.iterations + bias;
|
||||
let dirs = [r"C:\Program Files", r"C:\Program Files (x86)"];
|
||||
let mut count = 0usize;
|
||||
let mut last_len = 0u64;
|
||||
let _ = (|| -> std::io::Result<()> {
|
||||
let dirs = [r"C:\Program Files", r"C:\Program Files (x86)"];
|
||||
let mut count = 0usize;
|
||||
for dir_path in &dirs {
|
||||
if let Ok(dir) = std::fs::read_dir(dir_path) {
|
||||
for entry in dir {
|
||||
if count >= params.iterations {
|
||||
for (i, entry) in dir.enumerate() {
|
||||
if count >= limit {
|
||||
return Ok(());
|
||||
}
|
||||
if i < skip && count == 0 {
|
||||
continue;
|
||||
}
|
||||
let entry = entry?;
|
||||
if let Ok(meta) = entry.metadata() {
|
||||
black_box(meta.len());
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
black_box(meta.is_dir());
|
||||
}
|
||||
count += 1;
|
||||
@@ -157,61 +218,112 @@ fn enumerate_program_files(params: &TaskParams, _rng: &mut ThreadRng, _work: &Wo
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn enumerate_fonts(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_fonts(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 16;
|
||||
let bias = work.blend_seed() as usize % 8;
|
||||
let limit = params.iterations + bias;
|
||||
let mut last_len = 0u64;
|
||||
let _ = (|| -> std::io::Result<()> {
|
||||
let dir = std::fs::read_dir(r"C:\Windows\Fonts")?;
|
||||
for (i, entry) in dir.enumerate() {
|
||||
if i >= params.iterations {
|
||||
if i < skip {
|
||||
continue;
|
||||
}
|
||||
if i - skip >= limit {
|
||||
break;
|
||||
}
|
||||
let entry = entry?;
|
||||
black_box(entry.file_name());
|
||||
if let Ok(meta) = entry.metadata() {
|
||||
black_box(meta.len());
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn enumerate_drivers(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_drivers(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 16;
|
||||
let bias = work.blend_seed() as usize % 8;
|
||||
let limit = params.iterations + bias;
|
||||
let mut last_len = 0u64;
|
||||
let _ = (|| -> std::io::Result<()> {
|
||||
let dir = std::fs::read_dir(r"C:\Windows\System32\drivers")?;
|
||||
for (i, entry) in dir.enumerate() {
|
||||
if i >= params.iterations {
|
||||
if i < skip {
|
||||
continue;
|
||||
}
|
||||
if i - skip >= limit {
|
||||
break;
|
||||
}
|
||||
let entry = entry?;
|
||||
if let Ok(meta) = entry.metadata() {
|
||||
black_box(meta.len());
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn enumerate_prefetch(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_prefetch(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 16;
|
||||
let bias = work.blend_seed() as usize % 8;
|
||||
let limit = params.iterations + bias;
|
||||
let mut last_len = 0u64;
|
||||
let _ = (|| -> std::io::Result<()> {
|
||||
let dir = std::fs::read_dir(r"C:\Windows\Prefetch")?;
|
||||
for (i, entry) in dir.enumerate() {
|
||||
if i >= params.iterations {
|
||||
if i < skip {
|
||||
continue;
|
||||
}
|
||||
if i - skip >= limit {
|
||||
break;
|
||||
}
|
||||
let entry = entry?;
|
||||
black_box(entry.file_name());
|
||||
if let Ok(meta) = entry.metadata() {
|
||||
black_box(meta.len());
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn enumerate_logs(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_logs(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 16;
|
||||
let mut last_len = 0u64;
|
||||
let _ = (|| -> std::io::Result<()> {
|
||||
let mut count = 0usize;
|
||||
let mut skipped = 0usize;
|
||||
let base = std::path::Path::new(r"C:\Windows\Logs");
|
||||
let dir = std::fs::read_dir(base)?;
|
||||
for entry in dir {
|
||||
@@ -219,9 +331,14 @@ fn enumerate_logs(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
break;
|
||||
}
|
||||
let entry = entry?;
|
||||
if skipped < skip {
|
||||
skipped += 1;
|
||||
continue;
|
||||
}
|
||||
black_box(entry.file_name());
|
||||
if let Ok(meta) = entry.metadata() {
|
||||
black_box(meta.len());
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
if meta.is_dir() {
|
||||
if let Ok(subdir) = std::fs::read_dir(entry.path()) {
|
||||
for sub_entry in subdir {
|
||||
@@ -231,7 +348,8 @@ fn enumerate_logs(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
if let Ok(sub_entry) = sub_entry {
|
||||
black_box(sub_entry.file_name());
|
||||
if let Ok(sub_meta) = sub_entry.metadata() {
|
||||
black_box(sub_meta.len());
|
||||
last_len = sub_meta.len();
|
||||
black_box(last_len);
|
||||
}
|
||||
}
|
||||
count += 1;
|
||||
@@ -243,9 +361,15 @@ fn enumerate_logs(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn stat_common_dlls(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn stat_common_dlls(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let dlls = [
|
||||
r"C:\Windows\System32\kernel32.dll",
|
||||
r"C:\Windows\System32\ntdll.dll",
|
||||
@@ -268,16 +392,24 @@ fn stat_common_dlls(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData)
|
||||
r"C:\Windows\System32\ncrypt.dll",
|
||||
r"C:\Windows\System32\shlwapi.dll",
|
||||
];
|
||||
for _ in 0..params.iterations {
|
||||
if let Some(path) = dlls.choose(rng) {
|
||||
if let Ok(meta) = std::fs::metadata(path) {
|
||||
black_box(meta.len());
|
||||
}
|
||||
let start_idx = work.derive_usize(0) % dlls.len();
|
||||
let mut last_len = 0u64;
|
||||
for i in 0..params.iterations {
|
||||
let path = dlls[(start_idx + i) % dlls.len()];
|
||||
if let Ok(meta) = std::fs::metadata(path) {
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
}
|
||||
}
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_system_files_varied(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_system_files_varied(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let paths = [
|
||||
r"C:\Windows\win.ini",
|
||||
r"C:\Windows\system.ini",
|
||||
@@ -285,32 +417,54 @@ fn read_system_files_varied(params: &TaskParams, rng: &mut ThreadRng, _work: &Wo
|
||||
r"C:\Windows\System32\drivers\etc\services",
|
||||
r"C:\Windows\System32\drivers\etc\protocol",
|
||||
];
|
||||
for _ in 0..params.iterations {
|
||||
if let Some(path) = paths.choose(rng) {
|
||||
if let Ok(data) = std::fs::read(path) {
|
||||
black_box(data.len());
|
||||
}
|
||||
let start_idx = work.derive_usize(0) % paths.len();
|
||||
let mut last_data: Vec<u8> = Vec::new();
|
||||
for i in 0..params.iterations {
|
||||
let path = paths[(start_idx + i) % paths.len()];
|
||||
if let Ok(mut data) = std::fs::read(path) {
|
||||
work.blend_into(&mut data);
|
||||
scratch.blend_into(&mut data);
|
||||
black_box(data.len());
|
||||
last_data = data;
|
||||
}
|
||||
}
|
||||
if !last_data.is_empty() {
|
||||
let absorb_len = last_data.len().min(256);
|
||||
scratch.absorb(&last_data[..absorb_len]);
|
||||
}
|
||||
}
|
||||
|
||||
fn enumerate_user_profile(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_user_profile(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 16;
|
||||
let bias = work.blend_seed() as usize % 8;
|
||||
let limit = params.iterations + bias;
|
||||
let mut last_len = 0u64;
|
||||
let _ = (|| -> std::io::Result<()> {
|
||||
let profile = std::env::var("USERPROFILE").map_err(|_| {
|
||||
std::io::Error::new(std::io::ErrorKind::NotFound, "USERPROFILE not set")
|
||||
})?;
|
||||
let dir = std::fs::read_dir(profile)?;
|
||||
for (i, entry) in dir.enumerate() {
|
||||
if i >= params.iterations {
|
||||
if i < skip {
|
||||
continue;
|
||||
}
|
||||
if i - skip >= limit {
|
||||
break;
|
||||
}
|
||||
let entry = entry?;
|
||||
black_box(entry.file_name());
|
||||
if let Ok(meta) = entry.metadata() {
|
||||
black_box(meta.len());
|
||||
last_len = meta.len();
|
||||
black_box(last_len);
|
||||
black_box(meta.is_dir());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
scratch.absorb(&last_len.to_ne_bytes());
|
||||
}
|
||||
|
||||
+94
-99
@@ -1,5 +1,5 @@
|
||||
use crate::categories::Categories;
|
||||
use crate::tasks::{TaskDescriptor, TaskParams};
|
||||
use crate::tasks::{ScratchBuffer, TaskDescriptor, TaskParams};
|
||||
use crate::workdata::WorkData;
|
||||
use rand::rngs::ThreadRng;
|
||||
use rand::{Rng, RngCore};
|
||||
@@ -60,7 +60,12 @@ pub fn register() -> Vec<TaskDescriptor> {
|
||||
]
|
||||
}
|
||||
|
||||
fn alloc_touch_free(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn alloc_touch_free(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = params.buffer_size.min(1_048_576);
|
||||
for _ in 0..params.iterations.min(100) {
|
||||
let mut buf = vec![0u8; size];
|
||||
@@ -68,51 +73,88 @@ fn alloc_touch_free(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
buf[offset] = rng.gen();
|
||||
}
|
||||
work.blend_into(&mut buf);
|
||||
scratch.blend_into(&mut buf);
|
||||
black_box(&buf);
|
||||
}
|
||||
scratch.absorb(&size.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn memcpy_chain(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn memcpy_chain(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = params.buffer_size.min(1_048_576);
|
||||
let mut src = vec![0u8; size];
|
||||
let mut dst = vec![0u8; size];
|
||||
rng.fill_bytes(&mut src);
|
||||
work.blend_into(&mut src);
|
||||
scratch.blend_into(&mut src);
|
||||
for _ in 0..params.iterations.min(1000) {
|
||||
dst.copy_from_slice(&src);
|
||||
std::mem::swap(&mut src, &mut dst);
|
||||
}
|
||||
scratch.absorb(&src[..src.len().min(256)]);
|
||||
black_box(&src);
|
||||
}
|
||||
|
||||
fn sort_random_memory(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn sort_random_memory(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = (params.buffer_size / 8).max(1);
|
||||
let seed = work.blend_seed();
|
||||
let scratch_seed =
|
||||
u64::from_ne_bytes(scratch.read()[..8].try_into().unwrap_or([0; 8]));
|
||||
let mut last_bytes = Vec::new();
|
||||
for _ in 0..params.call_depth {
|
||||
let mut data: Vec<u64> = (0..size).map(|_| rng.gen::<u64>() ^ seed).collect();
|
||||
let mut data: Vec<u64> = (0..size)
|
||||
.map(|_| rng.gen::<u64>() ^ seed ^ scratch_seed)
|
||||
.collect();
|
||||
data.sort_unstable();
|
||||
last_bytes.clear();
|
||||
for val in data.iter().rev().take(32) {
|
||||
last_bytes.extend_from_slice(&val.to_ne_bytes());
|
||||
}
|
||||
black_box(&data);
|
||||
}
|
||||
scratch.absorb(&last_bytes[..last_bytes.len().min(256)]);
|
||||
}
|
||||
|
||||
fn pattern_fill_verify(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn pattern_fill_verify(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = params.buffer_size.min(1_048_576);
|
||||
let mut buf = vec![0u8; size];
|
||||
let wb = work.as_bytes();
|
||||
let scratch_data = *scratch.read();
|
||||
for round in 0..params.iterations.min(100) {
|
||||
let base_pattern: u8 = rng.gen();
|
||||
let pattern = if !wb.is_empty() {
|
||||
let mut pattern = if !wb.is_empty() {
|
||||
base_pattern ^ wb[round % wb.len()]
|
||||
} else {
|
||||
base_pattern
|
||||
};
|
||||
pattern ^= scratch_data[round % scratch_data.len()];
|
||||
buf.fill(pattern);
|
||||
let valid = buf.iter().all(|&b| b == pattern);
|
||||
black_box(valid);
|
||||
}
|
||||
scratch.absorb(&buf[..buf.len().min(256)]);
|
||||
}
|
||||
|
||||
fn heap_fragmentation(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn heap_fragmentation(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let count = params.iterations.min(500);
|
||||
let mut buffers: Vec<Option<Vec<u8>>> = Vec::with_capacity(count);
|
||||
|
||||
@@ -121,6 +163,7 @@ fn heap_fragmentation(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData)
|
||||
let mut buf = vec![0u8; size];
|
||||
rng.fill_bytes(&mut buf);
|
||||
work.blend_into(&mut buf);
|
||||
scratch.blend_into(&mut buf);
|
||||
buffers.push(Some(buf));
|
||||
}
|
||||
|
||||
@@ -137,6 +180,7 @@ fn heap_fragmentation(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData)
|
||||
let mut buf = vec![0u8; size];
|
||||
rng.fill_bytes(&mut buf);
|
||||
work.blend_into(&mut buf);
|
||||
scratch.blend_into(&mut buf);
|
||||
total_bytes += size;
|
||||
*slot = Some(buf);
|
||||
} else {
|
||||
@@ -144,14 +188,21 @@ fn heap_fragmentation(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData)
|
||||
}
|
||||
}
|
||||
|
||||
scratch.absorb(&total_bytes.to_ne_bytes());
|
||||
black_box(total_bytes);
|
||||
black_box(&buffers);
|
||||
}
|
||||
|
||||
fn ring_buffer_ops(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn ring_buffer_ops(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = params.buffer_size.min(1_048_576).max(1);
|
||||
let mut buffer = vec![0u8; size];
|
||||
work.blend_into(&mut buffer);
|
||||
scratch.blend_into(&mut buffer);
|
||||
let mut write_pos: usize = 0;
|
||||
let mut read_pos: usize = 0;
|
||||
|
||||
@@ -164,10 +215,16 @@ fn ring_buffer_ops(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
read_pos = (read_pos + 1) % size;
|
||||
}
|
||||
|
||||
scratch.absorb(&buffer[..buffer.len().min(256)]);
|
||||
black_box(&buffer);
|
||||
}
|
||||
|
||||
fn binary_search_repeated(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn binary_search_repeated(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let elem_count = (params.buffer_size / 8).max(1);
|
||||
let seed = work.blend_seed();
|
||||
let mut data: Vec<u64> = (0..elem_count).map(|_| rng.gen::<u64>() ^ seed).collect();
|
||||
@@ -181,30 +238,45 @@ fn binary_search_repeated(params: &TaskParams, rng: &mut ThreadRng, work: &WorkD
|
||||
}
|
||||
}
|
||||
|
||||
scratch.absorb(&hits.to_ne_bytes());
|
||||
black_box(hits);
|
||||
}
|
||||
|
||||
fn reverse_buffer(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn reverse_buffer(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = params.buffer_size.min(1_048_576).max(1);
|
||||
let mut buf = vec![0u8; size];
|
||||
rng.fill_bytes(&mut buf);
|
||||
work.blend_into(&mut buf);
|
||||
scratch.blend_into(&mut buf);
|
||||
|
||||
for _ in 0..params.iterations {
|
||||
buf.reverse();
|
||||
}
|
||||
|
||||
scratch.absorb(&buf[..buf.len().min(256)]);
|
||||
black_box(&buf);
|
||||
}
|
||||
|
||||
fn interleave_buffers(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn interleave_buffers(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let half_size = (params.buffer_size / 2).max(1);
|
||||
let mut last_interleaved = Vec::new();
|
||||
for _ in 0..params.call_depth {
|
||||
let mut buf_a = vec![0u8; half_size];
|
||||
let mut buf_b = vec![0u8; half_size];
|
||||
rng.fill_bytes(&mut buf_a);
|
||||
rng.fill_bytes(&mut buf_b);
|
||||
work.blend_into(&mut buf_a);
|
||||
scratch.blend_into(&mut buf_a);
|
||||
|
||||
let mut interleaved = Vec::with_capacity(half_size * 2);
|
||||
for i in 0..half_size {
|
||||
@@ -212,17 +284,25 @@ fn interleave_buffers(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData)
|
||||
interleaved.push(buf_b[i]);
|
||||
}
|
||||
|
||||
last_interleaved = interleaved.clone();
|
||||
black_box(&interleaved);
|
||||
}
|
||||
scratch.absorb(&last_interleaved[..last_interleaved.len().min(256)]);
|
||||
}
|
||||
|
||||
fn scatter_gather(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
fn scatter_gather(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let size = params.buffer_size.min(1_048_576).max(1);
|
||||
let index_count = (size / 4).max(1);
|
||||
|
||||
let mut buffer = vec![0u8; size];
|
||||
rng.fill_bytes(&mut buffer);
|
||||
work.blend_into(&mut buffer);
|
||||
scratch.blend_into(&mut buffer);
|
||||
|
||||
for _ in 0..params.iterations.min(100) {
|
||||
let indices: Vec<usize> = (0..index_count).map(|_| rng.gen_range(0..size)).collect();
|
||||
@@ -236,91 +316,6 @@ fn scatter_gather(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData) {
|
||||
}
|
||||
}
|
||||
|
||||
scratch.absorb(&buffer[..buffer.len().min(256)]);
|
||||
black_box(&buffer);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::workdata::WorkData;
|
||||
|
||||
#[test]
|
||||
fn alloc_buffer_incorporates_work() {
|
||||
let mut buf = vec![0u8; 4096];
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&0xDEADBEEFu32);
|
||||
work.blend_into(&mut buf);
|
||||
assert!(buf.iter().any(|&b| b != 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn memcpy_source_modified() {
|
||||
let mut src = vec![0u8; 1024];
|
||||
let mut work = WorkData::new();
|
||||
work.feed("memcpy_context");
|
||||
work.blend_into(&mut src);
|
||||
assert!(src.iter().any(|&b| b != 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sort_seed_nonzero() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u32);
|
||||
assert_ne!(work.blend_seed(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pattern_xor_correct() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&0x55u8);
|
||||
let wb = work.as_bytes();
|
||||
assert_eq!(0xAAu8 ^ wb[0], 0xFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ring_buffer_initial_blend() {
|
||||
let mut buffer = vec![0u8; 256];
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&[1, 2, 3, 4]);
|
||||
work.blend_into(&mut buffer);
|
||||
assert_eq!(&buffer[..4], &[1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn binary_search_seed_nonzero() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u32);
|
||||
assert_ne!(work.blend_seed(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interleave_blends_only_buf_a() {
|
||||
let mut a = vec![0u8; 64];
|
||||
let b = vec![0u8; 64];
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&[0xAA; 8]);
|
||||
work.blend_into(&mut a);
|
||||
assert!(a.iter().any(|&v| v != 0));
|
||||
assert!(b.iter().all(|&v| v == 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_byte_cycles_across_buffer() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&[0xAB]);
|
||||
let mut buf = vec![0u8; 8];
|
||||
work.blend_into(&mut buf);
|
||||
assert!(buf.iter().all(|&b| b == 0xAB));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blend_into_reversible() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&0xCAFEBABEu32);
|
||||
let original = vec![42u8; 256];
|
||||
let mut buf = original.clone();
|
||||
work.blend_into(&mut buf);
|
||||
assert_ne!(buf, original);
|
||||
work.blend_into(&mut buf);
|
||||
assert_eq!(buf, original);
|
||||
}
|
||||
}
|
||||
|
||||
+144
-12
@@ -12,6 +12,8 @@ pub mod network;
|
||||
pub mod registry;
|
||||
#[cfg(feature = "cat-winapi")]
|
||||
pub mod winapi_tasks;
|
||||
#[cfg(feature = "cat-com")]
|
||||
pub mod com;
|
||||
|
||||
use crate::categories::Categories;
|
||||
use crate::workdata::WorkData;
|
||||
@@ -23,7 +25,42 @@ pub struct TaskParams {
|
||||
pub call_depth: usize,
|
||||
}
|
||||
|
||||
pub type TaskFn = fn(&TaskParams, &mut ThreadRng, &WorkData);
|
||||
pub(crate) const SCRATCH_SIZE: usize = 256;
|
||||
|
||||
pub(crate) struct ScratchBuffer {
|
||||
buf: [u8; SCRATCH_SIZE],
|
||||
}
|
||||
|
||||
impl ScratchBuffer {
|
||||
pub fn new() -> Self {
|
||||
Self { buf: [0u8; SCRATCH_SIZE] }
|
||||
}
|
||||
|
||||
pub fn seed_from(&mut self, work: &WorkData) {
|
||||
work.blend_into(&mut self.buf);
|
||||
}
|
||||
|
||||
pub fn blend_into(&self, dst: &mut [u8]) {
|
||||
for (i, byte) in dst.iter_mut().enumerate() {
|
||||
*byte ^= self.buf[i % SCRATCH_SIZE];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn absorb(&mut self, src: &[u8]) {
|
||||
if src.is_empty() {
|
||||
return;
|
||||
}
|
||||
for (i, byte) in self.buf.iter_mut().enumerate() {
|
||||
*byte ^= src[i % src.len()];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self) -> &[u8; SCRATCH_SIZE] {
|
||||
&self.buf
|
||||
}
|
||||
}
|
||||
|
||||
pub type TaskFn = fn(&TaskParams, &mut ThreadRng, &WorkData, &mut ScratchBuffer);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct TaskDescriptor {
|
||||
@@ -48,6 +85,8 @@ pub fn all_tasks() -> Vec<TaskDescriptor> {
|
||||
tasks.extend(network::register());
|
||||
#[cfg(feature = "cat-crypto")]
|
||||
tasks.extend(crypto::register());
|
||||
#[cfg(feature = "cat-com")]
|
||||
tasks.extend(com::register());
|
||||
tasks
|
||||
}
|
||||
|
||||
@@ -56,18 +95,23 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::workdata::WorkData;
|
||||
|
||||
fn non_network_tasks() -> Vec<TaskDescriptor> {
|
||||
fn safe_tasks() -> Vec<TaskDescriptor> {
|
||||
all_tasks()
|
||||
.into_iter()
|
||||
.filter(|t| !t.category.contains(Categories::NETWORK))
|
||||
.filter(|t| {
|
||||
!t.category.contains(Categories::NETWORK)
|
||||
&& !t.category.contains(Categories::COM)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn run_every_task(params: &TaskParams, work: &WorkData) {
|
||||
let tasks = non_network_tasks();
|
||||
let tasks = safe_tasks();
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut scratch = ScratchBuffer::new();
|
||||
scratch.seed_from(work);
|
||||
for task in &tasks {
|
||||
(task.func)(params, &mut rng, work);
|
||||
(task.func)(params, &mut rng, work, &mut scratch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +121,94 @@ mod tests {
|
||||
w
|
||||
}
|
||||
|
||||
// ── ScratchBuffer unit tests ───────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn scratch_new_is_zeroed() {
|
||||
let s = ScratchBuffer::new();
|
||||
assert!(s.read().iter().all(|&b| b == 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scratch_seed_from_work() {
|
||||
let mut work = WorkData::new();
|
||||
work.feed(&42u32);
|
||||
let mut s = ScratchBuffer::new();
|
||||
s.seed_from(&work);
|
||||
assert!(s.read().iter().any(|&b| b != 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scratch_seed_from_empty_stays_zero() {
|
||||
let work = WorkData::new();
|
||||
let mut s = ScratchBuffer::new();
|
||||
s.seed_from(&work);
|
||||
assert!(s.read().iter().all(|&b| b == 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scratch_absorb_changes_state() {
|
||||
let mut s = ScratchBuffer::new();
|
||||
s.absorb(&[0xFF; 32]);
|
||||
assert!(s.read().iter().any(|&b| b != 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scratch_absorb_empty_is_noop() {
|
||||
let mut s = ScratchBuffer::new();
|
||||
s.absorb(&[]);
|
||||
assert!(s.read().iter().all(|&b| b == 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scratch_blend_into_xors() {
|
||||
let mut s = ScratchBuffer::new();
|
||||
s.absorb(&[0xAB; 4]);
|
||||
let mut buf = [0u8; 4];
|
||||
s.blend_into(&mut buf);
|
||||
assert!(buf.iter().any(|&b| b != 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scratch_different_absorbs_different_state() {
|
||||
let mut s1 = ScratchBuffer::new();
|
||||
s1.absorb(&[0xFF; 4]);
|
||||
let mut s2 = ScratchBuffer::new();
|
||||
s2.absorb(&[0xAA; 4]);
|
||||
assert_ne!(s1.read(), s2.read());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scratch_chain_with_transform_order_dependent() {
|
||||
let mut s1 = ScratchBuffer::new();
|
||||
s1.absorb(&[1, 2, 3]);
|
||||
let mut buf = [0u8; 8];
|
||||
s1.blend_into(&mut buf);
|
||||
for b in buf.iter_mut() { *b = b.wrapping_mul(7).wrapping_add(3); }
|
||||
s1.absorb(&buf);
|
||||
|
||||
let mut s2 = ScratchBuffer::new();
|
||||
s2.absorb(&[4, 5, 6]);
|
||||
let mut buf = [0u8; 8];
|
||||
s2.blend_into(&mut buf);
|
||||
for b in buf.iter_mut() { *b = b.wrapping_mul(7).wrapping_add(3); }
|
||||
s2.absorb(&buf);
|
||||
|
||||
assert_ne!(s1.read(), s2.read(), "different initial data + transform = different chain");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scratch_chain_accumulates() {
|
||||
let mut s = ScratchBuffer::new();
|
||||
let state_0 = *s.read();
|
||||
s.absorb(&[0xFF]);
|
||||
let state_1 = *s.read();
|
||||
s.absorb(&[0xAA]);
|
||||
let state_2 = *s.read();
|
||||
assert_ne!(state_0, state_1);
|
||||
assert_ne!(state_1, state_2);
|
||||
}
|
||||
|
||||
// ── Registry completeness ──────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
@@ -121,9 +253,15 @@ mod tests {
|
||||
assert_eq!(n, 7, "expected 7 CRYPTO tasks");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_com_count() {
|
||||
let n = all_tasks().iter().filter(|t| t.category == Categories::COM).count();
|
||||
assert_eq!(n, 8, "expected 8 COM tasks");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_total() {
|
||||
assert_eq!(all_tasks().len(), 76, "expected 76 total tasks");
|
||||
assert_eq!(all_tasks().len(), 84, "expected 84 total tasks");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -137,8 +275,6 @@ mod tests {
|
||||
}
|
||||
|
||||
// ── Every task runs with every work-data shape ─────────────────────
|
||||
// These call every registered task function pointer directly, catching
|
||||
// panics from index-out-of-bounds, overflow, or allocation failures.
|
||||
|
||||
#[test]
|
||||
fn every_task_empty_work() {
|
||||
@@ -197,8 +333,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// ── Parameter edge cases × work data ───────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn every_task_zero_params_empty_work() {
|
||||
run_every_task(
|
||||
@@ -239,8 +373,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// ── Max-value work data that pushes derive_usize / blend_seed ──────
|
||||
|
||||
#[test]
|
||||
fn every_task_max_seed_work() {
|
||||
run_every_task(
|
||||
|
||||
+111
-94
@@ -1,8 +1,7 @@
|
||||
use crate::categories::Categories;
|
||||
use crate::tasks::{TaskDescriptor, TaskParams};
|
||||
use crate::tasks::{ScratchBuffer, TaskDescriptor, TaskParams};
|
||||
use crate::workdata::WorkData;
|
||||
use rand::rngs::ThreadRng;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::RngCore;
|
||||
use std::hint::black_box;
|
||||
use std::io::{Read, Write};
|
||||
@@ -67,7 +66,7 @@ pub fn register() -> Vec<TaskDescriptor> {
|
||||
]
|
||||
}
|
||||
|
||||
fn dns_lookups(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn dns_lookups(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let hosts = [
|
||||
"google.com:80",
|
||||
"microsoft.com:80",
|
||||
@@ -94,18 +93,23 @@ fn dns_lookups(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
"fastly.com:80",
|
||||
"aws.amazon.com:80",
|
||||
];
|
||||
for _ in 0..params.iterations.min(50) {
|
||||
if let Some(host) = hosts.choose(rng) {
|
||||
let _ = host.to_socket_addrs().map(|addrs| {
|
||||
for addr in addrs {
|
||||
black_box(addr);
|
||||
}
|
||||
});
|
||||
}
|
||||
let start_idx = work.derive_usize(0) % hosts.len();
|
||||
for i in 0..params.iterations.min(50) {
|
||||
let host = hosts[(start_idx + i) % hosts.len()];
|
||||
let _ = host.to_socket_addrs().map(|addrs| {
|
||||
for addr in addrs {
|
||||
let bytes = match addr {
|
||||
std::net::SocketAddr::V4(v4) => v4.ip().octets().to_vec(),
|
||||
std::net::SocketAddr::V6(v6) => v6.ip().octets().to_vec(),
|
||||
};
|
||||
scratch.absorb(&bytes);
|
||||
black_box(addr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn http_get(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn http_get(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let targets: &[(&str, u16, &str)] = &[
|
||||
("httpbin.org", 80, "/get"),
|
||||
("ip-api.com", 80, "/json"),
|
||||
@@ -119,30 +123,33 @@ fn http_get(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
("checkip.amazonaws.com", 80, "/"),
|
||||
("api.myip.com", 80, "/"),
|
||||
];
|
||||
for _ in 0..params.call_depth.min(5) {
|
||||
if let Some(&(host, port, path)) = targets.choose(rng) {
|
||||
let addr = format!("{}:{}", host, port);
|
||||
let stream = match TcpStream::connect(&*addr) {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
set_socket_timeouts(&stream, 3000);
|
||||
let request = format!(
|
||||
"GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n",
|
||||
path, host
|
||||
);
|
||||
let mut stream = stream;
|
||||
if stream.write_all(request.as_bytes()).is_err() {
|
||||
continue;
|
||||
}
|
||||
let mut response = vec![0u8; 4096];
|
||||
let _ = stream.read(&mut response);
|
||||
black_box(&response);
|
||||
let start_idx = work.derive_usize(0) % targets.len();
|
||||
for i in 0..params.call_depth.min(5) {
|
||||
let &(host, port, path) = &targets[(start_idx + i) % targets.len()];
|
||||
let addr = format!("{}:{}", host, port);
|
||||
let stream = match TcpStream::connect(&*addr) {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
set_socket_timeouts(&stream, 3000);
|
||||
let request = format!(
|
||||
"GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n",
|
||||
path, host
|
||||
);
|
||||
let mut stream = stream;
|
||||
if stream.write_all(request.as_bytes()).is_err() {
|
||||
continue;
|
||||
}
|
||||
let mut response = vec![0u8; 4096];
|
||||
let _ = stream.read(&mut response);
|
||||
work.blend_into(&mut response);
|
||||
scratch.blend_into(&mut response);
|
||||
scratch.absorb(&response[..response.len().min(256)]);
|
||||
black_box(&response);
|
||||
}
|
||||
}
|
||||
|
||||
fn ntp_query(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn ntp_query(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let servers = [
|
||||
"pool.ntp.org:123",
|
||||
"time.google.com:123",
|
||||
@@ -152,11 +159,9 @@ fn ntp_query(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
"time.nist.gov:123",
|
||||
"ntp.ubuntu.com:123",
|
||||
];
|
||||
for _ in 0..params.call_depth.min(5) {
|
||||
let server = match servers.choose(rng) {
|
||||
Some(s) => *s,
|
||||
None => continue,
|
||||
};
|
||||
let start_idx = work.derive_usize(0) % servers.len();
|
||||
for i in 0..params.call_depth.min(5) {
|
||||
let server = servers[(start_idx + i) % servers.len()];
|
||||
let socket = match UdpSocket::bind("0.0.0.0:0") {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
@@ -169,11 +174,12 @@ fn ntp_query(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
}
|
||||
let mut response = [0u8; 48];
|
||||
let _ = socket.recv_from(&mut response);
|
||||
scratch.absorb(&response);
|
||||
black_box(&response);
|
||||
}
|
||||
}
|
||||
|
||||
fn http_head_request(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn http_head_request(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let targets: &[(&str, u16, &str)] = &[
|
||||
("httpbin.org", 80, "/get"),
|
||||
("httpbin.org", 80, "/headers"),
|
||||
@@ -186,30 +192,31 @@ fn http_head_request(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData)
|
||||
("icanhazip.com", 80, "/"),
|
||||
("api.ipify.org", 80, "/"),
|
||||
];
|
||||
for _ in 0..params.call_depth.min(5) {
|
||||
if let Some(&(host, port, path)) = targets.choose(rng) {
|
||||
let addr = format!("{}:{}", host, port);
|
||||
let stream = match TcpStream::connect(&*addr) {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
set_socket_timeouts(&stream, 3000);
|
||||
let request = format!(
|
||||
"HEAD {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n",
|
||||
path, host
|
||||
);
|
||||
let mut stream = stream;
|
||||
if stream.write_all(request.as_bytes()).is_err() {
|
||||
continue;
|
||||
}
|
||||
let mut response = vec![0u8; 2048];
|
||||
let _ = stream.read(&mut response);
|
||||
black_box(&response);
|
||||
let start_idx = work.derive_usize(0) % targets.len();
|
||||
for i in 0..params.call_depth.min(5) {
|
||||
let &(host, port, path) = &targets[(start_idx + i) % targets.len()];
|
||||
let addr = format!("{}:{}", host, port);
|
||||
let stream = match TcpStream::connect(&*addr) {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
set_socket_timeouts(&stream, 3000);
|
||||
let request = format!(
|
||||
"HEAD {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n",
|
||||
path, host
|
||||
);
|
||||
let mut stream = stream;
|
||||
if stream.write_all(request.as_bytes()).is_err() {
|
||||
continue;
|
||||
}
|
||||
let mut response = vec![0u8; 2048];
|
||||
let _ = stream.read(&mut response);
|
||||
scratch.absorb(&response[..response.len().min(256)]);
|
||||
black_box(&response);
|
||||
}
|
||||
}
|
||||
|
||||
fn tcp_connect_probe(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn tcp_connect_probe(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let targets: &[(&str, u16)] = &[
|
||||
("google.com", 80),
|
||||
("google.com", 443),
|
||||
@@ -222,18 +229,20 @@ fn tcp_connect_probe(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData)
|
||||
("1.1.1.1", 53),
|
||||
("8.8.8.8", 53),
|
||||
];
|
||||
for _ in 0..params.iterations.min(10) {
|
||||
if let Some(&(host, port)) = targets.choose(rng) {
|
||||
let addr = format!("{}:{}", host, port);
|
||||
if let Ok(stream) = TcpStream::connect(&*addr) {
|
||||
set_socket_timeouts(&stream, 2000);
|
||||
black_box(&stream);
|
||||
}
|
||||
let start_idx = work.derive_usize(0) % targets.len();
|
||||
for i in 0..params.iterations.min(10) {
|
||||
let &(host, port) = &targets[(start_idx + i) % targets.len()];
|
||||
let addr = format!("{}:{}", host, port);
|
||||
if let Ok(stream) = TcpStream::connect(&*addr) {
|
||||
set_socket_timeouts(&stream, 2000);
|
||||
let marker = [host.as_bytes()[0], port as u8];
|
||||
scratch.absorb(&marker);
|
||||
black_box(&stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dns_varied_ports(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn dns_varied_ports(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let hosts = [
|
||||
"example.com:21",
|
||||
"example.com:22",
|
||||
@@ -251,18 +260,23 @@ fn dns_varied_ports(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData)
|
||||
"example.net:25",
|
||||
"example.net:8080",
|
||||
];
|
||||
for _ in 0..params.iterations.min(40) {
|
||||
if let Some(host) = hosts.choose(rng) {
|
||||
let _ = host.to_socket_addrs().map(|addrs| {
|
||||
for addr in addrs {
|
||||
black_box(addr);
|
||||
}
|
||||
});
|
||||
}
|
||||
let start_idx = work.derive_usize(0) % hosts.len();
|
||||
for i in 0..params.iterations.min(40) {
|
||||
let host = hosts[(start_idx + i) % hosts.len()];
|
||||
let _ = host.to_socket_addrs().map(|addrs| {
|
||||
for addr in addrs {
|
||||
let bytes = match addr {
|
||||
std::net::SocketAddr::V4(v4) => v4.ip().octets().to_vec(),
|
||||
std::net::SocketAddr::V6(v6) => v6.ip().octets().to_vec(),
|
||||
};
|
||||
scratch.absorb(&bytes);
|
||||
black_box(addr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn http_post_discard(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn http_post_discard(params: &TaskParams, rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let targets: &[(&str, u16, &str, &str)] = &[
|
||||
("httpbin.org", 80, "/post", "POST"),
|
||||
("httpbin.org", 80, "/anything", "POST"),
|
||||
@@ -274,27 +288,30 @@ fn http_post_discard(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData)
|
||||
let body_size = params.buffer_size.min(1024);
|
||||
let mut body = vec![0u8; body_size];
|
||||
rng.fill_bytes(&mut body);
|
||||
work.blend_into(&mut body);
|
||||
scratch.blend_into(&mut body);
|
||||
let body_hex: String = body.iter().map(|b| format!("{:02x}", b)).collect();
|
||||
|
||||
for _ in 0..params.call_depth.min(5) {
|
||||
if let Some(&(host, port, path, method)) = targets.choose(rng) {
|
||||
let addr = format!("{}:{}", host, port);
|
||||
let stream = match TcpStream::connect(&*addr) {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
set_socket_timeouts(&stream, 3000);
|
||||
let request = format!(
|
||||
"{} {} HTTP/1.1\r\nHost: {}\r\nContent-Type: text/plain\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
|
||||
method, path, host, body_hex.len(), body_hex
|
||||
);
|
||||
let mut stream = stream;
|
||||
if stream.write_all(request.as_bytes()).is_err() {
|
||||
continue;
|
||||
}
|
||||
let mut response = vec![0u8; 4096];
|
||||
let _ = stream.read(&mut response);
|
||||
black_box(&response);
|
||||
let start_idx = work.derive_usize(0) % targets.len();
|
||||
for i in 0..params.call_depth.min(5) {
|
||||
let &(host, port, path, method) = &targets[(start_idx + i) % targets.len()];
|
||||
let addr = format!("{}:{}", host, port);
|
||||
let stream = match TcpStream::connect(&*addr) {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
set_socket_timeouts(&stream, 3000);
|
||||
let request = format!(
|
||||
"{} {} HTTP/1.1\r\nHost: {}\r\nContent-Type: text/plain\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
|
||||
method, path, host, body_hex.len(), body_hex
|
||||
);
|
||||
let mut stream = stream;
|
||||
if stream.write_all(request.as_bytes()).is_err() {
|
||||
continue;
|
||||
}
|
||||
let mut response = vec![0u8; 4096];
|
||||
let _ = stream.read(&mut response);
|
||||
scratch.absorb(&response[..response.len().min(256)]);
|
||||
black_box(&response);
|
||||
}
|
||||
}
|
||||
|
||||
+47
-22
@@ -1,5 +1,5 @@
|
||||
use crate::categories::Categories;
|
||||
use crate::tasks::{TaskDescriptor, TaskParams};
|
||||
use crate::tasks::{ScratchBuffer, TaskDescriptor, TaskParams};
|
||||
use crate::workdata::WorkData;
|
||||
use rand::rngs::ThreadRng;
|
||||
use std::hint::black_box;
|
||||
@@ -137,7 +137,7 @@ unsafe fn enum_values(hkey: HKEY, max_values: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_installed_software(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_installed_software(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
const PATH: &[u16] = &{
|
||||
let mut arr = [0u16; 60];
|
||||
let bytes = b"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\0";
|
||||
@@ -148,12 +148,14 @@ fn read_installed_software(params: &TaskParams, _rng: &mut ThreadRng, _work: &Wo
|
||||
}
|
||||
arr
|
||||
};
|
||||
let iterations = params.iterations + work.derive_usize(0) % 8;
|
||||
unsafe {
|
||||
enum_subkeys(HKEY_LOCAL_MACHINE, PATH, params.iterations);
|
||||
enum_subkeys(HKEY_LOCAL_MACHINE, PATH, iterations);
|
||||
}
|
||||
scratch.absorb(&iterations.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_system_info_reg(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_system_info_reg(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
const PATH: &[u16] = &{
|
||||
let mut arr = [0u16; 50];
|
||||
let bytes = b"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\0";
|
||||
@@ -164,6 +166,7 @@ fn read_system_info_reg(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkD
|
||||
}
|
||||
arr
|
||||
};
|
||||
let call_depth = params.call_depth + work.blend_seed() as usize % 4;
|
||||
unsafe {
|
||||
let mut hkey = HKEY::default();
|
||||
let result = RegOpenKeyExW(
|
||||
@@ -174,6 +177,7 @@ fn read_system_info_reg(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkD
|
||||
&mut hkey,
|
||||
);
|
||||
if result.0 != 0 {
|
||||
scratch.absorb(&call_depth.to_ne_bytes());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -182,7 +186,7 @@ fn read_system_info_reg(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkD
|
||||
&encode_wide_const::<20>(b"CurrentBuild\0"),
|
||||
&encode_wide_const::<20>(b"EditionID\0"),
|
||||
];
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..call_depth {
|
||||
for name in value_names {
|
||||
read_string_value(hkey, name);
|
||||
}
|
||||
@@ -190,9 +194,10 @@ fn read_system_info_reg(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkD
|
||||
|
||||
let _ = RegCloseKey(hkey);
|
||||
}
|
||||
scratch.absorb(&call_depth.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn enumerate_services_reg(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_services_reg(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
const PATH: &[u16] = &{
|
||||
let mut arr = [0u16; 50];
|
||||
let bytes = b"SYSTEM\\CurrentControlSet\\Services\0";
|
||||
@@ -203,12 +208,14 @@ fn enumerate_services_reg(params: &TaskParams, _rng: &mut ThreadRng, _work: &Wor
|
||||
}
|
||||
arr
|
||||
};
|
||||
let iterations = params.iterations + work.derive_usize(0) % 8;
|
||||
unsafe {
|
||||
enum_subkeys(HKEY_LOCAL_MACHINE, PATH, params.iterations);
|
||||
enum_subkeys(HKEY_LOCAL_MACHINE, PATH, iterations);
|
||||
}
|
||||
scratch.absorb(&iterations.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_timezone_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_timezone_info(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
const PATH: &[u16] = &{
|
||||
let mut arr = [0u16; 60];
|
||||
let bytes = b"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\0";
|
||||
@@ -219,6 +226,7 @@ fn read_timezone_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
}
|
||||
arr
|
||||
};
|
||||
let call_depth = params.call_depth + work.blend_seed() as usize % 4;
|
||||
unsafe {
|
||||
let mut hkey = HKEY::default();
|
||||
let result = RegOpenKeyExW(
|
||||
@@ -229,6 +237,7 @@ fn read_timezone_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
&mut hkey,
|
||||
);
|
||||
if result.0 != 0 {
|
||||
scratch.absorb(&call_depth.to_ne_bytes());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -236,7 +245,7 @@ fn read_timezone_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
&encode_wide_const::<30>(b"TimeZoneKeyName\0"),
|
||||
&encode_wide_const::<20>(b"StandardName\0"),
|
||||
];
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..call_depth {
|
||||
for name in value_names {
|
||||
read_string_value(hkey, name);
|
||||
}
|
||||
@@ -244,9 +253,10 @@ fn read_timezone_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
|
||||
let _ = RegCloseKey(hkey);
|
||||
}
|
||||
scratch.absorb(&call_depth.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_environment_vars(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_environment_vars(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
const PATH: &[u16] = &{
|
||||
let mut arr = [0u16; 70];
|
||||
let bytes = b"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\0";
|
||||
@@ -257,6 +267,7 @@ fn read_environment_vars(params: &TaskParams, _rng: &mut ThreadRng, _work: &Work
|
||||
}
|
||||
arr
|
||||
};
|
||||
let call_depth = params.call_depth + work.blend_seed() as usize % 4;
|
||||
unsafe {
|
||||
let mut hkey = HKEY::default();
|
||||
let result = RegOpenKeyExW(
|
||||
@@ -267,6 +278,7 @@ fn read_environment_vars(params: &TaskParams, _rng: &mut ThreadRng, _work: &Work
|
||||
&mut hkey,
|
||||
);
|
||||
if result.0 != 0 {
|
||||
scratch.absorb(&call_depth.to_ne_bytes());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -281,7 +293,7 @@ fn read_environment_vars(params: &TaskParams, _rng: &mut ThreadRng, _work: &Work
|
||||
&encode_wide_const::<15>(b"ComSpec\0"),
|
||||
&encode_wide_const::<15>(b"windir\0"),
|
||||
];
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..call_depth {
|
||||
for name in value_names {
|
||||
read_string_value(hkey, name);
|
||||
}
|
||||
@@ -289,9 +301,10 @@ fn read_environment_vars(params: &TaskParams, _rng: &mut ThreadRng, _work: &Work
|
||||
|
||||
let _ = RegCloseKey(hkey);
|
||||
}
|
||||
scratch.absorb(&call_depth.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_network_config(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_network_config(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
const PATH: &[u16] = &{
|
||||
let mut arr = [0u16; 60];
|
||||
let bytes = b"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\0";
|
||||
@@ -312,6 +325,7 @@ fn read_network_config(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDa
|
||||
}
|
||||
arr
|
||||
};
|
||||
let call_depth = params.call_depth + work.blend_seed() as usize % 4;
|
||||
unsafe {
|
||||
let mut hkey = HKEY::default();
|
||||
let result = RegOpenKeyExW(
|
||||
@@ -329,7 +343,7 @@ fn read_network_config(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDa
|
||||
&encode_wide_const::<20>(b"NV Hostname\0"),
|
||||
&encode_wide_const::<20>(b"ICSDomain\0"),
|
||||
];
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..call_depth {
|
||||
for name in value_names {
|
||||
read_string_value(hkey, name);
|
||||
}
|
||||
@@ -339,9 +353,10 @@ fn read_network_config(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDa
|
||||
|
||||
enum_subkeys(HKEY_LOCAL_MACHINE, INTERFACES_PATH, params.iterations);
|
||||
}
|
||||
scratch.absorb(&call_depth.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_hardware_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_hardware_info(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
const PATH: &[u16] = &{
|
||||
let mut arr = [0u16; 60];
|
||||
let bytes = b"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\0";
|
||||
@@ -352,6 +367,7 @@ fn read_hardware_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
}
|
||||
arr
|
||||
};
|
||||
let call_depth = params.call_depth + work.blend_seed() as usize % 4;
|
||||
unsafe {
|
||||
let mut hkey = HKEY::default();
|
||||
let result = RegOpenKeyExW(
|
||||
@@ -362,6 +378,7 @@ fn read_hardware_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
&mut hkey,
|
||||
);
|
||||
if result.0 != 0 {
|
||||
scratch.absorb(&call_depth.to_ne_bytes());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -373,7 +390,7 @@ fn read_hardware_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
&encode_wide_const::<20>(b"FeatureSet\0"),
|
||||
&encode_wide_const::<15>(b"Update Status\0"),
|
||||
];
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..call_depth {
|
||||
for name in value_names {
|
||||
read_string_value(hkey, name);
|
||||
}
|
||||
@@ -381,9 +398,10 @@ fn read_hardware_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
|
||||
let _ = RegCloseKey(hkey);
|
||||
}
|
||||
scratch.absorb(&call_depth.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_font_list(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_font_list(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
const PATH: &[u16] = &{
|
||||
let mut arr = [0u16; 60];
|
||||
let bytes = b"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\0";
|
||||
@@ -394,6 +412,7 @@ fn read_font_list(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
}
|
||||
arr
|
||||
};
|
||||
let iterations = params.iterations + work.derive_usize(0) % 8;
|
||||
unsafe {
|
||||
let mut hkey = HKEY::default();
|
||||
let result = RegOpenKeyExW(
|
||||
@@ -404,16 +423,18 @@ fn read_font_list(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
&mut hkey,
|
||||
);
|
||||
if result.0 != 0 {
|
||||
scratch.absorb(&iterations.to_ne_bytes());
|
||||
return;
|
||||
}
|
||||
|
||||
enum_values(hkey, params.iterations);
|
||||
enum_values(hkey, iterations);
|
||||
|
||||
let _ = RegCloseKey(hkey);
|
||||
}
|
||||
scratch.absorb(&iterations.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_startup_programs(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_startup_programs(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
const PATH_HKLM: &[u16] = &{
|
||||
let mut arr = [0u16; 50];
|
||||
let bytes = b"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\0";
|
||||
@@ -434,6 +455,7 @@ fn read_startup_programs(params: &TaskParams, _rng: &mut ThreadRng, _work: &Work
|
||||
}
|
||||
arr
|
||||
};
|
||||
let iterations = params.iterations + work.derive_usize(0) % 8;
|
||||
unsafe {
|
||||
let mut hkey = HKEY::default();
|
||||
let result = RegOpenKeyExW(
|
||||
@@ -444,7 +466,7 @@ fn read_startup_programs(params: &TaskParams, _rng: &mut ThreadRng, _work: &Work
|
||||
&mut hkey,
|
||||
);
|
||||
if result.0 == 0 {
|
||||
enum_values(hkey, params.iterations);
|
||||
enum_values(hkey, iterations);
|
||||
let _ = RegCloseKey(hkey);
|
||||
}
|
||||
|
||||
@@ -457,16 +479,18 @@ fn read_startup_programs(params: &TaskParams, _rng: &mut ThreadRng, _work: &Work
|
||||
&mut hkey,
|
||||
);
|
||||
if result.0 == 0 {
|
||||
enum_values(hkey, params.iterations);
|
||||
enum_values(hkey, iterations);
|
||||
let _ = RegCloseKey(hkey);
|
||||
}
|
||||
}
|
||||
scratch.absorb(&iterations.to_ne_bytes());
|
||||
}
|
||||
|
||||
fn read_file_associations(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_file_associations(params: &TaskParams, _rng: &mut ThreadRng, work: &WorkData, scratch: &mut ScratchBuffer) {
|
||||
let iterations = params.iterations + work.derive_usize(0) % 8;
|
||||
unsafe {
|
||||
let mut name_buf = [0u16; 256];
|
||||
for i in 0..params.iterations as u32 {
|
||||
for i in 0..iterations as u32 {
|
||||
let mut name_len = name_buf.len() as u32;
|
||||
let result = RegEnumKeyExW(
|
||||
HKEY_CLASSES_ROOT,
|
||||
@@ -486,6 +510,7 @@ fn read_file_associations(params: &TaskParams, _rng: &mut ThreadRng, _work: &Wor
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch.absorb(&iterations.to_ne_bytes());
|
||||
}
|
||||
|
||||
const fn encode_wide_const<const N: usize>(bytes: &[u8]) -> [u16; N] {
|
||||
|
||||
+223
-29
@@ -1,5 +1,5 @@
|
||||
use crate::categories::Categories;
|
||||
use crate::tasks::{TaskDescriptor, TaskParams};
|
||||
use crate::tasks::{ScratchBuffer, TaskDescriptor, TaskParams};
|
||||
use crate::workdata::WorkData;
|
||||
use rand::rngs::ThreadRng;
|
||||
use rand::Rng;
|
||||
@@ -107,21 +107,41 @@ unsafe extern "system" fn enum_window_callback(hwnd: HWND, lparam: LPARAM) -> BO
|
||||
BOOL(1)
|
||||
}
|
||||
|
||||
fn enumerate_windows(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_windows(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 8;
|
||||
unsafe {
|
||||
let mut windows: Vec<HWND> = Vec::new();
|
||||
let ptr = &mut windows as *mut Vec<HWND> as isize;
|
||||
let _ = EnumWindows(Some(enum_window_callback), LPARAM(ptr));
|
||||
|
||||
for hwnd in windows.iter().take(params.iterations) {
|
||||
let mut last_text = [0u16; 256];
|
||||
for hwnd in windows.iter().skip(skip).take(params.iterations) {
|
||||
let mut text = [0u16; 256];
|
||||
GetWindowTextW(*hwnd, &mut text);
|
||||
last_text = text;
|
||||
black_box(&text);
|
||||
}
|
||||
let text_bytes: &[u8] = std::slice::from_raw_parts(
|
||||
last_text.as_ptr() as *const u8,
|
||||
last_text.len() * 2,
|
||||
);
|
||||
scratch.absorb(text_bytes);
|
||||
black_box(&last_text);
|
||||
}
|
||||
}
|
||||
|
||||
fn enumerate_processes(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn enumerate_processes(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 4;
|
||||
unsafe {
|
||||
let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
let snapshot = match snapshot {
|
||||
@@ -134,8 +154,22 @@ fn enumerate_processes(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDa
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut last_pid: u32 = 0;
|
||||
if Process32FirstW(snapshot, &mut entry).is_ok() {
|
||||
let mut skipped = 0;
|
||||
loop {
|
||||
if skipped < skip {
|
||||
skipped += 1;
|
||||
if Process32NextW(snapshot, &mut entry).is_err() {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for _ in 0..params.iterations {
|
||||
last_pid = entry.th32ProcessID;
|
||||
black_box(entry.th32ProcessID);
|
||||
black_box(&entry.szExeFile);
|
||||
if Process32NextW(snapshot, &mut entry).is_err() {
|
||||
@@ -144,13 +178,21 @@ fn enumerate_processes(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDa
|
||||
}
|
||||
}
|
||||
|
||||
scratch.absorb(&last_pid.to_ne_bytes());
|
||||
black_box(last_pid);
|
||||
let _ = CloseHandle(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
fn query_system_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn query_system_info(
|
||||
_params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let loops = _params.call_depth + (work.blend_seed() % 2) as usize;
|
||||
unsafe {
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..loops {
|
||||
let mut sys_info = SYSTEM_INFO::default();
|
||||
GetSystemInfo(&mut sys_info);
|
||||
black_box(sys_info.dwNumberOfProcessors);
|
||||
@@ -161,22 +203,37 @@ fn query_system_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData
|
||||
};
|
||||
let _ = GlobalMemoryStatusEx(&mut mem_status);
|
||||
black_box(mem_status.ullTotalPhys);
|
||||
|
||||
scratch.absorb(&sys_info.dwNumberOfProcessors.to_ne_bytes());
|
||||
scratch.absorb(&mem_status.ullTotalPhys.to_ne_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_clipboard(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn read_clipboard(
|
||||
_params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let loops = _params.call_depth + (work.blend_seed() % 2) as usize;
|
||||
unsafe {
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..loops {
|
||||
if OpenClipboard(HWND::default()).is_ok() {
|
||||
let _ = black_box(GetClipboardData(1));
|
||||
let _ = CloseClipboard();
|
||||
}
|
||||
scratch.absorb(&[0xCB]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_system_metrics(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_system_metrics(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
const METRIC_INDICES: [i32; 10] = [
|
||||
0, // SM_CXSCREEN
|
||||
1, // SM_CYSCREEN
|
||||
@@ -190,19 +247,27 @@ fn get_system_metrics(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData
|
||||
67, // SM_CLEANBOOT
|
||||
];
|
||||
|
||||
let start_idx = work.derive_usize(0) % 10;
|
||||
unsafe {
|
||||
for _ in 0..params.iterations {
|
||||
let idx = rng.gen_range(0..METRIC_INDICES.len());
|
||||
let idx = (start_idx + rng.gen_range(0..METRIC_INDICES.len())) % METRIC_INDICES.len();
|
||||
let metric = METRIC_INDICES[idx];
|
||||
let value = GetSystemMetrics(SYSTEM_METRICS_INDEX(metric));
|
||||
scratch.absorb(&value.to_ne_bytes());
|
||||
black_box(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_foreground_window_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_foreground_window_info(
|
||||
_params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let loops = _params.call_depth + (work.blend_seed() % 2) as usize;
|
||||
unsafe {
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..loops {
|
||||
let hwnd = GetForegroundWindow();
|
||||
if hwnd.0 == std::ptr::null_mut() {
|
||||
continue;
|
||||
@@ -217,24 +282,49 @@ fn get_foreground_window_info(params: &TaskParams, _rng: &mut ThreadRng, _work:
|
||||
black_box(rect.top);
|
||||
black_box(rect.right);
|
||||
black_box(rect.bottom);
|
||||
|
||||
let rect_bytes: &[u8] = std::slice::from_raw_parts(
|
||||
&rect as *const RECT as *const u8,
|
||||
std::mem::size_of::<RECT>(),
|
||||
);
|
||||
scratch.absorb(rect_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cursor_position(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_cursor_position(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
_work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let mut last_point = POINT::default();
|
||||
unsafe {
|
||||
for _ in 0..params.iterations {
|
||||
let mut point = POINT::default();
|
||||
let _ = GetCursorPos(&mut point);
|
||||
last_point = point;
|
||||
black_box(point.x);
|
||||
black_box(point.y);
|
||||
}
|
||||
let point_bytes: &[u8] = std::slice::from_raw_parts(
|
||||
&last_point as *const POINT as *const u8,
|
||||
std::mem::size_of::<POINT>(),
|
||||
);
|
||||
scratch.absorb(point_bytes);
|
||||
black_box(&last_point);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_desktop_window_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_desktop_window_info(
|
||||
_params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let loops = _params.call_depth + (work.blend_seed() % 2) as usize;
|
||||
unsafe {
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..loops {
|
||||
let hwnd = GetDesktopWindow();
|
||||
|
||||
let mut rect = RECT::default();
|
||||
@@ -252,11 +342,23 @@ fn get_desktop_window_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &Wo
|
||||
let mut text = [0u16; 256];
|
||||
GetWindowTextW(hwnd, &mut text);
|
||||
black_box(&text);
|
||||
|
||||
let rect_bytes: &[u8] = std::slice::from_raw_parts(
|
||||
&rect as *const RECT as *const u8,
|
||||
std::mem::size_of::<RECT>(),
|
||||
);
|
||||
scratch.absorb(rect_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_logical_drives_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_logical_drives_info(
|
||||
_params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let extra_loops = _params.call_depth + (work.blend_seed() % 2) as usize;
|
||||
unsafe {
|
||||
let mask = GetLogicalDrives();
|
||||
if mask == 0 {
|
||||
@@ -274,16 +376,25 @@ fn get_logical_drives_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &Wo
|
||||
black_box(drive_type);
|
||||
}
|
||||
|
||||
for _ in 1..params.call_depth {
|
||||
for _ in 1..extra_loops {
|
||||
let m = GetLogicalDrives();
|
||||
black_box(m);
|
||||
}
|
||||
|
||||
scratch.absorb(&mask.to_ne_bytes());
|
||||
black_box(mask);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_volume_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_volume_info(
|
||||
_params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let loops = _params.call_depth + (work.blend_seed() % 2) as usize;
|
||||
unsafe {
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..loops {
|
||||
let mut volume_name = [0u16; 260];
|
||||
let mut serial_number: u32 = 0;
|
||||
let mut max_component_length: u32 = 0;
|
||||
@@ -304,14 +415,21 @@ fn get_volume_info(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData)
|
||||
black_box(max_component_length);
|
||||
black_box(fs_flags);
|
||||
black_box(&fs_name);
|
||||
scratch.absorb(&serial_number.to_ne_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_disk_free_space(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_disk_free_space(
|
||||
_params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let loops = _params.call_depth + (work.blend_seed() % 2) as usize;
|
||||
unsafe {
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..loops {
|
||||
let mut free_bytes_available: u64 = 0;
|
||||
let mut total_bytes: u64 = 0;
|
||||
let mut total_free_bytes: u64 = 0;
|
||||
@@ -326,12 +444,19 @@ fn get_disk_free_space(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDa
|
||||
black_box(free_bytes_available);
|
||||
black_box(total_bytes);
|
||||
black_box(total_free_bytes);
|
||||
scratch.absorb(&total_free_bytes.to_ne_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_files_pattern(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn find_files_pattern(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let skip = work.derive_usize(0) % 8;
|
||||
unsafe {
|
||||
let mut find_data = WIN32_FIND_DATAW::default();
|
||||
let handle = FindFirstFileW(w!("C:\\Windows\\System32\\*.dll"), &mut find_data);
|
||||
@@ -340,6 +465,17 @@ fn find_files_pattern(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// Skip first N entries
|
||||
for _ in 0..skip {
|
||||
if FindNextFileW(handle, &mut find_data).is_err() {
|
||||
let _ = FindClose(handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Process up to iterations entries
|
||||
let mut last_size: u64 =
|
||||
((find_data.nFileSizeHigh as u64) << 32) | (find_data.nFileSizeLow as u64);
|
||||
black_box(&find_data.cFileName);
|
||||
black_box(find_data.nFileSizeHigh);
|
||||
black_box(find_data.nFileSizeLow);
|
||||
@@ -348,16 +484,25 @@ fn find_files_pattern(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkDat
|
||||
if FindNextFileW(handle, &mut find_data).is_err() {
|
||||
break;
|
||||
}
|
||||
last_size =
|
||||
((find_data.nFileSizeHigh as u64) << 32) | (find_data.nFileSizeLow as u64);
|
||||
black_box(&find_data.cFileName);
|
||||
black_box(find_data.nFileSizeHigh);
|
||||
black_box(find_data.nFileSizeLow);
|
||||
}
|
||||
|
||||
scratch.absorb(&last_size.to_ne_bytes());
|
||||
black_box(last_size);
|
||||
let _ = FindClose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_module_handles(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_module_handles(
|
||||
params: &TaskParams,
|
||||
rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let dll_names: &[PCWSTR] = &[
|
||||
w!("kernel32.dll"),
|
||||
w!("ntdll.dll"),
|
||||
@@ -373,12 +518,15 @@ fn get_module_handles(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData
|
||||
w!("combase.dll"),
|
||||
];
|
||||
|
||||
let start_idx = work.derive_usize(0) % 12;
|
||||
let mut last_handle: usize = 0;
|
||||
unsafe {
|
||||
for _ in 0..params.iterations {
|
||||
let idx = rng.gen_range(0..dll_names.len());
|
||||
let idx = (start_idx + rng.gen_range(0..dll_names.len())) % dll_names.len();
|
||||
let result = GetModuleHandleW(dll_names[idx]);
|
||||
match result {
|
||||
Ok(h) => {
|
||||
last_handle = h.0 as usize;
|
||||
black_box(h);
|
||||
}
|
||||
Err(_) => {
|
||||
@@ -386,13 +534,22 @@ fn get_module_handles(params: &TaskParams, rng: &mut ThreadRng, _work: &WorkData
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch.absorb(&last_handle.to_ne_bytes());
|
||||
black_box(last_handle);
|
||||
}
|
||||
}
|
||||
|
||||
fn virtual_query_memory(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn virtual_query_memory(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let bias = work.derive_usize(0) % 65536;
|
||||
unsafe {
|
||||
let mut addr: usize = 0;
|
||||
let mut addr: usize = bias;
|
||||
let info_size = std::mem::size_of::<MEMORY_BASIC_INFORMATION>();
|
||||
let mut last_info = MEMORY_BASIC_INFORMATION::default();
|
||||
|
||||
for _ in 0..params.iterations {
|
||||
let mut info = MEMORY_BASIC_INFORMATION::default();
|
||||
@@ -404,6 +561,7 @@ fn virtual_query_memory(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkD
|
||||
if result == 0 {
|
||||
break;
|
||||
}
|
||||
last_info = info;
|
||||
black_box(info.BaseAddress);
|
||||
black_box(info.RegionSize);
|
||||
black_box(info.State);
|
||||
@@ -419,35 +577,71 @@ fn virtual_query_memory(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkD
|
||||
None => break,
|
||||
};
|
||||
}
|
||||
|
||||
let info_bytes: &[u8] = std::slice::from_raw_parts(
|
||||
&last_info as *const MEMORY_BASIC_INFORMATION as *const u8,
|
||||
std::mem::size_of::<MEMORY_BASIC_INFORMATION>(),
|
||||
);
|
||||
scratch.absorb(info_bytes);
|
||||
black_box(&last_info);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_system_directories(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_system_directories(
|
||||
_params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
let loops = _params.call_depth + (work.blend_seed() % 2) as usize;
|
||||
unsafe {
|
||||
for _ in 0..params.call_depth {
|
||||
for _ in 0..loops {
|
||||
let mut sys_dir = [0u16; 260];
|
||||
let len = GetSystemDirectoryW(Some(&mut sys_dir));
|
||||
if len > 0 {
|
||||
let dir_bytes: &[u8] = std::slice::from_raw_parts(
|
||||
sys_dir.as_ptr() as *const u8,
|
||||
(len as usize) * 2,
|
||||
);
|
||||
scratch.absorb(dir_bytes);
|
||||
black_box(&sys_dir[..len as usize]);
|
||||
}
|
||||
|
||||
let mut win_dir = [0u16; 260];
|
||||
let len = GetWindowsDirectoryW(Some(&mut win_dir));
|
||||
if len > 0 {
|
||||
let dir_bytes: &[u8] = std::slice::from_raw_parts(
|
||||
win_dir.as_ptr() as *const u8,
|
||||
(len as usize) * 2,
|
||||
);
|
||||
scratch.absorb(dir_bytes);
|
||||
black_box(&win_dir[..len as usize]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_process_thread_ids(params: &TaskParams, _rng: &mut ThreadRng, _work: &WorkData) {
|
||||
fn get_process_thread_ids(
|
||||
params: &TaskParams,
|
||||
_rng: &mut ThreadRng,
|
||||
_work: &WorkData,
|
||||
scratch: &mut ScratchBuffer,
|
||||
) {
|
||||
unsafe {
|
||||
let mut last_pid: u32 = 0;
|
||||
let mut last_tid: u32 = 0;
|
||||
for _ in 0..params.iterations {
|
||||
let pid = GetCurrentProcessId();
|
||||
last_pid = pid;
|
||||
black_box(pid);
|
||||
|
||||
let tid = GetCurrentThreadId();
|
||||
last_tid = tid;
|
||||
black_box(tid);
|
||||
}
|
||||
scratch.absorb(&last_pid.to_ne_bytes());
|
||||
scratch.absorb(&last_tid.to_ne_bytes());
|
||||
black_box(last_pid);
|
||||
black_box(last_tid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,6 +163,11 @@ fn feed_crypto_no_panic() {
|
||||
sample_feed().allow(Categories::CRYPTO).run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn feed_com_no_panic() {
|
||||
sample_feed().allow(Categories::COM).run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn feed_all_categories_no_panic() {
|
||||
sample_feed().deny(Categories::NETWORK).run();
|
||||
|
||||
@@ -51,4 +51,10 @@ fn available_returns_all_compiled() {
|
||||
assert!(avail.contains(Categories::COMPUTE));
|
||||
assert!(avail.contains(Categories::MEMORY));
|
||||
assert!(avail.contains(Categories::FILESYSTEM));
|
||||
assert!(avail.contains(Categories::COM));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn high_com_only() {
|
||||
busywork_with(Intensity::High, Categories::COM);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user