core/fault
Shared: available on every enabled target.
Deterministic allocation-failure injection over any allocator, with cumulative counters.
new wraps a provider in an injector. The budget counts delegated attempts, including attempts the inner provider refuses, so wrapping an arena counts both injected failures and the arena's own. permit replaces that budget without resetting evidence. Free calls delegate to the parent; in-place growth is refused so allocation-failure tests remain predictable.
Items
- injector type
- attempts function
- delegated function
- frees function
- injected_failures function
- inner_failures function
- live function
- new function
- permit function
- remaining function
- successes function
Executable example
This complete program is maintained in the repository runtime tests. View source.
import core/mem import core/fault exercise: () -> (ok: bool) ! mem.out_of_memory = ok = false mut backing: [32]u8 = zeroed mut inner := mem.arena_over_unchecked(addr backing[0], 32) mut state := fault.new(addr inner, usize(1)) address := try mem.allocate(state, usize(4), usize(1)) address.val = 42 return when address.val <> 42 _ = mem.allocate(state, usize(4), usize(1)) else (problem) _ = problem ok = fault.successes(state) == 1 and fault.injected_failures(state) == 1 mem.free(state, address, usize(4)) return end end exercise public main: () -> (code: i32) = code = 1 ok := exercise() else false if ok then code = 42 end if end main
injector type
public injector: type (inner_provider: type) = struct
inner: ptr mut inner_provider
remaining: usize
attempts: usize
delegated: usize
successes: usize
injected_failures: usize
inner_failures: usize
frees: usize
live: usize
end injectorAllocator wrapper with deterministic failure injection and cumulative counters. Borrows its inner provider, delegates permitted allocations and frees, and refuses in-place growth.
attempts function
public attempts: (inner_provider: type,
state: injector(inner_provider)) -> (count: usize)Return all allocation attempts, including injected and inner failures.
delegated function
public delegated: (inner_provider: type,
state: injector(inner_provider)) -> (count: usize)Return allocation attempts passed through to the inner provider.
frees function
public frees: (inner_provider: type,
state: injector(inner_provider)) -> (count: usize)Return the number of delegated free calls.
injected_failures function
public injected_failures: (inner_provider: type,
state: injector(inner_provider))
-> (count: usize)Return attempts rejected by the wrapper before calling the inner provider.
inner_failures function
public inner_failures: (inner_provider: type,
state: injector(inner_provider)) -> (count: usize)Return allocation failures reported by the inner provider.
live function
public live: (inner_provider: type,
state: injector(inner_provider)) -> (count: usize)Return successful allocations minus free calls, bounded below by zero. Exact under the allocator contract; malformed or duplicate frees are not validated here.
new function
public new: (inner_provider: type is mem.allocator,
inner: ptr mut inner_provider,
allowed_attempts: usize)
-> (state: injector(inner_provider) from inner)Wrap an allocator with a budget of allowed_attempts allocation calls that may reach it. An inner failure consumes one of them too; an injected failure never calls the inner provider and counts only in attempts and injected_failures.
permit function
public permit: (inner_provider: type,
inout state: injector(inner_provider),
allowed_attempts: usize) -> noneReplace the future delegation budget without resetting the counters, so failed and successful calls stay distinguishable across retries.
remaining function
public remaining: (inner_provider: type,
state: injector(inner_provider)) -> (count: usize)Return how many allocation attempts may still reach the inner provider.
successes function
public successes: (inner_provider: type,
state: injector(inner_provider)) -> (count: usize)Return the number of successful delegated allocations.