2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 10:58:58 +00:00

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
This commit is contained in:
Jay Berkenbilt 2022-02-05 08:15:07 -05:00
parent 88c3d556d5
commit 5f3f78822b
14 changed files with 54 additions and 23 deletions

View File

@ -1,3 +1,9 @@
2022-02-05 Jay Berkenbilt <ejb@ql.org>
* Add QUtil::make_unique_cstr to return a std::unique_ptr<char[]>
as an alternative to QUtil::copy_string and
QUtil::make_shared_cstr.
2022-02-04 Jay Berkenbilt <ejb@ql.org> 2022-02-04 Jay Berkenbilt <ejb@ql.org>
* New preprocessor symbols QPDF_MAJOR_VERSION, QPDF_MINOR_VERSION, * New preprocessor symbols QPDF_MAJOR_VERSION, QPDF_MINOR_VERSION,

10
TODO
View File

@ -1,6 +1,9 @@
10.6 10.6
==== ====
* Expose emptyPDF to the C API. Ensure that qpdf_get_qpdf_version is
always static.
* Consider doing one big commit to reformat the entire codebase using * Consider doing one big commit to reformat the entire codebase using
clang-format or a similar tool. Consider using blame.ignoreRevsFile clang-format or a similar tool. Consider using blame.ignoreRevsFile
or similar (or otherwise study git blame to see how to minimize the 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();
Derived* x = new Derived(); PointerHolder<Base> x_ph(x) --> Derived* x = new Derived(); PointerHolder<Base> x_ph(x) -->
Derived* x = new Derived(); auto x_ph = std::shared_pointer<Base>(x); Derived* x = new Derived(); auto x_ph = std::shared_pointer<Base>(x);
Also remember
auto x = std::shared_ptr(new T[5], std::default_delete<T[]>())
vs.
auto x = std::make_unique<T[]>(5)
PointerHolder in public API: PointerHolder in public API:
QUtil::read_file_into_memory( QUtil::read_file_into_memory(

View File

@ -161,6 +161,10 @@ namespace QUtil
QPDF_DLL QPDF_DLL
std::shared_ptr<char> make_shared_cstr(std::string const&); std::shared_ptr<char> make_shared_cstr(std::string const&);
// Copy string as a unique_ptr to an array.
QPDF_DLL
std::unique_ptr<char[]> make_unique_cstr(std::string const&);
// Returns lower-case hex-encoded version of the string, treating // Returns lower-case hex-encoded version of the string, treating
// each character in the input string as unsigned. The output // each character in the input string as unsigned. The output
// string will be twice as long as the input string. // string will be twice as long as the input string.

View File

@ -19,12 +19,8 @@ AES_PDF_native::AES_PDF_native(bool encrypt, unsigned char const* key,
nrounds(0) nrounds(0)
{ {
size_t keybits = 8 * key_bytes; size_t keybits = 8 * key_bytes;
this->key = std::unique_ptr<unsigned char[]>( this->key = std::make_unique<unsigned char[]>(key_bytes);
new unsigned char[key_bytes], this->rk = std::make_unique<uint32_t[]>(RKLENGTH(keybits));
std::default_delete<unsigned char[]>());
this->rk = std::unique_ptr<uint32_t[]>(
new uint32_t[RKLENGTH(keybits)],
std::default_delete<uint32_t[]>());
size_t rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t); size_t rk_bytes = RKLENGTH(keybits) * sizeof(uint32_t);
std::memcpy(this->key.get(), key, key_bytes); std::memcpy(this->key.get(), key, key_bytes);
std::memset(this->rk.get(), 0, rk_bytes); std::memset(this->rk.get(), 0, rk_bytes);

View File

@ -25,9 +25,7 @@ Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next,
use_specified_iv(false), use_specified_iv(false),
disable_padding(false) disable_padding(false)
{ {
this->key = std::unique_ptr<unsigned char[]>( this->key = std::make_unique<unsigned char[]>(key_bytes);
new unsigned char[key_bytes],
std::default_delete<unsigned char[]>());
std::memcpy(this->key.get(), key, key_bytes); std::memcpy(this->key.get(), key, key_bytes);
std::memset(this->inbuf, 0, this->buf_size); std::memset(this->inbuf, 0, this->buf_size);
std::memset(this->outbuf, 0, this->buf_size); std::memset(this->outbuf, 0, this->buf_size);

View File

@ -20,7 +20,7 @@ QPDFArgParser::Members::Members(
option_table(nullptr), option_table(nullptr),
final_check_handler(nullptr) final_check_handler(nullptr)
{ {
auto tmp = QUtil::make_shared_cstr(argv[0]); auto tmp = QUtil::make_unique_cstr(argv[0]);
char* p = QUtil::getWhoami(tmp.get()); char* p = QUtil::getWhoami(tmp.get());
// Remove prefix added by libtool for consistency during testing. // Remove prefix added by libtool for consistency during testing.
if (strncmp(p, "lt-", 3) == 0) if (strncmp(p, "lt-", 3) == 0)

View File

@ -3379,7 +3379,7 @@ QPDFJob::setEncryptionOptions(QPDF& pdf, QPDFWriter& w)
static void parse_version(std::string const& full_version_string, static void parse_version(std::string const& full_version_string,
std::string& version, int& extension_level) std::string& version, int& extension_level)
{ {
auto vp = QUtil::make_shared_cstr(full_version_string); auto vp = QUtil::make_unique_cstr(full_version_string);
char* v = vp.get(); char* v = vp.get();
char* p1 = strchr(v, '.'); char* p1 = strchr(v, '.');
char* p2 = (p1 ? strchr(1 + p1, '.') : 0); char* p2 = (p1 ? strchr(1 + p1, '.') : 0);

View File

@ -1919,7 +1919,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
} }
else else
{ {
auto tmp_ph = QUtil::make_shared_cstr(val); auto tmp_ph = QUtil::make_unique_cstr(val);
char* tmp = tmp_ph.get(); char* tmp = tmp_ph.get();
size_t vlen = val.length(); size_t vlen = val.length();
RC4 rc4(QUtil::unsigned_char_pointer(this->m->cur_data_key), RC4 rc4(QUtil::unsigned_char_pointer(this->m->cur_data_key),

View File

@ -1211,7 +1211,7 @@ QPDF::decryptString(std::string& str, int objid, int generation)
size_t vlen = str.length(); size_t vlen = str.length();
// Using PointerHolder guarantees that tmp will // Using PointerHolder guarantees that tmp will
// be freed even if rc4.process throws an exception. // be freed even if rc4.process throws an exception.
auto tmp = QUtil::make_shared_cstr(str); auto tmp = QUtil::make_unique_cstr(str);
RC4 rc4(QUtil::unsigned_char_pointer(key), toI(key.length())); RC4 rc4(QUtil::unsigned_char_pointer(key), toI(key.length()));
rc4.process(QUtil::unsigned_char_pointer(tmp.get()), vlen); rc4.process(QUtil::unsigned_char_pointer(tmp.get()), vlen);
str = std::string(tmp.get(), vlen); str = std::string(tmp.get(), vlen);

View File

@ -744,6 +744,16 @@ QUtil::make_shared_cstr(std::string const& str)
return result; return result;
} }
std::unique_ptr<char[]>
QUtil::make_unique_cstr(std::string const& str)
{
auto result = std::make_unique<char[]>(str.length() + 1);
// Use memcpy in case string contains nulls
result.get()[str.length()] = '\0';
memcpy(result.get(), str.c_str(), str.length());
return result;
}
std::string std::string
QUtil::hex_encode(std::string const& input) QUtil::hex_encode(std::string const& input)
{ {
@ -2625,7 +2635,7 @@ call_main_from_wmain(bool, int argc, wchar_t const* const argv[],
// other systems. That way the rest of qpdf.cc can just act like // other systems. That way the rest of qpdf.cc can just act like
// arguments are UTF-8. // arguments are UTF-8.
std::vector<std::shared_ptr<char>> utf8_argv; std::vector<std::unique_ptr<char[]>> utf8_argv;
for (int i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i)
{ {
std::string utf16; std::string utf16;
@ -2638,11 +2648,9 @@ call_main_from_wmain(bool, int argc, wchar_t const* const argv[],
QIntC::to_uchar(codepoint & 0xff))); QIntC::to_uchar(codepoint & 0xff)));
} }
std::string utf8 = QUtil::utf16_to_utf8(utf16); std::string utf8 = QUtil::utf16_to_utf8(utf16);
utf8_argv.push_back(QUtil::make_shared_cstr(utf8)); utf8_argv.push_back(QUtil::make_unique_cstr(utf8));
} }
auto utf8_argv_sp = auto utf8_argv_sp = std::make_unique<char*[]>(1+utf8_argv.size());
std::shared_ptr<char*>(
new char*[1+utf8_argv.size()], std::default_delete<char*[]>());
char** new_argv = utf8_argv_sp.get(); char** new_argv = utf8_argv_sp.get();
for (size_t i = 0; i < utf8_argv.size(); ++i) for (size_t i = 0; i < utf8_argv.size(); ++i)
{ {

View File

@ -9,7 +9,7 @@
int qpdfjob_run_from_argv(char const* const argv[]) int qpdfjob_run_from_argv(char const* const argv[])
{ {
auto whoami_p = QUtil::make_shared_cstr(argv[0]); auto whoami_p = QUtil::make_unique_cstr(argv[0]);
auto whoami = QUtil::getWhoami(whoami_p.get()); auto whoami = QUtil::getWhoami(whoami_p.get());
QUtil::setLineBuf(stdout); QUtil::setLineBuf(stdout);

View File

@ -23,6 +23,7 @@ one
7 7
compare okay compare okay
compare okay compare okay
compare okay
-2147483648 to int: PASSED -2147483648 to int: PASSED
2147483647 to int: PASSED 2147483647 to int: PASSED
2147483648 to int threw (integer out of range converting 2147483648 from a 8-byte signed type to a 4-byte signed type): PASSED 2147483648 to int threw (integer out of range converting 2147483648 from a 8-byte signed type to a 4-byte signed type): PASSED

View File

@ -150,7 +150,7 @@ void string_conversion_test()
std::cout << "compare failed" << std::endl; std::cout << "compare failed" << std::endl;
} }
delete [] tmp; delete [] tmp;
// Also test with make_shared_cstr // Also test with make_shared_cstr and make_unique_cstr
auto tmp2 = QUtil::make_shared_cstr(embedded_null); auto tmp2 = QUtil::make_shared_cstr(embedded_null);
if (memcmp(tmp2.get(), embedded_null.c_str(), 7) == 0) if (memcmp(tmp2.get(), embedded_null.c_str(), 7) == 0)
{ {
@ -160,6 +160,15 @@ void string_conversion_test()
{ {
std::cout << "compare failed" << std::endl; std::cout << "compare failed" << std::endl;
} }
auto tmp3 = QUtil::make_unique_cstr(embedded_null);
if (memcmp(tmp3.get(), embedded_null.c_str(), 7) == 0)
{
std::cout << "compare okay" << std::endl;
}
else
{
std::cout << "compare failed" << std::endl;
}
std::string int_max_str = QUtil::int_to_string(INT_MAX); std::string int_max_str = QUtil::int_to_string(INT_MAX);
std::string int_min_str = QUtil::int_to_string(INT_MIN); std::string int_min_str = QUtil::int_to_string(INT_MIN);
@ -417,7 +426,7 @@ void transcoding_test()
void print_whoami(char const* str) void print_whoami(char const* str)
{ {
auto dup = QUtil::make_shared_cstr(str); auto dup = QUtil::make_unique_cstr(str);
std::cout << QUtil::getWhoami(dup.get()) << std::endl; std::cout << QUtil::getWhoami(dup.get()) << std::endl;
} }

View File

@ -14,8 +14,7 @@ static void other_tests()
// Test cases not covered by the pipeline: string as key, convert // Test cases not covered by the pipeline: string as key, convert
// in place // in place
RC4 r(reinterpret_cast<unsigned char const*>("quack")); RC4 r(reinterpret_cast<unsigned char const*>("quack"));
auto data = std::unique_ptr<unsigned char[]>( auto data = std::make_unique<unsigned char[]>(6);
new unsigned char[6], std::default_delete<unsigned char[]>());
memcpy(data.get(), "potato", 6); memcpy(data.get(), "potato", 6);
r.process(data.get(), 6); r.process(data.get(), 6);
assert(memcmp(data.get(), "\xa5\x6f\xe7\x27\x2b\x5c", 6) == 0); assert(memcmp(data.get(), "\xa5\x6f\xe7\x27\x2b\x5c", 6) == 0);