Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
def3d35
feat(libSceAddressSanitizer): implement shadow poisoning, access chec…
Oct 30, 2026
45ddafe
fix(libSceAddressSanitizer): check every granule of misaligned 16-byt…
Oct 30, 2026
78dc5a8
fix(libSceAddressSanitizer): reserve the free parts of the Windows sh…
Oct 30, 2026
ee42f86
feat(libSceAddressSanitizer): implement exp access callbacks, memory …
Oct 30, 2026
30183ed
feat(libSceAddressSanitizer): implement UBSan runtime error handlers
Oct 30, 2026
5fbda40
feat(libSceAddressSanitizer): implement the heap allocator, quarantin…
Oct 30, 2026
9a8df94
feat(libSceAddressSanitizer): implement fake stacks, globals registra…
Oct 30, 2026
7fa600d
feat(libSceAddressSanitizer): implement coverage, report file, stack …
Oct 30, 2026
e087542
docs(libSceAddressSanitizer): record the remaining runtime gaps
Oct 30, 2026
3c659de
feat(libSceAddressSanitizer): add legacy UBSan callbacks and sanitize…
Oct 30, 2026
00ebcda
fix(libSceAddressSanitizer): guard global arrays and retain Linux fak…
Oct 30, 2026
34c6b8d
chore: merge current main for AddressSanitizer runtime review
Oct 30, 2026
c12b02a
chore: merge current main before sanitizer runtime submission
Oct 30, 2026
e37a9a8
fix(libSceAddressSanitizer): keep Windows backing blocks outside shadow
Oct 30, 2026
1bb57ba
chore: merge current main for sanitizer allocation review
Oct 30, 2026
8ec8867
build(libSceAddressSanitizer): build the LLVM-derived runtime from a …
Oct 30, 2026
6a94331
chore: merge current main for sanitizer provenance review
Oct 30, 2026
cc6b42e
fix(libSceAddressSanitizer): retain native names for the runtime bridge
Oct 30, 2026
f186899
build(libSceAddressSanitizer): keep notice packaging separate from je…
Oct 30, 2026
954a91d
test(libSceAddressSanitizer): isolate the notice archive regression
Oct 30, 2026
ead33bf
build(libSceAddressSanitizer): pin compiler-rt source notices
Oct 30, 2026
363dc3e
chore: merge current main and keep both new submodules
Oct 31, 2026
a1ab7bd
test(libSceAddressSanitizer): check the exit status of fatal diagnostics
Nov 1, 2026
dfb095e
fix(libSceAddressSanitizer): keep the LLVM notice and build the POSIX…
Nov 1, 2026
0363753
chore: merge the LLVM notice and non-Windows shadow fixes from #13265
Nov 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
[submodule "3rdparty/nghttp2"]
path = 3rdparty/nghttp2
url = https://github.com/nghttp2/nghttp2.git
[submodule "3rdparty/compiler-rt"]
path = 3rdparty/compiler-rt
url = https://github.com/PrivacyOnion/compiler-rt.git
shallow = true
[submodule "3rdparty/quickjs"]
path = 3rdparty/quickjs
url = https://github.com/quickjs-ng/quickjs.git
1 change: 1 addition & 0 deletions 3rdparty/compiler-rt
Submodule compiler-rt added at 040178
282 changes: 282 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/CMakeLists.txt

Large diffs are not rendered by default.

1,434 changes: 566 additions & 868 deletions core/libs/prx/libSceAddressSanitizer/Export.cpp

Large diffs are not rendered by default.

572 changes: 287 additions & 285 deletions core/libs/prx/libSceAddressSanitizer/include/Api.hpp

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/Allocator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/Allocator.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/BackingMemory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/BackingMemory.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/Container.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/Container.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/Coverage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/Coverage.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/Describe.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/Describe.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/ErrorReport.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/ErrorReport.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/FakeStack.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/FakeStack.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/Globals.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/Globals.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/ModuleLookup.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/ModuleLookup.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/Report.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/Report.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/ReportFile.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/ReportFile.hpp"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/ShadowAddressSpace.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/ShadowCheck.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/ShadowCheck.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/ShadowRequire.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/ShadowRequire.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/StackBounds.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/StackBounds.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/StackTrace.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/StackTrace.hpp"
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAddressSanitizer/src/Ubsan.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "asan_anyps5/src/Ubsan.hpp"
8 changes: 8 additions & 0 deletions core/libs/tests/AddressSanitizerDiagnostic.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
execute_process(COMMAND "${EXECUTABLE}" ${MODE} ${ARGUMENT} OUTPUT_VARIABLE output ERROR_VARIABLE output RESULT_VARIABLE result)
if(NOT result STREQUAL STATUS)
message(FATAL_ERROR "${MODE} ${ARGUMENT}: exit status ${result}, expected ${STATUS}\n${output}")
endif()
if(NOT output MATCHES "${PATTERN}")
message(FATAL_ERROR "${MODE} ${ARGUMENT}: output does not match ${PATTERN}\n${output}")
endif()
message(STATUS "${MODE} ${ARGUMENT}: exit status ${result} and diagnostic matched")
113 changes: 113 additions & 0 deletions core/libs/tests/GuestAddressSanitizerBacking.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#include "prx/libSceAddressSanitizer/include/Api.hpp"
#include "prx/libSceAddressSanitizer/src/BackingMemory.hpp"
#include "prx/libSceAddressSanitizer/src/ShadowRequire.hpp"
#include <windows.h>
#include <array>
#include <cstdio>
#include <cstring>
#include <limits>
#include <stdexcept>
#include <thread>
#include <utility>

static bool GuestRange(std::uintptr_t address, std::size_t size) {
return address < (1ull << 47) && size <= (1ull << 47) - address &&
(address + size <= AsanRuntime::ShadowBase || address >= AsanRuntime::ShadowBase + AsanRuntime::ShadowSize);
}

static bool Released(void* pointer) {
MEMORY_BASIC_INFORMATION memory{};
return VirtualQuery(pointer, &memory, sizeof(memory)) == sizeof(memory) && memory.State == MEM_FREE;
}

static int InvalidRanges(std::uintptr_t host) {
const std::array<std::pair<std::uintptr_t, std::size_t>, 5> ranges{{
{host, 8},
{AsanRuntime::ShadowBase - 8, 16},
{(1ull << 47) - 8, 16},
{1ull << 47, 8},
{8, std::numeric_limits<std::size_t>::max()}
}};
for (const auto& [address, size] : ranges) {
try {
RequireShadowRange_nid_no_patch(address, size, __func__);
std::fprintf(stderr, "accepted invalid backing range: %p size=%zu\n", reinterpret_cast<void*>(address), size);
return 1;
} catch (const std::invalid_argument&) {
}
}
return 0;
}

int main() {
constexpr auto firstGuest = AsanRuntime::ShadowBase + AsanRuntime::ShadowSize;
constexpr auto hostAddress = AsanRuntime::ShadowBase + (firstGuest >> 3);
SYSTEM_INFO info{};
GetSystemInfo(&info);
const auto hostBytes = static_cast<std::size_t>(info.dwAllocationGranularity);
auto* host = static_cast<unsigned char*>(VirtualAlloc(reinterpret_cast<void*>(hostAddress), hostBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
if (host != reinterpret_cast<void*>(hostAddress)) return 1;
std::memset(host, 0x5a, hostBytes);
if (!AsanRuntime::InitializeShadow_nid_no_patch()) return 2;
if (AsanRuntime::ShadowRangeAvailable_nid_no_patch(hostAddress, hostAddress + hostBytes)) return 3;
const auto projected = AsanRuntime::ShadowBase + (hostAddress >> 3);
if (!AsanRuntime::ShadowRangeAvailable_nid_no_patch(projected, projected + 1)) return 4;
if (InvalidRanges(hostAddress)) return 5;

for (const auto alignment : {std::size_t{8}, std::size_t{65536}, std::size_t{1} << 20}) {
void* block = AsanRuntime::AllocateBacking_nid_no_patch(8193, alignment);
const auto address = reinterpret_cast<std::uintptr_t>(block);
if (!block || !GuestRange(address, 8193) || address % alignment != 0) {
std::fprintf(stderr, "backing allocation failed: pointer=%p alignment=%zu error=%lu\n", block, alignment, GetLastError());
return 6;
}
RequireShadowRange_nid_no_patch(address, 8193, __func__);
std::memset(block, 0x39, 8193);
AsanRuntime::FreeBacking_nid_no_patch(block, alignment);
if (!Released(block)) return 7;
}

auto* p = static_cast<unsigned char*>(__asan_malloc(13));
if (!p || !GuestRange(reinterpret_cast<std::uintptr_t>(p), 13)) return 8;
if (__asan_address_is_poisoned(p) || __asan_address_is_poisoned(p + 12) || !__asan_address_is_poisoned(p + 13) || !__asan_address_is_poisoned(p - 1)) return 9;
__asan_memset(p, 0x6b, 13);
p = static_cast<unsigned char*>(__asan_realloc(p, 257));
if (!p || !GuestRange(reinterpret_cast<std::uintptr_t>(p), 257)) return 10;
for (std::size_t i = 0; i < 13; ++i) if (p[i] != 0x6b) return 11;
if (__asan_region_is_poisoned(reinterpret_cast<std::uintptr_t>(p), 257) || !__asan_address_is_poisoned(p + 257)) return 12;
std::uintptr_t begin = 0;
std::uintptr_t size = 0;
if (std::strcmp(__asan_locate_address(reinterpret_cast<std::uintptr_t>(p), nullptr, 0, &begin, &size), "heap") || begin != reinterpret_cast<std::uintptr_t>(p) || size != 257) return 13;
MEMORY_BASIC_INFORMATION heapMemory{};
if (VirtualQuery(p, &heapMemory, sizeof(heapMemory)) != sizeof(heapMemory)) return 14;
__asan_free(p);
if (!__asan_address_is_poisoned(p)) return 15;
__sanitizer_purge_allocator();
if (!Released(heapMemory.AllocationBase)) return 16;

void* fakeBase = nullptr;
int fakeResult = 0;
std::thread thread([&] {
const auto frame = __asan_stack_malloc_always_0(64);
if (!frame || !GuestRange(frame, 64) || __asan_region_is_poisoned(frame, 64)) {
fakeResult = 17;
return;
}
__asan_memset(reinterpret_cast<void*>(frame), 0x42, 32);
MEMORY_BASIC_INFORMATION memory{};
if (VirtualQuery(reinterpret_cast<void*>(frame), &memory, sizeof(memory)) != sizeof(memory)) {
fakeResult = 18;
return;
}
fakeBase = memory.AllocationBase;
__asan_stack_free_0(frame, 64);
if (!__asan_address_is_poisoned(reinterpret_cast<void*>(frame))) fakeResult = 19;
});
thread.join();
if (fakeResult) return fakeResult;
if (!fakeBase || !Released(fakeBase)) return 20;
for (std::size_t i = 0; i < hostBytes; ++i) if (host[i] != 0x5a) return 21;
std::printf("host allocation in shadow=%p; heap=%p; fake stack backing=%p; shadow hole preserved\n", static_cast<void*>(host), static_cast<void*>(p), fakeBase);
if (!VirtualFree(host, 0, MEM_RELEASE)) return 22;
return 0;
}
Loading
Loading