From ec09b914434b8dbc23bf6043b13ee5d5ecf4c2a6 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Thu, 4 Nov 2021 13:52:41 -0400 Subject: [PATCH] Add QIntC::range_check_subtract --- ChangeLog | 4 ++++ include/qpdf/QIntC.hh | 28 ++++++++++++++++++++++++++++ libtests/qintc.cc | 32 ++++++++++++++++++++++++++++++++ libtests/qtest/qintc/qintc.out | 9 +++++++++ 4 files changed, 73 insertions(+) diff --git a/ChangeLog b/ChangeLog index ed435242..56a2be61 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2021-11-04 Jay Berkenbilt + * Add QIntC::range_check_substract to do range checking on + subtraction, which has different boundary conditions from + addition. + * Bug fix: fix crash that could occur under certain conditions when using --pages with files that had form fields. Fixes #548. diff --git a/include/qpdf/QIntC.hh b/include/qpdf/QIntC.hh index 2349e775..03da8853 100644 --- a/include/qpdf/QIntC.hh +++ b/include/qpdf/QIntC.hh @@ -250,6 +250,34 @@ namespace QIntC // QIntC = qpdf Integer Conversion throw std::range_error(msg.str()); } } + + template + void range_check_substract(T const& cur, T const& delta) + { + if ((delta >= 0) == (cur >= 0)) + { + return; + } + + if ((delta > 0) && + ((std::numeric_limits::min() + delta) > cur)) + { + std::ostringstream msg; + msg.imbue(std::locale::classic()); + msg << "subtracting " << delta << " from " << cur + << " would cause an integer underflow"; + throw std::range_error(msg.str()); + } + else if ((delta < 0) && + ((std::numeric_limits::max() + delta) < cur)) + { + std::ostringstream msg; + msg.imbue(std::locale::classic()); + msg << "subtracting " << delta << " from " << cur + << " would cause an integer overflow"; + throw std::range_error(msg.str()); + } + } }; #endif // QINTC_HH diff --git a/libtests/qintc.cc b/libtests/qintc.cc index 32c3713f..f9ca9558 100644 --- a/libtests/qintc.cc +++ b/libtests/qintc.cc @@ -48,6 +48,29 @@ static void try_range_check_real( std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl; } +#define try_range_check_subtract(exp_pass, a, b) \ + try_range_check_subtract_real(#a " - " #b, exp_pass, a, b) + +template +static void try_range_check_subtract_real( + char const* description, bool exp_pass, + T const& a, T const& b) +{ + bool passed = false; + try + { + QIntC::range_check_substract(a, b); + std::cout << description << ": okay"; + passed = true; + } + catch (std::range_error& e) + { + std::cout << description << ": " << e.what(); + passed = false; + } + std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl; +} + int main() { uint32_t u1 = 3141592653U; // Too big for signed type @@ -96,5 +119,14 @@ int main() try_range_check(false, min_ll, -1LL); try_range_check(false, max_sc, max_sc); try_range_check(true, '!', '#'); + try_range_check_subtract(true, 1, 2); + try_range_check_subtract(true, -1, -2); + try_range_check_subtract(true, 1, 10); + try_range_check_subtract(true, -1, -10); + try_range_check_subtract(false, 0LL, min_ll); + try_range_check_subtract(false, 1LL, min_ll); + try_range_check_subtract(true, 0LL, max_ll); + try_range_check_subtract(true, -1LL, max_ll); + try_range_check_subtract(false, -2LL, max_ll); return 0; } diff --git a/libtests/qtest/qintc/qintc.out b/libtests/qtest/qintc/qintc.out index 5520c635..c78f02ab 100644 --- a/libtests/qtest/qintc/qintc.out +++ b/libtests/qtest/qintc/qintc.out @@ -26,3 +26,12 @@ min_ll + 0LL: okay PASSED min_ll + -1LL: adding -1 to -9223372036854775808 would cause an integer underflow PASSED max_sc + max_sc: adding  to  would cause an integer overflow PASSED '!' + '#': okay PASSED +1 - 2: okay PASSED +-1 - -2: okay PASSED +1 - 10: okay PASSED +-1 - -10: okay PASSED +0LL - min_ll: subtracting -9223372036854775808 from 0 would cause an integer overflow PASSED +1LL - min_ll: subtracting -9223372036854775808 from 1 would cause an integer overflow PASSED +0LL - max_ll: okay PASSED +-1LL - max_ll: okay PASSED +-2LL - max_ll: subtracting 9223372036854775807 from -2 would cause an integer underflow PASSED