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 <noreply@anthropic.com>
This commit is contained in:
Claude 2026-10-08 10:46:49 +00:00
parent b5c9945e1f
commit 8c714f76af
No known key found for this signature in database
2 changed files with 13 additions and 4 deletions

View File

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

View File

@ -2,6 +2,7 @@
#include <climits>
#include <cstddef>
#include <cstdlib>
#include <initializer_list>
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);