Commit 9d6448157175d8e03a42d6942d4c058b93daf42b
1 parent
4b4b31bf
Handle negative numbers in QIntC::range_check (fuzz issue 26994)
Showing
5 changed files
with
72 additions
and
0 deletions
ChangeLog
fuzz/qpdf_extra/26994.fuzz
0 → 100644
No preview for this file type
include/qpdf/QIntC.hh
| ... | ... | @@ -226,6 +226,11 @@ namespace QIntC // QIntC = qpdf Integer Conversion |
| 226 | 226 | template <typename T> |
| 227 | 227 | void range_check(T const& cur, T const& delta) |
| 228 | 228 | { |
| 229 | + if ((delta > 0) != (cur > 0)) | |
| 230 | + { | |
| 231 | + return; | |
| 232 | + } | |
| 233 | + | |
| 229 | 234 | if ((delta > 0) && |
| 230 | 235 | ((std::numeric_limits<T>::max() - cur) < delta)) |
| 231 | 236 | { |
| ... | ... | @@ -235,6 +240,15 @@ namespace QIntC // QIntC = qpdf Integer Conversion |
| 235 | 240 | << " would cause an integer overflow"; |
| 236 | 241 | throw std::range_error(msg.str()); |
| 237 | 242 | } |
| 243 | + else if ((delta < 0) && | |
| 244 | + ((std::numeric_limits<T>::min() - cur) > delta)) | |
| 245 | + { | |
| 246 | + std::ostringstream msg; | |
| 247 | + msg.imbue(std::locale::classic()); | |
| 248 | + msg << "adding " << delta << " to " << cur | |
| 249 | + << " would cause an integer underflow"; | |
| 250 | + throw std::range_error(msg.str()); | |
| 251 | + } | |
| 238 | 252 | } |
| 239 | 253 | }; |
| 240 | 254 | ... | ... |
libtests/qintc.cc
| ... | ... | @@ -25,6 +25,29 @@ static void try_convert_real( |
| 25 | 25 | std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl; |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | +#define try_range_check(exp_pass, a, b) \ | |
| 29 | + try_range_check_real(#a " + " #b, exp_pass, a, b) | |
| 30 | + | |
| 31 | +template <typename T> | |
| 32 | +static void try_range_check_real( | |
| 33 | + char const* description, bool exp_pass, | |
| 34 | + T const& a, T const& b) | |
| 35 | +{ | |
| 36 | + bool passed = false; | |
| 37 | + try | |
| 38 | + { | |
| 39 | + QIntC::range_check(a, b); | |
| 40 | + std::cout << description << ": okay"; | |
| 41 | + passed = true; | |
| 42 | + } | |
| 43 | + catch (std::range_error& e) | |
| 44 | + { | |
| 45 | + std::cout << description << ": " << e.what(); | |
| 46 | + passed = false; | |
| 47 | + } | |
| 48 | + std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl; | |
| 49 | +} | |
| 50 | + | |
| 28 | 51 | int main() |
| 29 | 52 | { |
| 30 | 53 | uint32_t u1 = 3141592653U; // Too big for signed type |
| ... | ... | @@ -56,5 +79,22 @@ int main() |
| 56 | 79 | try_convert(true, QIntC::to_uchar<char>, c2); |
| 57 | 80 | try_convert(true, QIntC::to_char<char>, c2); |
| 58 | 81 | |
| 82 | + auto constexpr max_ll = std::numeric_limits<long long>::max(); | |
| 83 | + auto constexpr max_ull = std::numeric_limits<unsigned long long>::max(); | |
| 84 | + auto constexpr min_ll = std::numeric_limits<long long>::min(); | |
| 85 | + auto constexpr max_sc = std::numeric_limits<signed char>::max(); | |
| 86 | + try_range_check(true, 1, 2); | |
| 87 | + try_range_check(true, -1, 2); | |
| 88 | + try_range_check(true, -100, -200); | |
| 89 | + try_range_check(true, max_ll, 0LL); | |
| 90 | + try_range_check(false, max_ll, 1LL); | |
| 91 | + try_range_check(true, max_ll, 0LL); | |
| 92 | + try_range_check(false, max_ll, 1LL); | |
| 93 | + try_range_check(true, max_ull, 0ULL); | |
| 94 | + try_range_check(false, max_ull, 1ULL); | |
| 95 | + try_range_check(true, min_ll, 0LL); | |
| 96 | + try_range_check(false, min_ll, -1LL); | |
| 97 | + try_range_check(false, max_sc, max_sc); | |
| 98 | + try_range_check(true, '!', '#'); | |
| 59 | 99 | return 0; |
| 60 | 100 | } | ... | ... |
libtests/qtest/qintc/qintc.out
No preview for this file type