Commit ac57c049d82425039e4a46cd76401b6c45464734
1 parent
7c148c15
Introduce `util::internal_error_if` for concise handling of internal errors
- replace repetitive error handling with utility functions in BufferInputSource, OffsetBuffer, and QPDF_objects. - Remove some "internal error" labels from errors that could be due to user logic errors.
Showing
4 changed files
with
29 additions
and
34 deletions
libqpdf/BitStream.cc
| 1 | 1 | #include <qpdf/BitStream.hh> |
| 2 | 2 | |
| 3 | 3 | #include <qpdf/QIntC.hh> |
| 4 | +#include <qpdf/Util.hh> | |
| 4 | 5 | |
| 5 | 6 | // See comments in bits_functions.hh |
| 6 | 7 | #define BITS_READ 1 |
| 7 | 8 | #include <qpdf/bits_functions.hh> |
| 8 | 9 | |
| 10 | +using namespace qpdf; | |
| 11 | + | |
| 9 | 12 | BitStream::BitStream(unsigned char const* p, size_t nbytes) : |
| 10 | 13 | start(p), |
| 11 | 14 | nbytes(nbytes) |
| ... | ... | @@ -56,9 +59,8 @@ BitStream::skipToNextByte() |
| 56 | 59 | { |
| 57 | 60 | if (bit_offset != 7) { |
| 58 | 61 | size_t bits_to_skip = bit_offset + 1; |
| 59 | - if (bits_available < bits_to_skip) { | |
| 60 | - throw std::logic_error("INTERNAL ERROR: overflow skipping to next byte in bitstream"); | |
| 61 | - } | |
| 62 | + util::internal_error_if( | |
| 63 | + bits_available < bits_to_skip, "overflow skipping to next byte in bitstream"); | |
| 62 | 64 | bit_offset = 7; |
| 63 | 65 | ++p; |
| 64 | 66 | bits_available -= bits_to_skip; | ... | ... |
libqpdf/BufferInputSource.cc
| ... | ... | @@ -41,9 +41,7 @@ BufferInputSource::~BufferInputSource() |
| 41 | 41 | qpdf_offset_t |
| 42 | 42 | BufferInputSource::findAndSkipNextEOL() |
| 43 | 43 | { |
| 44 | - if (cur_offset < 0) { | |
| 45 | - throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0"); | |
| 46 | - } | |
| 44 | + util::internal_error_if(cur_offset < 0, "BufferInputSource offset < 0"); | |
| 47 | 45 | qpdf_offset_t end_pos = max_offset; |
| 48 | 46 | if (cur_offset >= end_pos) { |
| 49 | 47 | last_offset = end_pos; |
| ... | ... | @@ -99,14 +97,10 @@ BufferInputSource::seek(qpdf_offset_t offset, int whence) |
| 99 | 97 | cur_offset = max_offset + offset; |
| 100 | 98 | break; |
| 101 | 99 | |
| 102 | - case SEEK_CUR: | |
| 100 | + default: | |
| 101 | + util::assertion(whence == SEEK_CUR, "invalid argument to BufferInputSource::seek"); | |
| 103 | 102 | QIntC::range_check(cur_offset, offset); |
| 104 | 103 | cur_offset += offset; |
| 105 | - break; | |
| 106 | - | |
| 107 | - default: | |
| 108 | - throw std::logic_error("INTERNAL ERROR: invalid argument to BufferInputSource::seek"); | |
| 109 | - break; | |
| 110 | 104 | } |
| 111 | 105 | |
| 112 | 106 | if (cur_offset < 0) { |
| ... | ... | @@ -123,9 +117,7 @@ BufferInputSource::rewind() |
| 123 | 117 | size_t |
| 124 | 118 | BufferInputSource::read(char* buffer, size_t length) |
| 125 | 119 | { |
| 126 | - if (cur_offset < 0) { | |
| 127 | - throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0"); | |
| 128 | - } | |
| 120 | + util::internal_error_if(cur_offset < 0, "BufferInputSource offset < 0"); | |
| 129 | 121 | qpdf_offset_t end_pos = max_offset; |
| 130 | 122 | if (cur_offset >= end_pos) { |
| 131 | 123 | last_offset = end_pos; |
| ... | ... | @@ -230,9 +222,7 @@ BufferInputSource::unreadCh(char ch) |
| 230 | 222 | qpdf_offset_t |
| 231 | 223 | is::OffsetBuffer::findAndSkipNextEOL() |
| 232 | 224 | { |
| 233 | - if (pos < 0) { | |
| 234 | - throw std::logic_error("INTERNAL ERROR: is::OffsetBuffer offset < 0"); | |
| 235 | - } | |
| 225 | + util::internal_error_if(pos < 0, "is::OffsetBuffer offset < 0"); | |
| 236 | 226 | auto end_pos = static_cast<qpdf_offset_t>(view_.size()); |
| 237 | 227 | if (pos >= end_pos) { |
| 238 | 228 | last_offset = end_pos + global_offset; |
| ... | ... | @@ -276,14 +266,10 @@ is::OffsetBuffer::seek(qpdf_offset_t offset, int whence) |
| 276 | 266 | pos = static_cast<qpdf_offset_t>(view_.size()) + offset; |
| 277 | 267 | break; |
| 278 | 268 | |
| 279 | - case SEEK_CUR: | |
| 269 | + default: | |
| 270 | + util::assertion(whence == SEEK_CUR, "invalid argument to BufferInputSource::seek"); | |
| 280 | 271 | QIntC::range_check(pos, offset); |
| 281 | 272 | pos += offset; |
| 282 | - break; | |
| 283 | - | |
| 284 | - default: | |
| 285 | - throw std::logic_error("INTERNAL ERROR: invalid argument to BufferInputSource::seek"); | |
| 286 | - break; | |
| 287 | 273 | } |
| 288 | 274 | |
| 289 | 275 | if (pos < 0) { |
| ... | ... | @@ -294,9 +280,7 @@ is::OffsetBuffer::seek(qpdf_offset_t offset, int whence) |
| 294 | 280 | size_t |
| 295 | 281 | is::OffsetBuffer::read(char* buffer, size_t length) |
| 296 | 282 | { |
| 297 | - if (pos < 0) { | |
| 298 | - throw std::logic_error("INTERNAL ERROR: is::OffsetBuffer offset < 0"); | |
| 299 | - } | |
| 283 | + util::internal_error_if(pos < 0, "is::OffsetBuffer offset < 0"); | |
| 300 | 284 | auto end_pos = static_cast<qpdf_offset_t>(view_.size()); |
| 301 | 285 | if (pos >= end_pos) { |
| 302 | 286 | last_offset = end_pos + global_offset; | ... | ... |
libqpdf/QPDF_objects.cc
| ... | ... | @@ -238,13 +238,11 @@ Objects::parse(char const* password) |
| 238 | 238 | void |
| 239 | 239 | Objects::inParse(bool v) |
| 240 | 240 | { |
| 241 | - if (m->in_parse == v) { | |
| 241 | + util::internal_error_if( | |
| 242 | + m->in_parse == v, "QPDF: re-entrant parsing detected" | |
| 242 | 243 | // This happens if QPDFParser::parse tries to resolve an indirect object while it is |
| 243 | 244 | // parsing. |
| 244 | - throw std::logic_error( | |
| 245 | - "QPDF: re-entrant parsing detected. This is a qpdf bug." | |
| 246 | - " Please report at https://github.com/qpdf/qpdf/issues."); | |
| 247 | - } | |
| 245 | + ); | |
| 248 | 246 | m->in_parse = v; |
| 249 | 247 | } |
| 250 | 248 | |
| ... | ... | @@ -535,7 +533,7 @@ Objects::read_xref(qpdf_offset_t xref_offset, bool in_stream_recovery) |
| 535 | 533 | max_obj = std::max(max_obj, *(m->deleted_objects.rbegin())); |
| 536 | 534 | } |
| 537 | 535 | if (size < 1 || (size - 1) != max_obj) { |
| 538 | - if ((size - 2) == max_obj ){//&& qpdf.getObject(max_obj, 0).isStreamOfType("/XRef")) { | |
| 536 | + if ((size - 2) == max_obj) { //&& qpdf.getObject(max_obj, 0).isStreamOfType("/XRef")) { | |
| 539 | 537 | warn(damagedPDF( |
| 540 | 538 | "", |
| 541 | 539 | -1, | ... | ... |
libqpdf/qpdf/Util.hh
| ... | ... | @@ -7,6 +7,8 @@ |
| 7 | 7 | #include <string> |
| 8 | 8 | #include <utility> |
| 9 | 9 | |
| 10 | +using namespace std::literals; | |
| 11 | + | |
| 10 | 12 | namespace qpdf::util |
| 11 | 13 | { |
| 12 | 14 | // qpdf::util is a collection of useful utility functions for qpdf internal use. It includes |
| ... | ... | @@ -17,13 +19,22 @@ namespace qpdf::util |
| 17 | 19 | // |
| 18 | 20 | // DO NOT USE unless it is impractical or unnecessary to cover violations during CI Testing. |
| 19 | 21 | inline void |
| 20 | - assertion(bool cond, std::string const msg) | |
| 22 | + assertion(bool cond, std::string const& msg) | |
| 21 | 23 | { |
| 22 | 24 | if (!cond) { |
| 23 | 25 | throw std::logic_error(msg); |
| 24 | 26 | } |
| 25 | 27 | } |
| 26 | 28 | |
| 29 | + inline void | |
| 30 | + internal_error_if(bool cond, std::string const& msg) | |
| 31 | + { | |
| 32 | + if (cond) { | |
| 33 | + throw std::logic_error("INTERNAL ERROR: "s.append(msg).append( | |
| 34 | + "\nThis is a qpdf bug. Please report at https://github.com/qpdf/qpdf/issues")); | |
| 35 | + } | |
| 36 | + } | |
| 37 | + | |
| 27 | 38 | inline constexpr char |
| 28 | 39 | hex_decode_char(char digit) |
| 29 | 40 | { | ... | ... |