Commit ec09b914434b8dbc23bf6043b13ee5d5ecf4c2a6

Authored by Jay Berkenbilt
1 parent 4a648b9a

Add QIntC::range_check_subtract

ChangeLog
1 1 2021-11-04 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * Add QIntC::range_check_substract to do range checking on
  4 + subtraction, which has different boundary conditions from
  5 + addition.
  6 +
3 7 * Bug fix: fix crash that could occur under certain conditions
4 8 when using --pages with files that had form fields. Fixes #548.
5 9  
... ...
include/qpdf/QIntC.hh
... ... @@ -250,6 +250,34 @@ namespace QIntC // QIntC = qpdf Integer Conversion
250 250 throw std::range_error(msg.str());
251 251 }
252 252 }
  253 +
  254 + template <typename T>
  255 + void range_check_substract(T const& cur, T const& delta)
  256 + {
  257 + if ((delta >= 0) == (cur >= 0))
  258 + {
  259 + return;
  260 + }
  261 +
  262 + if ((delta > 0) &&
  263 + ((std::numeric_limits<T>::min() + delta) > cur))
  264 + {
  265 + std::ostringstream msg;
  266 + msg.imbue(std::locale::classic());
  267 + msg << "subtracting " << delta << " from " << cur
  268 + << " would cause an integer underflow";
  269 + throw std::range_error(msg.str());
  270 + }
  271 + else if ((delta < 0) &&
  272 + ((std::numeric_limits<T>::max() + delta) < cur))
  273 + {
  274 + std::ostringstream msg;
  275 + msg.imbue(std::locale::classic());
  276 + msg << "subtracting " << delta << " from " << cur
  277 + << " would cause an integer overflow";
  278 + throw std::range_error(msg.str());
  279 + }
  280 + }
253 281 };
254 282  
255 283 #endif // QINTC_HH
... ...
libtests/qintc.cc
... ... @@ -48,6 +48,29 @@ static void try_range_check_real(
48 48 std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl;
49 49 }
50 50  
  51 +#define try_range_check_subtract(exp_pass, a, b) \
  52 + try_range_check_subtract_real(#a " - " #b, exp_pass, a, b)
  53 +
  54 +template <typename T>
  55 +static void try_range_check_subtract_real(
  56 + char const* description, bool exp_pass,
  57 + T const& a, T const& b)
  58 +{
  59 + bool passed = false;
  60 + try
  61 + {
  62 + QIntC::range_check_substract(a, b);
  63 + std::cout << description << ": okay";
  64 + passed = true;
  65 + }
  66 + catch (std::range_error& e)
  67 + {
  68 + std::cout << description << ": " << e.what();
  69 + passed = false;
  70 + }
  71 + std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl;
  72 +}
  73 +
51 74 int main()
52 75 {
53 76 uint32_t u1 = 3141592653U; // Too big for signed type
... ... @@ -96,5 +119,14 @@ int main()
96 119 try_range_check(false, min_ll, -1LL);
97 120 try_range_check(false, max_sc, max_sc);
98 121 try_range_check(true, '!', '#');
  122 + try_range_check_subtract(true, 1, 2);
  123 + try_range_check_subtract(true, -1, -2);
  124 + try_range_check_subtract(true, 1, 10);
  125 + try_range_check_subtract(true, -1, -10);
  126 + try_range_check_subtract(false, 0LL, min_ll);
  127 + try_range_check_subtract(false, 1LL, min_ll);
  128 + try_range_check_subtract(true, 0LL, max_ll);
  129 + try_range_check_subtract(true, -1LL, max_ll);
  130 + try_range_check_subtract(false, -2LL, max_ll);
99 131 return 0;
100 132 }
... ...
libtests/qtest/qintc/qintc.out
No preview for this file type