Add debug-only stomp allocator mode to the D3D12 backend - #314
Draft
Jasper-Bekkers wants to merge 1 commit into
Draft
Jasper-Bekkers wants to merge 1 commit into
Jasper-Bekkers wants to merge 1 commit into
Conversation
Opt-in guard-page detection for resources created through `Allocator::create_resource()`. A stomp resource is a reserved (tiled) resource: payload tiles map into the normal sub-allocator blocks, guard tiles map to a 64KB heap created with `CREATE_NOT_RESIDENT` that is never made resident. A GPU access past the end (or, optionally, before the start) page-faults and removes the device with `DXGI_ERROR_DEVICE_HUNG`. Freed resources can be quarantined so that use-after-free faults too. Public API: `AllocatorCreateDesc::stomp: Option<StompSettings>`, `StompSettings::new(queue)` with `mode` (`All`, `Random`, `OptIn`, `Filter`), `tail_guard`, `head_guard`, `payload_alignment` for byte-precise tail guards via `Resource::offset()`, and `quarantine`; `ResourceCreateDesc::stomp: Option<bool>` per-resource override; `Resource::is_stomp_guarded()` / `stomp_layout()`; `Allocator::stomp_statistics()`. The first design tried adjacent heaps with tight placed resource alignment and no offset contract; measured on NVIDIA it guards only 55 to 105 of 500 buffers under churn and breaks across threads, see docs/d3d12-stomp-allocator.md section 8. Tests: 8 unit, 26 device tests (run on WARP in CI), 9 hardware fault tests behind `GPU_ALLOCATOR_STOMP_FAULT_TESTS=1`, and an example. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Opt-in guard-page ("stomp") detection for D3D12 resources created through
Allocator::create_resource(). Off by default, zero cost whenAllocatorCreateDesc::stompisNone.A stomp resource is a reserved (tiled) resource. Payload tiles map into the normal sub-allocator blocks, so placement, leak reports and the visualizer keep working. Guard tiles map to one 64KB heap per memory type created with
D3D12_HEAP_FLAG_CREATE_NOT_RESIDENTand never made resident (Evictis only a hint, per Jesse Natalie). A GPU access to a guard tile page-faults and removes the device withDXGI_ERROR_DEVICE_HUNG. Withquarantineon, freed resources have every tile remapped to that heap and stay alive until the allocator drops, so use-after-free faults too.All stomp code lives in
src/d3d12/stomp.rs;mod.rsonly has the hook points.API
AllocatorCreateDesc::stomp: Option<StompSettings>StompSettings::new(queue)withmode(All,Random { probability },OptIn,Filter(fn)),seed,tail_guard(default on),head_guard(default off),payload_alignment: Option<u64>(byte-precise tail guard, caller addsResource::offset()),quarantine(default on)ResourceCreateDesc::stomp: Option<bool>per-resource overrideResource::offset(),is_stomp_guarded(),stomp_layout()Allocator::stomp_statistics(),committed_statistics()AllocationError::InvalidStompSettingsBreaking: both descs gained a field.
What it catches
Accesses the hardware does not bounds-check: root descriptor SRV/UAV/CBV, acceleration structure builds and scratch, DXR shader tables,
ExecuteIndirectarguments. Descriptor-table views are clamped by hardware.CopyBufferRegionoverruns are rejected by the runtime atClose(). Textures get no guard tile (no unbounded write path exists), only use-after-free detection.CpuToGpu/GpuToCpu, MSAA and 3D below tiled tier 3 fall through to the normal path with a warning (reserved resources cannot beMap()ed).Why reserved resources and not tight placed resource alignment
The first design placed a tight-aligned resource at the end of its own heap and created a never-resident heap right after it, verified by probing GPU VAs. Measured on an RTX 5070 Ti it guards only 55 to 105 of 500 buffers under churn (freed VA gets recycled), and the driver's VA allocator is process-wide so other threads break adjacency. Reserved resources give adjacency by construction; the spec forbids tight alignment on them. Details and numbers in
docs/d3d12-stomp-allocator.md, section 8.Tests
tests/d3d12_stomp.rs, run on WARP in CI, with anID3D12InfoQueuesweep for debug-layer errors in every testtests/d3d12_stomp_fault.rs,#[ignore], one child process per test:GPU_ALLOCATOR_STOMP_FAULT_TESTS=1 cargo test --features d3d12 --test d3d12_stomp_fault -- --ignored --test-threads=1examples/d3d12-stomp.rsremoves the device by writing at the tail guardVerified on NVIDIA RTX 5070 Ti: tail overrun, head underrun, byte-precise boundary, in-bounds and slack writes clean, buffer and texture use-after-free, cross-queue use after COPY-queue mapping, 500/500 guarded under churn, 4 threads all guarded, no debug-layer messages.
Open points
offset() == 0with 64KB slack; byte precision needspayload_alignmentand the offset contract. Open to flipping the default.windows0.53 not built locally (dev-deps pin 0.58); relies on the minimal-versions CI job.馃 Generated with Claude Code