From ba5fb6916446d8bdf79cba25f08d759bc5595aec Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Tue, 27 Aug 2019 22:10:11 -0400 Subject: Make popping pipeline stack safer Use destructors to pop the pipeline stack, and ensure that code that pops the stack is actually popping the intended thing. --- include/qpdf/Pipeline.hh | 2 ++ include/qpdf/QPDFWriter.hh | 50 +++++++++++++++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/qpdf/Pipeline.hh b/include/qpdf/Pipeline.hh index 36a25df0..e8f62b4e 100644 --- a/include/qpdf/Pipeline.hh +++ b/include/qpdf/Pipeline.hh @@ -70,6 +70,8 @@ class QPDF_DLL_CLASS Pipeline virtual void write(unsigned char* data, size_t len) = 0; QPDF_DLL virtual void finish() = 0; + QPDF_DLL + std::string getIdentifier() const; protected: Pipeline* getNext(bool allow_null = false); diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh index 0fd114db..c3818ae4 100644 --- a/include/qpdf/QPDFWriter.hh +++ b/include/qpdf/QPDFWriter.hh @@ -473,6 +473,34 @@ class QPDFWriter enum trailer_e { t_normal, t_lin_first, t_lin_second }; + // An reference to a PipelinePopper instance is passed into + // activatePipelineStack. When the PipelinePopper goes out of + // scope, the pipeline stack is popped. PipelinePopper's + // destructor calls finish on the current pipeline and pops the + // pipeline stack until the top of stack is a previous active top + // of stack, and restores the pipeline to that point. It deletes + // any pipelines that it pops. If the bp argument is non-null and + // any of the stack items are of type Pl_Buffer, the buffer is + // retrieved. + class PipelinePopper + { + friend class QPDFWriter; + public: + PipelinePopper(QPDFWriter* qw, + PointerHolder* bp = 0) : + qw(qw), + bp(bp) + { + } + ~PipelinePopper(); + + private: + QPDFWriter* qw; + PointerHolder* bp; + std::string stack_id; + }; + friend class PipelinePopper; + unsigned int bytesNeeded(long long n); void writeBinary(unsigned long long val, unsigned int bytes); void writeString(std::string const& str); @@ -560,24 +588,17 @@ class QPDFWriter int calculateXrefStreamPadding(qpdf_offset_t xref_bytes); // When filtering subsections, push additional pipelines to the - // stack. When ready to switch, activate the pipeline stack. - // Pipelines passed to pushPipeline are deleted when - // clearPipelineStack is called. + // stack. When ready to switch, activate the pipeline stack. When + // the passed in PipelinePopper goes out of scope, the stack is + // popped. Pipeline* pushPipeline(Pipeline*); - void activatePipelineStack(); + void activatePipelineStack(PipelinePopper&); void initializePipelineStack(Pipeline *); - // Calls finish on the current pipeline and pops the pipeline - // stack until the top of stack is a previous active top of stack, - // and restores the pipeline to that point. Deletes any pipelines - // that it pops. If the bp argument is non-null and any of the - // stack items are of type Pl_Buffer, the buffer is retrieved. - void popPipelineStack(PointerHolder* bp = 0); - void adjustAESStreamLength(size_t& length); - void pushEncryptionFilter(); - void pushDiscardFilter(); - void pushMD5Pipeline(); + void pushEncryptionFilter(PipelinePopper&); + void pushDiscardFilter(PipelinePopper&); + void pushMD5Pipeline(PipelinePopper&); void computeDeterministicIDData(); void discardGeneration(std::map const& in, @@ -654,6 +675,7 @@ class QPDFWriter std::map object_to_object_stream; std::map > object_stream_to_objects; std::list pipeline_stack; + unsigned long long next_stack_id; bool deterministic_id; Pl_MD5* md5_pipeline; std::string deterministic_id_data; -- cgit v1.2.3-70-g09d2