feat(libc): implement std::_Throw(const std::bad_array_new_length&)

Follow the console libc.prx (PPSA02530) at 0xcb2d0: ignore the argument and throw the static bad_array_new_length object. Star Wars Racer (PPSA28416) imports it.
This commit is contained in:
Eduardo Ruiz committed 2026-10-29 01:03:00 +01:00
1 parent 3a2b919816
commit c7b70f44b0
5 files changed
+45

No files matched your search

+9
View File
@@ -1079,6 +1079,15 @@ if(BUILD_TESTING)
set_tests_properties(guest_underflow_error PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test_executable(guest_throw_bad_array_new_length_tests ${LIBS_INCLUDE_DIR}/tests/GuestThrowBadArrayNewLength.cpp)
target_include_directories(guest_throw_bad_array_new_length_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_throw_bad_array_new_length_tests PRIVATE libc)
configure_windows_unwind(guest_throw_bad_array_new_length_tests)
add_test(NAME guest_throw_bad_array_new_length COMMAND guest_throw_bad_array_new_length_tests)
if(WIN32)
set_tests_properties(guest_throw_bad_array_new_length PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
if(WIN32)
add_test_executable(exception_personality_tests ${LIBS_INCLUDE_DIR}/tests/ExceptionPersonality.cpp)
target_include_directories(exception_personality_tests PRIVATE ${LIBS_INCLUDE_DIR})
+1
View File
@@ -1404,6 +1404,7 @@ int APS5_VABI dl_iterate_phdr_nid_postfix(int (*callback)(dl_phdr_info*, std::si
[[noreturn]] void APS5_VABI __cxa_bad_cast_nid_postfix();
[[noreturn]] void APS5_VABI __cxa_bad_typeid_nid_postfix();
[[noreturn]] void APS5_VABI __cxa_throw_bad_array_new_length_nid_postfix();
[[noreturn]] void APS5_VABI _ZSt6_ThrowRKSt20bad_array_new_length_nid_postfix(const LibcException::ExceptionObject* error);
[[noreturn]] void APS5_VABI _ZSt11_Xbad_allocv_nid_postfix();
[[noreturn]] void APS5_VABI _ZSt14_Xout_of_rangePKc_nid_postfix(const char* message);
[[noreturn]] void APS5_VABI _ZSt14_Xlength_errorPKc_nid_postfix(const char* message);
@@ -551,6 +551,7 @@ const char* APS5_VABI _ZNKSt8ios_base7failure4whatEv_nid_postfix(const LibcExcep
[[noreturn]] void APS5_VABI __cxa_bad_cast_nid_postfix() { LibcException::ThrowPlain(_ZTVSt8bad_cast_nid_postfix); }
[[noreturn]] void APS5_VABI __cxa_bad_typeid_nid_postfix() { LibcException::ThrowPlain(_ZTVSt10bad_typeid_nid_postfix); }
[[noreturn]] void APS5_VABI __cxa_throw_bad_array_new_length_nid_postfix() { LibcException::ThrowPlain(_ZTVSt20bad_array_new_length_nid_postfix); }
[[noreturn]] void APS5_VABI _ZSt6_ThrowRKSt20bad_array_new_length_nid_postfix(const LibcException::ExceptionObject*) { LibcException::ThrowPlain(_ZTVSt20bad_array_new_length_nid_postfix); }
[[noreturn]] void APS5_VABI _ZSt11_Xbad_allocv_nid_postfix() { LibcException::ThrowPlain(_ZTVSt9bad_alloc_nid_postfix); }
[[noreturn]] void APS5_VABI _ZSt14_Xout_of_rangePKc_nid_postfix(const char* message) { LibcException::ThrowMessage(_ZTVSt12out_of_range_nid_postfix, message); }
[[noreturn]] void APS5_VABI _ZSt14_Xlength_errorPKc_nid_postfix(const char* message) { LibcException::ThrowMessage(_ZTVSt12length_error_nid_postfix, message); }
@@ -0,0 +1,33 @@
#include "prx/libc/include/Api.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstddef>
#include <cstdlib>
#include <cstring>
struct TypeRecord { const void* const* vtable; const char* name; const TypeRecord* base; };
struct Vtable { std::ptrdiff_t offset; const TypeRecord* type; const void* destroy; const void* deleteObject; const char* (APS5_VABI *what)(const LibcException::ExceptionObject*); };
extern "C" {
extern const TypeRecord _ZTISt9bad_alloc_nid_postfix;
extern const TypeRecord _ZTISt20bad_array_new_length_nid_postfix;
extern const Vtable _ZTVSt20bad_array_new_length_nid_postfix;
}
static void Require(bool value) { if (!value) std::abort(); }
int main() {
const auto& type = _ZTISt20bad_array_new_length_nid_postfix;
Require(std::strcmp(type.name, "St20bad_array_new_length") == 0);
Require(type.base == &_ZTISt9bad_alloc_nid_postfix);
const auto& table = _ZTVSt20bad_array_new_length_nid_postfix;
Require(table.offset == 0 && table.type == &type && table.what != nullptr);
bool thrown = false;
try {
_ZSt6_ThrowRKSt20bad_array_new_length_nid_postfix(nullptr);
} catch (...) {
thrown = true;
}
Require(thrown);
return 0;
}
+1
View File
@@ -191,6 +191,7 @@
- [std::clog, std::wclog and the facet ids](../../../core/libs/prx/libc/src/LocaleSupport.cpp) (libc): `std::clog` and `std::wclog` are 0x400-byte zeroed objects like the rest of the `NSTDSTR` stream set (the console's `libc.prx` sizes `std::clog` at 96 bytes, measured from its dynsym `st_size`), and the `numpunct<char>::id` and `time_put<char>::id` objects are 8-byte zeros like the other facet ids.
- [std::__throw_bad_variant_access](../../../core/libs/prx/libc/src/exception/StandardExceptions.cpp) (libc) throws `std::bad_variant_access` with the `what()` string `bad_variant_access`, the one [LLVM libc++](https://github.com/llvm/llvm-project/blob/main/libcxx/src/variant.cpp) returns, since the export carries libc++'s `__throw_bad_variant_access` name; the console's string is unverified. Onimusha: Way of the Sword (PPSA27836 01.000.001) imports it from `libc`, and its bundled `libc.prx` does not export it.
- [std::bad_optional_access and std::_Throw_bad_optional_access](../../../core/libs/prx/libc/src/exception/StandardExceptions.cpp) (libc) provide the exception type, constructor, destructor, and `what()` exports alongside `_Throw_bad_optional_access`, returning the `what()` string `bad_optional_access` matching Dinkumware and libc++ conventions; the console libc.prx string is unverified. PPSA26578 (issue #7624) and PPSA34015 import `_ZSt26_Throw_bad_optional_accessv` (`KwzEip7m6TM`) from `libc`.
- [std::_Throw(const std::bad_array_new_length&)](../../../core/libs/prx/libc/src/exception/StandardExceptions.cpp) (libc, NID `1cKlQv7Kvmg`) is a 52-byte function at `0xcb2d0` in the `libc.prx` bundled with PPSA02530: it ignores its argument, allocates the 8-byte exception object with the static `_ZTVSt20bad_array_new_length`, and throws it. Star Wars Racer (PPSA28416) imports it from `libc`.
- [The scanf family](../../../core/libs/prx/libc/src/Formatting.cpp) (libc), the `_s` forms included, decodes the input of the 16-bit wide conversions (`%ls`, `%lc`, `%l[`, `%S`, `%C`) on Linux as UTF-8, mirroring the narrow printf family, where FreeBSD uses the locale's `mbrtowc` (one byte per character in the C locale); the console's locale encoding is unverified. Input that is not UTF-8, a character outside the BMP, a scanset member outside ASCII, positional arguments next to a wide conversion and wide conversions in `fscanf` throw. Each character is stored as one 16-bit unit, widths and `_s` sizes count characters, and a `%lc` field cut short by the end of the input keeps what it read, as FreeBSD's `convert_wchar` does. Windows hands `%ls`, `%lc` and `%l[` to the host, whose `wchar_t` is 16 bits
- [The scanf family](../../../core/libs/prx/libc/include/WindowsScanning.hpp) (libc) on Windows returns 0, as C17 and FreeBSD do, when input fails after only suppressed conversions have completed (`sscanf("12", "%*d%d", &value)`). Linux hands the format to glibc, which returns `EOF` there. On Windows the host stops a `%x`, `%X`, `%i` or `%p` after the `x` of a `0x` that no hex digit follows (or that the width cuts off), and a float conversion (`%e`, `%f`, `%g`, `%a`) after the `e` of an exponent with no digits (`1e`), where C17 and FreeBSD stop before the `x` or the `e`
- [The scanf family](../../../core/libs/prx/libc/src/Formatting.cpp) (libc) on Linux reads a `q` length as `ll`, as glibc does. On Windows a `q` directive ends the scan with nothing stored, as the console's own libc does for `%qd`; FreeBSD 11.4's source reads it as `ll`.