Skip to content

feat(libSceAddressSanitizer): implement shadow poisoning, access checks and error reports - #13265

Open
PrivacyOnion wants to merge 5 commits into
boykopovar:mainfrom
PrivacyOnion:feat/addresssanitizer-runtime
Open

PrivacyOnion wants to merge 5 commits into
boykopovar:mainfrom
PrivacyOnion:feat/addresssanitizer-runtime

Conversation

@PrivacyOnion

@PrivacyOnion PrivacyOnion commented Oct 30, 2026 •

Copy link
Copy Markdown

What

Implements 100 of the 301 libSceAddressSanitizer exports. The other 201 still throw and stay under Unknown function info.

The export names are the LLVM compiler-rt AddressSanitizer interface. Signatures come from the LLVM 18.1.8 public headers (asan_interface.h, common_interface_defs.h) and from the callbacks the compiler emits. Behaviour follows the LLVM 18.1.8 runtime sources linked below.

  • Shadow memory: the PlayStation mapping from AddressSanitizer.cpp (kPS_ShadowOffset64 = 1ULL << 40, scale 3). The first export that touches the shadow reserves it. Windows reserves every free region between 1 and 17 TiB separately and commits pages on access through a vectored handler; host allocations already there (high-entropy ASLR places some in this range) become holes, and an export whose shadow falls in a hole throws instead of writing host memory. Linux uses mmap with MAP_FIXED_NOREPLACE | MAP_NORESERVE. After the first call the check is a single atomic load.
  • Shadow fills and queries: __asan_set_shadow_00, _01 to _07 and _f1, _f2, _f3, _f5, _f8; __asan_address_is_poisoned, __asan_region_is_poisoned, __asan_get_shadow_mapping.
  • Poisoning (asan_poisoning.cpp, asan_fake_stack.cpp): __asan_poison_memory_region and __asan_unpoison_memory_region; __asan_poison_stack_memory and __asan_unpoison_stack_memory; the intra-object redzones; __asan_alloca_poison and __asan_allocas_unpoison; __asan_poison_cxx_array_cookie and __asan_load_cxx_array_cookie.
  • Access checks (asan_rtl.cpp): __asan_load* and __asan_store* for sizes 1, 2, 4, 8, 16 and N, with their _noabort variants. The six __sanitizer_unaligned_* accesses follow CHECK_SMALL_REGION. A misaligned access larger than 8 bytes also checks its last byte, so a poisoned third granule is reported at the first bad address; the LLVM fast path reads only two shadow bytes and skips it.
  • Error reports (asan_report.cpp, asan_errors.cpp):
    • Exports: __asan_report_load*, __asan_report_store* and __asan_report_error.
    • The bug type comes from the ErrorGeneric classification. A report prints the separator, the header, the access line, the shadow dump and the legend.
    • Then it calls the __asan_set_error_report_callback callback, prints ABORTING, calls the __sanitizer_set_death_callback callback and exits with code 1 through _Exit.
    • __asan_report_present and __asan_get_report_* read the report in progress.
  • Defaults: __ubsan_default_options, __sancov_default_options, __sanitizer_malloc_hook and __sanitizer_free_hook, __sanitizer_get_estimated_allocated_size, __sanitizer_get_unmapped_bytes, and the __asan_version_mismatch_check_v6, _v7 and _v8 checks, as in LLVM 18.1.8.

Recorded in docs/dev/debt/libSceAddressSanitizer.md:

  • __asan_init, the allocator, global registration, fake stacks and the thread registry are still missing, so a clean shadow does not prove an address is valid.
  • Options are not parsed. The LLVM defaults apply: allow_user_poisoning, poison_array_cookie, poison_partial and halt_on_error are all true, so the _noabort variants also exit.
  • Reports have no pid prefix, stack trace, address description or summary line.
  • Instrumented code that touches a hole inline still reads or writes that host memory.
  • Console behaviour is unverified.

Ranges outside guest memory or overlapping the shadow, misaligned arguments that LLVM CHECKs, and shadow that falls in a hole throw std::invalid_argument or std::runtime_error; only the 201 unimplemented exports call NotImplemented_nid_no_patch.

Tested

Windows 11, MinGW-W64 GCC 16.1.0, Release. No title or homebrew; no dumped title uses the sanitizer runtime.

  • ctest runs 9 tests: guest_addresssanitizer_shadow, guest_addresssanitizer_mapping, guest_addresssanitizer_mapping_collision, and guest_addresssanitizer_report_{load4,load16,storeN,unaligned,partial,report_error}.
  • The report tests run in a child process. Their regex checks the classification, the access line, the shadow dump, the report queries called from inside the error callback, ABORTING and the death callback. The exit code is 1.
  • mapping_collision commits a host page at 1 << 40 before the first call: initialization succeeds, poisoning and checking a guest address whose shadow is in that page throw and leave it intact, and addresses elsewhere work. It fails without the hole check. The mapping and report tests also pass with host pages committed at 0x1f5…, 0x250… and 0x29f… before they start.
  • report_load16 calls __asan_load16 at offset 4 of a buffer whose third granule is poisoned; it fails without the last-byte check.
  • Mutation check: changing any of 8 behaviours fails at least one test. The behaviours are the partial-granule bound, a bug-type mapping, the reported first-bad address, the death callback, user-poison magic, alloca partial redzone, stack poisoning and report access type.
  • The library is built in the full Windows tree (-G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON). The 9 tests pass there on the current head; the tree was configured on e5186e88a6, and none of the 27 commits up to fae9e483bb touch the files changed here.
  • nid_patcher libSceAddressSanitizer gives 100 patched NIDs that match tools/nid_names.py compute_nid. The extern "C" helpers exported unpatched are InitializeShadow, ShadowRangeAvailable, CurrentErrorReport and LoadErrorReportCallback.
  • Linux: compile-only check. Export.cpp, src/ShadowLinux.cpp and GuestAddressSanitizerShadow.cpp compile as x86_64-linux-gnu objects (clang 21, -Wall -Wextra) with no warnings from this library. Nothing was run on Linux.
  • tools/progress.py counts 100 implemented libSceAddressSanitizer exports (9 behaviourally empty: the default options, hooks, unmapped bytes and version checks) and 201 unimplemented.
  • python3 core/libs/tests/test_public_headers.py --audit-only passes, and python3 tools/check_conventions.py --base upstream/main passes with no warnings.
  • python3 tools/pr_overlap.py --branch feat/addresssanitizer-runtime: no overlap with the 1474 open pull requests.

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: none
  • GPUs tested: n/a
  • AI-assisted: yes

…ks and error reports

Implement 100 AddressSanitizer exports following LLVM compiler-rt 18.1.8:
shadow fills and queries, stack, alloca, intra-object, array cookie and
user poisoning, the load/store access callbacks and their report entry
points, error report queries and callbacks, and the default hooks and
options. The shadow uses the PlayStation mapping (scale 3, offset 1 << 40)
reserved on first use. Remaining gaps are listed in the technical debt.
@oneandonlydean oneandonlydean self-assigned this Oct 30, 2026

@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.

Reviewed — changes requested

The fixed-width 16-byte access checker can miss poisoned bytes in the third shadow granule when the access is unaligned.

What I ran

Reviewed head def3d354c92f6b30bed17cbd1b5dcbfff4dc5daa against PR base fae9e483bbbfd05ab0ad2d00df42f59f1da7824d; a merge preview onto current main fae9e483bbbfd05ab0ad2d00df42f59f1da7824d was clean. Environment: Debian 12, x86-64, Python 3.11.2, Git 2.39.5. I did not compile or build AnyPS5.

git diff --check fae9e483bbbfd05ab0ad2d00df42f59f1da7824d...def3d354c92f6b30bed17cbd1b5dcbfff4dc5daa
python3 tools/pr_precheck.py --repo boykopovar/AnyPS5 --pr 13265
python3 tools/pr_abi_audit.py --repo /marc/AnyPS5 --base fae9e483bbbfd05ab0ad2d00df42f59f1da7824d --head def3d354c92f6b30bed17cbd1b5dcbfff4dc5daa --json
python3 /marc/AnyPS5/tools/pr_test_quality.py --root /tmp/AnyPS5-pr13265-review --json core/libs/prx/libSceAddressSanitizer/Export.cpp core/libs/prx/libSceAddressSanitizer/include/Api.hpp core/libs/prx/libSceAddressSanitizer/src/ErrorReport.hpp core/libs/prx/libSceAddressSanitizer/src/Report.hpp core/libs/prx/libSceAddressSanitizer/src/ShadowAddressSpace.hpp core/libs/prx/libSceAddressSanitizer/src/ShadowCheck.hpp core/libs/prx/libSceAddressSanitizer/src/ShadowLinux.cpp core/libs/prx/libSceAddressSanitizer/src/ShadowWindows.cpp core/libs/tests/GuestAddressSanitizerMapping.cpp core/libs/tests/GuestAddressSanitizerShadow.cpp
python3 tools/pr_overlap.py --branch refs/review/pr-13265 --jobs 16
git merge-tree --write-tree fae9e483bbbfd05ab0ad2d00df42f59f1da7824d def3d354c92f6b30bed17cbd1b5dcbfff4dc5daa

Results

Check Result
Patch whitespace Passed; git diff --check produced no output.
Repository conventions and PR template Passed.
No-build precheck Reported failed because the isolated checkout does not contain the local-only ABI and test-quality helper scripts; both were run manually against the exact head afterward. The precheck confirmed head/base stability.
ABI audit Passed with no findings; this lexical check does not establish runtime ABI or compilation correctness.
Test-quality heuristic Flagged both test source paths as possibly unregistered. Inspection confirms libSceAddressSanitizer/CMakeLists.txt registers both through ${LIBS_INCLUDE_DIR}/tests/...; the warnings are false positives.
Open-PR overlap scan Passed: no overlap with open PRs.
Current-main merge preview Passed; clean tree cd90b23ad63f9ec76cb6242d97201cd06071da92.
Hosted CI at review time Conventions, eligibility, intake, labels and report passed (conventions, eligibility, intake, labels, report). Windows was pending; Linux and specialized jobs were skipped.
Tests/build Not run locally. The PR description reports eight Windows tests on an earlier test tree and a Linux compile-only check; I did not independently run those checks. The intervening main commits did not change the PR’s implementation/test paths.
Unedited local check output

git diff --check:

Conventions:

All conventions checks passed.

ABI audit summary:

{
  "status": "passed",
  "findings": []
}

Test-quality heuristic:

{
  "findings": [
    {
      "path": "core/libs/tests/GuestAddressSanitizerMapping.cpp",
      "line": 1,
      "kind": "possible-unregistered-cpp-test",
      "message": "Changed C++ test source path was not found literally in CMake files; inspect registration, generated source lists, and workflow coverage."
    },
    {
      "path": "core/libs/tests/GuestAddressSanitizerShadow.cpp",
      "line": 1,
      "kind": "possible-unregistered-cpp-test",
      "message": "Changed C++ test source path was not found literally in CMake files; inspect registration, generated source lists, and workflow coverage."
    }
  ],
  "negative_control_candidates": [],
  "limits": [
    "Heuristics can miss weak assertions and can flag valid tests; inspect every finding.",
    "A test that passes against base is not by itself proof that the PR test is inadequate.",
    "Negative controls are only candidates until the test actually runs against base and fails by assertion rather than import/setup error."
  ]
}

Precheck command output:

/tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13265-def3d354c92f/report.md
/tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13265-def3d354c92f/report.json
Conclusion: checks failed

Overlap scan:

No overlap with open pull requests.

Merge preview:

cd90b23ad63f9ec76cb6242d97201cd06071da92

Findings

Blocking

CheckAccess_nid_no_patch reads only the first two shadow bytes for accesses larger than eight bytes, then returns when those bytes are both zero. An unaligned 16-byte access can span three 8-byte granules; if only the third granule is poisoned, __asan_load16/__asan_store16 and their variants return without reporting it. The current tests exercise 16-byte checks at an aligned address, so they do not cover this case. Please inspect every shadow granule intersecting the access and add a child-process regression test with an unaligned 16-byte access whose third granule is poisoned.

Non-blocking

No additional confirmed findings.

Sources

Not verified

No local build, C++ test execution, native Windows run, Linux runtime test, title/homebrew run, or PS5 console behavior. The hosted Windows check was pending when checked; Linux and specialized jobs were skipped.

To get this to a good state

Update the access checker to cover all granules touched by a fixed-width access, add a regression for the unaligned 16-byte/third-granule case, and provide fresh CI on the new head. I will rerun the same relevant no-build checks and review the new head.

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Progress report (a4eca2a → ca0788f)

📈 System libraries: 26.31% (+0.27%, +100 implemented functions)

✅ 100 implemented
Library Name
libSceAddressSanitizer __asan_address_is_poisoned
libSceAddressSanitizer __asan_alloca_poison
libSceAddressSanitizer __asan_allocas_unpoison
libSceAddressSanitizer __asan_get_report_access_size
libSceAddressSanitizer __asan_get_report_access_type
libSceAddressSanitizer __asan_get_report_address
libSceAddressSanitizer __asan_get_report_bp
libSceAddressSanitizer __asan_get_report_description
libSceAddressSanitizer __asan_get_report_pc
libSceAddressSanitizer __asan_get_report_sp
libSceAddressSanitizer __asan_get_shadow_mapping
libSceAddressSanitizer __asan_load1
libSceAddressSanitizer __asan_load16
libSceAddressSanitizer __asan_load16_noabort
libSceAddressSanitizer __asan_load1_noabort
libSceAddressSanitizer __asan_load2
libSceAddressSanitizer __asan_load2_noabort
libSceAddressSanitizer __asan_load4
libSceAddressSanitizer __asan_load4_noabort
libSceAddressSanitizer __asan_load8
libSceAddressSanitizer __asan_load8_noabort
libSceAddressSanitizer __asan_loadN
libSceAddressSanitizer __asan_loadN_noabort
libSceAddressSanitizer __asan_load_cxx_array_cookie
libSceAddressSanitizer __asan_poison_cxx_array_cookie
libSceAddressSanitizer __asan_poison_intra_object_redzone
libSceAddressSanitizer __asan_poison_memory_region
libSceAddressSanitizer __asan_poison_stack_memory
libSceAddressSanitizer __asan_region_is_poisoned
libSceAddressSanitizer __asan_report_error
libSceAddressSanitizer __asan_report_load1
libSceAddressSanitizer __asan_report_load16
libSceAddressSanitizer __asan_report_load16_noabort
libSceAddressSanitizer __asan_report_load1_noabort
libSceAddressSanitizer __asan_report_load2
libSceAddressSanitizer __asan_report_load2_noabort
libSceAddressSanitizer __asan_report_load4
libSceAddressSanitizer __asan_report_load4_noabort
libSceAddressSanitizer __asan_report_load8
libSceAddressSanitizer __asan_report_load8_noabort
libSceAddressSanitizer __asan_report_load_n
libSceAddressSanitizer __asan_report_load_n_noabort
libSceAddressSanitizer __asan_report_present
libSceAddressSanitizer __asan_report_store1
libSceAddressSanitizer __asan_report_store16
libSceAddressSanitizer __asan_report_store16_noabort
libSceAddressSanitizer __asan_report_store1_noabort
libSceAddressSanitizer __asan_report_store2
libSceAddressSanitizer __asan_report_store2_noabort
libSceAddressSanitizer __asan_report_store4
libSceAddressSanitizer __asan_report_store4_noabort
libSceAddressSanitizer __asan_report_store8
libSceAddressSanitizer __asan_report_store8_noabort
libSceAddressSanitizer __asan_report_store_n
libSceAddressSanitizer __asan_report_store_n_noabort
libSceAddressSanitizer __asan_set_error_report_callback
libSceAddressSanitizer __asan_set_shadow_00
libSceAddressSanitizer __asan_set_shadow_01
libSceAddressSanitizer __asan_set_shadow_02
libSceAddressSanitizer __asan_set_shadow_03
libSceAddressSanitizer __asan_set_shadow_04
libSceAddressSanitizer __asan_set_shadow_05
libSceAddressSanitizer __asan_set_shadow_06
libSceAddressSanitizer __asan_set_shadow_07
libSceAddressSanitizer __asan_set_shadow_f1
libSceAddressSanitizer __asan_set_shadow_f2
libSceAddressSanitizer __asan_set_shadow_f3
libSceAddressSanitizer __asan_set_shadow_f5
libSceAddressSanitizer __asan_set_shadow_f8
libSceAddressSanitizer __asan_store1
libSceAddressSanitizer __asan_store16
libSceAddressSanitizer __asan_store16_noabort
libSceAddressSanitizer __asan_store1_noabort
libSceAddressSanitizer __asan_store2
libSceAddressSanitizer __asan_store2_noabort
libSceAddressSanitizer __asan_store4
libSceAddressSanitizer __asan_store4_noabort
libSceAddressSanitizer __asan_store8
libSceAddressSanitizer __asan_store8_noabort
libSceAddressSanitizer __asan_storeN
libSceAddressSanitizer __asan_storeN_noabort
libSceAddressSanitizer __asan_unpoison_intra_object_redzone
libSceAddressSanitizer __asan_unpoison_memory_region
libSceAddressSanitizer __asan_unpoison_stack_memory
libSceAddressSanitizer __asan_version_mismatch_check_v6
libSceAddressSanitizer __asan_version_mismatch_check_v7
libSceAddressSanitizer __asan_version_mismatch_check_v8
libSceAddressSanitizer __sancov_default_options
libSceAddressSanitizer __sanitizer_free_hook
libSceAddressSanitizer __sanitizer_get_estimated_allocated_size
libSceAddressSanitizer __sanitizer_get_unmapped_bytes
libSceAddressSanitizer __sanitizer_malloc_hook
libSceAddressSanitizer __sanitizer_set_death_callback
libSceAddressSanitizer __sanitizer_unaligned_load16
libSceAddressSanitizer __sanitizer_unaligned_load32
libSceAddressSanitizer __sanitizer_unaligned_load64
libSceAddressSanitizer __sanitizer_unaligned_store16
libSceAddressSanitizer __sanitizer_unaligned_store32
libSceAddressSanitizer __sanitizer_unaligned_store64
libSceAddressSanitizer __ubsan_default_options
⚪ 9 behaviourally empty (constant return or throw)
Library Name
libSceAddressSanitizer __asan_version_mismatch_check_v6
libSceAddressSanitizer __asan_version_mismatch_check_v7
libSceAddressSanitizer __asan_version_mismatch_check_v8
libSceAddressSanitizer __sancov_default_options
libSceAddressSanitizer __sanitizer_free_hook
libSceAddressSanitizer __sanitizer_get_estimated_allocated_size
libSceAddressSanitizer __sanitizer_get_unmapped_bytes
libSceAddressSanitizer __sanitizer_malloc_hook
libSceAddressSanitizer __ubsan_default_options

Changed libraries (implemented exports)

Library Before After Change
libSceAddressSanitizer 0/301 (0.00%) 100/301 (33.22%) +33.22%

…e accesses

Invalid ranges and a failed shadow reservation throw std::invalid_argument and std::runtime_error instead of NotImplemented_nid_no_patch.
@JJenkx

JJenkx commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Windows run of this head (def3d354c9), merged onto main a5939f10a8 (clean merge, local only). Windows 11 Enterprise 10.0.22621, Ryzen 9 5950X, WinLibs GCC 15.2.0 UCRT r7, Ninja, Release, BUILD_TESTING=ON.

6 of the 8 tests fail here, deterministically: guest_addresssanitizer_mapping (the program exits with 7), and all five guest_addresssanitizer_report_*, with what(): __asan_poison_memory_region not implemented. guest_addresssanitizer_shadow and _mapping_collision pass. A full rebuild (fresh patched and unpatched libSceAddressSanitizer.prx) gives the same result, so a stale library isn't the cause.

The cause is the 16 TiB shadow reservation colliding with ordinary Windows allocations. InitializeShadow_nid_no_patch reserves [1 << 40, 1 << 40 + 1 << 44), i.e. 1–17 TiB, in one VirtualAlloc(MEM_RESERVE). A 64-bit Windows process's own early allocations (process heaps, PEB/TEB-adjacent regions, loader data) are placed by high-entropy ASLR right in that span, so the reservation fails with ERROR_INVALID_ADDRESS (487). __asan_poison_memory_region then reaches its NotImplemented_nid_no_patch fallback, and the mapping test's thread check fails (exit 7).

A standalone probe with the same toolchain lists what is already mapped in 1–17 TiB at main(), before loading any AnyPS5 module, and then tries the same reservation:

before: commit base=00000250a39b0000 allocation=00000250a39b0000 size=0x10000
before: commit base=00000250a39c0000 ...
load .../libc.prx -> ok
load .../libSceAddressSanitizer.prx -> ok
shadow reserve at 1 TB -> 0000000000000000 (error 487)

Over 20 fresh processes, the first occupied region was always at 0x1f5… to 0x29f… (about 2.0–2.7 TiB), and the reservation failed 20 of 20 times. That randomized placement probably explains why it passed on your machine.

Since instrumented code computes the shadow address with the fixed kPS_ShadowOffset64, the shadow can't move. One way to make it work on Windows is to stop requiring the whole 16 TiB range up front: reserve and commit shadow pages on demand (your vectored handler already commits pages inside the reservation, and it could also VirtualAlloc(MEM_RESERVE | MEM_COMMIT) a free page). Report the case where a needed shadow page is occupied by an unrelated host allocation, rather than failing all poisoning. I haven't tried that, so it's only a suggestion.

Note: the head moved to 45ddafe1b8 while I was posting. That commit only changes the granule checks in ShadowCheck.hpp; ShadowWindows.cpp and the 16 TiB reservation are unchanged, so the finding above applies to it too.

AI-assisted: yes (Claude Code).

…adow range

High-entropy ASLR places host allocations between 1 and 17 TiB, so a single 16 TiB reservation fails. The runtime now reserves each free region, records the host allocations as holes, and throws when an export needs shadow inside a hole.
@PrivacyOnion

Copy link
Copy Markdown
Author

Both findings are fixed on 78dc5a8.

@MarcZX10 (45ddafe): a misaligned access larger than 8 bytes now also checks its last byte and reports the first poisoned address. Added guest_addresssanitizer_report_load16 (16-byte load at offset 4, third granule poisoned); it fails without the fix.

@JJenkx (78dc5a8): thanks, reproduced. Windows now reserves each free region of the 1–17 TiB shadow range separately and records host allocations already there as holes; an export whose shadow falls in a hole throws instead of writing host memory. mapping_collision now commits a host page at 1 << 40 first and checks that initialization succeeds, that poisoning or checking an address shadowed by that page throws and leaves it intact, and that other addresses work; it fails without the hole check. The mapping and report tests also pass with host pages committed at 0x1f5…, 0x250… and 0x29f… before they start. Inline instrumented accesses to a hole are recorded in the debt file.

Also, guards on invalid ranges now throw std::invalid_argument / std::runtime_error instead of NotImplemented_nid_no_patch, so tools/progress.py counts the 100 implemented exports.

9/9 guest_addresssanitizer_* tests pass on Windows (MinGW GCC 16.1.0, Release); Linux compile-only.

@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.

Re-checked — new head, verification pending

At head 78dc5a8136054ba2b62a68e0cf83de7b989f1de3, the earlier unaligned 16-byte access gap is addressed in source and covered by a new regression case, but the changed Windows shadow-reservation path still needs an exact-head Windows run before I can approve it.

What I ran

Reviewed PR head 78dc5a8136054ba2b62a68e0cf83de7b989f1de3 against PR base fae9e483bbbfd05ab0ad2d00df42f59f1da7824d. The merge preview onto fetched current main 663832e75756973e10f03518cbd4224829ce6780 was clean (tree 9ce0e33a7eef4ec681d67b05a01afba739ba5c8f). Environment: Debian 12, x86-64, Python 3.11.2, Git 2.39.5, GCC 12.2.0. I did not configure, build, compile, or run C++ tests.

git diff --check fae9e483bbbfd05ab0ad2d00df42f59f1da7824d...78dc5a8136054ba2b62a68e0cf83de7b989f1de3
python3 tools/pr_precheck.py --repo boykopovar/AnyPS5 --pr 13265
python3 tools/check_conventions.py --base fae9e483bbbfd05ab0ad2d00df42f59f1da7824d --head 78dc5a8136054ba2b62a68e0cf83de7b989f1de3 --title 'feat(libSceAddressSanitizer): implement shadow poisoning, access checks and error reports' --body /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13265-78dc5a813605/pr-body.md
python3 tools/pr_abi_audit.py --repo /marc/AnyPS5 --base fae9e483bbbfd05ab0ad2d00df42f59f1da7824d --head 78dc5a8136054ba2b62a68e0cf83de7b989f1de3 --json
python3 tools/pr_test_quality.py --root /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13265-78dc5a813605/head-78dc5a813605-efdfde44 --json core/libs/prx/libSceAddressSanitizer/CMakeLists.txt core/libs/prx/libSceAddressSanitizer/Export.cpp core/libs/prx/libSceAddressSanitizer/include/Api.hpp core/libs/prx/libSceAddressSanitizer/src/ErrorReport.hpp core/libs/prx/libSceAddressSanitizer/src/Report.hpp core/libs/prx/libSceAddressSanitizer/src/ShadowAddressSpace.hpp core/libs/prx/libSceAddressSanitizer/src/ShadowCheck.hpp core/libs/prx/libSceAddressSanitizer/src/ShadowLinux.cpp core/libs/prx/libSceAddressSanitizer/src/ShadowWindows.cpp core/libs/tests/GuestAddressSanitizerMapping.cpp core/libs/tests/GuestAddressSanitizerShadow.cpp docs/dev/debt/libSceAddressSanitizer.md
git merge-tree --write-tree 663832e75756973e10f03518cbd4224829ce6780 refs/review/pr-13265-new
gh pr checks 13265 -R boykopovar/AnyPS5

Results

Check Result
Patch whitespace Passed; git diff --check produced no output.
Repository conventions and PR template Passed.
No-build precheck Completed against the exact head and confirmed head/base stability; overall status was failed only because the isolated PR checkout lacks the workspace-local ABI-audit and test-quality scripts. Both were run manually below.
ABI audit Passed with no findings. This lexical audit does not establish binary ABI or runtime correctness.
Test-quality heuristic Reported possible unregistered C++ tests. Manual inspection confirms the library CMake file registers both test sources; the warning is a heuristic false positive.
Current-main merge preview Passed; clean tree 9ce0e33a7eef4ec681d67b05a01afba739ba5c8f.
Hosted CI At final check, eligibility, conventions and report were pending; a duplicate conventions run was cancelled. No build/test result was available.
C++ tests/build Not run locally; these require building.
Unedited check output

git diff --check produced no output.

All conventions checks passed.

ABI audit summary from its JSON output:

{
  "status": "passed",
  "findings": []
}

Test-quality heuristic output:

{
  "findings": [
    {
      "path": "core/libs/tests/GuestAddressSanitizerMapping.cpp",
      "line": 1,
      "kind": "possible-unregistered-cpp-test",
      "message": "Changed C++ test source path was not found literally in CMake files; inspect registration, generated source lists, and workflow coverage."
    },
    {
      "path": "core/libs/tests/GuestAddressSanitizerShadow.cpp",
      "line": 1,
      "kind": "possible-unregistered-cpp-test",
      "message": "Changed C++ test source path was not found literally in CMake files; inspect registration, generated source lists, and workflow coverage."
    }
  ],
  "negative_control_candidates": [],
  "limits": [
    "Heuristics can miss weak assertions and can flag valid tests; inspect every finding.",
    "A test that passes against base is not by itself proof that the PR test is inadequate.",
    "Negative controls are only candidates until the test actually runs against base and fails by assertion rather than import/setup error."
  ]
}

Precheck command output:

/tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13265-78dc5a813605/report.md
/tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13265-78dc5a813605/report.json
Conclusion: checks failed

Merge preview output:

9ce0e33a7eef4ec681d67b05a01afba739ba5c8f

Hosted check output:

conventions	fail	0	https://github.com/boykopovar/AnyPS5/actions/runs/41043322043/job/124021179230
eligibility	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41043324203/job/124021373192
labels	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41043322948/job/124021884141
report	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41043324228/job/124021184581

Findings

Blocking

No new source-level blocker was confirmed in this review.

Non-blocking

The previous review's fixed-width unaligned 16-byte access finding is addressed by checking the final access byte when the fast-path shadow bytes are clear; the new guest_addresssanitizer_report_load16 case calls the clean aligned access and then an unaligned 16-byte access whose final granule is poisoned. The new test is registered in CMake. I inspected this source but did not execute it.

Sources

Not verified

The new Windows-only implementation reserves discontiguous free shadow ranges and commits pages through a vectored exception handler. No test or build result for head 78dc5a8… was available at review time. The PR discussion reports a Windows test run on the previous head def3d354c92f6b30bed17cbd1b5dcbfff4dc5daa; that result does not verify this head's changed Windows path. Linux runtime, console behavior, and the new Windows guest_addresssanitizer_mapping_collision test were not independently run here.

To get this to a good state

Please run the focused Windows AddressSanitizer tests, including guest_addresssanitizer_mapping_collision and guest_addresssanitizer_report_load16, on head 78dc5a8136054ba2b62a68e0cf83de7b989f1de3 and provide the exact commands and results. I will re-check the same evidence against the updated head.

@PrivacyOnion

Copy link
Copy Markdown
Author

@MarcZX10 Exact-head Windows run of 78dc5a8 (clean worktree, git status --porcelain empty).

Environment: Windows 11 Pro 10.0.26200, WinLibs MinGW-W64 GCC 16.1.0 UCRT r2, Ninja, Release, BUILD_TESTING=ON. The library and test objects, the libSceAddressSanitizer.prx and both test executables were deleted first, so everything below is rebuilt from this head.

git rev-parse HEAD
78dc5a8136054ba2b62a68e0cf83de7b989f1de3
cmake --build build --target guest_addresssanitizer_mapping_tests guest_addresssanitizer_shadow_tests
  Building CXX object .../libSceAddressSanitizer.dir/src/ShadowWindows.cpp.obj
  Building CXX object .../libSceAddressSanitizer.dir/Export.cpp.obj
  Building CXX object .../guest_addresssanitizer_mapping_tests.dir/.../GuestAddressSanitizerMapping.cpp.obj
  Building CXX object .../guest_addresssanitizer_shadow_tests.dir/.../GuestAddressSanitizerShadow.cpp.obj
  Linking CXX shared library core\libs\libs\unpatched\libSceAddressSanitizer.prx
  Linking CXX executable tests\guest_addresssanitizer_shadow_tests.exe
  Linking CXX executable tests\guest_addresssanitizer_mapping_tests.exe
ctest --test-dir build -R guest_addresssanitizer --output-on-failure
1/9 Test #735: guest_addresssanitizer_shadow ................   Passed    0.05 sec
2/9 Test #736: guest_addresssanitizer_mapping ...............   Passed    0.05 sec
3/9 Test #737: guest_addresssanitizer_mapping_collision .....   Passed    0.01 sec
4/9 Test #738: guest_addresssanitizer_report_load4 ..........   Passed    0.01 sec
5/9 Test #739: guest_addresssanitizer_report_load16 .........   Passed    0.01 sec
6/9 Test #740: guest_addresssanitizer_report_storeN .........   Passed    0.01 sec
7/9 Test #741: guest_addresssanitizer_report_unaligned ......   Passed    0.01 sec
8/9 Test #742: guest_addresssanitizer_report_partial ........   Passed    0.01 sec
9/9 Test #743: guest_addresssanitizer_report_report_error ...   Passed    0.01 sec
100% tests passed, 0 tests failed out of 9

ctest -R report_load16 -V (child process output matched by the regex):

ERROR: AddressSanitizer: use-after-poison on address 0x7ff649421098 at pc 0x7ff64941b178 bp 0x0000005ffbd0 sp 0x0000005ffb98
READ of size 16 at 0x7ff649421098 thread T-1
callback present=1 type=0 size=16 desc=use-after-poison address=ok text=ok
ABORTING
death callback

Negative controls on this code, each rebuilt and run, then reverted:

  • last-byte check disabled in CheckAccess_nid_no_patch: guest_addresssanitizer_report_load16 fails (regex not found, the load returns).
  • hole check disabled in ShadowRangeAvailable_nid_no_patch: mapping_tests collision exits 5 (poisoning wrote into the host page).
  • host pages committed at 0x1f500000000, 0x25000000000, 0x25000013000 and 0x29f00000000 before main continues: guest_addresssanitizer_mapping and all six report_* tests pass.

The conventions failure in the checks list is the cancelled duplicate run 41043322043.

@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.

Re-checked — new head, looks good

The previously reported Windows shadow-reservation and unaligned 16-byte access issues are addressed in head 78dc5a8136054ba2b62a68e0cf83de7b989f1de3, and the author supplied focused exact-head Windows test evidence.

What I ran

I re-read the current PR discussion, refreshed the head and hosted checks, and reviewed the exact-head test report. The PR is based on main at fae9e483bbbfd05ab0ad2d00df42f59f1da7824d; the prior local merge preview onto fetched main 663832e75756973e10f03518cbd4224829ce6780 was clean. Local environment for the earlier no-build review: Debian 12 x86-64, Python 3.11.2, Git 2.39.5, GCC 12.2.0. I did not build or run C++ tests locally. The Windows test run below was reported by the PR author, not run by me.

git diff --check fae9e483bbbfd05ab0ad2d00df42f59f1da7824d...78dc5a8136054ba2b62a68e0cf83de7b989f1de3
python3 tools/check_conventions.py --base fae9e483bbbfd05ab0ad2d00df42f59f1da7824d --head 78dc5a8136054ba2b62a68e0cf83de7b989f1de3 --title 'feat(libSceAddressSanitizer): implement shadow poisoning, access checks and error reports' --body /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13265-78dc5a813605/pr-body.md
python3 tools/pr_abi_audit.py --repo /marc/AnyPS5 --base fae9e483bbbfd05ab0ad2d00df42f59f1da7824d --head 78dc5a8136054ba2b62a68e0cf83de7b989f1de3 --json
ctest --test-dir build -R guest_addresssanitizer --output-on-failure  # author-reported Windows run

Results

Check Result
Local diff whitespace, conventions, ABI audit, test registration/source review Passed in the previous review; ABI audit had no findings.
Author-reported Windows exact-head tests 9/9 guest_addresssanitizer_* tests passed after rebuilding the library and test executables from this SHA.
Author-reported negative controls Both targeted mutations caused their regression tests to fail as expected; additional occupied host pages did not break mapping/report tests.
Hosted CI Conventions, eligibility, and progress report passed; Windows was pending at recheck; Linux and specialized jobs were skipped.

The exact commands and unedited Windows output are in the author’s exact-head test report.

Negative control

Assertion Change reported in the test code Result
Unaligned 16-byte load checks the final poisoned granule Disabled the final-byte check in CheckAccess_nid_no_patch guest_addresssanitizer_report_load16 failed as expected.
Shadow mapping preserves host allocations in reserved-range holes Disabled the hole check in ShadowRangeAvailable_nid_no_patch The collision test exited 5 as expected.

Findings

Blocking

None found in the reviewed head.

Non-blocking

The Windows evidence is author-reported. I did not independently run the Windows tests, and hosted Windows CI was still pending when checked.

Sources

Not verified

I did not independently build or run the Windows tests. Linux runtime, console behavior, and the pending hosted Windows job were not verified in this recheck.

@THEMANnt THEMANnt left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed 78dc5a8136054ba2b62a68e0cf83de7b989f1de3. No new actionable issue found in the shadow runtime and its documented limits. Reviewed the free-region reservation/hole guard and unaligned 16-byte access fix; the latter checks the final granule instead of stopping after two shadow bytes.

Independently built the pinned library and passed all nine registered Windows sanitizer tests, including the occupied-shadow collision control and third-granule load16 regression, using MSYS2 GCC 16.2 Release in an isolated DLL-linked harness. Whitespace passes. The hosted Windows job compiled the library but selected no guest tests, so its success is not counted as execution of these regressions. Local support forwards termination to the host and throws for unimplemented calls; this does not establish full guest libc, Linux, inline accesses through shadow holes, or console/game behavior.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@PrivacyOnion two things on 78dc5a8136.

  1. Licence notice. Large parts of Export.cpp are ported from compiler-rt rather than written from the interface. For example, __asan_poison_memory_region follows asan_poisoning.cpp from llvmorg-18.1.8 branch for branch, with the same ShadowSegmentEndpoint logic and names. The repository's rule for code taken from permissively licensed projects is to keep the original notice at the top of the file, verbatim. For LLVM that's:

    // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
    // See https://llvm.org/LICENSE.txt for license information.
    // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
    

    Could you add it to Export.cpp and to any other file derived from compiler-rt code (you'll know best whether Report.hpp or ShadowCheck.hpp qualify)?

  2. macOS build. CMakeLists.txt adds ShadowWindows.cpp on Windows and ShadowLinux.cpp on Linux, and nothing on other systems, while ShadowLinux.cpp is guarded by __linux__. On macOS nothing defines InitializeShadow_nid_no_patch or ShadowRangeAvailable_nid_no_patch, which Export.cpp calls, so the shared library and guest_addresssanitizer_shadow should fail to link there. Could you add a fallback for other systems (for example build the POSIX file everywhere but Windows and return false where MAP_FIXED_NOREPLACE is missing, or a small unsupported backend that reports the shadow unavailable)? A macOS run would confirm it.

… shadow on every non-Windows host

Export.cpp, ShadowCheck.hpp, Report.hpp and ErrorReport.hpp follow compiler-rt and now start with the LLVM Apache-2.0 WITH LLVM-exception notice. ShadowLinux.cpp is built on every host but Windows; without MAP_FIXED_NOREPLACE (macOS) it reserves no shadow, so the library links and the exports that need shadow throw. The shadow test is registered only where a shadow can be reserved.
PrivacyOnion pushed a commit to PrivacyOnion/AnyPS5 that referenced this pull request Nov 1, 2026
…ovar#13265

The compiler-rt port gitlink moves to 040178683306 (POSIX shadow and module lookup on every non-Windows host); the in-tree adapters keep no copied runtime code, so the notice stays in the port. Sanitizer tests are registered on Windows and Linux only.
@PrivacyOnion

Copy link
Copy Markdown
Author

@oneandonlydean thanks, both addressed in dfb095e.

Licence notice. Export.cpp, src/ShadowCheck.hpp, src/Report.hpp and src/ErrorReport.hpp follow compiler-rt (asan_poisoning.cpp, asan_rtl.cpp, asan_report.cpp, asan_errors.cpp) and now start with the LLVM notice, verbatim:

// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

ShadowAddressSpace.hpp only holds the PlayStation mapping constants of the instrumentation, and ShadowWindows.cpp/ShadowLinux.cpp are the host reservation backends, so they carry no notice.

Other hosts. CMakeLists.txt now builds src/ShadowLinux.cpp on every host but Windows, and the file no longer has a __linux__ guard. Without MAP_FIXED_NOREPLACE (macOS) it takes the existing path that reserves nothing and returns false, so InitializeShadow_nid_no_patch and ShadowRangeAvailable_nid_no_patch are defined, the library links, and every export that needs shadow throws. guest_addresssanitizer_shadow is registered only on Windows and Linux, where a shadow can be reserved. The debt entry says so. I have no macOS machine, so the macOS link is unverified here; Export.cpp and ShadowWindows.cpp compile to objects with the real APS5_VABI, and conventions pass.

#13331 is updated the same way, in 0363753:

  • there the runtime lives in the compiler-rt port, so the fork (0401786) builds its POSIX shadow and its dladdr module lookup on every non-Windows host;
  • the sanitizer tests are registered on Windows and Linux only.

@PrivacyOnion

Copy link
Copy Markdown
Author

The failing Build / windows check on dfb095e is unrelated to this PR. In the job log:

  • 2593 of the 2594 selected tests pass, including all nine guest_addresssanitizer_* tests (shadow, mapping, mapping_collision, report_load4, report_load16, report_storeN, report_unaligned, report_partial, report_report_error).
  • The one failure is guest_filesystem (libkernel), which exits with 0xc0000409 after its parent-path sceKernelOpen cases.

This PR changes only core/libs/prx/libSceAddressSanitizer, its two test sources in core/libs/tests and its debt file. It touches nothing in libkernel or libc. GuestFilesystem.cpp changed on main recently (#12922), and the job tests the merge with current main.

I can't rerun the job from a fork. Could a maintainer rerun the failed Windows job?

@THEMANnt THEMANnt left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-reviewed dfb095e1d08c5470cb97e70f2bbff04b2f50e04c. No new actionable issue found in the follow-up. The LLVM notices are present, the non-Windows backend is included, and hosts without MAP_FIXED_NOREPLACE return shadow-unavailable instead of leaving unresolved backend symbols.

Windows/MSYS2 GCC 16.2 Release: rebuilt the pinned library in the existing isolated DLL-linked harness; all nine registered sanitizer tests pass, including occupied-shadow and unaligned load16 controls. Hosted Windows is red: its log reports one failure, guest_filesystem, out of 2,594 tests. I have not independently reproduced that filesystem failure or proved its cause. This approval covers the sanitizer change; it does not clear the red check. No macOS/Linux runtime or console execution was performed.

@PrivacyOnion

Copy link
Copy Markdown
Author

More evidence that the red Build / windows on dfb095e isn't caused by this PR:

  • The job (run 41303686885) tested this head merged onto main at about 12:27 UTC, after fix(libkernel): report a 64 KiB st_blksize for directories #12922 (GuestFilesystem.cpp, st_blksize compared to the host value) landed on main at 11:25 UTC.
  • The same guest_filesystem test passes on main's own later Windows runs, with fix(libkernel): report a 64 KiB st_blksize for directories #12922 already in: 41308372721 (12:50 UTC, 3277/3277) and 41311735538 (13:32 UTC, 3276/3276).
  • In the failing job, the test aborts in its own assertion right after sceKernelOpen("/") and sceKernelOpen(".") with O_DIRECTORY. Neither path goes through libSceAddressSanitizer, and guest_filesystem_tests doesn't link it.

So it looks intermittent or runner-dependent, not caused by this change. Could a maintainer rerun the failed Windows job? Both approvals are on this exact head, so I'd rather not push a new commit just to retrigger CI.

@CnRJay CnRJay 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.

Withdrawn on the title-ID point; Unblocks: none is allowed. The reservation question stands: is the 16 TiB shadow reservation made only when an export is called, or can merely linking the library trigger it? A test showing nothing is reserved when no sanitizer export is called would settle it.

@PrivacyOnion

Copy link
Copy Markdown
Author

@CnRJay the shadow is reserved only when an export first needs it. Loading or linking the library reserves nothing.

  • There is no static initializer, DllMain or module-start hook in libSceAddressSanitizer. InitializeShadow_nid_no_patch runs only from ShadowRangeAvailable_nid_no_patch, which the poisoning, check and report exports call before they touch shadow memory (Export.cpp).
  • On Windows, the first call reserves the free ranges of [1 TiB, 17 TiB) with MEM_RESERVE and PAGE_NOACCESS; pages are committed one at a time from the vectored exception handler. On Linux it is a single MAP_NORESERVE mapping made at that same first call.

ca0788f adds guest_addresssanitizer_mapping_lazy. The test process has libSceAddressSanitizer and libc loaded. It checks that VirtualQuery reports MEM_FREE at the shadow base before any sanitizer export is called, calls __asan_poison_memory_region once, then checks the base is no longer free. It passes on Windows (GCC 15) together with the other 9 AddressSanitizer tests. As a negative control, I added a static initializer that reserves the shadow when the library loads, and the new test then fails.

@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ AMD GPU test: passed

PR head ca0788f merged onto main f2d874c · tested 2026-11-02 18:59 UTC · 29 min

GPU AMD Radeon RX 6300 (RADV NAVI24), driver Mesa 25.2.8-0ubuntu0.24.04.4, Vulkan 1.4.318
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-42-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 1,616 passed · 8 failed (0 new, 5 also fail on main, 3 unstable on main) · 7 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 1,631 of 3,168 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (743 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.3 s, ⚠️ public_headers 84.2 s, ⚠️ unwrap_self 76.0 s, ⚠️ agc_driver_sdwa_move_selectors 58.6 s, ⚠️ agc_driver_bda_device 57.6 s
Unstable on main (3, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_array_layer_target_cpu: failed in 1 of the last 5 main runs
agc_driver_pipeline_journal: failed in 3 of the last 5 main runs
agc_driver_submit_progress: failed in 3 of the last 5 main runs
Failing on main too (5, not counted against this PR)
agc_driver_image_table
agc_driver_native_depth_bda_clear
agc_driver_native_depth_buffer_clear
agc_driver_native_multisample_depth
guest_mmap_executable
Passed on retry (5, failed in the parallel run, passed when re-run with a 360 s timeout; not counted against this PR)
agc_driver_depth_fast_clear_submit: Failed in the parallel run; also passed only on retry in 20 other runs in the last 7 days
agc_driver_dithered_alpha_to_coverage: Timeout in the parallel run; also passed only on retry in 2 other runs in the last 7 days
agc_driver_emulated_color_compare: Timeout in the parallel run; also passed only on retry in 16 other runs in the last 7 days
agc_driver_emulated_color_compare_srgb_decode: Timeout in the parallel run; also passed only on retry in 3 other runs in the last 7 days
trace_digest_TraceDigestTests_test_cli_rejects_invalid_event_fields_without_partial_output: Timeout in the parallel run; also passed only on retry in 16 other runs in the last 7 days
Validated but not compared (1, not in the main baseline's validation pass)
trace_digest_TraceDigestTests_test_cli_rejects_invalid_event_fields_without_partial_output
Validation IDs already present on main (5 IDs in 606 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (606 tests): agc_compute_pipeline_replay, agc_driver_address_passes, agc_driver_address_passes_draw_transitions, agc_driver_address_passes_targets_split, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_array_layer_target_cpu, and 598 more
VUID-vkCmdCopyImage-srcImage-01548 (11 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, and 3 more
VUID-vkCmdCopyImage-srcImage-01551 (11 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, and 3 more
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (2 tests): agc_driver_prepared_exports, agc_driver_srgb8_color_target
VUID-VkShaderModuleCreateInfo-pCode-08737 (1 test): agc_driver_image_sample_derivatives
Skipped (7)
agc_driver_copied_writer_label_order: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_copied_writer_label_order_drain: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_linear_target_direct_write_completion: skipped, the device does not keep host imports write-watched, so no completion stamp over the target is tracked
agc_driver_ngg_vertex_wave_reduction: skipped, s3 describes a 32-lane wave only on 32-lane subgroups, and the device has 64 lanes
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_vertex_elected_atomic_max: skipped, the device runs vertex programs in subgroups, so they keep their cross-lane reductions
video_out_flip_unopened: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
Reproduce
git fetch origin ca0788ffc774266d69d6bca62795ff5c2514a9d1 f2d874c1fdccf781c0fa5d86619bb5dd8894b958
git checkout f2d874c1fdccf781c0fa5d86619bb5dd8894b958 && git merge --no-ff ca0788ffc774266d69d6bca62795ff5c2514a9d1
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 12 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 16 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants