Commit 9d6448157175d8e03a42d6942d4c058b93daf42b

Authored by Jay Berkenbilt
1 parent 4b4b31bf

Handle negative numbers in QIntC::range_check (fuzz issue 26994)

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 6 2020-11-11 Jay Berkenbilt <ejb@ql.org>
2 7  
3 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 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