mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-10-28 18:07:16 +08:00
Merge pull request #422 from sahvx655-wq/is-integer-signed-overflow
avoid signed overflow in is_integer on negative wchar_t units
This commit is contained in:
commit
91aef729bd
@ -32,7 +32,13 @@ template <typename UC> fastfloat_really_inline constexpr bool has_simd_opt() {
|
|||||||
// able to optimize it well.
|
// able to optimize it well.
|
||||||
template <typename UC>
|
template <typename UC>
|
||||||
fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
|
fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
|
||||||
return static_cast<unsigned>(c - UC('0')) <= 9u;
|
// UC can be signed (wchar_t is a signed int on Linux and macOS), and the
|
||||||
|
// subtraction is then promoted to int and overflows for code units near the
|
||||||
|
// bottom of the range. Subtracting in the unsigned type wraps instead, which
|
||||||
|
// selects the same code units, as ch_to_digit already does.
|
||||||
|
using UnsignedUC = typename std::make_unsigned<UC>::type;
|
||||||
|
return static_cast<UnsignedUC>(static_cast<UnsignedUC>(c) -
|
||||||
|
static_cast<UnsignedUC>(UC('0'))) <= 9u;
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
||||||
|
|||||||
@ -70,9 +70,34 @@ bool test_non_space_with_space_low_byte() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is_integer subtracts UC('0') from the code unit. When wchar_t is signed the
|
||||||
|
// subtraction is promoted to int and overflows for code units near the bottom
|
||||||
|
// of the range, so the sanitized build aborts on input the library is supposed
|
||||||
|
// to reject. Such a unit is not a digit, so both entry points must fail.
|
||||||
|
bool test_code_unit_below_zero_digit() {
|
||||||
|
if (!std::is_signed<wchar_t>::value) {
|
||||||
|
return true; // only reproducible where wchar_t is signed
|
||||||
|
}
|
||||||
|
wchar_t const input[] = {(std::numeric_limits<wchar_t>::min)(), L'1'};
|
||||||
|
double result;
|
||||||
|
auto answer = fast_float::from_chars(input, input + 2, result);
|
||||||
|
if (answer.ec != std::errc::invalid_argument) {
|
||||||
|
std::cerr << "a code unit below L'0' must not start a number\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unsigned long long integer;
|
||||||
|
auto int_answer = fast_float::from_chars(input, input + 2, integer, 10);
|
||||||
|
if (int_answer.ec != std::errc::invalid_argument) {
|
||||||
|
std::cerr << "a code unit below L'0' must not start an integer\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
if (test_minus() && test_plus() && test_space() && test_nan() &&
|
if (test_minus() && test_plus() && test_space() && test_nan() &&
|
||||||
test_non_space_with_space_low_byte()) {
|
test_non_space_with_space_low_byte() &&
|
||||||
|
test_code_unit_below_zero_digit()) {
|
||||||
std::cout << "all ok" << std::endl;
|
std::cout << "all ok" << std::endl;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user