2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-23 03:18:59 +00:00

enhance PointerHolder so that it can explicitly be told to use delete [] instead of delete, thus making it useful to run valgrind over qpdf during its test suite

This commit is contained in:
Jay Berkenbilt 2011-08-11 11:56:37 -04:00
parent 14fe2e6de3
commit 76b1659177
13 changed files with 153 additions and 49 deletions

View File

@ -1,6 +1,27 @@
Release Reminders Release Reminders
================= =================
* Consider running tests with latest gcc and/or valgrind. To do
this, replace, build with debugging and without shared libraries.
In build, create z and move each executable into z. Then create a
script called exec-z that contains:
#!/bin/sh
exec valgrind --suppressions=/tmp/a.supp -q \
`dirname $0`/z/`basename $0` ${1+"$@"}
Symlink exec-v to each executable. /tmp/a.supp can be populated
with suppressions for libraries, for example:
{
zlib1
Memcheck:Cond
fun:inflateReset2
fun:inflateInit2_
}
You can generate these by running valgrind with --gen-suppressions=yes.
* Check all open issues in the sourceforge trackers. * Check all open issues in the sourceforge trackers.
* If any interfaces were added or changed, check C API to see whether * If any interfaces were added or changed, check C API to see whether

2
TODO
View File

@ -3,8 +3,6 @@
* Provide an example of using replace and swap. Maybe. * Provide an example of using replace and swap. Maybe.
* Add C API for writing to memory if possible
General General
======= =======

View File

@ -8,8 +8,6 @@
#ifndef __POINTERHOLDER_HH__ #ifndef __POINTERHOLDER_HH__
#define __POINTERHOLDER_HH__ #define __POINTERHOLDER_HH__
#include <iostream>
// This class is basically boost::shared_pointer but predates that by // This class is basically boost::shared_pointer but predates that by
// several years. // several years.
@ -45,43 +43,42 @@ class PointerHolder
class Data class Data
{ {
public: public:
Data(T* pointer, bool tracing) : Data(T* pointer, bool array) :
pointer(pointer), pointer(pointer),
tracing(tracing), array(array),
refcount(0) refcount(0)
{ {
static int next_id = 0;
this->unique_id = ++next_id;
} }
~Data() ~Data()
{ {
if (this->tracing) if (array)
{ {
std::cerr << "PointerHolder deleting pointer " delete [] this->pointer;
<< (void*)pointer
<< std::endl;
} }
delete this->pointer; else
if (this->tracing)
{ {
std::cerr << "PointerHolder done deleting pointer " delete this->pointer;
<< (void*)pointer
<< std::endl;
} }
} }
T* pointer; T* pointer;
bool tracing; bool array;
int refcount; int refcount;
int unique_id;
private: private:
Data(Data const&); Data(Data const&);
Data& operator=(Data const&); Data& operator=(Data const&);
}; };
public: public:
// "tracing" is not used but is kept for interface backward compatbility
PointerHolder(T* pointer = 0, bool tracing = false) PointerHolder(T* pointer = 0, bool tracing = false)
{ {
this->init(new Data(pointer, tracing)); this->init(new Data(pointer, false));
}
// Special constructor indicating to free memory with delete []
// instead of delete
PointerHolder(bool, T* pointer)
{
this->init(new Data(pointer, true));
} }
PointerHolder(PointerHolder const& rhs) PointerHolder(PointerHolder const& rhs)
{ {
@ -148,12 +145,6 @@ class PointerHolder
this->data = data; this->data = data;
{ {
++this->data->refcount; ++this->data->refcount;
if (this->data->tracing)
{
std::cerr << "PointerHolder " << this->data->unique_id
<< " refcount increased to " << this->data->refcount
<< std::endl;
}
} }
} }
void copy(PointerHolder const& rhs) void copy(PointerHolder const& rhs)
@ -168,13 +159,6 @@ class PointerHolder
{ {
gone = true; gone = true;
} }
if (this->data->tracing)
{
std::cerr << "PointerHolder " << this->data->unique_id
<< " refcount decreased to "
<< this->data->refcount
<< std::endl;
}
} }
if (gone) if (gone)
{ {

View File

@ -285,6 +285,25 @@ extern "C" {
QPDF_DLL QPDF_DLL
QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename); QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename);
/* Initialize for writing but indicate that the PDF file should be
* written to memory. Call qpdf_get_buffer_length and
* qpdf_get_buffer to retrieve the resulting buffer. The memory
* containing the PDF file will be destroyed when qpdf_cleanup is
* called.
*/
QPDF_DLL
QPDF_ERROR_CODE qpdf_init_write_memory(qpdf_data qpdf);
/* Retrieve the buffer used if the file was written to memory.
* qpdf_get_buffer returns a null pointer if data was not written
* to memory. The memory is freed when qpdf_cleanup is called or
* if a subsequent call to qpdf_init_write or
* qpdf_init_write_memory is called. */
QPDF_DLL
unsigned long qpdf_get_buffer_length(qpdf_data qpdf);
QPDF_DLL
unsigned char const* qpdf_get_buffer(qpdf_data qpdf);
QPDF_DLL QPDF_DLL
void qpdf_set_object_stream_mode(qpdf_data qpdf, void qpdf_set_object_stream_mode(qpdf_data qpdf,
enum qpdf_object_stream_e mode); enum qpdf_object_stream_e mode);

View File

@ -403,10 +403,9 @@ QPDF::parse(char const* password)
this->file->rewind(); this->file->rewind();
} }
char* buf = new char[tbuf_size + 1]; char* buf = new char[tbuf_size + 1];
// Put buf in a PointerHolder to guarantee deletion of buf. This // Put buf in an array-style PointerHolder to guarantee deletion
// calls delete rather than delete [], but it's okay since buf is // of buf.
// an array of fundamental types. PointerHolder<char> b(true, buf);
PointerHolder<char> b(buf);
memset(buf, '\0', tbuf_size + 1); memset(buf, '\0', tbuf_size + 1);
this->file->read(buf, tbuf_size); this->file->read(buf, tbuf_size);

View File

@ -589,12 +589,9 @@ QPDF::decryptString(std::string& str, int objid, int generation)
{ {
QTC::TC("qpdf", "QPDF_encryption rc4 decode string"); QTC::TC("qpdf", "QPDF_encryption rc4 decode string");
unsigned int vlen = str.length(); unsigned int vlen = str.length();
// Using PointerHolder will cause a new char[] to be deleted // Using PointerHolder guarantees that tmp will
// with delete instead of delete [], but it's okay since the
// array is of a fundamental type, so there is no destructor
// to be called. Using PointerHolder guarantees that tmp will
// be freed even if rc4.process throws an exception. // be freed even if rc4.process throws an exception.
PointerHolder<char> tmp = QUtil::copy_string(str); PointerHolder<char> tmp(true, QUtil::copy_string(str));
RC4 rc4((unsigned char const*)key.c_str(), key.length()); RC4 rc4((unsigned char const*)key.c_str(), key.length());
rc4.process((unsigned char*)tmp.getPointer(), vlen); rc4.process((unsigned char*)tmp.getPointer(), vlen);
str = std::string(tmp.getPointer(), vlen); str = std::string(tmp.getPointer(), vlen);

View File

@ -88,7 +88,7 @@ QPDF::isLinearized()
char* buf = new char[tbuf_size]; char* buf = new char[tbuf_size];
this->file->seek(0, SEEK_SET); this->file->seek(0, SEEK_SET);
PointerHolder<char> b(buf); // guarantee deletion PointerHolder<char> b(true, buf);
memset(buf, '\0', tbuf_size); memset(buf, '\0', tbuf_size);
this->file->read(buf, tbuf_size - 1); this->file->read(buf, tbuf_size - 1);

View File

@ -33,11 +33,15 @@ struct _qpdf_data
char const* buffer; char const* buffer;
unsigned long size; unsigned long size;
char const* password; char const* password;
bool write_memory;
Buffer* output_buffer;
}; };
_qpdf_data::_qpdf_data() : _qpdf_data::_qpdf_data() :
qpdf(0), qpdf(0),
qpdf_writer(0) qpdf_writer(0),
write_memory(false),
output_buffer(0)
{ {
} }
@ -45,6 +49,7 @@ _qpdf_data::~_qpdf_data()
{ {
delete qpdf_writer; delete qpdf_writer;
delete qpdf; delete qpdf;
delete output_buffer;
} }
// must set qpdf->filename and qpdf->password // must set qpdf->filename and qpdf->password
@ -66,6 +71,12 @@ static void call_init_write(qpdf_data qpdf)
qpdf->qpdf_writer = new QPDFWriter(*(qpdf->qpdf), qpdf->filename); qpdf->qpdf_writer = new QPDFWriter(*(qpdf->qpdf), qpdf->filename);
} }
static void call_init_write_memory(qpdf_data qpdf)
{
qpdf->qpdf_writer = new QPDFWriter(*(qpdf->qpdf));
qpdf->qpdf_writer->setOutputMemory();
}
static void call_write(qpdf_data qpdf) static void call_write(qpdf_data qpdf)
{ {
qpdf->qpdf_writer->write(); qpdf->qpdf_writer->write();
@ -408,21 +419,71 @@ QPDF_BOOL qpdf_allow_modify_all(qpdf_data qpdf)
return qpdf->qpdf->allowModifyAll(); return qpdf->qpdf->allowModifyAll();
} }
QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename) static void qpdf_init_write_internal(qpdf_data qpdf)
{ {
QPDF_ERROR_CODE status = QPDF_SUCCESS;
if (qpdf->qpdf_writer) if (qpdf->qpdf_writer)
{ {
QTC::TC("qpdf", "qpdf-c called qpdf_init_write multiple times"); QTC::TC("qpdf", "qpdf-c called qpdf_init_write multiple times");
delete qpdf->qpdf_writer; delete qpdf->qpdf_writer;
qpdf->qpdf_writer = 0; qpdf->qpdf_writer = 0;
if (qpdf->output_buffer)
{
delete qpdf->output_buffer;
qpdf->output_buffer = 0;
qpdf->write_memory = false;
qpdf->filename = 0;
} }
}
}
QPDF_ERROR_CODE qpdf_init_write(qpdf_data qpdf, char const* filename)
{
qpdf_init_write_internal(qpdf);
qpdf->filename = filename; qpdf->filename = filename;
status = trap_errors(qpdf, &call_init_write); QPDF_ERROR_CODE status = trap_errors(qpdf, &call_init_write);
QTC::TC("qpdf", "qpdf-c called qpdf_init_write", status); QTC::TC("qpdf", "qpdf-c called qpdf_init_write", status);
return status; return status;
} }
QPDF_ERROR_CODE qpdf_init_write_memory(qpdf_data qpdf)
{
qpdf_init_write_internal(qpdf);
QPDF_ERROR_CODE status = trap_errors(qpdf, &call_init_write_memory);
QTC::TC("qpdf", "qpdf-c called qpdf_init_write_memory");
qpdf->write_memory = true;
return status;
}
static void qpdf_get_buffer_internal(qpdf_data qpdf)
{
if (qpdf->write_memory && (qpdf->output_buffer == 0))
{
qpdf->output_buffer = qpdf->qpdf_writer->getBuffer();
}
}
unsigned long qpdf_get_buffer_length(qpdf_data qpdf)
{
qpdf_get_buffer_internal(qpdf);
unsigned long result = 0L;
if (qpdf->output_buffer)
{
result = qpdf->output_buffer->getSize();
}
return result;
}
unsigned char const* qpdf_get_buffer(qpdf_data qpdf)
{
unsigned char const* result = 0;
qpdf_get_buffer_internal(qpdf);
if (qpdf->output_buffer)
{
result = qpdf->output_buffer->getBuffer();
}
return result;
}
void qpdf_set_object_stream_mode(qpdf_data qpdf, qpdf_object_stream_e mode) void qpdf_set_object_stream_mode(qpdf_data qpdf, qpdf_object_stream_e mode)
{ {
QTC::TC("qpdf", "qpdf-c called qpdf_set_object_stream_mode"); QTC::TC("qpdf", "qpdf-c called qpdf_set_object_stream_mode");

View File

@ -3,6 +3,7 @@
#include <qpdf/Pl_Discard.hh> #include <qpdf/Pl_Discard.hh>
#include <stdlib.h> #include <stdlib.h>
#include <stdexcept> #include <stdexcept>
#include <iostream>
typedef unsigned char* uc; typedef unsigned char* uc;

View File

@ -2131,6 +2131,14 @@ print "\n";
<literal>/Info</literal> dictionary. <literal>/Info</literal> dictionary.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
Add functions <function>qpdf_init_write_memory</function>,
<function>qpdf_get_buffer_length</function>, and
<function>qpdf_get_buffer</function> to the C API for writing
PDF files to a memory buffer instead of a file.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -337,6 +337,10 @@ static void test16(char const* infile,
char const* outfile, char const* outfile,
char const* outfile2) char const* outfile2)
{ {
unsigned long buflen = 0L;
unsigned char const* buf = 0;
FILE* f = 0;
qpdf_read(qpdf, infile, password); qpdf_read(qpdf, infile, password);
print_info("/Author"); print_info("/Author");
print_info("/Producer"); print_info("/Producer");
@ -347,11 +351,22 @@ static void test16(char const* infile,
print_info("/Author"); print_info("/Author");
print_info("/Producer"); print_info("/Producer");
print_info("/Creator"); print_info("/Creator");
qpdf_init_write(qpdf, outfile); qpdf_init_write_memory(qpdf);
qpdf_set_static_ID(qpdf, QPDF_TRUE); qpdf_set_static_ID(qpdf, QPDF_TRUE);
qpdf_set_static_aes_IV(qpdf, QPDF_TRUE); qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
qpdf_set_stream_data_mode(qpdf, qpdf_s_uncompress); qpdf_set_stream_data_mode(qpdf, qpdf_s_uncompress);
qpdf_write(qpdf); qpdf_write(qpdf);
f = fopen(outfile, "wb");
if (f == NULL)
{
fprintf(stderr, "%s: unable to open %s: %s\n",
whoami, outfile, strerror(errno));
exit(2);
}
buflen = qpdf_get_buffer_length(qpdf);
buf = qpdf_get_buffer(qpdf);
fwrite(buf, 1, buflen, f);
fclose(f);
report_errors(); report_errors();
} }

View File

@ -199,3 +199,4 @@ qpdf-c set_info_key to value 0
qpdf-c set_info_key to null 0 qpdf-c set_info_key to null 0
qpdf-c set-info-key use existing info 0 qpdf-c set-info-key use existing info 0
qpdf-c add info to trailer 0 qpdf-c add info to trailer 0
qpdf-c called qpdf_init_write_memory 0

View File

@ -76,7 +76,7 @@ void runtest(int n, char const* filename)
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
size_t size = (size_t) ftell(f); size_t size = (size_t) ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
file_buf = new char[size]; file_buf = PointerHolder<char>(true, new char[size]);
char* buf_p = file_buf.getPointer(); char* buf_p = file_buf.getPointer();
size_t bytes_read = 0; size_t bytes_read = 0;
size_t len = 0; size_t len = 0;