Commit ec09b914434b8dbc23bf6043b13ee5d5ecf4c2a6
1 parent
4a648b9a
Add QIntC::range_check_subtract
Showing
4 changed files
with
73 additions
and
0 deletions
ChangeLog
| 1 | 2021-11-04 Jay Berkenbilt <ejb@ql.org> | 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 | * Bug fix: fix crash that could occur under certain conditions | 7 | * Bug fix: fix crash that could occur under certain conditions |
| 4 | when using --pages with files that had form fields. Fixes #548. | 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,6 +250,34 @@ namespace QIntC // QIntC = qpdf Integer Conversion | ||
| 250 | throw std::range_error(msg.str()); | 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 | #endif // QINTC_HH | 283 | #endif // QINTC_HH |
libtests/qintc.cc
| @@ -48,6 +48,29 @@ static void try_range_check_real( | @@ -48,6 +48,29 @@ static void try_range_check_real( | ||
| 48 | std::cout << ((passed == exp_pass) ? " PASSED" : " FAILED") << std::endl; | 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 | int main() | 74 | int main() |
| 52 | { | 75 | { |
| 53 | uint32_t u1 = 3141592653U; // Too big for signed type | 76 | uint32_t u1 = 3141592653U; // Too big for signed type |
| @@ -96,5 +119,14 @@ int main() | @@ -96,5 +119,14 @@ int main() | ||
| 96 | try_range_check(false, min_ll, -1LL); | 119 | try_range_check(false, min_ll, -1LL); |
| 97 | try_range_check(false, max_sc, max_sc); | 120 | try_range_check(false, max_sc, max_sc); |
| 98 | try_range_check(true, '!', '#'); | 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 | return 0; | 131 | return 0; |
| 100 | } | 132 | } |
libtests/qtest/qintc/qintc.out
No preview for this file type