Commit e1e62e610ff8d09e4a7e14caa4fd87fb6b2e2ba9

Authored by m-holger
1 parent 90cb87f9

Refactor error handling and simplify logic across multiple pipelines

- Replace `std::logic_error` and `std::runtime_error` with `util::assertion` and `util::no_ci_rt_error_if` for consistent error handling.
libqpdf/InputSource.cc
@@ -2,10 +2,13 @@ @@ -2,10 +2,13 @@
2 2
3 #include <qpdf/QIntC.hh> 3 #include <qpdf/QIntC.hh>
4 #include <qpdf/QTC.hh> 4 #include <qpdf/QTC.hh>
  5 +#include <qpdf/Util.hh>
  6 +
5 #include <cstring> 7 #include <cstring>
6 #include <stdexcept> 8 #include <stdexcept>
7 9
8 using namespace std::literals; 10 using namespace std::literals;
  11 +using namespace qpdf;
9 12
10 void 13 void
11 InputSource::setLastOffset(qpdf_offset_t offset) 14 InputSource::setLastOffset(qpdf_offset_t offset)
@@ -73,10 +76,10 @@ InputSource::findFirst(char const* start_chars, qpdf_offset_t offset, size_t len @@ -73,10 +76,10 @@ InputSource::findFirst(char const* start_chars, qpdf_offset_t offset, size_t len
73 // To enable us to guarantee null-termination, save an extra byte so that buf[size] is valid 76 // To enable us to guarantee null-termination, save an extra byte so that buf[size] is valid
74 // memory. 77 // memory.
75 size_t size = sizeof(buf) - 1; 78 size_t size = sizeof(buf) - 1;
76 - if ((strlen(start_chars) < 1) || (strlen(start_chars) > size)) {  
77 - throw std::logic_error(  
78 - "InputSource::findSource called with too small or too large of a character sequence");  
79 - } 79 + util::assertion(
  80 + !(strlen(start_chars) < 1 || strlen(start_chars) > size),
  81 + "InputSource::findSource called with too small or too large of a character sequence" //
  82 + );
80 83
81 char* p = nullptr; 84 char* p = nullptr;
82 qpdf_offset_t buf_offset = offset; 85 qpdf_offset_t buf_offset = offset;
@@ -155,7 +158,6 @@ InputSource::findFirst(char const* start_chars, qpdf_offset_t offset, size_t len @@ -155,7 +158,6 @@ InputSource::findFirst(char const* start_chars, qpdf_offset_t offset, size_t len
155 p = buf + bytes_read; 158 p = buf + bytes_read;
156 } 159 }
157 } 160 }
158 - throw std::logic_error("InputSource after while (true)");  
159 } 161 }
160 162
161 bool 163 bool
libqpdf/OffsetInputSource.cc
1 #include <qpdf/OffsetInputSource.hh> 1 #include <qpdf/OffsetInputSource.hh>
2 2
  3 +#include <qpdf/Util.hh>
  4 +
3 #include <limits> 5 #include <limits>
4 #include <sstream> 6 #include <sstream>
5 #include <stdexcept> 7 #include <stdexcept>
6 8
  9 +using namespace qpdf;
  10 +
7 OffsetInputSource::OffsetInputSource( 11 OffsetInputSource::OffsetInputSource(
8 std::shared_ptr<InputSource> proxied, qpdf_offset_t global_offset) : 12 std::shared_ptr<InputSource> proxied, qpdf_offset_t global_offset) :
9 proxied(proxied), 13 proxied(proxied),
10 global_offset(global_offset) 14 global_offset(global_offset)
11 { 15 {
12 - if (global_offset < 0) {  
13 - throw std::logic_error("OffsetInputSource constructed with negative offset");  
14 - }  
15 - this->max_safe_offset = std::numeric_limits<qpdf_offset_t>::max() - global_offset; 16 + util::assertion(global_offset >= 0, "OffsetInputSource constructed with negative offset");
  17 + max_safe_offset = std::numeric_limits<qpdf_offset_t>::max() - global_offset;
16 } 18 }
17 19
18 qpdf_offset_t 20 qpdf_offset_t
19 OffsetInputSource::findAndSkipNextEOL() 21 OffsetInputSource::findAndSkipNextEOL()
20 { 22 {
21 - return this->proxied->findAndSkipNextEOL() - this->global_offset; 23 + return proxied->findAndSkipNextEOL() - global_offset;
22 } 24 }
23 25
24 std::string const& 26 std::string const&
25 OffsetInputSource::getName() const 27 OffsetInputSource::getName() const
26 { 28 {
27 - return this->proxied->getName(); 29 + return proxied->getName();
28 } 30 }
29 31
30 qpdf_offset_t 32 qpdf_offset_t
31 OffsetInputSource::tell() 33 OffsetInputSource::tell()
32 { 34 {
33 - return this->proxied->tell() - this->global_offset; 35 + return proxied->tell() - global_offset;
34 } 36 }
35 37
36 void 38 void
37 OffsetInputSource::seek(qpdf_offset_t offset, int whence) 39 OffsetInputSource::seek(qpdf_offset_t offset, int whence)
38 { 40 {
39 if (whence == SEEK_SET) { 41 if (whence == SEEK_SET) {
40 - if (offset > this->max_safe_offset) { 42 + if (offset > max_safe_offset) {
41 std::ostringstream msg; 43 std::ostringstream msg;
42 msg.imbue(std::locale::classic()); 44 msg.imbue(std::locale::classic());
43 msg << "seeking to " << offset << " offset by " << global_offset 45 msg << "seeking to " << offset << " offset by " << global_offset
44 << " would cause an overflow of the offset type"; 46 << " would cause an overflow of the offset type";
45 throw std::range_error(msg.str()); 47 throw std::range_error(msg.str());
46 } 48 }
47 - this->proxied->seek(offset + global_offset, whence); 49 + proxied->seek(offset + global_offset, whence);
48 } else { 50 } else {
49 - this->proxied->seek(offset, whence);  
50 - }  
51 - if (tell() < 0) {  
52 - throw std::runtime_error("offset input source: seek before beginning of file"); 51 + proxied->seek(offset, whence);
53 } 52 }
  53 + util::no_ci_rt_error_if(tell() < 0, "offset input source: seek before beginning of file");
54 } 54 }
55 55
56 void 56 void
@@ -62,13 +62,13 @@ OffsetInputSource::rewind() @@ -62,13 +62,13 @@ OffsetInputSource::rewind()
62 size_t 62 size_t
63 OffsetInputSource::read(char* buffer, size_t length) 63 OffsetInputSource::read(char* buffer, size_t length)
64 { 64 {
65 - size_t result = this->proxied->read(buffer, length);  
66 - this->setLastOffset(this->proxied->getLastOffset() - global_offset); 65 + size_t result = proxied->read(buffer, length);
  66 + setLastOffset(proxied->getLastOffset() - global_offset);
67 return result; 67 return result;
68 } 68 }
69 69
70 void 70 void
71 OffsetInputSource::unreadCh(char ch) 71 OffsetInputSource::unreadCh(char ch)
72 { 72 {
73 - this->proxied->unreadCh(ch); 73 + proxied->unreadCh(ch);
74 } 74 }
libqpdf/Pl_PNGFilter.cc
@@ -2,11 +2,14 @@ @@ -2,11 +2,14 @@
2 2
3 #include <qpdf/QTC.hh> 3 #include <qpdf/QTC.hh>
4 #include <qpdf/QUtil.hh> 4 #include <qpdf/QUtil.hh>
  5 +#include <qpdf/Util.hh>
5 6
6 #include <climits> 7 #include <climits>
7 #include <cstring> 8 #include <cstring>
8 #include <stdexcept> 9 #include <stdexcept>
9 10
  11 +using namespace qpdf;
  12 +
10 namespace 13 namespace
11 { 14 {
12 unsigned long long memory_limit{0}; 15 unsigned long long memory_limit{0};
@@ -28,25 +31,19 @@ Pl_PNGFilter::Pl_PNGFilter( @@ -28,25 +31,19 @@ Pl_PNGFilter::Pl_PNGFilter(
28 Pipeline(identifier, next), 31 Pipeline(identifier, next),
29 action(action) 32 action(action)
30 { 33 {
31 - if (!next) {  
32 - throw std::logic_error("Attempt to create Pl_PNGFilter with nullptr as next");  
33 - }  
34 - if (samples_per_pixel < 1) {  
35 - throw std::runtime_error("PNGFilter created with invalid samples_per_pixel");  
36 - }  
37 - if (!((bits_per_sample == 1) || (bits_per_sample == 2) || (bits_per_sample == 4) ||  
38 - (bits_per_sample == 8) || (bits_per_sample == 16))) {  
39 - throw std::runtime_error(  
40 - "PNGFilter created with invalid bits_per_sample not 1, 2, 4, 8, or 16");  
41 - } 34 + util::assertion(next, "Attempt to create Pl_PNGFilter with nullptr as next");
  35 + util::no_ci_rt_error_if(
  36 + samples_per_pixel < 1, "PNGFilter created with invalid samples_per_pixel");
  37 + util::no_ci_rt_error_if(
  38 + !(bits_per_sample == 1 || bits_per_sample == 2 || bits_per_sample == 4 ||
  39 + bits_per_sample == 8 || bits_per_sample == 16),
  40 + "PNGFilter created with invalid bits_per_sample not 1, 2, 4, 8, or 16");
42 bytes_per_pixel = ((bits_per_sample * samples_per_pixel) + 7) / 8; 41 bytes_per_pixel = ((bits_per_sample * samples_per_pixel) + 7) / 8;
43 unsigned long long bpr = ((columns * bits_per_sample * samples_per_pixel) + 7) / 8; 42 unsigned long long bpr = ((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
44 - if ((bpr == 0) || (bpr > (UINT_MAX - 1))) {  
45 - throw std::runtime_error("PNGFilter created with invalid columns value");  
46 - }  
47 - if (memory_limit > 0 && bpr > (memory_limit / 2U)) {  
48 - throw std::runtime_error("PNGFilter memory limit exceeded");  
49 - } 43 + util::no_ci_rt_error_if(
  44 + bpr == 0 || bpr > (UINT_MAX - 1), "PNGFilter created with invalid columns value");
  45 + util::no_ci_rt_error_if(
  46 + memory_limit > 0 && bpr > (memory_limit / 2U), "PNGFilter memory limit exceeded");
50 bytes_per_row = bpr & UINT_MAX; 47 bytes_per_row = bpr & UINT_MAX;
51 buf1 = QUtil::make_shared_array<unsigned char>(bytes_per_row + 1); 48 buf1 = QUtil::make_shared_array<unsigned char>(bytes_per_row + 1);
52 buf2 = QUtil::make_shared_array<unsigned char>(bytes_per_row + 1); 49 buf2 = QUtil::make_shared_array<unsigned char>(bytes_per_row + 1);
libqpdf/Pl_RunLength.cc
1 #include <qpdf/Pl_RunLength.hh> 1 #include <qpdf/Pl_RunLength.hh>
2 2
3 #include <qpdf/QTC.hh> 3 #include <qpdf/QTC.hh>
4 -#include <qpdf/QUtil.hh> 4 +#include <qpdf/Util.hh>
  5 +
  6 +using namespace qpdf;
5 7
6 namespace 8 namespace
7 { 9 {
@@ -29,9 +31,7 @@ Pl_RunLength::Pl_RunLength(char const* identifier, Pipeline* next, action_e acti @@ -29,9 +31,7 @@ Pl_RunLength::Pl_RunLength(char const* identifier, Pipeline* next, action_e acti
29 Pipeline(identifier, next), 31 Pipeline(identifier, next),
30 m(std::make_unique<Members>(action)) 32 m(std::make_unique<Members>(action))
31 { 33 {
32 - if (!next) {  
33 - throw std::logic_error("Attempt to create Pl_RunLength with nullptr as next");  
34 - } 34 + util::assertion(next, "Attempt to create Pl_RunLength with nullptr as next");
35 } 35 }
36 36
37 void 37 void
@@ -40,10 +40,7 @@ Pl_RunLength::setMemoryLimit(unsigned long long limit) @@ -40,10 +40,7 @@ Pl_RunLength::setMemoryLimit(unsigned long long limit)
40 memory_limit = limit; 40 memory_limit = limit;
41 } 41 }
42 42
43 -Pl_RunLength::~Pl_RunLength() // NOLINT (modernize-use-equals-default)  
44 -{  
45 - // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer  
46 -} 43 +Pl_RunLength::~Pl_RunLength() = default;
47 44
48 void 45 void
49 Pl_RunLength::write(unsigned char const* data, size_t len) 46 Pl_RunLength::write(unsigned char const* data, size_t len)
@@ -59,12 +56,12 @@ void @@ -59,12 +56,12 @@ void
59 Pl_RunLength::encode(unsigned char const* data, size_t len) 56 Pl_RunLength::encode(unsigned char const* data, size_t len)
60 { 57 {
61 for (size_t i = 0; i < len; ++i) { 58 for (size_t i = 0; i < len; ++i) {
62 - if ((m->state == st_top) != (m->length <= 1)) {  
63 - throw std::logic_error("Pl_RunLength::encode: state/length inconsistency");  
64 - } 59 + util::assertion(
  60 + (m->state == st_top) == (m->length <= 1),
  61 + "Pl_RunLength::encode: state/length inconsistency");
65 unsigned char ch = data[i]; 62 unsigned char ch = data[i];
66 - if ((m->length > 0) && ((m->state == st_copying) || (m->length < 128)) &&  
67 - (ch == m->buf[m->length - 1])) { 63 + if (m->length > 0 && (m->state == st_copying || m->length < 128) &&
  64 + ch == m->buf[m->length - 1]) {
68 QTC::TC("libtests", "Pl_RunLength: switch to run", (m->length == 128) ? 0 : 1); 65 QTC::TC("libtests", "Pl_RunLength: switch to run", (m->length == 128) ? 0 : 1);
69 if (m->state == st_copying) { 66 if (m->state == st_copying) {
70 --m->length; 67 --m->length;
@@ -76,7 +73,7 @@ Pl_RunLength::encode(unsigned char const* data, size_t len) @@ -76,7 +73,7 @@ Pl_RunLength::encode(unsigned char const* data, size_t len)
76 m->buf[m->length] = ch; 73 m->buf[m->length] = ch;
77 ++m->length; 74 ++m->length;
78 } else { 75 } else {
79 - if ((m->length == 128) || (m->state == st_run)) { 76 + if (m->length == 128 || m->state == st_run) {
80 flush_encode(); 77 flush_encode();
81 } else if (m->length > 0) { 78 } else if (m->length > 0) {
82 m->state = st_copying; 79 m->state = st_copying;
@@ -90,9 +87,8 @@ Pl_RunLength::encode(unsigned char const* data, size_t len) @@ -90,9 +87,8 @@ Pl_RunLength::encode(unsigned char const* data, size_t len)
90 void 87 void
91 Pl_RunLength::decode(unsigned char const* data, size_t len) 88 Pl_RunLength::decode(unsigned char const* data, size_t len)
92 { 89 {
93 - if (memory_limit && (len + m->out.size()) > memory_limit) {  
94 - throw std::runtime_error("Pl_RunLength memory limit exceeded");  
95 - } 90 + util::no_ci_rt_error_if(
  91 + memory_limit && (len + m->out.size()) > memory_limit, "Pl_RunLength memory limit exceeded");
96 m->out.reserve(len); 92 m->out.reserve(len);
97 for (size_t i = 0; i < len; ++i) { 93 for (size_t i = 0; i < len; ++i) {
98 unsigned char const& ch = data[i]; 94 unsigned char const& ch = data[i];
@@ -142,9 +138,9 @@ Pl_RunLength::flush_encode() @@ -142,9 +138,9 @@ Pl_RunLength::flush_encode()
142 QTC::TC("libtests", "Pl_RunLength flush empty buffer"); 138 QTC::TC("libtests", "Pl_RunLength flush empty buffer");
143 } 139 }
144 if (m->state == st_run) { 140 if (m->state == st_run) {
145 - if ((m->length < 2) || (m->length > 128)) {  
146 - throw std::logic_error("Pl_RunLength: invalid length in flush_encode for run");  
147 - } 141 + util::assertion(
  142 + !(m->length < 2 || m->length > 128),
  143 + "Pl_RunLength: invalid length in flush_encode for run");
148 auto ch = static_cast<unsigned char>(257 - m->length); 144 auto ch = static_cast<unsigned char>(257 - m->length);
149 next()->write(&ch, 1); 145 next()->write(&ch, 1);
150 next()->write(&m->buf[0], 1); 146 next()->write(&m->buf[0], 1);
libqpdf/Pl_StdioFile.cc
@@ -3,9 +3,13 @@ @@ -3,9 +3,13 @@
3 #include <qpdf/Pl_StdioFile.hh> 3 #include <qpdf/Pl_StdioFile.hh>
4 4
5 #include <qpdf/QUtil.hh> 5 #include <qpdf/QUtil.hh>
  6 +#include <qpdf/Util.hh>
  7 +
6 #include <cerrno> 8 #include <cerrno>
7 #include <stdexcept> 9 #include <stdexcept>
8 10
  11 +using namespace qpdf;
  12 +
9 class Pl_StdioFile::Members 13 class Pl_StdioFile::Members
10 { 14 {
11 public: 15 public:
@@ -46,7 +50,7 @@ Pl_StdioFile::write(unsigned char const* buf, size_t len) @@ -46,7 +50,7 @@ Pl_StdioFile::write(unsigned char const* buf, size_t len)
46 void 50 void
47 Pl_StdioFile::finish() 51 Pl_StdioFile::finish()
48 { 52 {
49 - if ((fflush(m->file) == -1) && (errno == EBADF)) {  
50 - throw std::logic_error(this->identifier + ": Pl_StdioFile::finish: stream already closed");  
51 - } 53 + util::assertion(
  54 + !(fflush(m->file) == -1 && errno == EBADF),
  55 + identifier + ": Pl_StdioFile::finish: stream already closed");
52 } 56 }
libqpdf/Pl_TIFFPredictor.cc
@@ -3,10 +3,13 @@ @@ -3,10 +3,13 @@
3 #include <qpdf/BitStream.hh> 3 #include <qpdf/BitStream.hh>
4 #include <qpdf/BitWriter.hh> 4 #include <qpdf/BitWriter.hh>
5 #include <qpdf/QTC.hh> 5 #include <qpdf/QTC.hh>
  6 +#include <qpdf/Util.hh>
6 7
7 #include <climits> 8 #include <climits>
8 #include <stdexcept> 9 #include <stdexcept>
9 10
  11 +using namespace qpdf;
  12 +
10 namespace 13 namespace
11 { 14 {
12 unsigned long long memory_limit{0}; 15 unsigned long long memory_limit{0};
@@ -25,22 +28,17 @@ Pl_TIFFPredictor::Pl_TIFFPredictor( @@ -25,22 +28,17 @@ Pl_TIFFPredictor::Pl_TIFFPredictor(
25 samples_per_pixel(samples_per_pixel), 28 samples_per_pixel(samples_per_pixel),
26 bits_per_sample(bits_per_sample) 29 bits_per_sample(bits_per_sample)
27 { 30 {
28 - if (!next) {  
29 - throw std::logic_error("Attempt to create Pl_TIFFPredictor with nullptr as next");  
30 - }  
31 - if (samples_per_pixel < 1) {  
32 - throw std::runtime_error("TIFFPredictor created with invalid samples_per_pixel");  
33 - }  
34 - if ((bits_per_sample < 1) || (bits_per_sample > (8 * (sizeof(unsigned long long))))) {  
35 - throw std::runtime_error("TIFFPredictor created with invalid bits_per_sample");  
36 - } 31 + util::assertion(next, "Attempt to create Pl_TIFFPredictor with nullptr as next");
  32 + util::no_ci_rt_error_if(
  33 + samples_per_pixel < 1, "TIFFPredictor created with invalid samples_per_pixel");
  34 + util::no_ci_rt_error_if(
  35 + bits_per_sample < 1 || bits_per_sample > (8 * (sizeof(unsigned long long))),
  36 + "TIFFPredictor created with invalid bits_per_sample");
37 unsigned long long bpr = ((columns * bits_per_sample * samples_per_pixel) + 7) / 8; 37 unsigned long long bpr = ((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
38 - if ((bpr == 0) || (bpr > (UINT_MAX - 1))) {  
39 - throw std::runtime_error("TIFFPredictor created with invalid columns value");  
40 - }  
41 - if (memory_limit > 0 && bpr > (memory_limit / 2U)) {  
42 - throw std::runtime_error("TIFFPredictor memory limit exceeded");  
43 - } 38 + util::no_ci_rt_error_if(
  39 + bpr == 0 || bpr > (UINT_MAX - 1), "TIFFPredictor created with invalid columns value");
  40 + util::no_ci_rt_error_if(
  41 + memory_limit > 0 && bpr > (memory_limit / 2U), "TIFFPredictor memory limit exceeded");
44 this->bytes_per_row = bpr & UINT_MAX; 42 this->bytes_per_row = bpr & UINT_MAX;
45 } 43 }
46 44
libqpdf/qpdf/Pl_MD5.hh
@@ -3,12 +3,11 @@ @@ -3,12 +3,11 @@
3 3
4 #include <qpdf/MD5.hh> 4 #include <qpdf/MD5.hh>
5 #include <qpdf/Pipeline.hh> 5 #include <qpdf/Pipeline.hh>
6 -  
7 -#include <stdexcept> 6 +#include <qpdf/Util.hh>
8 7
9 // This pipeline sends its output to its successor unmodified. After calling finish, the MD5 8 // This pipeline sends its output to its successor unmodified. After calling finish, the MD5
10 // checksum of the data that passed through the pipeline is available. 9 // checksum of the data that passed through the pipeline is available.
11 - 10 +//
12 // This pipeline is reusable; i.e., it is safe to call write() after calling finish(). The first 11 // This pipeline is reusable; i.e., it is safe to call write() after calling finish(). The first
13 // call to write() after a call to finish() initializes a new MD5 object. 12 // call to write() after a call to finish() initializes a new MD5 object.
14 class Pl_MD5 final: public Pipeline 13 class Pl_MD5 final: public Pipeline
@@ -34,9 +33,7 @@ class Pl_MD5 final: public Pipeline @@ -34,9 +33,7 @@ class Pl_MD5 final: public Pipeline
34 std::string 33 std::string
35 getHexDigest() 34 getHexDigest()
36 { 35 {
37 - if (!enabled) {  
38 - throw std::logic_error("digest requested for a disabled MD5 Pipeline");  
39 - } 36 + qpdf::util::assertion(enabled, "digest requested for a disabled MD5 Pipeline");
40 in_progress = false; 37 in_progress = false;
41 return md5.unparse(); 38 return md5.unparse();
42 } 39 }