Fix two out-of-bounds cache accesses causing device loss under dense caches (#4, #5) - #6
Open
halukoral wants to merge 2 commits into
Open
Conversation
…fore the cache-index mask When a hash-grid bucket is full, HashGridInsertEntry returns HASH_GRID_INVALID_CACHE_INDEX and SharcUpdateHit stores that sentinel into sharcState.cacheIndices verbatim. The propagation loops in SharcUpdateHit and SharcUpdateMiss then run the stored index through an unconditional '& SHARC_CACHE_INDEX_BIT_MASK' (compiled in whenever SHARC_ENABLE_RESPONSIVE_LIGHTING is defined, regardless of the runtime toggle), which rewrites 0xFFFFFFFF to SHARC_CACHE_INDEX_BIT_MASK. That forged value passes SharcAddVoxelData's INVALID guard and the interlocked adds land ~2 GiB past the accumulation buffer (with the default 26-bit index layout and the 32-byte SH accumulation stride), losing the device once the table gets dense enough for buckets to fill. Verified against a driver-reported fault address: the faulting page was exactly accumulationBase + SHARC_CACHE_INDEX_BIT_MASK * 32 rounded to page granularity, bit-identical across independent device losses. Skip the sentinel at the top of both loops, before the responsive offset code: a post-mask compare would not be enough because SharcGetResponsiveIndexOffset can shift the sentinel first when responsive lighting is enabled at runtime. Fixes NVIDIA-RTX#4
The sampleNumPrev == 0 recovery path probes forward blindly by SHARC_LINEAR_PROBE_WINDOW_SIZE entries. An application is allowed to allocate exactly 'capacity' entries per buffer (as the samples do), so for entries in the last probe window this loop reads past the end of both the hash-entry and resolved buffers. With buffer-device-address access there is no robustness backstop, and once the high table slots become occupied the read crosses the allocation's last page and the device is lost. Before those slots fill up the loop breaks early on empty keys (HASH_GRID_LIMIT_EMPTY_SLOTS), which is why the bug hides in light scenes. HashGridGetBaseSlot keeps normal bucket probes in range; this entry-relative probe needs its own clamp. Fixes NVIDIA-RTX#5
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.
Fixes #4, fixes #5 — two independent out-of-bounds accesses, both surfacing as
VK_ERROR_DEVICE_LOSTonce the hash table becomes dense (large sceneScale,geometry-dense views).
SharcUpdateHit/SharcUpdateMiss): a full-bucketHASH_GRID_INVALID_CACHE_INDEXsentinel stored incacheIndicesis rewrittenby the unconditional
& SHARC_CACHE_INDEX_BIT_MASKinto a forged in-rangevalue, bypassing
SharcAddVoxelData's guard; the atomics then land~2 GiB past the accumulation buffer. Fixed by skipping the sentinel before the
responsive offset/mask block (a post-mask compare is insufficient — the
responsive offset can shift the sentinel first). Verified against
driver-reported fault addresses: the faulting page was exactly
accumulationBase + SHARC_CACHE_INDEX_BIT_MASK * 32(SH layout), bit-identicalacross independent device losses.
SharcResolveEntry): thesampleNumPrev == 0recovery probe reads upto
SHARC_LINEAR_PROBE_WINDOW_SIZEentries pastcapacityfor entries in thelast window. Fixed by clamping the probe end to the table capacity.
With both fixes our previously 100%-reproducing case (25k–100k instance dynamic
scene, sceneScale 100, capacity 2^22, Vulkan/GLSL path with
SHARC_ENABLE_RESPONSIVE_LIGHTING=1+SHARC_ENABLE_SH_ENCODING=1) runsindefinitely without device loss.