Skip to content

fix(shader): poison an SRT read below a pointer loaded from memory - #12208

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
XairRrR:fix/shader-srt-read-below-loaded-pointer
Oct 29, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
XairRrR:fix/shader-srt-read-below-loaded-pointer

Conversation

@XairRrR

@XairRrR XairRrR commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

What

A flat SRT read through a null or unmapped pointer that the walker loaded from guest memory is recorded as an SRT poison and faults only if the program executes it (the debt entry for flat SRT reads describes this). A read at a negative offset from such a pointer never got there: AddSignedAddress refused the address below zero, and EvaluateRawRead returned without recording anything, so the walk threw cannot evaluate ... SRT read at flat offset ....

PPSA05684 (Uncharted: Legacy of Thieves Collection) threw it in Uncharted: The Lost Legacy while loading its first level: compute programs read s_load ... offset:-4 through a pointer that is null behind a guarded branch.

The read is now recorded as inaccessible at its address wrapped to 48 bits (0xfffffffffffc for offset -4 from null), like any other unreadable address, so the binding faults only if the shader takes that path. The debt entry says the console's fault address for it is not measured.

Tested

Arch Linux 7.2.11-zen, GCC 16.2.1, Ninja, Release, on main 3ca715e:

  • agc_shader_memory: verifyGuardedNullPointers gains a read at offset -4 below the nested pointer: mapped (holds its word, no poison), then null with the guard taken (one poison at its pc and wrapped address, reported through the fault buffer) and skipped (no poison). With SrtEvaluator.cpp from main it fails with the title's error.
  • Full ctest -j8 (this branch together with my five other branches of today, on the same main): 2619 of 2620 pass; agc_driver_mesh_barycentric_emulation fails the same way on main on this GPU (the pixel shader did not emulate barycentrics).
  • tools/check_conventions.py --base origin/main passes.
  • PPSA05684: The Lost Legacy loads its first level (Sri Lanka) past the throw.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: PPSA05684 Uncharted: Legacy of Thieves Collection (PPSA05684) on Linux / NVIDIA #4001 (The Lost Legacy throws while loading its first level)
  • GPUs tested: NVIDIA GeForce RTX 4070 Ti SUPER, driver 615.78.08, Arch Linux 7.2.11-zen
  • AI-assisted: yes

@github-actions github-actions Bot added the unblocks title Names a title ID on the Unblocks line label Oct 28, 2026
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 5021 docs/dev/debt/shader.md
PR 5371 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 5609 core/shader/recompiler/Optimization/src/SrtWalker/SrtEvaluator.cpp
PR 6235 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 6280 docs/dev/debt/shader.md
PR 6412 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 6488 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 6924 docs/dev/debt/shader.md
PR 7642 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 7684 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 7922 docs/dev/debt/shader.md
PR 8004 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 9356 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 9387 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 9508 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 9748 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 9889 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 9897 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 10193 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 10233 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 10652 docs/dev/debt/shader.md
PR 10757 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 11551 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 12132 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md

@Amoenus

Amoenus commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@XairRrR A merge-order point before I submit our indexed scalar-descriptor correction, with comparison/limits here. Your negative-immediate underflow case and our runtime-loaded scalar-offset case are distinct. Your three production lines handle AddSignedAddress failing; ours changes the later inaccessible-read predicate and planning eligibility. Both edit the flat-SRT debt paragraph, flagged at comparison base7fe69e276fc4.

I propose #12208 first, then preserve your wrapped-address/console-unmeasured note when refreshing ours, as merge order only. No technical prerequisite or combined build is claimed. Our fork candidate passes12 focused processes, including3/3 new GPU runs per RTX5080/Radeon, with matched main-production failures. This is not validation of your head or the original #11469 T# report.

Does that order work for you? No duplicate upstream PR opened. AI-assisted:yes(Codex); author responsible.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new negative-offset poison handling is consistent with the existing inaccessible-read path, and the test covers mapped, executed-null and guarded-away cases. I found no separate logic defect in the diff. This branch is 60 commits behind current main; please rebase and rerun agc_shader_memory on current main and the rebased change. Because this touches the shader recompiler/AGC, the repository rules also require the same focused run with ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1 and VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, with logs checked for missing-layer warnings and new VUID- errors. Please report those results before approval.

@maskym

maskym commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Windows + NVIDIA result for head 12c0427e5e, merged into main 3b979d42a9 (the PR's GPUs tested line names no NVIDIA run on Windows).

This PR's own tests: agc_shader_memory (0.70 s), all passed.

Host: Windows 11 26300, Intel i7-12700K, NVIDIA GeForce RTX 2070 SUPER (vendor 0x10de, device 0x1e84; Vulkan loader 1.4.357 from the NVIDIA driver 621.01), Khronos Validation Layers nightly 1.4.366 (b2b44c0d37) through VK_ADD_LAYER_PATH, WinLibs GCC 15.2.0 (x86_64-ucrt-posix-seh, r6), Release, BUILD_TESTING=ON, Ninja. Build clean.

Same focused run on main 3b979d42a9 and on this tree, same machine and GPU: VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ANYPS5_NO_SHADER_CACHE=1, ANYPS5_REQUIRE_VULKAN=1, VK_LOADER_DEBUG=error,warn,layer, ctest --test-dir build -R '^(agc|guest_video_out|video_out)' --parallel 4 -V.

The tree also carried the open PRs #12298, #12272, #12262, #12256, #12250, #12234, #12228, #12211, #12210, #12209, #12207, all merged cleanly, so the run is a joint one. Not run on a PS5.

AI-assisted: yes (Claude Code), the runs and the numbers above are from this machine.

A read at a negative offset from a pointer the walker loaded from guest
memory (a null pointer behind a guarded branch, offset -4) wrapped below
zero in AddSignedAddress, and the walk threw "cannot evaluate" instead of
recording the read as inaccessible. Uncharted: The Lost Legacy threw it
while loading its first level. The read is now recorded as an SRT poison
at its address wrapped to 48 bits, like any other unreadable address, so
the binding faults only if the shader takes that path.

verifyGuardedNullPointers gains the case for both branch outcomes; it
throws the title's error without the change.

AI-assisted: yes
@XairRrR
XairRrR force-pushed the fix/shader-srt-read-below-loaded-pointer branch from 12c0427 to 91bbd2f Compare October 28, 2026 19:01
@XairRrR

XairRrR commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on main e4da19a (head 91bbd2f), no conflicts. agc_shader_memory passes on the rebased head.

Rebased on main e4da19a. Arch Linux 7.2.11-zen, GCC 16.2.1, Release, RTX 4070 Ti SUPER (NVIDIA 615.78.08), Khronos validation layers 1.4.363. VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ANYPS5_NO_SHADER_CACHE=1 ANYPS5_REQUIRE_VULKAN=1 VK_LOADER_DEBUG=error,warn,layer ctest -R '^(agc|guest_video_out|video_out|guest_process_time)' on main plus #12206, #12207, #12208, #12210 and #12238 rebased: 1145/1145 pass. The loader inserted the layer 1000 times, no log line says it was not found, and the only VUID is VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (18 times), the one maskym's run reports on main (#6782). I did not run main alone on Linux; maskym's paired Windows run above covers that side.

@Amoenus that order works for me: #12208 first, then your indexed scalar-descriptor change refreshes the flat-SRT debt paragraph and keeps the wrapped-address note.

AI-assisted: yes

@adriadam10
adriadam10 merged commit 5e6c22e into boykopovar:main Oct 29, 2026
13 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the three-line change in SrtEvaluator.cpp against the existing inaccessible-read path, the verifyGuardedNullPointers cases (mapped, null with the guard taken, null with the guard skipped; the taken case fails on main with the title's error), and the debt entry; the rebase and validation-layer runs asked for earlier are covered by the author's and @maskym's runs; merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* docs shader core/shader unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants