diff --git a/libqpdf/NNTree.cc b/libqpdf/NNTree.cc index 170bf5c..85f2a94 100644 --- a/libqpdf/NNTree.cc +++ b/libqpdf/NNTree.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -65,10 +66,8 @@ NNTreeIterator::updateIValue(bool allow_invalid) } if (item_number < 0 || !node) { - if (!allow_invalid) { - throw std::logic_error( - "attempt made to dereference an invalid name/number tree iterator"); - } + util::assertion( + allow_invalid, "attempt made to dereference an invalid name/number tree iterator"); return; } impl.error(node, "update ivalue: items array is too short"); @@ -210,9 +209,7 @@ NNTreeIterator::split(Dictionary to_split, std::list::iterator pare // node: A // item_number: 0 - if (!valid()) { - throw std::logic_error("NNTreeIterator::split called an invalid iterator"); - } + util::assertion(valid(), "NNTreeIterator::split called an invalid iterator"); // Find the array we actually need to split, which is either this node's kids or items. Array kids = to_split["/Kids"]; @@ -228,13 +225,12 @@ NNTreeIterator::split(Dictionary to_split, std::list::iterator pare first_half = kids; n = nkids; key = "/Kids"; - } else if (nitems > 0) { + } else { + util::assertion(nitems > 0, "NNTreeIterator::split called on invalid node"); first_half = items; n = nitems; threshold *= 2; key = impl.itemsKey(); - } else { - throw std::logic_error("NNTreeIterator::split called on invalid node"); } if (n <= threshold) { @@ -369,9 +365,7 @@ NNTreeIterator::remove() { // Remove this item, leaving the tree valid and this iterator pointing to the next item. - if (!valid()) { - throw std::logic_error("attempt made to remove an invalid iterator"); - } + util::assertion(valid(), "attempt made to remove an invalid iterator"); Array items = node[impl.itemsKey()]; int nitems = static_cast(items.size()); if (std::cmp_greater(item_number + 2, nitems)) { @@ -396,13 +390,12 @@ NNTreeIterator::remove() // the previous item. item_number -= 2; increment(false); - } else if (item_number < nitems) { + } else { + util::assertion( + item_number < nitems, "NNTreeIterator::remove: item_number > nitems after erase"); // We don't have to do anything since the removed item's successor now occupies its // former location. updateIValue(); - } else { - // We already checked to ensure this condition would not happen. - throw std::logic_error("NNTreeIterator::remove: item_number > nitems after erase"); } return; } diff --git a/libqpdf/Pl_AES_PDF.cc b/libqpdf/Pl_AES_PDF.cc index 3d47b97..b5e0364 100644 --- a/libqpdf/Pl_AES_PDF.cc +++ b/libqpdf/Pl_AES_PDF.cc @@ -3,10 +3,13 @@ #include #include #include +#include + #include -#include #include +using namespace qpdf; + bool Pl_AES_PDF::use_static_iv = false; Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, bool encrypt, std::string key) : @@ -15,12 +18,8 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, bool encrypt, std crypto(QPDFCryptoProvider::getImpl()), encrypt(encrypt) { - if (!next) { - throw std::logic_error("Attempt to create Pl_AES_PDF with nullptr as next"); - } - if (!(key.size() == 32 || key.size() == 16)) { - throw std::runtime_error("unsupported key length"); - } + util::assertion(next, "Attempt to create Pl_AES_PDF with nullptr as next"); + util::no_ci_rt_error_if(!(key.size() == 32 || key.size() == 16), "unsupported key length"); std::memset(this->inbuf, 0, this->buf_size); std::memset(this->outbuf, 0, this->buf_size); std::memset(this->cbc_block, 0, this->buf_size); @@ -41,12 +40,10 @@ Pl_AES_PDF::disablePadding() void Pl_AES_PDF::setIV(unsigned char const* iv, size_t bytes) { - if (bytes != buf_size) { - throw std::logic_error( - "Pl_AES_PDF: specified initialization vector" - " size in bytes must be " + + util::assertion( + bytes == buf_size, + "Pl_AES_PDF: specified initialization vector size in bytes must be " + std::to_string(bytes)); - } use_specified_iv = true; memcpy(specified_iv, iv, bytes); } @@ -103,9 +100,7 @@ Pl_AES_PDF::finish() // This is never supposed to happen as the output is always supposed to be padded. // However, we have encountered files for which the output is not a multiple of the // block size. In this case, pad with zeroes and hope for the best. - if (offset >= buf_size) { - throw std::logic_error("buffer overflow in AES encryption pipeline"); - } + util::assertion(offset < buf_size, "buffer overflow in AES encryption pipeline"); std::memset(inbuf + offset, 0, buf_size - offset); offset = buf_size; } @@ -136,9 +131,7 @@ Pl_AES_PDF::initializeVector() void Pl_AES_PDF::flush(bool strip_padding) { - if (offset != buf_size) { - throw std::logic_error("AES pipeline: flush called when buffer was not full"); - } + util::assertion(offset == buf_size, "AES pipeline: flush called when buffer was not full"); if (first) { first = false; diff --git a/libqpdf/Pl_ASCII85Decoder.cc b/libqpdf/Pl_ASCII85Decoder.cc index 28905ec..0373d22 100644 --- a/libqpdf/Pl_ASCII85Decoder.cc +++ b/libqpdf/Pl_ASCII85Decoder.cc @@ -1,15 +1,17 @@ #include #include +#include + #include #include +using namespace qpdf; + Pl_ASCII85Decoder::Pl_ASCII85Decoder(char const* identifier, Pipeline* next) : Pipeline(identifier, next) { - if (!next) { - throw std::logic_error("Attempt to create Pl_ASCII85Decoder with nullptr as next"); - } + util::assertion(next, "Attempt to create Pl_ASCII85Decoder with nullptr as next"); } void @@ -33,12 +35,9 @@ Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len) if (eod > 1) { break; } else if (eod == 1) { - if (buf[i] == '>') { - flush(); - eod = 2; - } else { - throw std::runtime_error("broken end-of-data sequence in base 85 data"); - } + util::no_ci_rt_error_if(buf[i] != '>', "broken end-of-data sequence in base 85 data"); + flush(); + eod = 2; } else { switch (buf[i]) { case '~': @@ -48,12 +47,10 @@ Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len) case 'z': if (pos != 0) { throw std::runtime_error("unexpected z during base 85 decode"); - } else { - QTC::TC("libtests", "Pl_ASCII85Decoder read z"); - unsigned char zeroes[4]; - memset(zeroes, '\0', 4); - next()->write(zeroes, 4); } + unsigned char zeroes[4]; + memset(zeroes, '\0', 4); + next()->write(zeroes, 4); break; default: @@ -76,7 +73,6 @@ void Pl_ASCII85Decoder::flush() { if (this->pos == 0) { - QTC::TC("libtests", "Pl_ASCII85Decoder no-op flush"); return; } unsigned long lval = 0; diff --git a/libqpdf/Pl_ASCIIHexDecoder.cc b/libqpdf/Pl_ASCIIHexDecoder.cc index 795dfc0..9df282e 100644 --- a/libqpdf/Pl_ASCIIHexDecoder.cc +++ b/libqpdf/Pl_ASCIIHexDecoder.cc @@ -1,17 +1,18 @@ #include #include +#include + #include #include +using namespace qpdf; using namespace std::literals; Pl_ASCIIHexDecoder::Pl_ASCIIHexDecoder(char const* identifier, Pipeline* next) : Pipeline(identifier, next) { - if (!next) { - throw std::logic_error("Attempt to create Pl_ASCIIHexDecoder with nullptr as next"); - } + util::assertion(next, "Attempt to create Pl_ASCIIHexDecoder with nullptr as next"); } void diff --git a/libqpdf/Pl_Buffer.cc b/libqpdf/Pl_Buffer.cc index 38fadb3..ef2b4a7 100644 --- a/libqpdf/Pl_Buffer.cc +++ b/libqpdf/Pl_Buffer.cc @@ -1,10 +1,14 @@ #include +#include + #include #include #include #include +using namespace qpdf; + class Pl_Buffer::Members { public: @@ -50,9 +54,7 @@ Pl_Buffer::finish() Buffer* Pl_Buffer::getBuffer() { - if (!m->ready) { - throw std::logic_error("Pl_Buffer::getBuffer() called when not ready"); - } + util::assertion(m->ready, "Pl_Buffer::getBuffer() called when not ready"); auto* b = new Buffer(std::move(m->data)); m->data.clear(); return b; @@ -61,9 +63,7 @@ Pl_Buffer::getBuffer() std::string Pl_Buffer::getString() { - if (!m->ready) { - throw std::logic_error("Pl_Buffer::getString() called when not ready"); - } + util::assertion(m->ready, "Pl_Buffer::getString() called when not ready"); auto s = std::move(m->data); m->data.clear(); return s; @@ -78,9 +78,7 @@ Pl_Buffer::getBufferSharedPointer() void Pl_Buffer::getMallocBuffer(unsigned char** buf, size_t* len) { - if (!m->ready) { - throw std::logic_error("Pl_Buffer::getMallocBuffer() called when not ready"); - } + util::assertion(m->ready, "Pl_Buffer::getMallocBuffer() called when not ready"); auto size = m->data.size(); *len = size; if (size > 0) { diff --git a/libqpdf/Pl_Concatenate.cc b/libqpdf/Pl_Concatenate.cc index fa95bea..776f2eb 100644 --- a/libqpdf/Pl_Concatenate.cc +++ b/libqpdf/Pl_Concatenate.cc @@ -1,13 +1,13 @@ #include -#include +#include + +using namespace qpdf; Pl_Concatenate::Pl_Concatenate(char const* identifier, Pipeline* next) : Pipeline(identifier, next) { - if (!next) { - throw std::logic_error("Attempt to create Pl_Concatenate with nullptr as next"); - } + util::assertion(next, "Attempt to create Pl_Concatenate with nullptr as next"); } // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer diff --git a/libqpdf/Pl_Count.cc b/libqpdf/Pl_Count.cc index bca217c..2b9e261 100644 --- a/libqpdf/Pl_Count.cc +++ b/libqpdf/Pl_Count.cc @@ -1,6 +1,9 @@ #include #include +#include + +using namespace qpdf; class Pl_Count::Members { @@ -18,15 +21,11 @@ Pl_Count::Pl_Count(char const* identifier, Pipeline* next) : Pipeline(identifier, next), m(std::make_unique()) { - if (!next) { - throw std::logic_error("Attempt to create Pl_Count with nullptr as next"); - } + util::assertion(next, "Attempt to create Pl_Count with nullptr as next"); } -Pl_Count::~Pl_Count() // NOLINT (modernize-use-equals-default) -{ - // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer -} +Pl_Count::~Pl_Count() = default; +// Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer void Pl_Count::write(unsigned char const* buf, size_t len) diff --git a/libqpdf/Pl_DCT.cc b/libqpdf/Pl_DCT.cc index 02abda1..b059d30 100644 --- a/libqpdf/Pl_DCT.cc +++ b/libqpdf/Pl_DCT.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -11,6 +12,8 @@ # error "qpdf does not support libjpeg built with BITS_IN_JSAMPLE != 8" #endif +using namespace qpdf; + namespace { class FunctionCallbackConfig: public Pl_DCT::CompressConfig @@ -118,9 +121,7 @@ Pl_DCT::Pl_DCT(char const* identifier, Pipeline* next) : Pipeline(identifier, next), m(std::make_unique()) { - if (!next) { - throw std::logic_error("Attempt to create Pl_DCT with nullptr as next"); - } + util::assertion(next, "Attempt to create Pl_DCT with nullptr as next"); } void @@ -285,12 +286,10 @@ fill_buffer_input_buffer(j_decompress_ptr) static void skip_buffer_input_data(j_decompress_ptr cinfo, long num_bytes) { - if (num_bytes < 0) { - throw std::runtime_error( - "reading jpeg: jpeg library requested skipping a negative number of bytes"); - } + util::no_ci_rt_error_if( + num_bytes < 0, "reading jpeg: jpeg library requested skipping a negative number of bytes"); size_t to_skip = QIntC::to_size(num_bytes); - if ((to_skip > 0) && (to_skip <= cinfo->src->bytes_in_buffer)) { + if (to_skip > 0 && to_skip <= cinfo->src->bytes_in_buffer) { cinfo->src->next_input_byte += to_skip; cinfo->src->bytes_in_buffer -= to_skip; } else if (to_skip != 0) { @@ -354,11 +353,10 @@ Pl_DCT::compress(void* cinfo_p) unsigned int width = cinfo->image_width * QIntC::to_uint(cinfo->input_components); size_t expected_size = QIntC::to_size(cinfo->image_height) * QIntC::to_size(cinfo->image_width) * QIntC::to_size(cinfo->input_components); - if (m->buf.size() != expected_size) { - throw std::runtime_error( - "Pl_DCT: image buffer size = " + std::to_string(m->buf.size()) + + util::no_ci_rt_error_if( + m->buf.size() != expected_size, + "Pl_DCT: image buffer size = " + std::to_string(m->buf.size()) + "; expected size = " + std::to_string(expected_size)); - } JSAMPROW row_pointer[1]; auto buffer = reinterpret_cast(m->buf.data()); while (cinfo->next_scanline < cinfo->image_height) { diff --git a/libqpdf/Pl_Flate.cc b/libqpdf/Pl_Flate.cc index 9a575ad..63ff66d 100644 --- a/libqpdf/Pl_Flate.cc +++ b/libqpdf/Pl_Flate.cc @@ -6,12 +6,15 @@ #include #include +#include #include #ifdef ZOPFLI # include #endif +using namespace qpdf; + namespace { unsigned long long memory_limit_{0}; @@ -31,10 +34,9 @@ Pl_Flate::Members::Members(size_t out_bufsize, action_e action) : // development files available, which particularly helps in a Windows environment. zdata = new z_stream; - if (out_bufsize > UINT_MAX) { - throw std::runtime_error( - "Pl_Flate: zlib doesn't support buffer sizes larger than unsigned int"); - } + util::no_ci_rt_error_if( + out_bufsize > UINT_MAX, + "Pl_Flate: zlib doesn't support buffer sizes larger than unsigned int"); z_stream& zstream = *(static_cast(this->zdata)); zstream.zalloc = nullptr; @@ -70,9 +72,7 @@ Pl_Flate::Pl_Flate( Pipeline(identifier, next), m(std::make_unique(QIntC::to_size(out_bufsize_int), action)) { - if (!next) { - throw std::logic_error("Attempt to create Pl_Flate with nullptr as next"); - } + util::assertion(next, "Attempt to create Pl_Flate with nullptr as next"); } // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer @@ -107,10 +107,8 @@ Pl_Flate::warn(char const* msg, int code) void Pl_Flate::write(unsigned char const* data, size_t len) { - if (!m->outbuf) { - throw std::logic_error( - this->identifier + ": Pl_Flate: write() called after finish() called"); - } + util::assertion( + m->outbuf.get(), identifier + ": Pl_Flate: write() called after finish() called"); if (m->zopfli_buf) { m->zopfli_buf->append(reinterpret_cast(data), len); return; @@ -131,9 +129,8 @@ Pl_Flate::write(unsigned char const* data, size_t len) void Pl_Flate::handleData(unsigned char const* data, size_t len, int flush) { - if (len > UINT_MAX) { - throw std::runtime_error("Pl_Flate: zlib doesn't support data blocks larger than int"); - } + util::no_ci_rt_error_if( + len > UINT_MAX, "Pl_Flate: zlib doesn't support data blocks larger than int"); z_stream& zstream = *(static_cast(m->zdata)); // zlib is known not to modify the data pointed to by next_in but doesn't declare the field // value const unless compiled to do so. @@ -216,7 +213,6 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush) default: checkError("data", err); - break; } } } diff --git a/libqpdf/Pl_LZWDecoder.cc b/libqpdf/Pl_LZWDecoder.cc index cdb4d4d..71fb39c 100644 --- a/libqpdf/Pl_LZWDecoder.cc +++ b/libqpdf/Pl_LZWDecoder.cc @@ -2,17 +2,17 @@ #include #include -#include +#include #include #include +using namespace qpdf; + Pl_LZWDecoder::Pl_LZWDecoder(char const* identifier, Pipeline* next, bool early_code_change) : Pipeline(identifier, next), code_change_delta(early_code_change) { - if (!next) { - throw std::logic_error("Attempt to create Pl_LZWDecoder with nullptr as next"); - } + util::assertion(next, "Attempt to create Pl_LZWDecoder with nullptr as next"); } void @@ -78,21 +78,17 @@ Pl_LZWDecoder::sendNextCode() unsigned char Pl_LZWDecoder::getFirstChar(unsigned int code) { - unsigned char result = '\0'; if (code < 256) { - result = static_cast(code); - } else if (code > 257) { - unsigned int idx = code - 258; - if (idx >= table.size()) { - throw std::runtime_error("Pl_LZWDecoder::getFirstChar: table overflow"); - } - Buffer& b = table.at(idx); - result = b.getBuffer()[0]; - } else { - throw std::runtime_error( - "Pl_LZWDecoder::getFirstChar called with invalid code (" + std::to_string(code) + ")"); + return static_cast(code); } - return result; + util::no_ci_rt_error_if( + code <= 257, + "Pl_LZWDecoder::getFirstChar called with invalid code (" + std::to_string(code) + ")"); + + unsigned int idx = code - 258; + util::no_ci_rt_error_if(idx >= table.size(), "Pl_LZWDecoder::getFirstChar: table overflow"); + Buffer& b = table.at(idx); + return b.getBuffer()[0]; } void @@ -106,18 +102,16 @@ Pl_LZWDecoder::addToTable(unsigned char c) tmp[0] = static_cast(last_code); last_data = tmp; last_size = 1; - } else if (last_code > 257) { + } else { + util::no_ci_rt_error_if( + last_code <= 257, + "Pl_LZWDecoder::addToTable called with invalid code (" + std::to_string(last_code) + + ")"); unsigned int idx = last_code - 258; - if (idx >= table.size()) { - throw std::runtime_error("Pl_LZWDecoder::addToTable: table overflow"); - } + util::no_ci_rt_error_if(idx >= table.size(), "Pl_LZWDecoder::addToTable: table overflow"); Buffer& b = table.at(idx); last_data = b.getBuffer(); last_size = QIntC::to_uint(b.getSize()); - } else { - throw std::runtime_error( - "Pl_LZWDecoder::addToTable called with invalid code (" + std::to_string(last_code) + - ")"); } Buffer entry(1 + last_size); @@ -158,19 +152,16 @@ Pl_LZWDecoder::handleCode(unsigned int code) } else if (idx == table_size) { // The encoder would have just created this entry, so the first character of // this entry would have been the same as the first character of the last entry. - QTC::TC("libtests", "Pl_LZWDecoder last was table size"); next_c = getFirstChar(last_code); } else { next_c = getFirstChar(code); } } unsigned int new_idx = 258 + table_size; - if (new_idx == 4096) { - throw std::runtime_error("LZWDecoder: table full"); - } + util::no_ci_rt_error_if(new_idx == 4096, "LZWDecoder: table full"); addToTable(next_c); unsigned int change_idx = new_idx + code_change_delta; - if ((change_idx == 511) || (change_idx == 1023) || (change_idx == 2047)) { + if (change_idx == 511 || change_idx == 1023 || change_idx == 2047) { ++code_size; } } diff --git a/libqpdf/Pl_RC4.cc b/libqpdf/Pl_RC4.cc index a71ace1..78ea1be 100644 --- a/libqpdf/Pl_RC4.cc +++ b/libqpdf/Pl_RC4.cc @@ -1,24 +1,23 @@ #include #include +#include + +using namespace qpdf; Pl_RC4::Pl_RC4(char const* identifier, Pipeline* next, std::string key, size_t out_bufsize) : Pipeline(identifier, next), out_bufsize(out_bufsize), rc4(reinterpret_cast(key.data()), static_cast(key.size())) { - if (!next) { - throw std::logic_error("Attempt to create Pl_RC4 with nullptr as next"); - } + util::assertion(next, "Attempt to create Pl_RC4 with nullptr as next"); this->outbuf = QUtil::make_shared_array(out_bufsize); } void Pl_RC4::write(unsigned char const* data, size_t len) { - if (this->outbuf == nullptr) { - throw std::logic_error(this->identifier + ": Pl_RC4: write() called after finish() called"); - } + util::assertion(outbuf.get(), "Pl_RC4: write() called after finish() called"); size_t bytes_left = len; unsigned char const* p = data; @@ -26,7 +25,6 @@ Pl_RC4::write(unsigned char const* data, size_t len) while (bytes_left > 0) { size_t bytes = (bytes_left < this->out_bufsize ? bytes_left : out_bufsize); bytes_left -= bytes; - // lgtm[cpp/weak-cryptographic-algorithm] rc4.process(p, bytes, outbuf.get()); p += bytes; next()->write(outbuf.get(), bytes); diff --git a/libqpdf/Pl_SHA2.cc b/libqpdf/Pl_SHA2.cc index 546ff63..1b11317 100644 --- a/libqpdf/Pl_SHA2.cc +++ b/libqpdf/Pl_SHA2.cc @@ -2,8 +2,9 @@ #include #include +#include -#include +using namespace qpdf; Pl_SHA2::Pl_SHA2(int bits, Pipeline* next) : Pipeline("sha2", next) @@ -49,9 +50,7 @@ Pl_SHA2::finish() void Pl_SHA2::resetBits(int bits) { - if (in_progress) { - throw std::logic_error("bit reset requested for in-progress SHA2 Pipeline"); - } + util::assertion(!in_progress, "bit reset requested for in-progress SHA2 Pipeline"); crypto = QPDFCryptoProvider::getImpl(); crypto->SHA2_init(bits); } @@ -59,17 +58,13 @@ Pl_SHA2::resetBits(int bits) std::string Pl_SHA2::getRawDigest() { - if (in_progress) { - throw std::logic_error("digest requested for in-progress SHA2 Pipeline"); - } + util::assertion(!in_progress, "digest requested for in-progress SHA2 Pipeline"); return crypto->SHA2_digest(); } std::string Pl_SHA2::getHexDigest() { - if (in_progress) { - throw std::logic_error("digest requested for in-progress SHA2 Pipeline"); - } + util::assertion(!in_progress, "digest requested for in-progress SHA2 Pipeline"); return QUtil::hex_encode(getRawDigest()); } diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 3dabac0..d86f604 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -672,10 +672,7 @@ QPDF::getXRefTable() std::map const& Objects::xref_table() { - if (!m->parsed) { - throw std::logic_error("QPDF::getXRefTable called before parsing."); - } - + util::assertion(m->parsed, "QPDF::getXRefTable called before parsing"); return m->xref_table; } diff --git a/libqpdf/QPDFArgParser.cc b/libqpdf/QPDFArgParser.cc index 18cb501..3ec6cad 100644 --- a/libqpdf/QPDFArgParser.cc +++ b/libqpdf/QPDFArgParser.cc @@ -56,7 +56,6 @@ QPDFArgParser::selectOptionTable(std::string const& name) { auto t = m->option_tables.find(name); if (t == m->option_tables.end()) { - QTC::TC("libtests", "QPDFArgParser select unregistered table"); throw std::logic_error("QPDFArgParser: selecting unregistered option table " + name); } m->option_table = &(t->second); @@ -67,7 +66,6 @@ void QPDFArgParser::registerOptionTable(std::string const& name, bare_arg_handler_t end_handler) { if (m->option_tables.contains(name)) { - QTC::TC("libtests", "QPDFArgParser register registered table"); throw std::logic_error( "QPDFArgParser: registering already registered option table " + name); } @@ -80,7 +78,6 @@ QPDFArgParser::OptionEntry& QPDFArgParser::registerArg(std::string const& arg) { if (m->option_table->contains(arg)) { - QTC::TC("libtests", "QPDFArgParser duplicate handler"); throw std::logic_error( "QPDFArgParser: adding a duplicate handler for option " + arg + " in " + m->option_table_name + " option table"); @@ -138,7 +135,6 @@ QPDFArgParser::addInvalidChoiceHandler(std::string const& arg, param_arg_handler { auto i = m->option_table->find(arg); if (i == m->option_table->end()) { - QTC::TC("libtests", "QPDFArgParser invalid choice handler to unknown"); throw std::logic_error( "QPDFArgParser: attempt to add invalid choice handler to unknown argument"); } @@ -448,11 +444,9 @@ QPDFArgParser::parseArgs() // Special case for -- option, which is used to break out of subparsers. oep = m->option_table->find("--"); end_option = true; - if (oep == m->option_table->end()) { - // This is registered automatically, so this can't happen. - throw std::logic_error("QPDFArgParser: -- handler not registered"); - } - } else if ((arg[0] == '-') && (strcmp(arg, "-") != 0)) { + util::internal_error_if( + oep == m->option_table->end(), "QPDFArgParser: -- handler not registered"); + } else if (arg[0] == '-' && strcmp(arg, "-") != 0) { ++arg; if (arg[0] == '-') { // Be lax about -arg vs --arg @@ -678,15 +672,12 @@ QPDFArgParser::addHelpTopic( std::string const& topic, std::string const& short_text, std::string const& long_text) { if (topic == "all") { - QTC::TC("libtests", "QPDFArgParser add reserved help topic"); throw std::logic_error("QPDFArgParser: can't register reserved help topic " + topic); } if (topic.empty() || topic.at(0) == '-') { - QTC::TC("libtests", "QPDFArgParser bad topic for help"); throw std::logic_error("QPDFArgParser: help topics must not start with -"); } if (m->help_topics.contains(topic)) { - QTC::TC("libtests", "QPDFArgParser add existing topic"); throw std::logic_error("QPDFArgParser: topic " + topic + " has already been added"); } @@ -701,17 +692,14 @@ QPDFArgParser::addOptionHelp( std::string const& short_text, std::string const& long_text) { - if (!((option_name.length() > 2) && (option_name.at(0) == '-') && (option_name.at(1) == '-'))) { - QTC::TC("libtests", "QPDFArgParser bad option for help"); + if (!(option_name.length() > 2 && option_name.starts_with("--"))) { throw std::logic_error("QPDFArgParser: options for help must start with --"); } if (m->option_help.contains(option_name)) { - QTC::TC("libtests", "QPDFArgParser duplicate option help"); throw std::logic_error("QPDFArgParser: option " + option_name + " already has help"); } auto ht = m->help_topics.find(topic); if (ht == m->help_topics.end()) { - QTC::TC("libtests", "QPDFArgParser add to unknown topic"); throw std::logic_error( "QPDFArgParser: unable to add option " + option_name + " to unknown help topic " + topic); diff --git a/libqpdf/qpdf/Util.hh b/libqpdf/qpdf/Util.hh index 9e3c499..fa2f419 100644 --- a/libqpdf/qpdf/Util.hh +++ b/libqpdf/qpdf/Util.hh @@ -35,6 +35,14 @@ namespace qpdf::util } } + inline void + no_ci_rt_error_if(bool cond, std::string const& msg) + { + if (cond) { + throw std::runtime_error(msg); + } + } + inline constexpr char hex_decode_char(char digit) { diff --git a/libtests/libtests.testcov b/libtests/libtests.testcov index 2367ff6..f7c2bcf 100644 --- a/libtests/libtests.testcov +++ b/libtests/libtests.testcov @@ -1,9 +1,6 @@ ignored-scope: qpdf Pl_LZWDecoder intermediate reset 0 -Pl_LZWDecoder last was table size 0 Pl_ASCII85Decoder ignore space 0 -Pl_ASCII85Decoder read z 0 -Pl_ASCII85Decoder no-op flush 0 Pl_ASCII85Decoder partial flush 1 bits leftover 1 bits bit_offset 2 @@ -41,22 +38,12 @@ QPDFArgParser read args from stdin 0 QPDFArgParser read args from file 0 QPDFArgParser required choices 0 QPDFArgParser required parameter 0 -QPDFArgParser select unregistered table 0 -QPDFArgParser register registered table 0 -QPDFArgParser duplicate handler 0 QPDFArgParser missing -- 0 QPDFArgParser single dash 0 QPDFArgParser help option 0 QPDFArgParser positional 0 QPDFArgParser unrecognized 0 QPDFArgParser complete choices 0 -QPDFArgParser add reserved help topic 0 -QPDFArgParser add existing topic 0 -QPDFArgParser add to unknown topic 0 -QPDFArgParser duplicate option help 0 -QPDFArgParser bad option for help 0 -QPDFArgParser bad topic for help 0 -QPDFArgParser invalid choice handler to unknown 0 JSON parse junk after object 0 JSON parse invalid keyword 0 JSON parse expected colon 0 diff --git a/libtests/qtest/qutil/qutil.out b/libtests/qtest/qutil/qutil.out index a5f7b10..511a061 100644 --- a/libtests/qtest/qutil/qutil.out +++ b/libtests/qtest/qutil/qutil.out @@ -137,3 +137,8 @@ D:20210209191925Z done ---- memory usage memory usage okay +---- error handlers +caught exception: msg2 +caught exception: INTERNAL ERROR: msg4 +This is a qpdf bug. Please report at https://github.com/qpdf/qpdf/issues +caught exception: msg6 diff --git a/libtests/qutil.cc b/libtests/qutil.cc index 62cd9df..bb3eac2 100644 --- a/libtests/qutil.cc +++ b/libtests/qutil.cc @@ -3,6 +3,8 @@ #include #include #include +#include + #include #include #include @@ -743,6 +745,29 @@ memory_usage_test() std::cout << "memory usage okay" << '\n'; } +void +error_handler_test() +{ + qpdf::util::assertion(true, "msg1"); + try { + qpdf::util::assertion(false, "msg2"); + } catch (std::logic_error const& e) { + std::cout << "caught exception: " << e.what() << '\n'; + } + qpdf::util::internal_error_if(false, "msg3"); + try { + qpdf::util::internal_error_if(true, "msg4"); + } catch (std::logic_error const& e) { + std::cout << "caught exception: " << e.what() << '\n'; + } + qpdf::util::no_ci_rt_error_if(false, "msg5"); + try { + qpdf::util::no_ci_rt_error_if(true, "msg6"); + } catch (std::runtime_error const& e) { + std::cout << "caught exception: " << e.what() << '\n'; + } +} + int main(int argc, char* argv[]) { @@ -782,6 +807,8 @@ main(int argc, char* argv[]) is_long_long_test(); std::cout << "---- memory usage" << '\n'; memory_usage_test(); + std::cout << "---- error handlers" << '\n'; + error_handler_test(); } catch (std::exception& e) { std::cout << "unexpected exception: " << e.what() << '\n'; }