Commit 5f3f78822b5d43e9b02082da5268d186ba7101c0
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
Showing
14 changed files
with
54 additions
and
23 deletions
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, |
TODO
| 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<X>(); X* x = x_ph.get(); | @@ -364,6 +367,13 @@ auto x_ph = std::make_shared<X>(); 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& pdf, QPDFWriter& w) | @@ -3379,7 +3379,7 @@ QPDFJob::setEncryptionOptions(QPDF& pdf, QPDFWriter& 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& str, int objid, int generation) | @@ -1211,7 +1211,7 @@ QPDF::decryptString(std::string& 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& str) | @@ -744,6 +744,16 @@ QUtil::make_shared_cstr(std::string const& 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); |