From 8c714f76af87742dc7d9e1d9793234f4efb3f4fc Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 8 Oct 2026 10:46:49 +0000 Subject: [PATCH] fix(libc): stop the wcstol family at a binary prefix on Linux wcstol, wcstoll, wcstoul and wcstoull parse the ASCII prefix of the guest's UTF-16 text with std::strtoll and std::strtoull, which glibc 2.38 and later bind to the C23 __isoc23_* functions: wcstol(u"0b101", &end, 0) returned 5 with the end pointer after the whole string. They now check StopAtBinaryPrefix_nid_no_patch first, like the narrow functions, and the end pointer maps back through ParseAsciiPrefix as before. Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libc/src/Strings.cpp | 8 ++++---- core/libs/tests/GuestWideStrings.cpp | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/libs/prx/libc/src/Strings.cpp b/core/libs/prx/libc/src/Strings.cpp index bf2c2e872..851ae3594 100644 --- a/core/libs/prx/libc/src/Strings.cpp +++ b/core/libs/prx/libc/src/Strings.cpp @@ -423,19 +423,19 @@ long double APS5_VABI wcstold_nid_postfix(const char16_t* str, char16_t** endptr } long long APS5_VABI wcstol_nid_postfix(const char16_t* str, char16_t** endptr, int base) { - return ParseAsciiPrefix(str, endptr, [base](const char* text, char** end) { return std::strtoll(text, end, base); }); + return ParseAsciiPrefix(str, endptr, [base](const char* text, char** end) { return StopAtBinaryPrefix_nid_no_patch(text, end, base) ? 0LL : std::strtoll(text, end, base); }); } long long APS5_VABI wcstoll_nid_postfix(const char16_t* str, char16_t** endptr, int base) { - return ParseAsciiPrefix(str, endptr, [base](const char* text, char** end) { return std::strtoll(text, end, base); }); + return ParseAsciiPrefix(str, endptr, [base](const char* text, char** end) { return StopAtBinaryPrefix_nid_no_patch(text, end, base) ? 0LL : std::strtoll(text, end, base); }); } unsigned long long APS5_VABI wcstoul_nid_postfix(const char16_t* str, char16_t** endptr, int base) { - return ParseAsciiPrefix(str, endptr, [base](const char* text, char** end) { return std::strtoull(text, end, base); }); + return ParseAsciiPrefix(str, endptr, [base](const char* text, char** end) { return StopAtBinaryPrefix_nid_no_patch(text, end, base) ? 0ULL : std::strtoull(text, end, base); }); } unsigned long long APS5_VABI wcstoull_nid_postfix(const char16_t* str, char16_t** endptr, int base) { - return ParseAsciiPrefix(str, endptr, [base](const char* text, char** end) { return std::strtoull(text, end, base); }); + return ParseAsciiPrefix(str, endptr, [base](const char* text, char** end) { return StopAtBinaryPrefix_nid_no_patch(text, end, base) ? 0ULL : std::strtoull(text, end, base); }); } int APS5_VABI wcscoll_nid_postfix(const char16_t* first, const char16_t* second) { diff --git a/core/libs/tests/GuestWideStrings.cpp b/core/libs/tests/GuestWideStrings.cpp index e08349ab4..2e01b4d33 100644 --- a/core/libs/tests/GuestWideStrings.cpp +++ b/core/libs/tests/GuestWideStrings.cpp @@ -2,6 +2,7 @@ #include #include #include +#include extern "C" { const char16_t* APS5_VABI wmemchr_nid_postfix(const char16_t* s, char16_t c, std::size_t n); @@ -125,6 +126,14 @@ int main() { require(wcstoull_nid_postfix(u"18446744073709551615", nullptr, 10) == ULLONG_MAX); const char16_t* letters = u"abc"; require(wcstol_nid_postfix(letters, &end, 10) == 0 && end == letters); + const char16_t* binary = u" -0b101"; + for (const int base : {0, 2}) { + require(wcstol_nid_postfix(binary, &end, base) == 0 && end == binary + 3); + require(wcstoll_nid_postfix(binary, &end, base) == 0 && end == binary + 3); + require(wcstoul_nid_postfix(binary, &end, base) == 0 && end == binary + 3); + require(wcstoull_nid_postfix(binary, &end, base) == 0 && end == binary + 3); + } + require(wcstoll_nid_postfix(binary + 2, &end, 16) == 0xb101 && end == binary + 7); const char16_t* scientific = u"3.5e2!"; require(wcstod_nid_postfix(scientific, &end) == 350.0 && end == scientific + 5);