Commit 5f3f78822b5d43e9b02082da5268d186ba7101c0

Authored by Jay Berkenbilt
1 parent 88c3d556

Improve use of std::unique_ptr

* Use unique_ptr in place of shared_ptr in some cases
* unique_ptr for arrays does not require a custom deleter
* use std::make_unique (c++14) where possible
ChangeLog
  1 +2022-02-05 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add QUtil::make_unique_cstr to return a std::unique_ptr<char[]>
  4 + as an alternative to QUtil::copy_string and
  5 + QUtil::make_shared_cstr.
  6 +
1 2022-02-04 Jay Berkenbilt <ejb@ql.org> 7 2022-02-04 Jay Berkenbilt <ejb@ql.org>
2 8
3 * New preprocessor symbols QPDF_MAJOR_VERSION, QPDF_MINOR_VERSION, 9 * New preprocessor symbols QPDF_MAJOR_VERSION, QPDF_MINOR_VERSION,
1 10.6 1 10.6
2 ==== 2 ====
3 3
  4 +* Expose emptyPDF to the C API. Ensure that qpdf_get_qpdf_version is
  5 + always static.
  6 +
4 * Consider doing one big commit to reformat the entire codebase using 7 * Consider doing one big commit to reformat the entire codebase using
5 clang-format or a similar tool. Consider using blame.ignoreRevsFile 8 clang-format or a similar tool. Consider using blame.ignoreRevsFile
6 or similar (or otherwise study git blame to see how to minimize the 9 or similar (or otherwise study git blame to see how to minimize the
@@ -364,6 +367,13 @@ auto x_ph = std::make_shared&lt;X&gt;(); X* x = x_ph.get(); @@ -364,6 +367,13 @@ auto x_ph = std::make_shared&lt;X&gt;(); X* x = x_ph.get();
364 Derived* x = new Derived(); PointerHolder<Base> x_ph(x) --> 367 Derived* x = new Derived(); PointerHolder<Base> x_ph(x) -->
365 Derived* x = new Derived(); auto x_ph = std::shared_pointer<Base>(x); 368 Derived* x = new Derived(); auto x_ph = std::shared_pointer<Base>(x);
366 369
  370 +Also remember
  371 +
  372 +auto x = std::shared_ptr(new T[5], std::default_delete<T[]>())
  373 +vs.
  374 +auto x = std::make_unique<T[]>(5)
  375 +
  376 +
367 PointerHolder in public API: 377 PointerHolder in public API:
368 378
369 QUtil::read_file_into_memory( 379 QUtil::read_file_into_memory(
include/qpdf/QUtil.hh
@@ -161,6 +161,10 @@ namespace QUtil @@ -161,6 +161,10 @@ namespace QUtil
161 QPDF_DLL 161 QPDF_DLL
162 std::shared_ptr<char> make_shared_cstr(std::string const&); 162 std::shared_ptr<char> make_shared_cstr(std::string const&);
163 163
  164 + // Copy string as a unique_ptr to an array.
  165 + QPDF_DLL
  166 + std::unique_ptr<char[]> make_unique_cstr(std::string const&);
  167 +
164 // Returns lower-case hex-encoded version of the string, treating 168 // Returns lower-case hex-encoded version of the string, treating
165 // each character in the input string as unsigned. The output 169 // each character in the input string as unsigned. The output
166 // string will be twice as long as the input string. 170 // string will be twice as long as the input string.
libqpdf/AES_PDF_native.cc
@@ -19,12 +19,8 @@ AES_PDF_native::AES_PDF_native(bool encrypt, unsigned char const* key, @@ -19,12 +19,8 @@ AES_PDF_native::AES_PDF_native(bool encrypt, unsigned char const* key,
19 nrounds(0) 19 nrounds(0)
20 { 20 {
21 size_t keybits = 8 * key_bytes; 21 size_t keybits = 8 * key_bytes;
22 - this->key = std::unique_ptr<unsigned char[]>(  
23 - new unsigned char[key_bytes],  
24 - std::default_delete<unsigned char[]>());  
25 - this->rk = std::unique_ptr<uint32_t[]>(  
26 - new uint32_t[RKLENGTH(keybits)],  
27 - std::default_delete<uint32_t[]>()); 22 + this->key = std::make_unique<unsigned char[]>(key_bytes);
  23 + this->rk = std::make_unique<uint32_t[]>(RKLENGTH(keybits));
28 size_t rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t); 24 size_t rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t);
29 std::memcpy(this->key.get(), key, key_bytes); 25 std::memcpy(this->key.get(), key, key_bytes);
30 std::memset(this->rk.get(), 0, rk_bytes); 26 std::memset(this->rk.get(), 0, rk_bytes);
libqpdf/Pl_AES_PDF.cc
@@ -25,9 +25,7 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, @@ -25,9 +25,7 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next,
25 use_specified_iv(false), 25 use_specified_iv(false),
26 disable_padding(false) 26 disable_padding(false)
27 { 27 {
28 - this->key = std::unique_ptr<unsigned char[]>(  
29 - new unsigned char[key_bytes],  
30 - std::default_delete<unsigned char[]>()); 28 + this->key = std::make_unique<unsigned char[]>(key_bytes);
31 std::memcpy(this->key.get(), key, key_bytes); 29 std::memcpy(this->key.get(), key, key_bytes);
32 std::memset(this->inbuf, 0, this->buf_size); 30 std::memset(this->inbuf, 0, this->buf_size);
33 std::memset(this->outbuf, 0, this->buf_size); 31 std::memset(this->outbuf, 0, this->buf_size);
libqpdf/QPDFArgParser.cc
@@ -20,7 +20,7 @@ QPDFArgParser::Members::Members( @@ -20,7 +20,7 @@ QPDFArgParser::Members::Members(
20 option_table(nullptr), 20 option_table(nullptr),
21 final_check_handler(nullptr) 21 final_check_handler(nullptr)
22 { 22 {
23 - auto tmp = QUtil::make_shared_cstr(argv[0]); 23 + auto tmp = QUtil::make_unique_cstr(argv[0]);
24 char* p = QUtil::getWhoami(tmp.get()); 24 char* p = QUtil::getWhoami(tmp.get());
25 // Remove prefix added by libtool for consistency during testing. 25 // Remove prefix added by libtool for consistency during testing.
26 if (strncmp(p, "lt-", 3) == 0) 26 if (strncmp(p, "lt-", 3) == 0)
libqpdf/QPDFJob.cc
@@ -3379,7 +3379,7 @@ QPDFJob::setEncryptionOptions(QPDF&amp; pdf, QPDFWriter&amp; w) @@ -3379,7 +3379,7 @@ QPDFJob::setEncryptionOptions(QPDF&amp; pdf, QPDFWriter&amp; w)
3379 static void parse_version(std::string const& full_version_string, 3379 static void parse_version(std::string const& full_version_string,
3380 std::string& version, int& extension_level) 3380 std::string& version, int& extension_level)
3381 { 3381 {
3382 - auto vp = QUtil::make_shared_cstr(full_version_string); 3382 + auto vp = QUtil::make_unique_cstr(full_version_string);
3383 char* v = vp.get(); 3383 char* v = vp.get();
3384 char* p1 = strchr(v, '.'); 3384 char* p1 = strchr(v, '.');
3385 char* p2 = (p1 ? strchr(1 + p1, '.') : 0); 3385 char* p2 = (p1 ? strchr(1 + p1, '.') : 0);
libqpdf/QPDFWriter.cc
@@ -1919,7 +1919,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level, @@ -1919,7 +1919,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
1919 } 1919 }
1920 else 1920 else
1921 { 1921 {
1922 - auto tmp_ph = QUtil::make_shared_cstr(val); 1922 + auto tmp_ph = QUtil::make_unique_cstr(val);
1923 char* tmp = tmp_ph.get(); 1923 char* tmp = tmp_ph.get();
1924 size_t vlen = val.length(); 1924 size_t vlen = val.length();
1925 RC4 rc4(QUtil::unsigned_char_pointer(this->m->cur_data_key), 1925 RC4 rc4(QUtil::unsigned_char_pointer(this->m->cur_data_key),
libqpdf/QPDF_encryption.cc
@@ -1211,7 +1211,7 @@ QPDF::decryptString(std::string&amp; str, int objid, int generation) @@ -1211,7 +1211,7 @@ QPDF::decryptString(std::string&amp; str, int objid, int generation)
1211 size_t vlen = str.length(); 1211 size_t vlen = str.length();
1212 // Using PointerHolder guarantees that tmp will 1212 // Using PointerHolder guarantees that tmp will
1213 // be freed even if rc4.process throws an exception. 1213 // be freed even if rc4.process throws an exception.
1214 - auto tmp = QUtil::make_shared_cstr(str); 1214 + auto tmp = QUtil::make_unique_cstr(str);
1215 RC4 rc4(QUtil::unsigned_char_pointer(key), toI(key.length())); 1215 RC4 rc4(QUtil::unsigned_char_pointer(key), toI(key.length()));
1216 rc4.process(QUtil::unsigned_char_pointer(tmp.get()), vlen); 1216 rc4.process(QUtil::unsigned_char_pointer(tmp.get()), vlen);
1217 str = std::string(tmp.get(), vlen); 1217 str = std::string(tmp.get(), vlen);
libqpdf/QUtil.cc
@@ -744,6 +744,16 @@ QUtil::make_shared_cstr(std::string const&amp; str) @@ -744,6 +744,16 @@ QUtil::make_shared_cstr(std::string const&amp; str)
744 return result; 744 return result;
745 } 745 }
746 746
  747 +std::unique_ptr<char[]>
  748 +QUtil::make_unique_cstr(std::string const& str)
  749 +{
  750 + auto result = std::make_unique<char[]>(str.length() + 1);
  751 + // Use memcpy in case string contains nulls
  752 + result.get()[str.length()] = '\0';
  753 + memcpy(result.get(), str.c_str(), str.length());
  754 + return result;
  755 +}
  756 +
747 std::string 757 std::string
748 QUtil::hex_encode(std::string const& input) 758 QUtil::hex_encode(std::string const& input)
749 { 759 {
@@ -2625,7 +2635,7 @@ call_main_from_wmain(bool, int argc, wchar_t const* const argv[], @@ -2625,7 +2635,7 @@ call_main_from_wmain(bool, int argc, wchar_t const* const argv[],
2625 // other systems. That way the rest of qpdf.cc can just act like 2635 // other systems. That way the rest of qpdf.cc can just act like
2626 // arguments are UTF-8. 2636 // arguments are UTF-8.
2627 2637
2628 - std::vector<std::shared_ptr<char>> utf8_argv; 2638 + std::vector<std::unique_ptr<char[]>> utf8_argv;
2629 for (int i = 0; i < argc; ++i) 2639 for (int i = 0; i < argc; ++i)
2630 { 2640 {
2631 std::string utf16; 2641 std::string utf16;
@@ -2638,11 +2648,9 @@ call_main_from_wmain(bool, int argc, wchar_t const* const argv[], @@ -2638,11 +2648,9 @@ call_main_from_wmain(bool, int argc, wchar_t const* const argv[],
2638 QIntC::to_uchar(codepoint & 0xff))); 2648 QIntC::to_uchar(codepoint & 0xff)));
2639 } 2649 }
2640 std::string utf8 = QUtil::utf16_to_utf8(utf16); 2650 std::string utf8 = QUtil::utf16_to_utf8(utf16);
2641 - utf8_argv.push_back(QUtil::make_shared_cstr(utf8)); 2651 + utf8_argv.push_back(QUtil::make_unique_cstr(utf8));
2642 } 2652 }
2643 - auto utf8_argv_sp =  
2644 - std::shared_ptr<char*>(  
2645 - new char*[1+utf8_argv.size()], std::default_delete<char*[]>()); 2653 + auto utf8_argv_sp = std::make_unique<char*[]>(1+utf8_argv.size());
2646 char** new_argv = utf8_argv_sp.get(); 2654 char** new_argv = utf8_argv_sp.get();
2647 for (size_t i = 0; i < utf8_argv.size(); ++i) 2655 for (size_t i = 0; i < utf8_argv.size(); ++i)
2648 { 2656 {
libqpdf/qpdfjob-c.cc
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 9
10 int qpdfjob_run_from_argv(char const* const argv[]) 10 int qpdfjob_run_from_argv(char const* const argv[])
11 { 11 {
12 - auto whoami_p = QUtil::make_shared_cstr(argv[0]); 12 + auto whoami_p = QUtil::make_unique_cstr(argv[0]);
13 auto whoami = QUtil::getWhoami(whoami_p.get()); 13 auto whoami = QUtil::getWhoami(whoami_p.get());
14 QUtil::setLineBuf(stdout); 14 QUtil::setLineBuf(stdout);
15 15
libtests/qtest/qutil/qutil.out
@@ -23,6 +23,7 @@ one @@ -23,6 +23,7 @@ one
23 7 23 7
24 compare okay 24 compare okay
25 compare okay 25 compare okay
  26 +compare okay
26 -2147483648 to int: PASSED 27 -2147483648 to int: PASSED
27 2147483647 to int: PASSED 28 2147483647 to int: PASSED
28 2147483648 to int threw (integer out of range converting 2147483648 from a 8-byte signed type to a 4-byte signed type): PASSED 29 2147483648 to int threw (integer out of range converting 2147483648 from a 8-byte signed type to a 4-byte signed type): PASSED
libtests/qutil.cc
@@ -150,7 +150,7 @@ void string_conversion_test() @@ -150,7 +150,7 @@ void string_conversion_test()
150 std::cout << "compare failed" << std::endl; 150 std::cout << "compare failed" << std::endl;
151 } 151 }
152 delete [] tmp; 152 delete [] tmp;
153 - // Also test with make_shared_cstr 153 + // Also test with make_shared_cstr and make_unique_cstr
154 auto tmp2 = QUtil::make_shared_cstr(embedded_null); 154 auto tmp2 = QUtil::make_shared_cstr(embedded_null);
155 if (memcmp(tmp2.get(), embedded_null.c_str(), 7) == 0) 155 if (memcmp(tmp2.get(), embedded_null.c_str(), 7) == 0)
156 { 156 {
@@ -160,6 +160,15 @@ void string_conversion_test() @@ -160,6 +160,15 @@ void string_conversion_test()
160 { 160 {
161 std::cout << "compare failed" << std::endl; 161 std::cout << "compare failed" << std::endl;
162 } 162 }
  163 + auto tmp3 = QUtil::make_unique_cstr(embedded_null);
  164 + if (memcmp(tmp3.get(), embedded_null.c_str(), 7) == 0)
  165 + {
  166 + std::cout << "compare okay" << std::endl;
  167 + }
  168 + else
  169 + {
  170 + std::cout << "compare failed" << std::endl;
  171 + }
163 172
164 std::string int_max_str = QUtil::int_to_string(INT_MAX); 173 std::string int_max_str = QUtil::int_to_string(INT_MAX);
165 std::string int_min_str = QUtil::int_to_string(INT_MIN); 174 std::string int_min_str = QUtil::int_to_string(INT_MIN);
@@ -417,7 +426,7 @@ void transcoding_test() @@ -417,7 +426,7 @@ void transcoding_test()
417 426
418 void print_whoami(char const* str) 427 void print_whoami(char const* str)
419 { 428 {
420 - auto dup = QUtil::make_shared_cstr(str); 429 + auto dup = QUtil::make_unique_cstr(str);
421 std::cout << QUtil::getWhoami(dup.get()) << std::endl; 430 std::cout << QUtil::getWhoami(dup.get()) << std::endl;
422 } 431 }
423 432
libtests/rc4.cc
@@ -14,8 +14,7 @@ static void other_tests() @@ -14,8 +14,7 @@ static void other_tests()
14 // Test cases not covered by the pipeline: string as key, convert 14 // Test cases not covered by the pipeline: string as key, convert
15 // in place 15 // in place
16 RC4 r(reinterpret_cast<unsigned char const*>("quack")); 16 RC4 r(reinterpret_cast<unsigned char const*>("quack"));
17 - auto data = std::unique_ptr<unsigned char[]>(  
18 - new unsigned char[6], std::default_delete<unsigned char[]>()); 17 + auto data = std::make_unique<unsigned char[]>(6);
19 memcpy(data.get(), "potato", 6); 18 memcpy(data.get(), "potato", 6);
20 r.process(data.get(), 6); 19 r.process(data.get(), 6);
21 assert(memcmp(data.get(), "\xa5\x6f\xe7\x27\x2b\x5c", 6) == 0); 20 assert(memcmp(data.get(), "\xa5\x6f\xe7\x27\x2b\x5c", 6) == 0);