aligned-vmem 0.2.0

Cross-platform aligned anonymous virtual memory: reserve, commit, decommit, and release power-of-two-aligned spans via mmap/VirtualAlloc. Zero dependencies, miri-friendly.
Documentation
use crate::error::VmemError;
#[cfg(all(feature = "fault-injection", not(aligned_vmem_mock)))]
use crate::fault_injection;
#[cfg(aligned_vmem_mock)]
use crate::mock;
#[cfg(not(aligned_vmem_mock))]
use crate::os::commit_range_impl;
use crate::page_size::{page_size_or_poison, PAGE_SIZE_QUERY_FAILED};

/// Commit pages `[base + start, base + end)` within an existing reservation.
///
/// This is the incremental-commit building block: after a
/// [`reserve_aligned_lazy`](crate::api::reserve_aligned_lazy) call that left some pages reserved-but-uncommitted,
/// `commit_range` commits exactly the requested sub-range so it becomes
/// writable. On Windows this issues `VirtualAlloc(MEM_COMMIT)`; on Unix and
/// under miri the pages are already accessible, so this is a no-op that always
/// returns `true`.
///
/// `start` and `end` must be multiples of the runtime page size ([`page_size()`](crate::page_size))
/// with `start <= end`. A well-formed no-op (an empty PAGE-ALIGNED range,
/// `start == end`) returns `true`; any other contract violation (misaligned,
/// or `start > end`) returns `false` (task #712: an earlier version of this
/// function clamped a
/// contract violation to the WRITE-PERMITTING `true` sentinel, which already
/// caused a real crash — see
/// <https://github.com/PHPCraftdream/sefer-alloc/blob/main/docs/CORRECTNESS_OPEN_ITEMS.md>
/// item 6 for the incident this class of bug produces on Windows).
///
/// Returns `true` if the range is now committed, `false` if the OS refused
/// (commit-charge exhaustion / true OOM) OR the offsets violated the contract
/// above. On `false` the caller MUST NOT write into the range. Never panics.
/// For the cause use [`try_commit_range`].
///
/// # Difference from [`recommit`](crate::api::recommit)
///
/// [`recommit`](crate::api::recommit) re-commits pages that were PREVIOUSLY committed and then
/// decommitted via [`decommit`](crate::api::decommit). `commit_range` commits pages that were NEVER
/// committed (reserved via the lazy path). The underlying Windows syscall is
/// the same; the semantic intent differs.
///
/// # Safety
///
/// `base` must be the [`as_ptr`](crate::Reservation::as_ptr) of a live reservation,
/// and `[base+start, base+end)` must fall within that reservation's usable span
/// (i.e. `end <= len`). The range must be currently reserved but not yet
/// committed (or already committed — recommitting is harmless on Windows).
///
/// **Concurrent calls are safe** (task #776, F14): multiple threads may call
/// `commit_range` concurrently on ranges within the SAME reservation, whether
/// the ranges overlap or not — `VirtualAlloc(MEM_COMMIT)` (Windows) is itself
/// thread-safe and idempotent, and the Unix/miri backends are no-ops (the
/// entire span is already committed eagerly on those platforms). This does
/// NOT relax the range/liveness contract above; it only states that issuing
/// several legal calls from different threads at once is not itself a new
/// hazard. (Scalability caveat, not a safety one: with the `fault-injection`
/// feature compiled in, the pre-syscall hook's `FAULT_STATE` mutex serializes
/// concurrent callers — see the hook comment in [`try_commit_range`].)
#[must_use]
#[cfg(feature = "lazy-commit")]
#[cfg_attr(docsrs, doc(cfg(feature = "lazy-commit")))]
pub unsafe fn commit_range(base: *mut u8, start: usize, end: usize) -> bool {
    // SAFETY: forwarded from the caller's contract.
    unsafe { try_commit_range(base, start, end).is_ok() }
}

/// Fallible [`commit_range`]: `Ok(())` on success (or was a well-formed no-op),
/// `Err(VmemError::invalid_argument())` if the offsets violated the contract
/// (misaligned, or `start > end`), `Err(VmemError)` carrying the OS cause on
/// genuine commit failure.
///
/// # Safety
///
/// Same as [`commit_range`].
#[cfg(feature = "lazy-commit")]
#[cfg_attr(docsrs, doc(cfg(feature = "lazy-commit")))]
pub unsafe fn try_commit_range(base: *mut u8, start: usize, end: usize) -> Result<(), VmemError> {
    let ps = page_size_or_poison();
    // Failed OS page-size query: fail closed with the OS-side no-code error
    // (NOT `invalid_argument` — the caller's arguments are not at fault).
    // See `page_size`'s "If the one-time OS query fails" paragraph.
    if ps == PAGE_SIZE_QUERY_FAILED {
        return Err(VmemError::os_refusal_unknown_code());
    }
    if start > end || !start.is_multiple_of(ps) || !end.is_multiple_of(ps) {
        return Err(VmemError::invalid_argument());
    }
    if start == end {
        return Ok(());
    }
    #[cfg(aligned_vmem_mock)]
    {
        mock::record(mock::Call::CommitRange {
            base: base.addr(),
            start,
            end,
        });
        mock::take_commit_fault().map_or(Ok(()), Err)
    }
    #[cfg(not(aligned_vmem_mock))]
    {
        // Real-path fault injection (feature `fault-injection`, DISTINCT from
        // `mock`): consult the armed hooks immediately before the real
        // syscall. Cost when the feature is compiled in (task #1068/F4
        // corrected this comment, which previously claimed "two relaxed
        // loads"): even with NOTHING armed, every real commit pays one atomic
        // read-modify-write (`FAIL_NEXT::fetch_update`) plus an unconditional
        // uncontended `FAULT_STATE` mutex acquire — the `target` check happens
        // under the lock — serializing concurrent committers process-wide for
        // as long as the feature is on (task #1021/R4-8 traded the old
        // two-atomics fast path for arm/fire atomicity). Acceptable because
        // the feature is test-only by design; when it is off, this block is
        // compiled out entirely and the production path is unchanged.
        #[cfg(feature = "fault-injection")]
        if fault_injection::should_fail_commit() {
            // task #713: this is a SIMULATED failure — no real syscall ran,
            // so `VmemError::last_os_error()` would read whatever `errno`/
            // `GetLastError` happens to be lying around from unrelated prior
            // code, not a cause tied to this call at all.
            // `os_refusal_unknown_code()` reports the no-code state without
            // manufacturing a misleading one. Task #1141: this comment used
            // to say the constructor "states plainly that the OS refused" —
            // which contradicts the line four above it. The OS did NOT
            // refuse; no syscall ran at all. This simulated fault is one of
            // the sentinel's two TEST-ONLY sources (task #1173/L2,
            // re-verified task #1194) — deliberately NOT one of the four
            // PRODUCTION causes its own doc enumerates (see
            // `VmemError::os_refusal_unknown_code`'s doc) — and it is
            // deliberately NOT named after an OS refusal either way.
            return Err(VmemError::os_refusal_unknown_code());
        }
        // SAFETY: forwarded from the caller's contract.
        unsafe { commit_range_impl(base, start, end) }
    }
}