libstdc++: Do not use std::isdigit in <charconv> [PR103911]

This avoids a potential race condition if std::setlocale is used
concurrently with std::from_chars.

libstdc++-v3/ChangeLog:

	PR libstdc++/103911
	* include/std/charconv (__from_chars_alpha_to_num): Return
	char instead of unsigned char. Change invalid return value to
	127 instead of using numeric trait.
	(__from_chars_alnum): Fix comment. Do not use std::isdigit.
	Change type of variable to char.
This commit is contained in:
Jonathan Wakely 2022-01-05 16:25:47 +00:00
parent db33b1059b
commit c83ecfbe74

View File

@ -39,7 +39,6 @@
#include <type_traits> #include <type_traits>
#include <bit> // for __bit_width #include <bit> // for __bit_width
#include <cctype> // for isdigit
#include <bits/charconv.h> // for __to_chars_len, __to_chars_10_impl #include <bits/charconv.h> // for __to_chars_len, __to_chars_10_impl
#include <bits/error_constants.h> // for std::errc #include <bits/error_constants.h> // for std::errc
#include <ext/numeric_traits.h> #include <ext/numeric_traits.h>
@ -466,7 +465,7 @@ namespace __detail
return true; return true;
} }
constexpr unsigned char constexpr char
__from_chars_alpha_to_num(char __c) __from_chars_alpha_to_num(char __c)
{ {
switch (__c) switch (__c)
@ -550,10 +549,10 @@ namespace __detail
case 'Z': case 'Z':
return 35; return 35;
} }
return __gnu_cxx::__int_traits<unsigned char>::__max; return 127;
} }
/// std::from_chars implementation for integers in bases 11 to 26. /// std::from_chars implementation for integers in bases 11 to 36.
template<typename _Tp> template<typename _Tp>
bool bool
__from_chars_alnum(const char*& __first, const char* __last, _Tp& __val, __from_chars_alnum(const char*& __first, const char* __last, _Tp& __val,
@ -562,8 +561,8 @@ namespace __detail
bool __valid = true; bool __valid = true;
while (__first != __last) while (__first != __last)
{ {
unsigned char __c = *__first; char __c = *__first;
if (std::isdigit(__c)) if ('0' <= __c && __c <= '9') // isdigit
__c -= '0'; __c -= '0';
else else
{ {