|
2 | 2 | #include <iostream> |
3 | 3 | #include <string> |
4 | 4 | #include <system_error> |
| 5 | +#include <type_traits> |
5 | 6 |
|
6 | 7 | bool tester(std::string s, double expected, |
7 | 8 | fast_float::chars_format fmt = fast_float::chars_format::general) { |
@@ -46,8 +47,32 @@ bool test_nan() { |
46 | 47 | return tester("nan", std::numeric_limits<double>::quiet_NaN()); |
47 | 48 | } |
48 | 49 |
|
| 50 | +// A wide code unit whose low byte is an ASCII space (0x20) but whose full value |
| 51 | +// is not whitespace must not be skipped by skip_white_space. When wchar_t is |
| 52 | +// signed such a unit can be negative, which used to slip past the range guard |
| 53 | +// in is_space and get treated as a space. |
| 54 | +bool test_non_space_with_space_low_byte() { |
| 55 | + if (!std::is_signed<wchar_t>::value) { |
| 56 | + return true; // only reproducible where wchar_t is signed |
| 57 | + } |
| 58 | + std::wstring input = L" 42"; |
| 59 | + // 0x...FF20: low byte 0x20, high bits set, so the value is negative. |
| 60 | + input[0] = static_cast<wchar_t>(~static_cast<unsigned int>(0xFF) | 0x20u); |
| 61 | + double result; |
| 62 | + auto answer = |
| 63 | + fast_float::from_chars(input.data(), input.data() + input.size(), result, |
| 64 | + fast_float::chars_format::general | |
| 65 | + fast_float::chars_format::skip_white_space); |
| 66 | + if (answer.ec == std::errc()) { |
| 67 | + std::cerr << "leading non-space code unit must not be skipped\n"; |
| 68 | + return false; |
| 69 | + } |
| 70 | + return true; |
| 71 | +} |
| 72 | + |
49 | 73 | int main() { |
50 | | - if (test_minus() && test_plus() && test_space() && test_nan()) { |
| 74 | + if (test_minus() && test_plus() && test_space() && test_nan() && |
| 75 | + test_non_space_with_space_low_byte()) { |
51 | 76 | std::cout << "all ok" << std::endl; |
52 | 77 | return EXIT_SUCCESS; |
53 | 78 | } |
|
0 commit comments