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
| 1 | +2020-11-21 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * Fix QIntC::range_check to handle negative numbers properly (fuzz | ||
| 4 | + issue 26994). | ||
| 5 | + | ||
| 1 | 2020-11-11 Jay Berkenbilt <ejb@ql.org> | 6 | 2020-11-11 Jay Berkenbilt <ejb@ql.org> |
| 2 | 7 | ||
| 3 | * Treat a direct page object as a runtime error rather than a | 8 | * Treat a direct page object as a runtime error rather than a |
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,6 +226,11 @@ namespace QIntC // QIntC = qpdf Integer Conversion | ||
| 226 | template <typename T> | 226 | template <typename T> |
| 227 | void range_check(T const& cur, T const& delta) | 227 | void range_check(T const& cur, T const& delta) |
| 228 | { | 228 | { |
| 229 | + if ((delta > 0) != (cur > 0)) | ||
| 230 | + { | ||
| 231 | + return; | ||
| 232 | + } | ||
| 233 | + | ||
| 229 | if ((delta > 0) && | 234 | if ((delta > 0) && |
| 230 | ((std::numeric_limits<T>::max() - cur) < delta)) | 235 | ((std::numeric_limits<T>::max() - cur) < delta)) |
| 231 | { | 236 | { |
| @@ -235,6 +240,15 @@ namespace QIntC // QIntC = qpdf Integer Conversion | @@ -235,6 +240,15 @@ namespace QIntC // QIntC = qpdf Integer Conversion | ||
| 235 | << " would cause an integer overflow"; | 240 | << " would cause an integer overflow"; |
| 236 | throw std::range_error(msg.str()); | 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,6 +25,29 @@ static void try_convert_real( | ||
| 25 | std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl; | 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 | int main() | 51 | int main() |
| 29 | { | 52 | { |
| 30 | uint32_t u1 = 3141592653U; // Too big for signed type | 53 | uint32_t u1 = 3141592653U; // Too big for signed type |
| @@ -56,5 +79,22 @@ int main() | @@ -56,5 +79,22 @@ int main() | ||
| 56 | try_convert(true, QIntC::to_uchar<char>, c2); | 79 | try_convert(true, QIntC::to_uchar<char>, c2); |
| 57 | try_convert(true, QIntC::to_char<char>, c2); | 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 | return 0; | 99 | return 0; |
| 60 | } | 100 | } |
libtests/qtest/qintc/qintc.out
No preview for this file type