Subject: Backported patches from poppler-0.20.3 - poppler-0.20.5 This patch includes these commits: pdfseparate: Return 0 on success autoconf: Do not assume the shell is bash compatible Fix conversion to ps when having multiple strips Make sure xScale and yScale are always initialized Splash: Blend mode enhancements for CMYK PSOutputDev: Fix Bitmaps in level2sep or level3sep Fix segfault when scaleImage returns NULL If NULL, NULL fails as password try EMPTY, EMPTY before failing Return NULL EmbFile if the FileSpec is not ok Accept FileSpec as Dict too and not only as Ref Only complain when the malloc really failed Fix crash in 589.pdf.SIGSEGV.8b1.929 Fix memory leak Fix memory leak Fix crash in 1028.pdf.SIGSEGV.ae6.33 Fix crash in 1162.pdf.SIGSEGV.28e.182 Add unlikelys to the ifs Fix memory leak Fix wrong memory access in 68.pdf.asan.7.1030 Add unlikely Fix crash in 1255.pdf.SIGSEGV.56f.285 Fix invalid memory access in 1106.pdf.asan.30.120.patch Fix invalid memory access in solves 1066.pdf.asan.38.75 Check for NaN in TextPage::addChar Do not use isnan as it is C99 Fix parsing of numbers Forgot to add the new test to autotools Don't close the stream if it's not a stream Fix crash in 158.pdf.asan.d.451 More fixes against broken files Add some unlikelys Less crashes in broken files Add unlikelys Fix more crashes in broken files More crash fixes for broken documents Initilize rootNum Fix crash when parsing some unknown colorspaces Do not render invalid outlines glib: chain up finalize to the parent class --- diff --git a/configure.ac b/configure.ac index 0facfdb..3626028 100644 --- a/configure.ac +++ b/configure.ac @@ -752,7 +752,7 @@ case "$enable_compile_warnings" in -fno-common $CXXFLAGS" ;; esac -case $($PKG_CONFIG --version) in +case `$PKG_CONFIG --version` in 0.?|0.1[0-7]) PC_REQUIRES_PRIVATE=""; PC_REQUIRES="poppler = $VERSION";; diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc index 24badd9..74d7635 100644 --- a/glib/poppler-document.cc +++ b/glib/poppler-document.cc @@ -356,6 +356,8 @@ poppler_document_finalize (GObject *object) poppler_document_layers_free (document); delete document->output_dev; delete document->doc; + + G_OBJECT_CLASS (poppler_document_parent_class)->finalize (object); } /** @@ -1957,6 +1959,8 @@ poppler_font_info_finalize (GObject *object) delete font_info->scanner; g_object_unref (font_info->document); + + G_OBJECT_CLASS (poppler_font_info_parent_class)->finalize (object); } /** @@ -2458,6 +2462,8 @@ poppler_ps_file_finalize (GObject *object) delete ps_file->out; g_object_unref (ps_file->document); g_free (ps_file->filename); + + G_OBJECT_CLASS (poppler_ps_file_parent_class)->finalize (object); } /** diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc index 156e2d7..2e0e44e 100644 --- a/glib/poppler-page.cc +++ b/glib/poppler-page.cc @@ -79,6 +79,8 @@ poppler_page_finalize (GObject *object) if (page->text != NULL) page->text->decRefCnt(); /* page->page is owned by the document */ + + G_OBJECT_CLASS (poppler_page_parent_class)->finalize (object); } /** diff --git a/poppler/Annot.cc b/poppler/Annot.cc index 24ef57d..aa8b9a8 100644 --- a/poppler/Annot.cc +++ b/poppler/Annot.cc @@ -15,7 +15,7 @@ // // Copyright (C) 2006 Scott Turner // Copyright (C) 2007, 2008 Julien Rebetez -// Copyright (C) 2007-2011 Albert Astals Cid +// Copyright (C) 2007-2012 Albert Astals Cid // Copyright (C) 2007-2011 Carlos Garcia Campos // Copyright (C) 2007, 2008 Iñigo Martínez // Copyright (C) 2007 Jeff Muizelaar @@ -25,6 +25,7 @@ // Copyright (C) 2009 Ilya Gorenbein // Copyright (C) 2011 José Aliste // Copyright (C) 2012 Fabio D'Urso +// Copyright (C) 2012 Thomas Freitag // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -4500,6 +4501,14 @@ void AnnotWidget::drawListBox(FormFieldChoice *fieldChoice, wMax = 0; for (i = 0; i < fieldChoice->getNumChoices(); ++i) { j = 0; + if (fieldChoice->getChoice(i) == NULL) { + error(errSyntaxError, -1, "Invalid annotation listbox"); + if (daToks) { + deleteGooList(daToks, GooString); + } + delete convertedText; + return; + } layoutText(fieldChoice->getChoice(i), convertedText, &j, font, &w, 0.0, NULL, gFalse); if (w > wMax) { wMax = w; diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc index 664c421..0f42356 100644 --- a/poppler/Catalog.cc +++ b/poppler/Catalog.cc @@ -14,7 +14,7 @@ // under GPL version 2 or later // // Copyright (C) 2005 Kristian Høgsberg -// Copyright (C) 2005-2011 Albert Astals Cid +// Copyright (C) 2005-2012 Albert Astals Cid // Copyright (C) 2005 Jeff Muizelaar // Copyright (C) 2005 Jonathan Blandford // Copyright (C) 2005 Marco Pesenti Gritti @@ -462,6 +462,8 @@ FileSpec *Catalog::embeddedFile(int i) Object fsDict; embeddedFile = new FileSpec(obj.fetch(xref, &fsDict)); fsDict.free(); + } else if (obj.isDict()) { + embeddedFile = new FileSpec(&obj); } else { Object null; embeddedFile = new FileSpec(&null); diff --git a/poppler/DCTStream.cc b/poppler/DCTStream.cc index 90a1377..6302c8b 100644 --- a/poppler/DCTStream.cc +++ b/poppler/DCTStream.cc @@ -5,11 +5,12 @@ // This file is licensed under the GPLv2 or later // // Copyright 2005 Jeff Muizelaar -// Copyright 2005-2010 Albert Astals Cid +// Copyright 2005-2010, 2012 Albert Astals Cid // Copyright 2009 Ryszard Trojnacki // Copyright 2010 Carlos Garcia Campos // Copyright 2011 Daiki Ueno // Copyright 2011 Tomas Hoger +// Copyright 2012 Thomas Freitag // //======================================================================== @@ -222,6 +223,9 @@ int DCTStream::getChars(int nChars, Guchar *buffer) { } int DCTStream::lookChar() { + if (unlikely(current == NULL)) { + return EOF; + } return *current; } diff --git a/poppler/FileSpec.cc b/poppler/FileSpec.cc index 1360608..1adcf5b 100644 --- a/poppler/FileSpec.cc +++ b/poppler/FileSpec.cc @@ -7,6 +7,7 @@ // // Copyright (C) 2008-2009 Carlos Garcia Campos // Copyright (C) 2009 Kovid Goyal +// Copyright (C) 2012 Albert Astals Cid // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -151,6 +152,9 @@ FileSpec::~FileSpec() EmbFile *FileSpec::getEmbeddedFile() { + if(!ok) + return NULL; + if (embFile) return embFile; diff --git a/poppler/Form.cc b/poppler/Form.cc index 99d7bbb..7d32ae0 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -521,8 +521,8 @@ FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *par obj1.free(); if (dict->lookup("Subtype", &obj1)->isName("Widget")) _createWidget(&obj, ref); - obj1.free(); } + obj1.free(); //flags if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { diff --git a/poppler/Function.cc b/poppler/Function.cc index 25e8f74..2c3aa8a 100644 --- a/poppler/Function.cc +++ b/poppler/Function.cc @@ -17,6 +17,7 @@ // Copyright (C) 2006 Jeff Muizelaar // Copyright (C) 2010 Christian Feuersänger // Copyright (C) 2011 Andrea Canciani +// Copyright (C) 2012 Thomas Freitag // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -1010,6 +1011,10 @@ public: return; } --sp; + if (sp + i + 1 >= psStackSize) { + error(errSyntaxError, -1, "Stack underflow in PostScript function"); + return; + } stack[sp] = stack[sp + 1 + i]; } void pop() diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index d7684d6..4e663b4 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -1671,6 +1671,10 @@ void Gfx::opSetStrokeColorN(Object args[], int numArgs) { state->setStrokeColor(&color); out->updateStrokeColor(state); } + if (unlikely(numArgs <= 0)) { + error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command"); + return; + } if (args[numArgs-1].isName() && (pattern = res->lookupPattern(args[numArgs-1].getName(), this))) { state->setStrokePattern(pattern); @@ -4356,6 +4360,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { dict->lookup("D", &obj1); } if (bits == 0) { + delete colorSpace; goto err2; } colorMap = new GfxImageColorMap(bits, &obj1, colorSpace); diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc index 252e88d..b8cb007 100644 --- a/poppler/GfxState.cc +++ b/poppler/GfxState.cc @@ -312,7 +312,7 @@ GfxColorSpace *GfxColorSpace::parse(Object *csObj, Gfx *gfx, int recursion) { } else if (obj1.isName("DeviceCMYK")) { cs = new GfxDeviceCMYKColorSpace(); } else { - error(errSyntaxWarning, -1, "Bad color space '{0:s}'", csObj->getName()); + error(errSyntaxWarning, -1, "Bad color space dict'"); } obj1.free(); } else { @@ -2173,10 +2173,16 @@ GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr, Gfx *gfx, int recursio if (!(funcA = Function::parse(&obj1))) { goto err4; } + if (funcA->getInputSize() != 1) { + error(errSyntaxWarning, -1, "Bad SeparationColorSpace function"); + goto err5; + } obj1.free(); cs = new GfxSeparationColorSpace(nameA, altA, funcA); return cs; + err5: + delete funcA; err4: delete altA; err3: @@ -3096,6 +3102,10 @@ void GfxUnivariateShading::getColor(double t, GfxColor *color) { out[i] = 0; } for (i = 0; i < nFuncs; ++i) { + if (funcs[i]->getInputSize() != 1) { + error(errSyntaxWarning, -1, "Invalid shading function (input != 1)"); + break; + } funcs[i]->transform(&t, &out[i]); } } @@ -3267,7 +3277,7 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict, Gfx *gfx) { dict->lookup("Function", &obj1); if (obj1.isArray()) { nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { + if (nFuncsA > gfxColorMaxComps || nFuncsA == 0) { error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary"); goto err1; } @@ -3292,9 +3302,19 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict, Gfx *gfx) { extend0A = extend1A = gFalse; if (dict->lookup("Extend", &obj1)->isArray() && obj1.arrayGetLength() == 2) { - extend0A = obj1.arrayGet(0, &obj2)->getBool(); + obj1.arrayGet(0, &obj2); + if (obj2.isBool()) { + extend0A = obj2.getBool(); + } else { + error(errSyntaxWarning, -1, "Invalid axial shading extend (0)"); + } obj2.free(); - extend1A = obj1.arrayGet(1, &obj2)->getBool(); + obj1.arrayGet(1, &obj2); + if (obj2.isBool()) { + extend1A = obj2.getBool(); + } else { + error(errSyntaxWarning, -1, "Invalid axial shading extend (1)"); + } obj2.free(); } obj1.free(); diff --git a/poppler/JBIG2Stream.cc b/poppler/JBIG2Stream.cc index 7ddcc81..afba8c6 100644 --- a/poppler/JBIG2Stream.cc +++ b/poppler/JBIG2Stream.cc @@ -18,6 +18,8 @@ // Copyright (C) 2006-2010, 2012 Albert Astals Cid // Copyright (C) 2009 David Benjamin // Copyright (C) 2011 Edward Jiang +// Copyright (C) 2012 William Bader +// Copyright (C) 2012 Thomas Freitag // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -584,6 +586,9 @@ int JBIG2MMRDecoder::getBlackCode() { } else { code = buf >> (bufLen - 12); } + if (unlikely((code & 0xff) < 64)) { + break; + } p = &blackTab2[(code & 0xff) - 64]; } else { if (bufLen <= 6) { @@ -712,13 +717,22 @@ JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): return; } // need to allocate one extra guard byte for use in combine() - data = (Guchar *)gmalloc(h * line + 1); - data[h * line] = 0; + data = (Guchar *)gmalloc_checkoverflow(h * line + 1); + if (data != NULL) { + data[h * line] = 0; + } } JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): JBIG2Segment(segNumA) { + if (unlikely(bitmap == NULL)) { + error(errSyntaxError, -1, "NULL bitmap in JBIG2Bitmap"); + w = h = line = 0; + data = NULL; + return; + } + w = bitmap->w; h = bitmap->h; line = bitmap->line; @@ -1091,8 +1105,8 @@ public: virtual ~JBIG2PatternDict(); virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; } Guint getSize() { return size; } - void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } - JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } + void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { if (likely(idx < size)) bitmaps[idx] = bitmap; } + JBIG2Bitmap *getBitmap(Guint idx) { return (idx < size) ? bitmaps[idx] : NULL; } private: @@ -1103,8 +1117,13 @@ private: JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA): JBIG2Segment(segNumA) { - size = sizeA; - bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); + bitmaps = (JBIG2Bitmap **)gmallocn_checkoverflow(sizeA, sizeof(JBIG2Bitmap *)); + if (bitmaps) { + size = sizeA; + } else { + size = 0; + error(errSyntaxError, -1, "JBIG2PatternDict: can't allocate bitmaps"); + } } JBIG2PatternDict::~JBIG2PatternDict() { @@ -1636,7 +1655,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, // get the input symbol bitmaps bitmaps = (JBIG2Bitmap **)gmallocn_checkoverflow(numInputSyms + numNewSyms, sizeof(JBIG2Bitmap *)); - if (!bitmaps) { + if (!bitmaps && (numInputSyms + numNewSyms > 0)) { error(errSyntaxError, curStr->getPos(), "Too many input symbols in JBIG2 symbol dictionary"); delete codeTables; goto eofError; @@ -1747,6 +1766,10 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, goto syntaxError; } symHeight += dh; + if (unlikely(symHeight > 0x40000000)) { + error(errSyntaxError, curStr->getPos(), "Bad height value in JBIG2 symbol dictionary"); + goto syntaxError; + } symWidth = 0; totalWidth = 0; j = i; @@ -1814,6 +1837,10 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, goto syntaxError; } refBitmap = bitmaps[symID]; + if (unlikely(refBitmap == NULL)) { + error(errSyntaxError, curStr->getPos(), "Invalid ref bitmap for symbol ID {0:d} in JBIG2 symbol dictionary", symID); + goto syntaxError; + } bitmaps[numInputSyms + i] = readGenericRefinementRegion(symWidth, symHeight, sdrTemplate, gFalse, @@ -1849,6 +1876,10 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight); bmSize = symHeight * ((totalWidth + 7) >> 3); p = collBitmap->getDataPtr(); + if (unlikely(p == NULL)) { + delete collBitmap; + goto syntaxError; + } for (k = 0; k < (Guint)bmSize; ++k) { if ((c = curStr->getChar()) == EOF) { break; @@ -2198,6 +2229,7 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, symCodeTab[i++].prefixLen = 0; } } else if (j > 0x100) { + if (unlikely(i == 0)) ++i; for (j -= 0x100; j && i < numSyms; --j) { symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen; ++i; @@ -2365,6 +2397,11 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, if (symID >= (Guint)numSyms) { error(errSyntaxError, curStr->getPos(), "Invalid symbol number in JBIG2 text region"); + if (unlikely(numInstances - inst > 0x800)) { + // don't loop too often with damaged JBIg2 streams + delete bitmap; + return NULL; + } } else { // get the symbol bitmap @@ -2416,8 +2453,24 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, //~ something is wrong here - refCorner shouldn't degenerate into //~ two cases bw = symbolBitmap->getWidth() - 1; + if (unlikely(symbolBitmap->getHeight() == 0)) { + error(errSyntaxError, curStr->getPos(), "Invalid symbol bitmap height"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bh = symbolBitmap->getHeight() - 1; if (transposed) { + if (unlikely(s > 2 * bitmap->getHeight())) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } switch (refCorner) { case 0: // bottom left bitmap->combine(symbolBitmap, tt, s, combOp); @@ -2436,15 +2489,47 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, } else { switch (refCorner) { case 0: // bottom left + if (unlikely(tt - (int) bh > 2 * bitmap->getHeight())) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bitmap->combine(symbolBitmap, s, tt - bh, combOp); break; case 1: // top left + if (unlikely(tt > 2 * bitmap->getHeight())) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bitmap->combine(symbolBitmap, s, tt, combOp); break; case 2: // bottom right + if (unlikely(tt - (int) bh > 2 * bitmap->getHeight())) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bitmap->combine(symbolBitmap, s, tt - bh, combOp); break; case 3: // top right + if (unlikely(tt > 2 * bitmap->getHeight())) { + error(errSyntaxError, curStr->getPos(), "Invalid JBIG2 combine"); + if (ri) { + delete symbolBitmap; + } + delete bitmap; + return NULL; + } bitmap->combine(symbolBitmap, s, tt, combOp); break; } @@ -2520,7 +2605,7 @@ void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) { // split up the bitmap x = 0; - for (i = 0; i <= grayMax; ++i) { + for (i = 0; i <= grayMax && i < patternDict->getSize(); ++i) { patternDict->setBitmap(i, bitmap->getSlice(x, 0, patternW, patternH)); x += patternW; } @@ -2671,6 +2756,10 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, for (n = 0; n < gridW; ++n) { if (!(enableSkip && skipBitmap->getPixel(n, m))) { patternBitmap = patternDict->getBitmap(grayImg[i]); + if (unlikely(patternBitmap == NULL)) { + error(errSyntaxError, curStr->getPos(), "Bad pattern bitmap"); + return; + } bitmap->combine(patternBitmap, xx >> 8, yy >> 8, combOp); } xx += stepX; @@ -3127,7 +3216,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, atx[2] >= -8 && atx[2] <= 8 && atx[3] >= -8 && atx[3] <= 8) { // set up the adaptive context - if (y + aty[0] >= 0) { + if (y + aty[0] >= 0 && y + aty[0] < bitmap->getHeight()) { atP0 = bitmap->getDataPtr() + (y + aty[0]) * bitmap->getLineSize(); atBuf0 = *atP0++ << 8; } else { @@ -3135,7 +3224,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, atBuf0 = 0; } atShift0 = 15 - atx[0]; - if (y + aty[1] >= 0) { + if (y + aty[1] >= 0 && y + aty[1] < bitmap->getHeight()) { atP1 = bitmap->getDataPtr() + (y + aty[1]) * bitmap->getLineSize(); atBuf1 = *atP1++ << 8; } else { @@ -3143,7 +3232,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, atBuf1 = 0; } atShift1 = 15 - atx[1]; - if (y + aty[2] >= 0) { + if (y + aty[2] >= 0 && y + aty[2] < bitmap->getHeight()) { atP2 = bitmap->getDataPtr() + (y + aty[2]) * bitmap->getLineSize(); atBuf2 = *atP2++ << 8; } else { @@ -3151,7 +3240,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, atBuf2 = 0; } atShift2 = 15 - atx[2]; - if (y + aty[3] >= 0) { + if (y + aty[3] >= 0 && y + aty[3] < bitmap->getHeight()) { atP3 = bitmap->getDataPtr() + (y + aty[3]) * bitmap->getLineSize(); atBuf3 = *atP3++ << 8; } else { @@ -3670,7 +3759,7 @@ void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm, refBitmap, 0, 0, atx, aty); // combine the region bitmap into the page bitmap - if (imm) { + if (imm && bitmap) { pageBitmap->combine(bitmap, x, y, extCombOp); delete bitmap; diff --git a/poppler/JPXStream.cc b/poppler/JPXStream.cc index 2cf616d..f1becc9 100644 --- a/poppler/JPXStream.cc +++ b/poppler/JPXStream.cc @@ -14,6 +14,7 @@ // under GPL version 2 or later // // Copyright (C) 2008, 2012 Albert Astals Cid +// Copyright (C) 2012 Thomas Freitag // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -257,6 +258,10 @@ JPXStream::JPXStream(Stream *strA): bitBufLen = 0; bitBufSkip = gFalse; byteCount = 0; + + curX = curY = 0; + curComp = 0; + readBufLen = 0; } JPXStream::~JPXStream() { @@ -410,6 +415,10 @@ void JPXStream::fillReadBuf() { tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles + (curX - img.xTileOffset) / img.xTileSize; #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid + if (img.tiles == NULL || tileIdx >= img.nXTiles * img.nYTiles || img.tiles[tileIdx].tileComps == NULL) { + error(errSyntaxError, getPos(), "Unexpected tileIdx in fillReadBuf in JPX stream"); + return; + } tileComp = &img.tiles[tileIdx].tileComps[curComp]; #else tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp]; @@ -420,6 +429,10 @@ void JPXStream::fillReadBuf() { error(errSyntaxError, getPos(), "Unexpected ty in fillReadBuf in JPX stream"); return; } + if (unlikely(tx >= (tileComp->x1 - tileComp->x0))) { + error(errSyntaxError, getPos(), "Unexpected tx in fillReadBuf in JPX stream"); + return; + } pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx]; pixBits = tileComp->prec; #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid @@ -535,7 +548,10 @@ void JPXStream::getImageParams(int *bitsPerComponent, } else { cover(4); for (i = 0; i < dataLen; ++i) { - bufStr->getChar(); + if (unlikely(bufStr->getChar() == EOF)) { + error(errSyntaxError, getPos(), "Unexpected EOF in getImageParams in JPX stream"); + break; + } } } } @@ -592,6 +608,13 @@ GBool JPXStream::readBoxes() { haveImgHdr = gFalse; + // initialize in case there is a parse error + img.xSize = img.ySize = 0; + img.xOffset = img.yOffset = 0; + img.xTileSize = img.yTileSize = 0; + img.xTileOffset = img.yTileOffset = 0; + img.nComps = 0; + // check for a naked JPEG 2000 codestream (without the JP2/JPX // wrapper) -- this appears to be a violation of the PDF spec, but // Acrobat allows it @@ -895,7 +918,7 @@ GBool JPXStream::readCodestream(Guint len) { JPXTileComp *tileComp; int segType; GBool haveSIZ, haveCOD, haveQCD, haveSOT; - Guint precinctSize, style; + Guint precinctSize, style, nDecompLevels; Guint segLen, capabilities, comp, i, j, r; //----- main header @@ -998,11 +1021,15 @@ GBool JPXStream::readCodestream(Guint len) { "JPX COD marker segment before SIZ segment"); return gFalse; } + if (img.tiles == NULL || img.nXTiles * img.nYTiles == 0 || img.tiles[0].tileComps == NULL) { + error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); + return gFalse; + } if (!readUByte(&img.tiles[0].tileComps[0].style) || !readUByte(&img.tiles[0].progOrder) || !readUWord(&img.tiles[0].nLayers) || !readUByte(&img.tiles[0].multiComp) || - !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) || + !readUByte(&nDecompLevels) || !readUByte(&img.tiles[0].tileComps[0].codeBlockW) || !readUByte(&img.tiles[0].tileComps[0].codeBlockH) || !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) || @@ -1010,12 +1037,13 @@ GBool JPXStream::readCodestream(Guint len) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } - if (img.tiles[0].tileComps[0].nDecompLevels > 32 || + if (nDecompLevels > 32 || img.tiles[0].tileComps[0].codeBlockW > 8 || img.tiles[0].tileComps[0].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } + img.tiles[0].tileComps[0].nDecompLevels = nDecompLevels; img.tiles[0].tileComps[0].codeBlockW += 2; img.tiles[0].tileComps[0].codeBlockH += 2; for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { @@ -1040,9 +1068,13 @@ GBool JPXStream::readCodestream(Guint len) { img.tiles[0].tileComps[0].transform; } img.tiles[i].tileComps[comp].resLevels = - (JPXResLevel *)gmallocn( + (JPXResLevel *)gmallocn_checkoverflow( (img.tiles[i].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); + if (img.tiles[i].tileComps[comp].resLevels == NULL) { + error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); + return gFalse; + } for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; } @@ -1089,7 +1121,7 @@ GBool JPXStream::readCodestream(Guint len) { (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&style) || - !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) || + !readUByte(&nDecompLevels) || !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) || !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) || !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) || @@ -1097,12 +1129,13 @@ GBool JPXStream::readCodestream(Guint len) { error(errSyntaxError, getPos(), "Error in JPX COC marker segment"); return gFalse; } - if (img.tiles[0].tileComps[comp].nDecompLevels > 32 || + if (nDecompLevels > 32 || img.tiles[0].tileComps[comp].codeBlockW > 8 || img.tiles[0].tileComps[comp].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COC marker segment"); return gFalse; } + img.tiles[0].tileComps[comp].nDecompLevels = nDecompLevels; img.tiles[0].tileComps[comp].style = (img.tiles[0].tileComps[comp].style & ~1) | (style & 1); img.tiles[0].tileComps[comp].codeBlockW += 2; @@ -1494,7 +1527,7 @@ GBool JPXStream::readTilePart() { GBool haveSOD; Guint tileIdx, tilePartLen, tilePartIdx, nTileParts; GBool tilePartToEOC; - Guint precinctSize, style; + Guint precinctSize, style, nDecompLevels; Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen; Guint i, j, k, cbX, cbY, r, pre, sb, cbi, cbj; int segType, level; @@ -1508,8 +1541,8 @@ GBool JPXStream::readTilePart() { return gFalse; } - if ((tilePartIdx > 0 && !img.tiles[tileIdx].init) || - tileIdx >= img.nXTiles * img.nYTiles) { + if (tileIdx >= img.nXTiles * img.nYTiles || + (tilePartIdx > 0 && !img.tiles[tileIdx].init)) { error(errSyntaxError, getPos(), "Weird tile index in JPX stream"); return gFalse; } @@ -1531,7 +1564,7 @@ GBool JPXStream::readTilePart() { !readUByte(&img.tiles[tileIdx].progOrder) || !readUWord(&img.tiles[tileIdx].nLayers) || !readUByte(&img.tiles[tileIdx].multiComp) || - !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) || + !readUByte(&nDecompLevels) || !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) || !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) || !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) || @@ -1539,12 +1572,13 @@ GBool JPXStream::readTilePart() { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } - if (img.tiles[tileIdx].tileComps[0].nDecompLevels > 32 || + if (nDecompLevels > 32 || img.tiles[tileIdx].tileComps[0].codeBlockW > 8 || img.tiles[tileIdx].tileComps[0].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } + img.tiles[tileIdx].tileComps[0].nDecompLevels = nDecompLevels; img.tiles[tileIdx].tileComps[0].codeBlockW += 2; img.tiles[tileIdx].tileComps[0].codeBlockH += 2; for (comp = 0; comp < img.nComps; ++comp) { @@ -1605,7 +1639,7 @@ GBool JPXStream::readTilePart() { (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&style) || - !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) || + !readUByte(&nDecompLevels) || !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) || !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) || !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) || @@ -1613,12 +1647,13 @@ GBool JPXStream::readTilePart() { error(errSyntaxError, getPos(), "Error in JPX COC marker segment"); return gFalse; } - if (img.tiles[tileIdx].tileComps[comp].nDecompLevels > 32 || + if (nDecompLevels > 32 || img.tiles[tileIdx].tileComps[comp].codeBlockW > 8 || img.tiles[tileIdx].tileComps[comp].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } + img.tiles[tileIdx].tileComps[comp].nDecompLevels = nDecompLevels; img.tiles[tileIdx].tileComps[comp].style = (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1); img.tiles[tileIdx].tileComps[comp].codeBlockW += 2; @@ -2350,6 +2385,12 @@ GBool JPXStream::readTilePartData(Guint tileIdx, tile->res = 0; } } + tileComp = &tile->tileComps[tile->comp]; + if (tile->res >= tileComp->nDecompLevels + 1) { + if (++tile->comp == img.nComps) { + return gTrue; + } + } } break; case 3: // precinct, component, resolution level, layer @@ -2840,7 +2881,13 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, // i-quant parameters if (qStyle == 0) { cover(100); - eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f; + const Guint stepIndex = 3*r - 2 + sb; + if (unlikely(stepIndex >= tileComp->nQuantSteps)) { + error(errSyntaxError, getPos(), + "Wrong index for quantSteps in inverseTransformLevel in JPX stream"); + break; + } + eps = (tileComp->quantSteps[stepIndex] >> 3) & 0x1f; shift = guard + eps - 1; mu = 0; // make gcc happy } else { @@ -2958,6 +3005,16 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, *bufPtr = dataPtr[x]; } } + if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { + x = tileComp->x1 - tileComp->x0 + 5; + } else { + x = tileComp->y1 - tileComp->y0 + 5; + } + if (offset + nx2 > x || nx2 == 0) { + error(errSyntaxError, getPos(), + "Invalid call of inverseTransform1D in inverseTransformLevel in JPX stream"); + return; + } inverseTransform1D(tileComp, tileComp->buf, offset, nx2); for (x = 0, bufPtr = tileComp->buf + offset; x < nx2; ++x, ++bufPtr) { dataPtr[x] = *bufPtr; @@ -2998,6 +3055,16 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, *bufPtr = dataPtr[y * tileComp->w]; } } + if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { + y = tileComp->x1 - tileComp->x0 + 5; + } else { + y = tileComp->y1 - tileComp->y0 + 5; + } + if (offset + ny2 > y || ny2 == 0) { + error(errSyntaxError, getPos(), + "Invalid call of inverseTransform1D in inverseTransformLevel in JPX stream"); + return; + } inverseTransform1D(tileComp, tileComp->buf, offset, ny2); for (y = 0, bufPtr = tileComp->buf + offset; y < ny2; ++y, ++bufPtr) { dataPtr[y * tileComp->w] = *bufPtr; diff --git a/poppler/Lexer.cc b/poppler/Lexer.cc index d12e2e8..01b730b 100644 --- a/poppler/Lexer.cc +++ b/poppler/Lexer.cc @@ -13,7 +13,7 @@ // All changes made under the Poppler project to this file are licensed // under GPL version 2 or later // -// Copyright (C) 2006-2010 Albert Astals Cid +// Copyright (C) 2006-2010, 2012 Albert Astals Cid // Copyright (C) 2006 Krzysztof Kowalczyk // Copyright (C) 2010 Carlos Garcia Campos // Copyright (C) 2012 Adrian Johnson @@ -237,7 +237,17 @@ Object *Lexer::getObj(Object *obj, int objNum) { if (overflownUnsignedInteger) { obj->initReal(xf); } else { - obj->initUint(xui); + if (neg) { + if (xui-1 == INT_MAX) { + obj->initInt(INT_MIN); + } else { + xf = xui; + xf = -xf; + obj->initReal(xf); + } + } else { + obj->initUint(xui); + } } } else { obj->initInt(xi); diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc index 5df506f..052bc74 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -27,6 +27,7 @@ // Copyright (C) 2009 Kovid Goyal // Copyright (C) 2009-2011 Adrian Johnson // Copyright (C) 2012 Fabio D'Urso +// Copyright (C) 2012 Lu Wang // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -2151,7 +2152,8 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) { writePS("%%EndResource\n"); err1: - strObj.streamClose(); + if (strObj.isStream()) + strObj.streamClose(); strObj.free(); } @@ -3049,7 +3051,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, double m0, m1, m2, m3, m4, m5; int nStripes, stripeH, stripeY; int c, w, h, x, y, comp, i; - int numComps; + int numComps, initialNumComps; #endif char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null Guchar digit; @@ -3132,6 +3134,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, stripeH = (sliceH + nStripes - 1) / nStripes; // render the stripes + initialNumComps = numComps; for (stripeY = sliceY; stripeY < sliceH; stripeY += stripeH) { // rasterize a stripe @@ -3151,6 +3154,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, // draw the rasterized image bitmap = splashOut->getBitmap(); + numComps = initialNumComps; w = bitmap->getWidth(); h = bitmap->getHeight(); writePS("gsave\n"); @@ -3519,6 +3523,7 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { saveState(NULL); } + xScale = yScale = 1; switch (mode) { case psModePSOrigPageSizes: @@ -3629,8 +3634,6 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { } else { yScale = xScale; } - } else { - xScale = yScale = 1; } // deal with odd bounding boxes or clipping if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { @@ -3692,7 +3695,6 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { if (tx != 0 || ty != 0) { writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty); } - xScale = yScale = 1; break; case psModeForm: @@ -3700,7 +3702,6 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { writePS("begin xpdf begin\n"); writePS("pdfStartPage\n"); tx = ty = 0; - xScale = yScale = 1; rotate = 0; break; } @@ -5840,7 +5841,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, } #endif if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && - colorMap->getColorSpace()->getMode() == csSeparation) { + colorMap->getColorSpace()->getMode() == csSeparation && colorMap->getBits() == 8) { color.c[0] = gfxColorComp1; sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); sepCS->getCMYK(&color, &cmyk); @@ -6199,7 +6200,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap, } else { if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && - colorMap->getColorSpace()->getMode() == csSeparation) { + colorMap->getColorSpace()->getMode() == csSeparation && colorMap->getBits() == 8) { color.c[0] = gfxColorComp1; sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); sepCS->getCMYK(&color, &cmyk); diff --git a/poppler/SecurityHandler.cc b/poppler/SecurityHandler.cc index 00c4ae1..a48449a 100644 --- a/poppler/SecurityHandler.cc +++ b/poppler/SecurityHandler.cc @@ -105,7 +105,12 @@ GBool SecurityHandler::checkEncryption(GooString *ownerPassword, } } if (!ok) { - error(errCommandLine, -1, "Incorrect password"); + if (!ownerPassword && !userPassword) { + GooString dummy; + return checkEncryption(&dummy, &dummy); + } else { + error(errCommandLine, -1, "Incorrect password"); + } } return ok; } diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc index be35c25..7e19a40 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -661,11 +661,6 @@ static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest, SplashColor rgbSrc; SplashColor rgbDest; SplashColor rgbBlend; - for (i = 0; i < 4; i++) { - // convert back to subtractive (s. Splash.cc) - src[i] = 0xff - src[i]; - dest[i] = 0xff - dest[i]; - } cmykToRGB(src, rgbSrc); cmykToRGB(dest, rgbDest); for (i = 0; i < 3; ++i) { @@ -681,10 +676,6 @@ static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest, } } rgbToCMYK(rgbBlend, blend); - for (i = 0; i < 4; i++) { - // convert back to additive (s. Splash.cc) - blend[i] = 0xff - blend[i]; - } } else #endif { @@ -848,6 +839,8 @@ static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest, Guchar r0, g0, b0; #ifdef SPLASH_CMYK Guchar r1, g1, b1; + int i; + SplashColor src2, dest2; #endif switch (cm) { @@ -866,15 +859,24 @@ static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: + for (i = 0; i < 4; i++) { + // convert to additive + src2[i] = 0xff - src[i]; + dest2[i] = 0xff - dest[i]; + } // NB: inputs have already been converted to additive mode - setSat(src[0], src[1], src[2], getSat(dest[0], dest[1], dest[2]), + setSat(src2[0], src2[1], src2[2], getSat(dest2[0], dest2[1], dest2[2]), &r0, &g0, &b0); - setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]), + setLum(r0, g0, b0, getLum(dest2[0], dest2[1], dest2[2]), &r1, &g1, &b1); blend[0] = r1; blend[1] = g1; blend[2] = b1; - blend[3] = dest[3]; + blend[3] = dest2[3]; + for (i = 0; i < 4; i++) { + // convert back to subtractive + blend[i] = 0xff - blend[i]; + } break; #endif } @@ -886,6 +888,8 @@ static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest, Guchar r0, g0, b0; #ifdef SPLASH_CMYK Guchar r1, g1, b1; + int i; + SplashColor src2, dest2; #endif switch (cm) { @@ -904,15 +908,23 @@ static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: - // NB: inputs have already been converted to additive mode - setSat(dest[0], dest[1], dest[2], getSat(src[0], src[1], src[2]), + for (i = 0; i < 4; i++) { + // convert to additive + src2[i] = 0xff - src[i]; + dest2[i] = 0xff - dest[i]; + } + setSat(dest2[0], dest2[1], dest2[2], getSat(src2[0], src2[1], src2[2]), &r0, &g0, &b0); - setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]), + setLum(r0, g0, b0, getLum(dest2[0], dest2[1], dest2[2]), &r1, &g1, &b1); blend[0] = r1; blend[1] = g1; blend[2] = b1; - blend[3] = dest[3]; + blend[3] = dest2[3]; + for (i = 0; i < 4; i++) { + // convert back to subtractive + blend[i] = 0xff - blend[i]; + } break; #endif } @@ -922,6 +934,8 @@ static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { #if SPLASH_CMYK Guchar r, g, b; + int i; + SplashColor src2, dest2; #endif switch (cm) { @@ -938,13 +952,21 @@ static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: - // NB: inputs have already been converted to additive mode - setLum(src[0], src[1], src[2], getLum(dest[0], dest[1], dest[2]), + for (i = 0; i < 4; i++) { + // convert to additive + src2[i] = 0xff - src[i]; + dest2[i] = 0xff - dest[i]; + } + setLum(src2[0], src2[1], src2[2], getLum(dest2[0], dest2[1], dest2[2]), &r, &g, &b); blend[0] = r; blend[1] = g; blend[2] = b; - blend[3] = dest[3]; + blend[3] = dest2[3]; + for (i = 0; i < 4; i++) { + // convert back to subtractive + blend[i] = 0xff - blend[i]; + } break; #endif } @@ -955,6 +977,8 @@ static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest, SplashColorMode cm) { #if SPLASH_CMYK Guchar r, g, b; + int i; + SplashColor src2, dest2; #endif switch (cm) { @@ -971,13 +995,21 @@ static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest, break; #if SPLASH_CMYK case splashModeCMYK8: - // NB: inputs have already been converted to additive mode - setLum(dest[0], dest[1], dest[2], getLum(src[0], src[1], src[2]), + for (i = 0; i < 4; i++) { + // convert to additive + src2[i] = 0xff - src[i]; + dest2[i] = 0xff - dest[i]; + } + setLum(dest2[0], dest2[1], dest2[2], getLum(src2[0], src2[1], src2[2]), &r, &g, &b); blend[0] = r; blend[1] = g; blend[2] = b; - blend[3] = src[3]; + blend[3] = src2[3]; + for (i = 0; i < 4; i++) { + // convert back to subtractive + blend[i] = 0xff - blend[i]; + } break; #endif } @@ -2250,6 +2282,14 @@ GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y, // create new entry in the font cache if (nT3Fonts == splashOutT3FontCacheSize) { + t3gs = t3GlyphStack; + while (t3gs != NULL) { + if (t3gs->cache == t3FontCache[nT3Fonts - 1]) { + error(errSyntaxWarning, -1, "t3FontCache reaches limit but font still on stack in SplashOutputDev::beginType3Char"); + return gTrue; + } + t3gs = t3gs->next; + } delete t3FontCache[nT3Fonts - 1]; --nT3Fonts; } diff --git a/poppler/Stream.cc b/poppler/Stream.cc index 4ce6c00..f287406 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -1707,7 +1707,7 @@ int CCITTFaxStream::lookChar() { // 2-D encoding if (nextLine2D) { - for (i = 0; codingLine[i] < columns; ++i) { + for (i = 0; i < columns && codingLine[i] < columns; ++i) { refLine[i] = codingLine[i]; } refLine[i++] = columns; @@ -1723,7 +1723,7 @@ int CCITTFaxStream::lookChar() { // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible // exception at right edge: // refLine[b1i] = refLine[b1i+1] = columns is possible - while (codingLine[a0i] < columns) { + while (codingLine[a0i] < columns && !err) { code1 = getTwoDimCode(); switch (code1) { case twoDimPass: @@ -1757,49 +1757,109 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } break; case twoDimVertR3: + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixels(refLine[b1i] + 3, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertR2: + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixels(refLine[b1i] + 2, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertR1: + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixels(refLine[b1i] + 1, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVert0: + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixels(refLine[b1i], blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertL3: + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixelsNeg(refLine[b1i] - 3, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { @@ -1810,10 +1870,22 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertL2: + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixelsNeg(refLine[b1i] - 2, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { @@ -1824,10 +1896,22 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; case twoDimVertL1: + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } addPixelsNeg(refLine[b1i] - 1, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { @@ -1838,6 +1922,12 @@ int CCITTFaxStream::lookChar() { } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; + if (unlikely(b1i > columns + 1)) { + error(errSyntaxError, getPos(), + "Bad 2D code {0:04x} in CCITTFax stream", code1); + err = gTrue; + break; + } } } break; @@ -2021,6 +2111,12 @@ int CCITTFaxStream::lookChar() { outputBits = 0; if (codingLine[a0i] < columns) { ++a0i; + if (unlikely(a0i > columns)) { + error(errSyntaxError, getPos(), + "Bad bits {0:04x} in CCITTFax stream", bits); + err = gTrue; + break; + } outputBits = codingLine[a0i] - codingLine[a0i - 1]; } else if (bits > 0) { buf <<= bits; diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc index e8d993b..a9c9d70 100644 --- a/poppler/TextOutputDev.cc +++ b/poppler/TextOutputDev.cc @@ -20,7 +20,7 @@ // Copyright (C) 2006 Jeff Muizelaar // Copyright (C) 2007, 2008 Adrian Johnson // Copyright (C) 2008 Koji Otani -// Copyright (C) 2008, 2010, 2011 Albert Astals Cid +// Copyright (C) 2008, 2010-2012 Albert Astals Cid // Copyright (C) 2008 Pino Toscano // Copyright (C) 2008, 2010 Hib Eris // Copyright (C) 2009 Ross Moore @@ -29,6 +29,7 @@ // Copyright (C) 2010 Suzuki Toshiya // Copyright (C) 2011 Sam Liao // Copyright (C) 2012 Horst Prote +// Copyright (C) 2012 Jason Crain // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -2299,7 +2300,9 @@ void TextPage::addChar(GfxState *state, double x, double y, state->transform(x, y, &x1, &y1); if (x1 + w1 < 0 || x1 > pageWidth || y1 + h1 < 0 || y1 > pageHeight || - w1 > pageWidth || h1 > pageHeight) { + w1 > pageWidth || h1 > pageHeight || + x1 != x1 || y1 != y1 || // IEEE way of checking for isnan + w1 != w1 || h1 != h1) { charPos += nBytes; return; } diff --git a/poppler/XRef.cc b/poppler/XRef.cc index 3564807..8865e17 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -267,6 +267,7 @@ void XRef::init() { objStrs = new PopplerCache(5); mainXRefEntriesOffset = 0; xRefStream = gFalse; + rootNum = -1; } XRef::XRef() { @@ -719,6 +720,10 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { error(errSyntaxError, -1, "Invalid 'size' inside xref table"); return gFalse; } + if (first + n > size) { + error(errSyntaxError, -1, "Invalid 'first' or 'n' inside xref table"); + return gFalse; + } } for (i = first; i < first + n; ++i) { if (w[0] == 0) { @@ -1085,6 +1090,8 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) { objStr = NULL; goto err; } else { + // XRef could be reconstructed in constructor of ObjectStream: + e = getEntry(num); ObjectStreamKey *newkey = new ObjectStreamKey(e->offset); ObjectStreamItem *newitem = new ObjectStreamItem(objStr); objStrs->put(newkey, newitem); diff --git a/qt4/tests/CMakeLists.txt b/qt4/tests/CMakeLists.txt index 028c1e1..9eaaa02 100644 --- a/qt4/tests/CMakeLists.txt +++ b/qt4/tests/CMakeLists.txt @@ -56,6 +56,7 @@ qt4_add_qtest(check_password check_password.cpp) qt4_add_qtest(check_permissions check_permissions.cpp) qt4_add_qtest(check_search check_search.cpp) qt4_add_qtest(check_actualtext check_actualtext.cpp) +qt4_add_qtest(check_lexer check_lexer.cpp) if (NOT WIN32) qt4_add_qtest(check_strings check_strings.cpp) endif (NOT WIN32) diff --git a/qt4/tests/Makefile.am b/qt4/tests/Makefile.am index be8ea35..6286d8c 100644 --- a/qt4/tests/Makefile.am +++ b/qt4/tests/Makefile.am @@ -79,7 +79,8 @@ TESTS = \ check_password \ check_pagelayout \ check_search \ - check_strings + check_strings \ + check_lexer check_PROGRAMS = $(TESTS) @@ -135,5 +136,9 @@ check_strings_SOURCES = check_strings.cpp check_strings.$(OBJEXT): check_strings.moc check_strings_LDADD = $(LDADDS) $(POPPLER_QT4_TEST_LIBS) +check_lexer_SOURCES = check_lexer.cpp +check_lexer.$(OBJEXT): check_lexer.moc +check_lexer_LDADD = $(LDADDS) $(POPPLER_QT4_TEST_LIBS) + endif diff --git a/qt4/tests/check_lexer.cpp b/qt4/tests/check_lexer.cpp new file mode 100644 index 0000000..904be14 --- /dev/null +++ b/qt4/tests/check_lexer.cpp @@ -0,0 +1,118 @@ +#include + +#include "Object.h" +#include "Lexer.h" + +class TestLexer : public QObject +{ + Q_OBJECT +private slots: + void testNumbers(); +}; + +void TestLexer::testNumbers() +{ + char *data = "0 1 -1 2147483647 -2147483647 2147483648 -2147483648 4294967297 -2147483649 0.1 1.1 -1.1 2147483647.1 -2147483647.1 2147483648.1 -2147483648.1 4294967297.1 -2147483649.1"; + Object dummy; + MemStream *stream = new MemStream(data, 0, strlen(data), &dummy); + Lexer *lexer = new Lexer(NULL, stream); + QVERIFY( lexer ); + + Object obj; + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objInt); + QCOMPARE(obj.getInt(), 0); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objInt); + QCOMPARE(obj.getInt(), 1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objInt); + QCOMPARE(obj.getInt(), -1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objInt); + QCOMPARE(obj.getInt(), 2147483647); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objInt); + QCOMPARE(obj.getInt(), -2147483647); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objUint); + QCOMPARE(obj.getUint(), (unsigned int)2147483648); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objInt); + QCOMPARE(obj.getInt(), (int)-2147483648); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), (double)4294967297); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), (double)-2147483649); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), 0.1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), 1.1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), -1.1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), 2147483647.1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), -2147483647.1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), 2147483648.1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), -2147483648.1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), 4294967297.1); + obj.free(); + + lexer->getObj(&obj); + QCOMPARE(obj.getType(), objReal); + QCOMPARE(obj.getReal(), -2147483649.1); + obj.free(); + + delete lexer; +} + +QTEST_MAIN(TestLexer) +#include "check_lexer.moc" + diff --git a/splash/Splash.cc b/splash/Splash.cc index 0e07c70..62d8f8d 100644 --- a/splash/Splash.cc +++ b/splash/Splash.cc @@ -16,6 +16,7 @@ // Copyright (C) 2010-2012 Thomas Freitag // Copyright (C) 2010 Christian Feuersänger // Copyright (C) 2011, 2012 William Bader +// Copyright (C) 2012 Markus Trippelsdorf // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -337,9 +338,6 @@ void Splash::pipeRun(SplashPipe *pipe) { SplashColorPtr cSrc; Guchar cResult0, cResult1, cResult2, cResult3; int t; -#if SPLASH_CMYK - SplashColor cSrc2, cDest2; -#endif //----- source color @@ -521,25 +519,6 @@ void Splash::pipeRun(SplashPipe *pipe) { //----- blend function if (state->blendFunc) { -#if SPLASH_CMYK - if (bitmap->mode == splashModeCMYK8) { - // convert colors to additive - cSrc2[0] = 0xff - cSrc[0]; - cSrc2[1] = 0xff - cSrc[1]; - cSrc2[2] = 0xff - cSrc[2]; - cSrc2[3] = 0xff - cSrc[3]; - cDest2[0] = 0xff - cDest[0]; - cDest2[1] = 0xff - cDest[1]; - cDest2[2] = 0xff - cDest[2]; - cDest2[3] = 0xff - cDest[3]; - (*state->blendFunc)(cSrc2, cDest2, cBlend, bitmap->mode); - // convert result back to subtractive - cBlend[0] = 0xff - cBlend[0]; - cBlend[1] = 0xff - cBlend[1]; - cBlend[2] = 0xff - cBlend[2]; - cBlend[3] = 0xff - cBlend[3]; - } else -#endif (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode); } @@ -3456,6 +3435,9 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, } scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, scaledWidth, scaledHeight); + if (scaledImg == NULL) { + return splashErrBadArg; + } blitImage(scaledImg, srcAlpha, x0, y0, clipRes); delete scaledImg; } @@ -3491,6 +3473,9 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, } scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, scaledWidth, scaledHeight); + if (scaledImg == NULL) { + return splashErrBadArg; + } vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps); blitImage(scaledImg, srcAlpha, x0, y0, clipRes); delete scaledImg; diff --git a/splash/SplashClip.cc b/splash/SplashClip.cc index 41b73c8..fb18831 100644 --- a/splash/SplashClip.cc +++ b/splash/SplashClip.cc @@ -384,4 +384,27 @@ void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) { for (i = 0; i < length; ++i) { scanners[i]->clipAALine(aaBuf, x0, x1, y); } + if (*x0 > *x1) { + *x0 = *x1; + } + if (*x0 < 0) { + *x0 = 0; + } + if ((*x0>>1) >= aaBuf->getRowSize()) { + xx0 = *x0; + *x0 = (aaBuf->getRowSize() - 1) << 1; + if (xx0 & 1) { + *x0 = *x0 + 1; + } + } + if (*x1 < *x0) { + *x1 = *x0; + } + if ((*x1>>1) >= aaBuf->getRowSize()) { + xx0 = *x1; + *x1 = (aaBuf->getRowSize() - 1) << 1; + if (xx0 & 1) { + *x1 = *x1 + 1; + } + } } diff --git a/splash/SplashFTFont.cc b/splash/SplashFTFont.cc index f18b58b..e57425e 100644 --- a/splash/SplashFTFont.cc +++ b/splash/SplashFTFont.cc @@ -16,6 +16,7 @@ // Copyright (C) 2009 Petr Gajdos // Copyright (C) 2010 Suzuki Toshiya // Copyright (C) 2011 Andreas Hartmetz +// Copyright (C) 2012 Thomas Freitag // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -428,6 +429,9 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { if (FT_Get_Glyph(slot, &glyph)) { return NULL; } + if (FT_Outline_Check(&((FT_OutlineGlyph)glyph)->outline)) { + return NULL; + } path.path = new SplashPath(); path.textScale = textScale; path.needClose = gFalse; diff --git a/splash/SplashXPathScanner.cc b/splash/SplashXPathScanner.cc index c9fe5e5..738cef7 100644 --- a/splash/SplashXPathScanner.cc +++ b/splash/SplashXPathScanner.cc @@ -441,6 +441,9 @@ void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, } } } + if (xxMin > xxMax) { + xxMin = xxMax; + } *x0 = xxMin / splashAASize; *x1 = (xxMax - 1) / splashAASize; } diff --git a/utils/pdfseparate.cc b/utils/pdfseparate.cc index 9fbbc3a..25fac5a 100644 --- a/utils/pdfseparate.cc +++ b/utils/pdfseparate.cc @@ -5,6 +5,7 @@ // This file is licensed under the GPLv2 or later // // Copyright (C) 2011, 2012 Thomas Freitag +// Copyright (C) 2012 Albert Astals Cid // //======================================================================== #include "config.h" @@ -109,7 +110,10 @@ main (int argc, char *argv[]) goto err0; } globalParams = new GlobalParams(); - extractPages (argv[1], argv[2]); + ok = extractPages (argv[1], argv[2]); + if (ok) { + exitCode = 0; + } delete globalParams; err0: