Merge pull request #3978 from zmeizy/claude/asprintf-guest-wide

fix(libc): format 16-bit wide arguments in asprintf on Linux
This commit is contained in:
Dean 2026-10-12 16:11:47 +13:00 committed by GitHub
commit d2d4c07aab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 24 additions and 42 deletions

View File

@ -1,20 +1,15 @@
#include "prx/libc/include/ApplicationHeap.hpp"
#include "prx/libc/include/General.hpp"
#include "SceTypes.hpp"
#include <cerrno>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <new>
#include <string>
#ifdef _WIN32
#include "prx/libc/include/WindowsFormatting.hpp"
#endif
extern "C" {
int APS5_VABI vasprintf_nid_postfix(char** destination, const char* format, VaList* args);
char* APS5_VABI strndup_nid_postfix(const char* source, std::size_t limit) {
std::size_t length = 0;
while (length < limit && source[length] != '\0') ++length;
@ -35,9 +30,6 @@ char* APS5_VABI strdup_nid_postfix(const char* source) {
}
int APS5_VABI asprintf_nid_postfix(char** destination, const char* format, ...) {
if (!destination) { errno = 22; return -1; }
*destination = nullptr;
if (!format) { errno = 22; return -1; }
#ifdef _WIN32
__builtin_sysv_va_list args;
__builtin_sysv_va_start(args, format);
@ -45,36 +37,7 @@ int APS5_VABI asprintf_nid_postfix(char** destination, const char* format, ...)
std::va_list args;
va_start(args, format);
#endif
int result = -1;
try {
#ifdef _WIN32
std::string text;
const int count = LibcDetail::FormatWindows(nullptr, 0, format, args, &text);
const char* source = text.c_str();
#else
char* text = nullptr;
const int count = ::vasprintf(&text, format, args);
std::unique_ptr<char, decltype(&std::free)> owner(text, std::free);
const char* source = text;
#endif
if (count >= 0) {
auto* output = static_cast<char*>(ApplicationHeapAllocate_nid_no_patch(static_cast<std::size_t>(count) + 1));
if (output) {
std::memcpy(output, source, static_cast<std::size_t>(count) + 1);
*destination = output;
result = count;
} else errno = 12;
}
} catch (const std::bad_alloc&) {
errno = 12;
} catch (...) {
#ifdef _WIN32
__builtin_sysv_va_end(args);
#else
va_end(args);
#endif
throw;
}
const int result = vasprintf_nid_postfix(destination, format, reinterpret_cast<VaList*>(args));
#ifdef _WIN32
__builtin_sysv_va_end(args);
#else

View File

@ -1,5 +1,9 @@
#include "SceTypes.hpp"
#include "prx/libc/include/ApplicationHeap.hpp"
#include "prx/libc/include/GuestHeap.hpp"
#include <algorithm>
#include <array>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <cstdint>
@ -15,6 +19,8 @@ int APS5_VABI vsnprintf_nid_postfix(char*, size_t, const char*, VaList*);
int APS5_VABI vsnprintf_s_nid_postfix(char*, size_t, const char*, VaList*);
int APS5_VABI vsscanf_s_nid_postfix(const char*, const char*, VaList*);
int APS5_VABI vprintf_nid_postfix(const char*, VaList*);
int APS5_VABI asprintf_nid_postfix(char**, const char*, ...);
void APS5_VABI free_nid_postfix(void*);
}
static void Require(bool condition) {
@ -228,4 +234,17 @@ __attribute__((noinline)) static void APS5_VABI RunChecks() {
std::puts("Formatting checks passed: 10000 iterations");
}
int main() { RunChecks(); return CheckWidePrecision() ? 0 : 1; }
static void* APS5_VABI Allocate(std::size_t bytes) { return GuestHeap::GuestHeapAllocate_nid_postfix(bytes); }
static void APS5_VABI Release(void* pointer) { GuestHeap::GuestHeapFree_nid_postfix(pointer); }
static void* APS5_VABI Unused() { std::abort(); }
static void CheckAllocatingFormat() {
const std::array<void*, 10> api{reinterpret_cast<void*>(&Allocate), reinterpret_cast<void*>(&Release), reinterpret_cast<void*>(&Unused),
reinterpret_cast<void*>(&Unused), reinterpret_cast<void*>(&Unused), reinterpret_cast<void*>(&Unused), reinterpret_cast<void*>(&Unused)};
ApplicationHeapRegister_nid_no_patch(api.data());
char* allocated = nullptr;
Require(asprintf_nid_postfix(&allocated, "%ls:%S:%lc:%d", u"\u00e9", u"ab", 0x20ac, 7) == 11 && std::strcmp(allocated, "\xc3\xa9:ab:\xe2\x82\xac:7") == 0);
free_nid_postfix(allocated);
}
int main() { RunChecks(); CheckAllocatingFormat(); return CheckWidePrecision() ? 0 : 1; }