#include "prx/libc/include/Api.hpp" #include #include #include #include #include #include #include #include #include static void Require(bool condition) { if (!condition) { std::fputs("GuestWcscmpBoundary check failed\n", stderr); std::abort(); } } #ifdef _WIN32 #include #else #include #include #endif class Buffer { unsigned char* allocation; std::size_t page; public: Buffer() { #ifdef _WIN32 SYSTEM_INFO info{}; GetSystemInfo(&info); page = info.dwPageSize; allocation = static_cast(VirtualAlloc(nullptr, page * 3, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS)); Require(allocation != nullptr); DWORD previous; Require(VirtualProtect(allocation + page, page, PAGE_READWRITE, &previous) != 0); #else const long size = sysconf(_SC_PAGESIZE); Require(size > 0); page = static_cast(size); allocation = static_cast(mmap(nullptr, page * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); Require(allocation != MAP_FAILED); Require(mprotect(allocation + page, page, PROT_READ | PROT_WRITE) == 0); #endif std::memset(allocation + page, 0xa5, page); } ~Buffer() { #ifdef _WIN32 Require(VirtualFree(allocation, 0, MEM_RELEASE) != 0); #else Require(munmap(allocation, page * 3) == 0); #endif } Buffer(const Buffer&) = delete; Buffer& operator=(const Buffer&) = delete; template T* At(std::size_t count) { Require(count <= (page - 32) / sizeof(T)); return reinterpret_cast(allocation + page * 2 - (std::max)(count, std::size_t{1}) * sizeof(T)); } }; static int Sign(int value) { return (value > 0) - (value < 0); } int main() { Buffer first, second; for (std::size_t length = 0; length <= 128; ++length) { auto* left = first.At(length + 1); auto* right = second.At(length + 1); for (std::size_t i = 0; i < length; ++i) left[i] = static_cast(0x100 + i * 257); left[length] = 0; const std::u16string saved(left, length + 1); for (std::size_t position = 0; position <= length; ++position) { for (char16_t value : {0, 1, 0xff, 0x100, 0x8000, 0xd800, 0xffff}) { if (position == length && value != 0) continue; std::copy(saved.begin(), saved.end(), right); right[position] = value; int expected = 0; for (std::size_t i = 0; i <= length; ++i) { if (left[i] != right[i]) { expected = left[i] > right[i] ? 1 : -1; break; } if (left[i] == 0) break; } const std::u16string other(right, length + 1); Require(Sign(wcscmp_nid_postfix(left, right)) == expected); Require(Sign(wcscmp_nid_postfix(right, left)) == -expected); Require(std::equal(saved.begin(), saved.end(), left) && std::equal(other.begin(), other.end(), right)); } } } }