Commit ec09b914434b8dbc23bf6043b13ee5d5ecf4c2a6
1 parent
4a648b9a
Add QIntC::range_check_subtract
Showing
4 changed files
with
73 additions
and
0 deletions
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