Skip to content

feat(libSceAddressSanitizer): add allocator, UBSan and runtime services - #13331

Open
PrivacyOnion wants to merge 25 commits into
boykopovar:mainfrom
PrivacyOnion:feat/addresssanitizer-remaining
Open

PrivacyOnion wants to merge 25 commits into
boykopovar:mainfrom
PrivacyOnion:feat/addresssanitizer-remaining

Conversation

@PrivacyOnion

@PrivacyOnion PrivacyOnion commented Oct 30, 2026 •

Copy link
Copy Markdown

What

Follow-up to #13265. This change replaces 185 additional throwing function stubs and replaces two function stubs with data exports. Relative to #13265, the library has 285 implemented function bodies out of 299 functions, 14 throwing stubs, and two data exports. The progress script counts functions and does not include the two data objects.

This PR is stacked on #13265: its head 78dc5a8136054ba2b62a68e0cf83de7b989f1de3 is a real ancestor. main d6401d794e47ef5abef80502c2ac1bfa03d7b20a is integrated. The 185 additional functions and two data objects are measured against #13265; the main-to-head diff also includes the prerequisite's 100 functions until it merges. Refresh the branch after #13265 lands.

Implemented areas:

  • Instrumented memory intrinsics, experimental access callbacks and contiguous/double-ended container annotations.
  • UBSan diagnostics, deduplication, recovery and fatal variants, with LLVM 18.1.8 metadata and legacy LLVM 3.8 type-mismatch/nonnull-return layouts.
  • Heap allocation, alignment, redzones, quarantine, ownership/size queries and allocation/free context queries.
  • Fake stacks, no-return cleanup, fiber switching, global/ELF-global registration, address location and ODR diagnostics.
  • Explicit coverage dumps, report paths/descriptors, host stack capture and module/offset formatting.
  • Data exports: __asan_option_detect_stack_use_after_return is a four-byte int; __ubsan_vptr_type_cache contains 128 pointer-sized hashes (1024 bytes on x86-64).

The Windows backing fix remains in this revision: heap and fake-stack backing use bounded VirtualAlloc2 allocations, their application addresses exclude the shadow, their projected shadow is available, and VirtualFree(..., MEM_RELEASE) releases the reservations. The shared range guard rejects shadow, overflowing and out-of-bounds application ranges. Global registration rejects null nonempty descriptor arrays and byte-count overflow. Linux retains the cached-fake-stack behavior of its TLS fast path.

Provenance and dependency integration:

The runtime adapts compiler-rt implementation algorithms and diagnostic text. The adapted implementation, including portions inherited from #13265, now lives in the compiler-rt port, built from source through CMake's compiler_rt_anyps5 object target. .gitmodules records 3rdparty/compiler-rt with URL https://github.com/PrivacyOnion/compiler-rt.git; its gitlink is pinned to 21681889623a86177efe37b19be8a69fb84f472e. The fork is based on LLVM 18.1.8 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff. Its published branch contains the compiler-rt source tree at the repository root so a shallow submodule checkout retrieves compiler-rt rather than the whole monorepo. A tree comparison confirms upstream compiler-rt is unchanged outside lib/asan_anyps5.

core/libs/prx/libSceAddressSanitizer/Export.cpp now contains the guest ABI adapters, the two data definitions and the documented default/throwing exports. Its source headers forward to the dependency's headers. The adapters pass the original caller PC/BP and function name explicitly to the runtime. The new native bridge symbols use C linkage and _nid_no_patch suffixes so the NID patcher retains their native names.

The port NOTICE records the origin and modifications. Source mapping:

Compiled port portion Implementation source or interface evidence
Runtime.cpp: shadow-segment/user/intra-object/alloca poisoning, access callbacks and report dispatch asan_poisoning.cpp, asan_rtl.cpp, asan_report.cpp; adapted range validation and caller transport
src/Container.hpp: FixUnalignedStorage, contiguous/double-ended transitions and FindBadAddress asan_poisoning.cpp
src/Allocator.cpp: redzone selection, size-class computation, parameter checks and diagnostics asan_allocator.cpp, sanitizer_allocator_size_class_map.h, asan_stats.cpp; host maps, backing and quarantine are port changes
src/FakeStack.cpp: flag/frame layout, class allocation, GC and fiber/no-return behavior asan_fake_stack.h, asan_fake_stack.cpp, asan_thread.cpp; modified allocation, TLS lifecycle and locking
src/Globals.cpp/.hpp, src/Describe.cpp/.hpp, src/Report.hpp, src/ShadowCheck.hpp asan_globals.cpp, asan_interface_internal.h, asan_descriptions.cpp, asan_errors.cpp, asan_report.cpp; modified host registry and validation
src/Ubsan.cpp: metadata, value decoding, handler decisions and diagnostics ubsan_handlers.cpp, ubsan_handlers.h, ubsan_value.cpp, ubsan_value.h, ubsan_diag.cpp, ubsan_monitor.cpp
Legacy UBSan metadata layouts LLVM 3.8 ABI declarations; no LLVM 3.8 implementation file is compiled
src/Coverage.cpp: interface and coverage-file format sanitizer_coverage_libcdep_new.cpp, sanitizer_coverage_interface.inc, with host file/module integration
Shadow/backing providers, module lookup, report files, stack bounds and stack capture AnyPS5 host integration using Windows/POSIX APIs; VirtualAlloc2 and MEM_ADDRESS_REQUIREMENTS define Windows bounds/alignment; the shadow scale/offset follows LLVM instrumentation

Licence treatment: the dependency retains the unmodified compiler-rt licence, LLVM exceptions and legacy notices. The external port carries per-file licence and modification notices; its AnyPS5 GPLv2 text is preserved in LICENSE.GPL-2.0, and the NOTICE identifies the derived portions and modified port. tools/package_release.py now includes all three documents under libs/licenses/ in both patched and unpatched ZIP/TAR archives. No licence file or comment header is added under core/libs/prx/.

Export names and NIDs come from the pinned ps5rs inventory; that inventory does not establish signatures or behavior. Console ABI, layouts and behavior remain unverified. The implementation is partial, with remaining gaps in docs/dev/debt/libSceAddressSanitizer.md: options/default overrides are ignored, the allocator has one global quarantine and one caller frame, mismatch checks are missing, Windows reserves each backing block separately, symbol formatting has no external symbolizer, and inline accesses to Windows shadow holes remain a limitation. Fourteen unsupported interfaces still call NotImplemented_nid_no_patch.

Tested

Windows 11 Pro 10.0.26200, x86-64, WinLibs MinGW-W64 GCC 16.1.0 UCRT, Ninja, Release, BUILD_TESTING=ON. Submitted head: ead33bff92dbf676b11292877475abb7414ac3ee; compiler-rt gitlink: 21681889623a86177efe37b19be8a69fb84f472e; integrated main: d6401d794e47ef5abef80502c2ac1bfa03d7b20a. No title, homebrew or console execution.

git rev-parse ead33bff92dbf676b11292877475abb7414ac3ee
cmake --build C:/Users/playl/AppData/Local/Temp/anyps5-asan-full --target guest_addresssanitizer_runtime_tests guest_addresssanitizer_mapping_tests guest_addresssanitizer_shadow_tests guest_addresssanitizer_backing_tests nid_patcher --parallel 4
ctest --test-dir C:/Users/playl/AppData/Local/Temp/anyps5-asan-full -R guest_addresssanitizer --output-on-failure
python tools/tests/test_package_release.py

Results:

  • 72/72 sanitizer CTests passed. This includes the forced Windows host-allocation/shadow-hole regression, all allocator/container/global/fiber tests, the original mapping-collision and unaligned-16-byte regressions, and the UBSan subprocess checks.
  • The new wrapper_call_sites case verifies that allocation, allocation-context update and free traces identify the test executable as the caller across the extracted runtime boundary. Replacing the forwarded malloc caller PC with zero makes this test fail; restoring the forwarding restores the passing suite.
  • 76 release-packaging tests ran: 61 passed, 15 skipped on Windows. The new regression checks the byte contents of all three notices in patched/unpatched ZIP/TAR archives. Removing or emptying each notice fails packaging before existing archives are modified.
  • The dependency was cloned separately from GitHub without a local object alternate, checked out at its pinned revision, and its 12 Windows runtime translation units were built from that checkout with CMake using the project's host headers.
  • Linux compile-only: 15/15 translation units compiled, comprising the guest adapter, 12 runtime sources and two portable test sources, using Zig 0.16.0 / Clang 21.1.0, -target x86_64-linux-gnu -std=c++20 -Wall -Wextra -fPIC -c. No Linux link, CTest or runtime result is claimed; compiler warnings are not represented as a warning-free build.

Additional checks:

  • Public-header audit: 374 libraries, 23569 exports; declarations and umbrella coverage passed.
  • Test-script registration: 223 scripts registered by CTest or workflows.
  • tools/pr_overlap.py compared the branch with 1535 open PRs. No conflicting lines or same exports were reported among comparable branches after separating the notice-packaging additions from feat(libSceJemspace): implement arena allocation and statistics #9855. The tool could not compare feat(input): add native SDL input configuration with ImGui #674, feat(aot): discuss native ARM64 compiler architecture and integration #1835, feat(aot): consolidate native ARM64 compiler, runtime and consumers #5021 and feat(libSceLibreSsl): implement CMAC with AES-CBC methods #9571 because their bases conflict; their shared-file patches were inspected manually: ImGui/input-tool packaging, Capstone/pyelftools/ps5link-sdk, and LibreSSL module entries are independent of the compiler-rt module and sanitizer notices. No additional dependency is introduced by those patches.
  • git diff --check and repository conventions against the integrated upstream main passed. The required python tools/check_conventions.py --base origin/main was run; the stale fork base still produces the same 140 baseline errors. That invocation is not represented as a passing check.
  • All 301 expected public NIDs remain present after patching the Windows binary. All 274 native bridge names retain _nid_no_patch rather than being converted to NIDs. Data objects retain their four-byte/1024-byte ABI layouts.
  • The Windows backing-layout correction was also independently rechecked at the earlier head 1bb57ba9ff by the original reviewer on the previously failing Windows/GCC 15.3 host in the PR conversation. The author results above cover the new extracted-runtime revision; no hosted-build result is inferred from those local runs.

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: feat(libSceAddressSanitizer): implement shadow poisoning, access checks and error reports #13265
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes
Windows focused CTest output on ead33bf
Test project C:/Users/playl/AppData/Local/Temp/anyps5-asan-full
      Start 736: guest_addresssanitizer_shadow
 1/72 Test #736: guest_addresssanitizer_shadow ................................   Passed    0.30 sec
      Start 737: guest_addresssanitizer_fake_stack_option
 2/72 Test #737: guest_addresssanitizer_fake_stack_option .....................   Passed    0.07 sec
      Start 738: guest_addresssanitizer_vptr_cache_data
 3/72 Test #738: guest_addresssanitizer_vptr_cache_data .......................   Passed    0.02 sec
      Start 739: guest_addresssanitizer_globals_invalid_array
 4/72 Test #739: guest_addresssanitizer_globals_invalid_array .................   Passed    0.01 sec
      Start 740: guest_addresssanitizer_legacy_ubsan
 5/72 Test #740: guest_addresssanitizer_legacy_ubsan ..........................   Passed    0.46 sec
      Start 741: guest_addresssanitizer_runtime_clean
 6/72 Test #741: guest_addresssanitizer_runtime_clean .........................   Passed    0.04 sec
      Start 742: guest_addresssanitizer_runtime_contiguous
 7/72 Test #742: guest_addresssanitizer_runtime_contiguous ....................   Passed    0.03 sec
      Start 743: guest_addresssanitizer_runtime_double_ended
 8/72 Test #743: guest_addresssanitizer_runtime_double_ended ..................   Passed    0.02 sec
      Start 744: guest_addresssanitizer_runtime_memory
 9/72 Test #744: guest_addresssanitizer_runtime_memory ........................   Passed    0.02 sec
      Start 745: guest_addresssanitizer_runtime_exp_load4
10/72 Test #745: guest_addresssanitizer_runtime_exp_load4 .....................   Passed    0.03 sec
      Start 746: guest_addresssanitizer_runtime_exp_store16_noabort
11/72 Test #746: guest_addresssanitizer_runtime_exp_store16_noabort ...........   Passed    0.02 sec
      Start 747: guest_addresssanitizer_runtime_exp_loadN
12/72 Test #747: guest_addresssanitizer_runtime_exp_loadN .....................   Passed    0.03 sec
      Start 748: guest_addresssanitizer_runtime_report_exp_store2
13/72 Test #748: guest_addresssanitizer_runtime_report_exp_store2 .............   Passed    0.04 sec
      Start 749: guest_addresssanitizer_runtime_report_exp_load_n
14/72 Test #749: guest_addresssanitizer_runtime_report_exp_load_n .............   Passed    0.02 sec
      Start 750: guest_addresssanitizer_runtime_memcpy_source
15/72 Test #750: guest_addresssanitizer_runtime_memcpy_source .................   Passed    0.03 sec
      Start 751: guest_addresssanitizer_runtime_memset_poison
16/72 Test #751: guest_addresssanitizer_runtime_memset_poison .................   Passed    0.02 sec
      Start 752: guest_addresssanitizer_runtime_memmove_poison
17/72 Test #752: guest_addresssanitizer_runtime_memmove_poison ................   Passed    0.09 sec
      Start 753: guest_addresssanitizer_runtime_memcpy_overlap
18/72 Test #753: guest_addresssanitizer_runtime_memcpy_overlap ................   Passed    0.03 sec
      Start 754: guest_addresssanitizer_runtime_memset_negative
19/72 Test #754: guest_addresssanitizer_runtime_memset_negative ...............   Passed    0.04 sec
      Start 755: guest_addresssanitizer_runtime_container_params
20/72 Test #755: guest_addresssanitizer_runtime_container_params ..............   Passed    0.02 sec
      Start 756: guest_addresssanitizer_runtime_double_ended_params
21/72 Test #756: guest_addresssanitizer_runtime_double_ended_params ...........   Passed    0.02 sec
      Start 757: guest_addresssanitizer_runtime_ubsan_arithmetic
22/72 Test #757: guest_addresssanitizer_runtime_ubsan_arithmetic ..............   Passed    0.03 sec
      Start 758: guest_addresssanitizer_runtime_ubsan_misc
23/72 Test #758: guest_addresssanitizer_runtime_ubsan_misc ....................   Passed    0.02 sec
      Start 759: guest_addresssanitizer_runtime_ubsan_data
24/72 Test #759: guest_addresssanitizer_runtime_ubsan_data ....................   Passed    0.03 sec
      Start 760: guest_addresssanitizer_runtime_ubsan_dedup
25/72 Test #760: guest_addresssanitizer_runtime_ubsan_dedup ...................   Passed    0.06 sec
      Start 761: guest_addresssanitizer_runtime_ubsan_abort
26/72 Test #761: guest_addresssanitizer_runtime_ubsan_abort ...................   Passed    0.04 sec
      Start 762: guest_addresssanitizer_runtime_ubsan_unreachable
27/72 Test #762: guest_addresssanitizer_runtime_ubsan_unreachable .............   Passed    0.05 sec
      Start 763: guest_addresssanitizer_runtime_heap
28/72 Test #763: guest_addresssanitizer_runtime_heap ..........................   Passed    0.04 sec
      Start 764: guest_addresssanitizer_runtime_wrapper_call_sites
29/72 Test #764: guest_addresssanitizer_runtime_wrapper_call_sites ............   Passed    0.04 sec
      Start 765: guest_addresssanitizer_runtime_heap_aligned
30/72 Test #765: guest_addresssanitizer_runtime_heap_aligned ..................   Passed    0.04 sec
      Start 766: guest_addresssanitizer_runtime_heap_stats
31/72 Test #766: guest_addresssanitizer_runtime_heap_stats ....................   Passed    0.04 sec
      Start 767: guest_addresssanitizer_runtime_heap_double_free
32/72 Test #767: guest_addresssanitizer_runtime_heap_double_free ..............   Passed    0.03 sec
      Start 768: guest_addresssanitizer_runtime_heap_bad_free
33/72 Test #768: guest_addresssanitizer_runtime_heap_bad_free .................   Passed    0.03 sec
      Start 769: guest_addresssanitizer_runtime_heap_interior_free
34/72 Test #769: guest_addresssanitizer_runtime_heap_interior_free ............   Passed    0.03 sec
      Start 770: guest_addresssanitizer_runtime_heap_usable_size_unowned
35/72 Test #770: guest_addresssanitizer_runtime_heap_usable_size_unowned ......   Passed    0.03 sec
      Start 771: guest_addresssanitizer_runtime_heap_allocated_size_unowned
36/72 Test #771: guest_addresssanitizer_runtime_heap_allocated_size_unowned ...   Passed    0.02 sec
      Start 772: guest_addresssanitizer_runtime_heap_calloc_overflow
37/72 Test #772: guest_addresssanitizer_runtime_heap_calloc_overflow ..........   Passed    0.06 sec
      Start 773: guest_addresssanitizer_runtime_heap_aligned_alloc_bad
38/72 Test #773: guest_addresssanitizer_runtime_heap_aligned_alloc_bad ........   Passed    0.03 sec
      Start 774: guest_addresssanitizer_runtime_heap_posix_memalign_bad
39/72 Test #774: guest_addresssanitizer_runtime_heap_posix_memalign_bad .......   Passed    0.04 sec
      Start 775: guest_addresssanitizer_runtime_heap_memalign_bad
40/72 Test #775: guest_addresssanitizer_runtime_heap_memalign_bad .............   Passed    0.03 sec
      Start 776: guest_addresssanitizer_runtime_heap_too_big
41/72 Test #776: guest_addresssanitizer_runtime_heap_too_big ..................   Passed    0.05 sec
      Start 777: guest_addresssanitizer_runtime_heap_realloc_freed
42/72 Test #777: guest_addresssanitizer_runtime_heap_realloc_freed ............   Passed    0.03 sec
      Start 778: guest_addresssanitizer_runtime_fake_stack
43/72 Test #778: guest_addresssanitizer_runtime_fake_stack ....................   Passed    0.02 sec
      Start 779: guest_addresssanitizer_runtime_no_return
44/72 Test #779: guest_addresssanitizer_runtime_no_return .....................   Passed    0.02 sec
      Start 780: guest_addresssanitizer_runtime_globals
45/72 Test #780: guest_addresssanitizer_runtime_globals .......................   Passed    0.02 sec
      Start 781: guest_addresssanitizer_runtime_globals_elf
46/72 Test #781: guest_addresssanitizer_runtime_globals_elf ...................   Passed    0.03 sec
      Start 782: guest_addresssanitizer_runtime_fibers
47/72 Test #782: guest_addresssanitizer_runtime_fibers ........................   Passed    0.05 sec
      Start 783: guest_addresssanitizer_runtime_locate
48/72 Test #783: guest_addresssanitizer_runtime_locate ........................   Passed    0.03 sec
      Start 784: guest_addresssanitizer_runtime_init
49/72 Test #784: guest_addresssanitizer_runtime_init ..........................   Passed    0.06 sec
      Start 785: guest_addresssanitizer_runtime_globals_odr_indicator
50/72 Test #785: guest_addresssanitizer_runtime_globals_odr_indicator .........   Passed    0.06 sec
      Start 786: guest_addresssanitizer_runtime_globals_odr_poison
51/72 Test #786: guest_addresssanitizer_runtime_globals_odr_poison ............   Passed    0.04 sec
      Start 787: guest_addresssanitizer_runtime_globals_describe
52/72 Test #787: guest_addresssanitizer_runtime_globals_describe ..............   Passed    0.03 sec
      Start 788: guest_addresssanitizer_runtime_describe_heap
53/72 Test #788: guest_addresssanitizer_runtime_describe_heap .................   Passed    0.03 sec
      Start 789: guest_addresssanitizer_runtime_fiber_unstarted
54/72 Test #789: guest_addresssanitizer_runtime_fiber_unstarted ...............   Passed    0.03 sec
      Start 790: guest_addresssanitizer_runtime_fiber_double_start
55/72 Test #790: guest_addresssanitizer_runtime_fiber_double_start ............   Passed    0.03 sec
      Start 791: guest_addresssanitizer_runtime_report_path
56/72 Test #791: guest_addresssanitizer_runtime_report_path ...................   Passed    0.06 sec
      Start 792: guest_addresssanitizer_runtime_report_stdout
57/72 Test #792: guest_addresssanitizer_runtime_report_stdout .................   Passed    0.03 sec
      Start 793: guest_addresssanitizer_runtime_report_descriptor
58/72 Test #793: guest_addresssanitizer_runtime_report_descriptor .............   Passed    0.09 sec
      Start 794: guest_addresssanitizer_runtime_stack_trace
59/72 Test #794: guest_addresssanitizer_runtime_stack_trace ...................   Passed    0.05 sec
      Start 795: guest_addresssanitizer_runtime_symbolize
60/72 Test #795: guest_addresssanitizer_runtime_symbolize .....................   Passed    0.03 sec
      Start 796: guest_addresssanitizer_runtime_symbolize_bad
61/72 Test #796: guest_addresssanitizer_runtime_symbolize_bad .................   Passed    0.04 sec
      Start 797: guest_addresssanitizer_runtime_coverage
62/72 Test #797: guest_addresssanitizer_runtime_coverage ......................   Passed    0.06 sec
      Start 798: guest_addresssanitizer_runtime_sandbox_notify
63/72 Test #798: guest_addresssanitizer_runtime_sandbox_notify ................   Passed    0.05 sec
      Start 799: guest_addresssanitizer_backing_layout
64/72 Test #799: guest_addresssanitizer_backing_layout ........................   Passed    0.14 sec
      Start 800: guest_addresssanitizer_mapping
65/72 Test #800: guest_addresssanitizer_mapping ...............................   Passed    0.10 sec
      Start 801: guest_addresssanitizer_mapping_collision
66/72 Test #801: guest_addresssanitizer_mapping_collision .....................   Passed    0.02 sec
      Start 802: guest_addresssanitizer_report_load4
67/72 Test #802: guest_addresssanitizer_report_load4 ..........................   Passed    0.02 sec
      Start 803: guest_addresssanitizer_report_load16
68/72 Test #803: guest_addresssanitizer_report_load16 .........................   Passed    0.02 sec
      Start 804: guest_addresssanitizer_report_storeN
69/72 Test #804: guest_addresssanitizer_report_storeN .........................   Passed    0.01 sec
      Start 805: guest_addresssanitizer_report_unaligned
70/72 Test #805: guest_addresssanitizer_report_unaligned ......................   Passed    0.02 sec
      Start 806: guest_addresssanitizer_report_partial
71/72 Test #806: guest_addresssanitizer_report_partial ........................   Passed    0.04 sec
      Start 807: guest_addresssanitizer_report_report_error
72/72 Test #807: guest_addresssanitizer_report_report_error ...................   Passed    0.03 sec

100% tests passed, 0 tests failed out of 72

Total Test time (real) =   6.19 sec

PrivacyOnion added 13 commits October 30, 2026 11:21
…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.
…e accesses

Invalid ranges and a failed shadow reservation throw std::invalid_argument and std::runtime_error instead of NotImplemented_nid_no_patch.
…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.
…e and heap queries

Add a redzone allocator with a 256 MiB quarantine that backs the __asan_malloc family, the __sanitizer_get_* heap queries, accumulated stats and the allocation and free stack lookups. Misuse such as double free, bad free, overflowing calloc and invalid alignments aborts with the LLVM 18.1.8 report text.
…tion, fibers and address description

Add the use-after-return fake stack with its stack_malloc and stack_free size classes, __asan_handle_no_return stack unpoisoning, fiber switching, global variable registration with ODR violation detection, and __asan_describe_address and __asan_locate_address backed by the heap, globals and shadow layout.
…trace and symbolizer exports

Add trace-pc-guard coverage with sancov dumping, the report path and descriptor redirection, module-and-offset stack trace rendering and the pc symbolizer, and route every report through the report file.
List the exports that stay unimplemented with their reason and describe how the allocator, globals, fake stacks, report file and symbolizer differ from LLVM 18.1.8.

@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 c12b02adb85c672825a3e494a81ca363f4cdc16a against main f91137142eafd5df646fca6419a1fc4ef61b89d9; the live #13265 head is an ancestor and that prerequisite is still open.

Requesting changes for one reproduced Windows allocation-layout bug, detailed inline. Fresh GCC 15.3 Release configuration/build succeeded, but the registered sanitizer suite passed 61/70, with 9 failures; all 9 failed again on a focused rerun. The heap/fake-stack cases abort on addresses returned by this runtime, while several diagnostic/location cases classify those allocations as shadow memory.

Independent probes reproduce both heap and fake-stack rejection. A control mapping at 32 TiB passes poison/query/memset checks. Separately, 1,234 contiguous/double-ended container configurations passed byte-by-byte shadow checks; recoverable UBSan overflow reported once across two calls and returned successfully, and its abort variant exited 1. No Linux runtime or console/game test is claimed. The new targets are absent from main; no equivalent baseline runtime result is claimed.

}
const auto raw = reinterpret_cast<std::uintptr_t>(block);
try {
RequireShadowRange_nid_no_patch(raw, total, __func__);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P1] Allocate guest heap and fake stacks outside the shadow range

On Windows, operator new can allocate from an existing host heap inside [ShadowBase, ShadowBase + ShadowSize) (1–17 TiB). RequireShadowRange_nid_no_patch only validates the projected shadow bytes, so this code accepts the block and returns it as guest memory. A direct p = __asan_malloc(13); __asan_address_is_poisoned(p); on this head returned 0x0000015184313eb8 and then aborted with std::invalid_argument: __asan_address_is_poisoned: address range outside guest memory or misaligned (exit 0xc0000409). __asan_stack_malloc_always_0(64) has the same issue through FakeStack.cpp's calloc. These are the runtime's own fresh allocations, not an external inline access to a documented shadow hole. Please allocate the heap and fake-stack backing storage from an address range valid for guest memory, with matching deallocation, and cover this Windows host-heap layout. Merely confirming that their shadow is mapped does not make the returned application address valid.

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Progress report (ba62780 → 0363753)

📈 System libraries: 27.07% (+0.83%, +285 implemented, -2 removed functions)

✅ 285 implemented
Library Name
libSceAddressSanitizer __asan_addr_is_in_fake_stack
libSceAddressSanitizer __asan_address_is_poisoned
libSceAddressSanitizer __asan_after_dynamic_init
libSceAddressSanitizer __asan_aligned_alloc
libSceAddressSanitizer __asan_alloca_poison
libSceAddressSanitizer __asan_allocas_unpoison
libSceAddressSanitizer __asan_before_dynamic_init
libSceAddressSanitizer __asan_calloc
libSceAddressSanitizer __asan_describe_address
libSceAddressSanitizer __asan_exp_load1
libSceAddressSanitizer __asan_exp_load16
libSceAddressSanitizer __asan_exp_load16_noabort
libSceAddressSanitizer __asan_exp_load1_noabort
libSceAddressSanitizer __asan_exp_load2
libSceAddressSanitizer __asan_exp_load2_noabort
libSceAddressSanitizer __asan_exp_load4
libSceAddressSanitizer __asan_exp_load4_noabort
libSceAddressSanitizer __asan_exp_load8
libSceAddressSanitizer __asan_exp_load8_noabort
libSceAddressSanitizer __asan_exp_loadN
libSceAddressSanitizer __asan_exp_loadN_noabort
libSceAddressSanitizer __asan_exp_store1
libSceAddressSanitizer __asan_exp_store16
libSceAddressSanitizer __asan_exp_store16_noabort
libSceAddressSanitizer __asan_exp_store1_noabort
libSceAddressSanitizer __asan_exp_store2
libSceAddressSanitizer __asan_exp_store2_noabort
libSceAddressSanitizer __asan_exp_store4
libSceAddressSanitizer __asan_exp_store4_noabort
libSceAddressSanitizer __asan_exp_store8
libSceAddressSanitizer __asan_exp_store8_noabort
libSceAddressSanitizer __asan_exp_storeN
libSceAddressSanitizer __asan_exp_storeN_noabort
libSceAddressSanitizer __asan_free
libSceAddressSanitizer __asan_get_alloc_stack
libSceAddressSanitizer __asan_get_current_fake_stack
libSceAddressSanitizer __asan_get_free_stack
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_handle_no_return
libSceAddressSanitizer __asan_init
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_locate_address
libSceAddressSanitizer __asan_malloc
libSceAddressSanitizer __asan_malloc_usable_size
libSceAddressSanitizer __asan_memalign
libSceAddressSanitizer __asan_memcpy
libSceAddressSanitizer __asan_memmove
libSceAddressSanitizer __asan_memset
libSceAddressSanitizer __asan_poison_cxx_array_cookie
libSceAddressSanitizer __asan_poison_intra_object_redzone
libSceAddressSanitizer __asan_poison_memory_region
libSceAddressSanitizer __asan_poison_stack_memory
libSceAddressSanitizer __asan_posix_memalign
libSceAddressSanitizer __asan_print_accumulated_stats
libSceAddressSanitizer __asan_realloc
libSceAddressSanitizer __asan_region_is_poisoned
libSceAddressSanitizer __asan_register_elf_globals
libSceAddressSanitizer __asan_register_globals
libSceAddressSanitizer __asan_report_error
libSceAddressSanitizer __asan_report_exp_load1
libSceAddressSanitizer __asan_report_exp_load16
libSceAddressSanitizer __asan_report_exp_load16_noabort
libSceAddressSanitizer __asan_report_exp_load1_noabort
libSceAddressSanitizer __asan_report_exp_load2
libSceAddressSanitizer __asan_report_exp_load2_noabort
libSceAddressSanitizer __asan_report_exp_load4
libSceAddressSanitizer __asan_report_exp_load4_noabort
libSceAddressSanitizer __asan_report_exp_load8
libSceAddressSanitizer __asan_report_exp_load8_noabort
libSceAddressSanitizer __asan_report_exp_load_n
libSceAddressSanitizer __asan_report_exp_load_n_noabort
libSceAddressSanitizer __asan_report_exp_store1
libSceAddressSanitizer __asan_report_exp_store16
libSceAddressSanitizer __asan_report_exp_store16_noabort
libSceAddressSanitizer __asan_report_exp_store1_noabort
libSceAddressSanitizer __asan_report_exp_store2
libSceAddressSanitizer __asan_report_exp_store2_noabort
libSceAddressSanitizer __asan_report_exp_store4
libSceAddressSanitizer __asan_report_exp_store4_noabort
libSceAddressSanitizer __asan_report_exp_store8
libSceAddressSanitizer __asan_report_exp_store8_noabort
... 185 more
⚪ 11 behaviourally empty (constant return or throw)
Library Name
libSceAddressSanitizer __asan_after_dynamic_init
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_unmapped_bytes
libSceAddressSanitizer __sanitizer_malloc_hook
libSceAddressSanitizer __sanitizer_ptr_cmp
libSceAddressSanitizer __sanitizer_ptr_sub
libSceAddressSanitizer __ubsan_default_options
🗑️ 2 removed
Library Name
libSceAddressSanitizer __asan_option_detect_stack_use_after_return
libSceAddressSanitizer __ubsan_vptr_type_cache

Changed libraries (implemented exports)

Library Before After Change
libSceAddressSanitizer 0/301 (0.00%) 285/299 (95.32%) +95.32%

@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, changes requested

The new Windows backing allocator and regression test address the reported shadow-range failure, but the PR still identifies compiler-rt-derived code whose provenance and licence treatment are unresolved.

What I ran

Reviewed head 1bb57ba9ff653a2cbffa1294c2cc151c1cc03a71 against PR base da026c70655a132031d45e2008c24f993870d801; the dependency check also previewed both PR heads separately against current upstream main d998343ced21f2c5b9c76dc06ef3a77507311565, and both previews were clean. Environment: Linux x86-64, Python 3.11.2, Git 2.39.5, GCC 12.2.0. I did not build or compile.

python3 tools/pr_precheck.py --repo boykopovar/AnyPS5 --pr 13331
git diff --check da026c70655a132031d45e2008c24f993870d801...1bb57ba9ff653a2cbffa1294c2cc151c1cc03a71
python3 tools/check_conventions.py --base da026c70655a132031d45e2008c24f993870d801 --head 1bb57ba9ff653a2cbffa1294c2cc151c1cc03a71 --title 'feat(libSceAddressSanitizer): add allocator, UBSan and runtime services' --body /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13331-1bb57ba9ff65/pr-body.md
python3 tools/check_test_registration.py --scripts

Results

Check Result
git diff --check Passed (exit 0; no output).
Repository conventions and PR template Passed.
Test registration Passed: 179 scripts registered by CTest or a workflow.
PR precheck overall Incomplete: ABI audit and test-quality helper scripts were absent from its isolated checkout; this is not a reported code failure. Other listed checks passed or were not applicable. Head/base stability was true.
Dependency and mergeability Fresh stack report: #13265 is an ancestor; both individual previews against main were clean.
Hosted CI At the latest snapshot, relevant jobs were queued or cancelled; no completed hosted build was available.
Windows sanitizer suite The PR reports 71/71 passing on this exact head, including the new forced shadow-host-allocation regression; author-reported, not run here.
Linux compile checks The PR reports 14/14 translation units compiled; author-reported, compile-only, no Linux runtime test.
Unedited output from completed local checks
All conventions checks passed.
179 test script(s), each run by an add_test or a workflow

The diff check exited 0 and emitted no output. The precheck reported that tools/pr_abi_audit.py and tools/pr_test_quality.py were missing from its isolated checkout.

Findings

Blocking

  • The PR description says compiler-rt-derived portions are included, names LLVM compiler-rt runtime sources as implementation references, and says provenance/licence treatment remains unresolved. Repository contribution rules require new third-party code to be added as a submodule rather than copied into the tree. Please identify which portions, if any, adapt or copy compiler-rt implementation code and document the provenance/licence treatment before merge. If the implementation was independently written from public interfaces and behavior, clarify that distinction and provide the relevant source mapping. This request concerns the unresolved repository-policy/licensing status; it is not a claim that algorithmic similarity alone proves copying.

Non-blocking

  • The previous Windows allocator failure appears addressed in the new source: Windows backing uses bounded VirtualAlloc2 allocation, the shared range guard rejects shadow addresses, and the added regression reserves a host allocation inside the shadow and exercises heap and fake-stack allocations. The Windows run supporting this is author-reported only.
  • Linux runtime behavior, PS5 ABI/signature compatibility, and console behavior remain unverified, as the PR description also states.

Sources

Not verified

I did not reproduce the Windows 71-test run or Linux compile report. I did not run Linux runtime tests or verify console signatures, layouts, or behavior. ABI-audit and test-quality helper checks could not run in the isolated precheck checkout.

To get this to a good state

Resolve the provenance/licence question in the PR description and ensure any incorporated third-party implementation follows the repository contribution rule. I will rerun the applicable checks on the new head after that update.

@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 1bb57ba9ff653a2cbffa1294c2cc151c1cc03a71 against main da026c70655a132031d45e2008c24f993870d801. The P1 allocation-layout finding is addressed. Windows heap and fake-stack backing now use bounded VirtualAlloc2 allocations with matching VirtualFree; the range guard rejects shadow and overflowing application ranges. No new actionable finding in this correction.

On the same Windows/GCC 15.3 Release host that previously failed 9 tests, a fresh pinned-source build passes 71/71 registered sanitizer tests, zero skipped, including the deterministic backing-layout regression. Both original independent reproducers now return pointers outside shadow and complete successfully. Additional independent checks pass for 169 allocation size/alignment cases and 1,234 container configurations. A deliberate heap overrun reports heap-buffer-overflow and exits 1; UBSan recovery still reports once across two calls, while the abort variant exits 1. Whitespace and public-header audit pass.

Hosted Build, Emscripten portability and Progress workflows are still queued, and prerequisite #13265 remains open. This clears the reported code finding; final approval remains pending those integration checks. No Linux runtime, game or console execution is claimed.

@PrivacyOnion

Copy link
Copy Markdown
Author

Updated in ead33bff92dbf676b11292877475abb7414ac3ee to address the provenance/licensing review request.

The implementation explicitly adapts LLVM compiler-rt algorithms and diagnostics. Those portions, including the implementation inherited from #13265, now live in the 3rdparty/compiler-rt submodule, pinned to 21681889623a86177efe37b19be8a69fb84f472e, and are built from source with CMake. The fork retains the upstream licence and the port's per-file licence/modification notices, GPLv2 text and source mapping. The release packager includes the three licence/notice documents in both patched and unpatched ZIP/TAR archives. The PR description now links the exact sources and explains the modifications.

Export coverage is unchanged:

Local validation on the updated revision: 72/72 Windows sanitizer CTests passed; 15/15 Linux translation units compiled (compile-only, no Linux link or execution); release-packaging tests reported 61 passed and 15 skipped on Windows. The new caller-site regression verifies that allocation/free traces still identify the calling executable across the extracted runtime boundary; a zero-caller-PC mutation makes it fail. All 301 expected public NIDs remain present, and all 274 native bridge names remain unpatched.

The runtime remains partial, with console ABI/behavior and Linux runtime execution unverified as documented. The updated source mapping and licence treatment are ready for re-review.

@github-actions

github-actions Bot commented Oct 30, 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 1835 .gitmodules
PR 5021 .gitmodules
PR 9776 .gitmodules
PR 9855 .gitmodules
tools/package_release.py
tools/tests/test_package_release.py
PR 13578 .gitmodules
PR 14080 tools/tests/test_package_release.py
PR 14333 tools/tests/test_package_release.py
PR 14357 tools/tests/test_package_release.py
PR 14433 tools/package_release.py
tools/tests/test_package_release.py
PR 14435 .gitmodules
tools/package_release.py
tools/tests/test_package_release.py
PR 14519 tools/tests/test_package_release.py
PR 15414 tools/tests/test_package_release.py
PR 15422 tools/package_release.py
tools/tests/test_package_release.py
PR 15798 .gitmodules
PR 15799 .gitmodules
PR 15800 .gitmodules
PR 15801 .gitmodules
PR 15802 .gitmodules
PR 15803 .gitmodules
PR 15804 .gitmodules
PR 15806 .gitmodules
PR 15807 .gitmodules
PR 16039 .gitmodules
PR 16502 tools/tests/test_package_release.py
PR 16507 .gitmodules

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

Deep re-review of ead33bff92dbf676b11292877475abb7414ac3ee against main d6401d794e47ef5abef80502c2ac1bfa03d7b20a, including the pinned compiler-rt port 21681889623a86177efe37b19be8a69fb84f472e. The previous P1 remains fixed. No new actionable finding in this scoped extraction/packaging review.

Windows/GCC 15.3 Release: built the runtime from the pinned dependency and passed 72/72 sanitizer CTests, zero skipped. The original allocation reproducers still pass. Independent checks cover 169 allocation cases, 1,234 container states, caller PCs verified through Windows module lookup, UBSan recovery/deduplication and abort, and a detected heap-overrun control.

Checked all 274 adapter argument lists and caller PC/BP/name transport. Their moved bodies and 29 support files match the previously tested version after include/notice/bridge normalization. A zero-malloc-caller-PC mutation makes both the registered caller-site test and independent check fail; restoring exact source bytes restores 72/72 passing tests. A disposable binary patch verified all 301 public NIDs, preservation of all 274 native bridge names, and writable non-executable data exports.

The fork's Git tree matches pinned upstream compiler-rt outside lib/asan_anyps5. Inspected the retained notices and source mapping. Packaging: 61 passed, 15 skipped on head; 60 passed, 15 skipped on base. The new notice-membership regression fails against the old packager. Conventions, public-header audit and test registration pass. These checks verify source/notice packaging mechanics, not a legal certification.

Hosted Conventions, Emscripten portability and Progress workflows report success; Build is still queued, and prerequisite #13265 remains open. Final approval remains pending integration. No local Linux link/runtime or console/game execution is claimed.

@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, awaiting integration checks

The updated head addresses the earlier provenance concern, but the hosted Windows and relinker builds are still running and Linux runtime behavior remains unverified.

What I ran

Re-checked head ead33bff92dbf676b11292877475abb7414ac3ee against the PR's base d6401d794e47ef5abef80502c2ac1bfa03d7b20a; the preview against current main 9f748f4d8e36ce3714f3b95f3386316e110a9b22 merged cleanly. Environment: Linux x86_64, Python 3.11.2, Git 2.39.5; no compiler was invoked.

git diff --check d6401d794e47ef5abef80502c2ac1bfa03d7b20a...ead33bff92dbf676b11292877475abb7414ac3ee
python3 tools/pr_precheck.py --repo boykopovar/AnyPS5
git merge-tree --write-tree refs/remotes/upstream/main refs/remotes/review/pr-13331
python3 tools/pr_abi_audit.py --repo /marc/AnyPS5 --base d6401d794e47ef5abef80502c2ac1bfa03d7b20a --head ead33bff92dbf676b11292877475abb7414ac3ee --json
python3 tools/pr_test_quality.py --root /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13331-ead33bff92db/head-ead33bff92db-e0ffdd9b --json core/libs/tests/GuestAddressSanitizerBacking.cpp core/libs/tests/GuestAddressSanitizerMapping.cpp core/libs/tests/GuestAddressSanitizerRuntime.cpp core/libs/tests/GuestAddressSanitizerShadow.cpp core/libs/tests/test_addresssanitizer_legacy.py tools/tests/test_package_release.py
gh pr checks 13331 -R boykopovar/AnyPS5

Results

Check Result
Diff, conventions, merge preview Diff check and conventions/template passed. The exact-head precheck reported a clean dependency/mergeability check; preview against current main also merged cleanly.
No-build Python checks py_compile, tools.tests.test_package_release (76 tests, 5 skipped), and test registration passed on the exact head.
ABI audit The lexical audit inspected 301 symbols and raised four warnings for the two data exports. I confirmed both names have data definitions in Export.cpp and extern declarations in Api.hpp; the helper treats these data symbols as missing function definitions. It does not verify their dynamic-library export table.
Test-quality heuristic Four C++ registration warnings were false positives: the source paths are registered through ${LIBS_INCLUDE_DIR}/tests/... in the PR's CMake file.
Negative control The package-release test against base ended with KeyError for the new license archive entry rather than an assertion failure; the precheck classifies this as not executable, so I do not count it as a successful assertion-based negative control.
Hosted CI Eligibility, conventions, library-portability, labels, report, and relinker-asan passed. Windows and two relinker jobs were in progress; macOS relinker jobs were queued. Linux and two specialized jobs were skipped by the workflow.
Unedited check output

The precheck reported:

All conventions checks passed.
Ran 76 tests in 0.584s
OK (skipped=5)
179 test script(s), each run by an add_test or a workflow

The base negative-control output ended with:

KeyError: "There is no item named 'libs/licenses/compiler-rt.txt' in the archive"
FAILED (errors=1, skipped=5)

The ABI audit findings were limited to:

__asan_option_detect_stack_use_after_return: definition-not-found, export-removed
__ubsan_vptr_type_cache: definition-not-found, export-removed

The precheck's isolated worktree could not run the local-only ABI/test-quality helper scripts; I reran them from the available local tools against the exact PR tree. No C++ tests or build were run locally.

Findings

Blocking

None identified in the targeted update. The earlier provenance finding on head 1bb57ba9ff653a2cbffa1294c2cc151c1cc03a71 is addressed: the adapted runtime is now pinned as the 3rdparty/compiler-rt submodule, and the PR adds attribution/license packaging and a regression test for the release archives.

Non-blocking

I am withholding approval until the in-progress hosted Windows and relinker checks complete. This is a large runtime change, and the Linux runtime path was skipped; the PR's Windows and Linux results in its description are author-reported rather than independently reproduced here. Prerequisite #13265 remains open, as declared by the PR.

Sources

Not verified

  • I did not build the full runtime or run its C++ tests locally.
  • I did not independently reproduce the reported Windows suite, Linux compile checks, or console behavior.
  • The hosted Windows and relinker jobs listed above had not completed at final refresh.

@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 compiler-rt provenance concern is resolved, and the exact-head Windows, sanitizer relinker, and cross-platform relinker jobs passed; Linux runtime and specialized jobs remain skipped. I approve head ead33bff92dbf676b11292877475abb7414ac3ee; I did not run a local build.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 31, 2026
@github-actions github-actions Bot added build docs prx and removed needs rebase Conflicts with main, rebase needed labels Oct 31, 2026

@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 363dc3e908dbd693f0dd22e61bc861a8996ce735. The sanitizer implementation, adapters, four C++ regression sources, legacy UBSan regression and pinned compiler-rt gitlink are byte-identical to my previously deep-reviewed ead33bff92dbf676b11292877475abb7414ac3ee within that scope. No new actionable finding in this follow-up; the previous backing-allocation defect remains fixed.

Rebuilt the exact pinned compiler-rt dependency 21681889623a86177efe37b19be8a69fb84f472e and passed all 72 registered Windows sanitizer CTests in an isolated MSYS2 GCC 16.2 Release harness. Packaging: 61 passed, 17 skipped on Windows. Hosted Windows executed the sanitizer cases and reported 2,592/2,592 selected tests passing; the relinker matrix and sanitizer relinker job also passed. Local libc/stdio support is a limited harness, not the full guest runtime. Declared prerequisite #13265 remains open and must land first; no Linux sanitizer-runtime or console/game validation is claimed.

@oneandonlydean oneandonlydean self-assigned this Nov 1, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@PrivacyOnion The new fatal-diagnostic tests in libSceAddressSanitizer/CMakeLists.txt use PASS_REGULAR_EXPRESSION. CTest ignores an ordinary nonzero exit status when this property matches. For example, the exp_load4 mode falls through to return 2 if the fatal callback returns, but its expected diagnostic text can still make the test pass. I reproduced that acceptance with the exact submitted regex and a small child that prints the diagnostic and ABORTING, then continues and exits 2; CTest reports PASS.

Please run the fatal cases through a wrapper that checks both the expected diagnostic and the intended fatal exit status, and add a control that prints the same diagnostic but returns instead. The existing legacy diagnostic wrapper already checks exit status explicitly and provides a suitable pattern. Keep the real argument-validation and diagnostic checks. This is a test-qualification gap; I am not claiming that the submitted runtime actually returns after a fatal callback.

The 43 runtime and 6 report diagnostic tests run through AddressSanitizerDiagnostic.cmake, which requires both the expected output and the expected exit status (1 for fatal reports, 0 otherwise) instead of PASS_REGULAR_EXPRESSION alone. fatal_control prints a fatal diagnostic and returns, and must fail.
@PrivacyOnion

Copy link
Copy Markdown
Author

@oneandonlydean thanks, fixed in a1ab7bd.

No sanitizer test uses PASS_REGULAR_EXPRESSION any more. The 43 guest_addresssanitizer_runtime_* diagnostic cases and the 6 guest_addresssanitizer_report_* cases now run through core/libs/tests/AddressSanitizerDiagnostic.cmake. It runs the test executable with execute_process, merges stdout and stderr in order, and fails unless both hold:

  • the exit status equals the expected one;
  • the output matches the same pattern as before (same CMake regex engine, so the patterns are unchanged).

The expected status comes from each mode's source:

  • 1 (the runtime's kExitCode) for the 30 fatal runtime modes and the 6 report modes. All of them fall through to return 2 if the fatal path returns.
  • 0 for the 13 reporting modes that are meant to continue: ubsan_arithmetic, ubsan_misc, ubsan_data, ubsan_dedup, heap_stats, globals_describe, describe_heap, report_path, report_stdout, report_descriptor, stack_trace, symbolize, coverage.

The argument-validation and diagnostic patterns are kept as they were.

Control: the new fatal_control mode prints the exact exp_load4 diagnostic followed by ABORTING, then returns 2. guest_addresssanitizer_runtime_fatal_control runs it through the same wrapper with the exp_load4 pattern and status 1, and is registered WILL_FAIL.

I checked the wrapper with a stand-in executable and the real exp_load4 pattern taken from the CMake file:

Child behaviour Result
prints the diagnostic and exits 1 passes
prints the diagnostic and returns 2 (your case) fails
exits 1 with other text fails

The modified test source compiles, git diff --check is clean, and conventions and check_test_registration.py --scripts pass. My local toolchain cannot build the guest sanitizer executables, so the registered CTest run on the guest build is left to CI.

PrivacyOnion added 2 commits November 1, 2026 12:50
… 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.
…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

Merged the #13265 fixes in 0363753. Here the compiler-rt-derived code is in the 3rdparty/compiler-rt port, which keeps the LLVM licence and per-file notices, so the in-tree adapters stay as they were. The port is bumped to 040178683306, which builds its POSIX shadow backend and its dladdr module lookup on every host but Windows; without MAP_FIXED_NOREPLACE (macOS) no shadow is reserved and the runtime fails cleanly instead of failing to link. The sanitizer tests are registered on Windows and Linux only. The fatal-diagnostic exit-status checks from a1ab7bd are unchanged.

@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 0363753e0939c3f08ac505df51992d05307aa325 and compiler-rt pin 040178683306fd2f85820a9e85ad47251c86b401. No new actionable issue found in this follow-up. The dependency delta changes only the non-Windows shadow/module-lookup selection; the earlier Windows backing-allocation fix remains.

Rebuilt with Windows/MSYS2 GCC 16.2 Release and passed all 73 registered sanitizer CTests in an isolated DLL-linked harness. The diagnostic wrapper now checks both exit status and text; the deliberately wrong-exit fatal control is rejected as intended. Hosted Windows, sanitizer relinker and the Windows/Linux/macOS relinker jobs pass. Local support substitutes selected libc functions; this is not a full guest-libc, Linux sanitizer-runtime or console test. Depends on #13265.

@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. The claim that maintainers require a title ID plus a log line is wrong; CONTRIBUTING allows Unblocks: none.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Nov 5, 2026

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

Labels

build docs needs rebase Conflicts with main, rebase needed prx

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants