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 <noreply@anthropic.com>
This commit is contained in:
milescoviello 2026-10-11 10:29:22 -07:00 committed by MarcZX100
parent d371ed3076
commit 910363657d
2 changed files with 4 additions and 1 deletions

View File

@ -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<unsigned char>(src[converted]);
if (dest) dest[converted] = value;
dest[converted] = value;
if (value == 0) return converted;
++converted;
}

View File

@ -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);