From 910363657dfeeb0bb21a11f9616ff34ffe318938 Mon Sep 17 00:00:00 2001 From: milescoviello Date: Sun, 11 Oct 2026 10:29:22 -0700 Subject: [PATCH] fix(libc): count the whole string in mbstowcs with a null destination mbstowcs, and libSceAmpr's copy of it, counted at most n characters when the destination was NULL, so the usual sizing call mbstowcs(NULL, s, 0) returned 0 and mbstowcs(NULL, s, 1) returned 1 for a three-character string. A caller that sizes its buffer that way got a buffer too small for the string and no terminator. POSIX says that with a null pwcs mbstowcs "shall return the length required to convert the entire array regardless of the value of n", and FreeBSD does that: lib/libc/locale/mbstowcs.c passes SIZE_T_MAX as the source limit, and the C locale's _none_mbsnrtowcs (none.c) returns the distance to the terminating NUL when "dst == NULL". With a null destination, SonyMbstowcs now returns the length of the whole string. Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libc/include/SonyCrt.hpp | 3 ++- core/libs/tests/GuestCrt.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/libs/prx/libc/include/SonyCrt.hpp b/core/libs/prx/libc/include/SonyCrt.hpp index 2016da156..56fe7b6a1 100644 --- a/core/libs/prx/libc/include/SonyCrt.hpp +++ b/core/libs/prx/libc/include/SonyCrt.hpp @@ -125,10 +125,11 @@ inline int SonyWcscpyS(std::uint16_t* dest, std::size_t size, const std::uint16_ inline std::size_t SonyMbstowcs(std::uint16_t* dest, const char* src, std::size_t size) { if (!src) return 0; + if (!dest) return std::strlen(src); std::size_t converted = 0; while (converted < size) { const auto value = static_cast(src[converted]); - if (dest) dest[converted] = value; + dest[converted] = value; if (value == 0) return converted; ++converted; } diff --git a/core/libs/tests/GuestCrt.cpp b/core/libs/tests/GuestCrt.cpp index 611ddc32a..f37cb68bb 100644 --- a/core/libs/tests/GuestCrt.cpp +++ b/core/libs/tests/GuestCrt.cpp @@ -144,6 +144,8 @@ int main() { Require(sceAmprMbstowcs(wide, "ABC", 8) == 3); Require(wide[0] == 65 && wide[1] == 66 && wide[2] == 67 && wide[3] == 0); Require(sceAmprMbstowcs(nullptr, "ABC", 8) == 3); + Require(sceAmprMbstowcs(nullptr, "ABC", 0) == 3 && sceAmprMbstowcs(nullptr, "ABC", 1) == 3); + Require(mbstowcs_nid_postfix(nullptr, "ABC", 0) == 3 && mbstowcs_nid_postfix(nullptr, "ABC", 1) == 3); Require(sceAmprMbstowcs(wide, "ABC", 2) == 2); Require(mbstowcs_nid_postfix(wide, "ABC", 8) == 3);