File poppler-CVE-2009-JBIG2.patch of Package poppler

diff --git a/poppler/JBIG2Stream.cc b/poppler/JBIG2Stream.cc
index 74b5ab8..33cd427 100644
--- a/poppler/JBIG2Stream.cc
+++ b/poppler/JBIG2Stream.cc
@@ -15,7 +15,7 @@
 //
 // Copyright (C) 2006 Raj Kumar <rkumar@archive.org>
 // Copyright (C) 2006 Paul Walmsley <paul@booyaka.com>
-// Copyright (C) 2006-2008 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006-2009 Albert Astals Cid <aacid@kde.org>
 //
 // 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
@@ -438,12 +438,14 @@ void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) {
   table[i] = table[len];
 
   // assign prefixes
-  i = 0;
-  prefix = 0;
-  table[i++].prefix = prefix++;
-  for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) {
-    prefix <<= table[i].prefixLen - table[i-1].prefixLen;
-    table[i].prefix = prefix++;
+  if (table[0].rangeLen != jbig2HuffmanEOT) {
+    i = 0;
+    prefix = 0;
+    table[i++].prefix = prefix++;
+    for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) {
+      prefix <<= table[i].prefixLen - table[i-1].prefixLen;
+      table[i].prefix = prefix++;
+    }
   }
 }
 
@@ -507,7 +509,7 @@ int JBIG2MMRDecoder::get2DCode() {
   }
   if (p->bits < 0) {
     error(str->getPos(), "Bad two dim code in JBIG2 MMR stream");
-    return 0;
+    return EOF;
   }
   bufLen -= p->bits;
   return p->n;
@@ -684,6 +686,7 @@ public:
   void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp);
   Guchar *getDataPtr() { return data; }
   int getDataSize() { return h * line; }
+  GBool isOk() { return data != NULL; }
 
 private:
 
@@ -778,6 +781,8 @@ void JBIG2Bitmap::clearToOne() {
 inline void JBIG2Bitmap::getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr) {
   if (y < 0 || y >= h || x >= w) {
     ptr->p = NULL;
+    ptr->shift = 0; // make gcc happy
+    ptr->x = 0; // make gcc happy
   } else if (x < 0) {
     ptr->p = &data[y * line];
     ptr->shift = 7;
@@ -822,6 +827,10 @@ void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y,
   Guint src0, src1, src, dest, s1, s2, m1, m2, m3;
   GBool oneByte;
 
+  // check for the pathological case where y = -2^31
+  if (y < -0x7fffffff) {
+    return;
+  }
   if (y < 0) {
     y0 = -y;
   } else {
@@ -1324,6 +1333,13 @@ void JBIG2Stream::readSegments() {
     // keep track of the start of the segment data 
     segDataPos = getPos();
 
+    // check for missing page information segment
+    if (!pageBitmap && ((segType >= 4 && segType <= 7) ||
+			(segType >= 20 && segType <= 43))) {
+      error(getPos(), "First JBIG2 segment associated with a page must be a page information segment");
+      goto syntaxError;
+    }
+
     // read the segment data
     switch (segType) {
     case 0:
@@ -1478,6 +1494,8 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
   Guint i, j, k;
   Guchar *p;
 
+  symWidths = NULL;
+
   // symbol dictionary flags
   if (!readUWord(&flags)) {
     goto eofError;
@@ -1538,7 +1556,13 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
     // part of it
     if ((seg = findSegment(refSegs[i]))) {
       if (seg->getType() == jbig2SegSymbolDict) {
-        numInputSyms += ((JBIG2SymbolDict *)seg)->getSize();
+	j = ((JBIG2SymbolDict *)seg)->getSize();
+	if (numInputSyms > UINT_MAX - j) {
+	  error(getPos(), "Too many input symbols in JBIG2 symbol dictionary");
+	  delete codeTables;
+	  goto eofError;
+	}
+	numInputSyms += j;
       } else if (seg->getType() == jbig2SegCodeTable) {
         codeTables->append(seg);
       }
@@ -1547,13 +1571,18 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
       return gFalse;
     }
   }
+  if (numInputSyms > UINT_MAX - numNewSyms) {
+    error(getPos(), "Too many input symbols in JBIG2 symbol dictionary");
+    delete codeTables;
+    goto eofError;
+  }
 
   // compute symbol code length
-  symCodeLen = 0;
-  i = 1;
-  while (i < numInputSyms + numNewSyms) {
+  symCodeLen = 1;
+  i = (numInputSyms + numNewSyms) >> 1;
+  while (i) {
     ++symCodeLen;
-    i <<= 1;
+    i >>= 1;
   }
 
   // get the input symbol bitmaps
@@ -1584,6 +1613,9 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
     } else if (huffDH == 1) {
       huffDHTable = huffTableE;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffDW == 0) {
@@ -1591,17 +1623,26 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
     } else if (huffDW == 1) {
       huffDWTable = huffTableC;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffBMSize == 0) {
       huffBMSizeTable = huffTableA;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffBMSizeTable =
 	  ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffAggInst == 0) {
       huffAggInstTable = huffTableA;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffAggInstTable =
 	  ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
@@ -1634,7 +1675,6 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
   }
 
   // allocate symbol widths storage
-  symWidths = NULL;
   if (huff && !refAgg) {
     symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint));
   }
@@ -1676,6 +1716,10 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
 	goto syntaxError;
       }
       symWidth += dw;
+      if (i >= numNewSyms) {
+	error(getPos(), "Too many symbols in JBIG2 symbol dictionary");
+	goto syntaxError;
+      }
 
       // using a collective bitmap, so don't read a bitmap here
       if (huff && !refAgg) {
@@ -1712,6 +1756,10 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
 	    arithDecoder->decodeInt(&refDX, iardxStats);
 	    arithDecoder->decodeInt(&refDY, iardyStats);
 	  }
+	  if (symID >= numInputSyms + i) {
+	    error(getPos(), "Invalid symbol ID in JBIG2 symbol dictionary");
+	    goto syntaxError;
+	  }
 	  refBitmap = bitmaps[symID];
 	  bitmaps[numInputSyms + i] =
 	      readGenericRefinementRegion(symWidth, symHeight,
@@ -1778,6 +1826,13 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
     } else {
       arithDecoder->decodeInt(&run, iaexStats);
     }
+    if (i + run > numInputSyms + numNewSyms ||
+	(ex && j + run > numExSyms)) {
+      error(getPos(), "Too many exported symbols in JBIG2 symbol dictionary");
+      for ( ; j < numExSyms; ++j) symbolDict->setBitmap(j, NULL);
+      delete symbolDict;
+      goto syntaxError;
+    }
     if (ex) {
       for (cnt = 0; cnt < run; ++cnt) {
 	symbolDict->setBitmap(j++, bitmaps[i++]->copy());
@@ -1787,6 +1842,12 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
     }
     ex = !ex;
   }
+  if (j != numExSyms) {
+    error(getPos(), "Too few symbols in JBIG2 symbol dictionary");
+    for ( ; j < numExSyms; ++j) symbolDict->setBitmap(j, NULL);
+    delete symbolDict;
+    goto syntaxError;
+  }
 
   for (i = 0; i < numNewSyms; ++i) {
     delete bitmaps[numInputSyms + i];
@@ -1809,6 +1870,10 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
 
   return gTrue;
 
+ codeTableError:
+  error(getPos(), "Missing code table in JBIG2 symbol dictionary");
+  delete codeTables;
+
  syntaxError:
   for (i = 0; i < numNewSyms; ++i) {
     if (bitmaps[numInputSyms + i]) {
@@ -1911,6 +1976,8 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
       }
     } else {
       error(getPos(), "Invalid segment reference in JBIG2 text region");
+      delete codeTables;
+      return;
     }
   }
   symCodeLen = 0;
@@ -1945,6 +2012,9 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
     } else if (huffFS == 1) {
       huffFSTable = huffTableG;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffFSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffDS == 0) {
@@ -1954,6 +2024,9 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
     } else if (huffDS == 2) {
       huffDSTable = huffTableJ;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffDSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffDT == 0) {
@@ -1963,6 +2036,9 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
     } else if (huffDT == 2) {
       huffDTTable = huffTableM;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffDTTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffRDW == 0) {
@@ -1970,6 +2046,9 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
     } else if (huffRDW == 1) {
       huffRDWTable = huffTableO;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffRDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffRDH == 0) {
@@ -1977,6 +2056,9 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
     } else if (huffRDH == 1) {
       huffRDHTable = huffTableO;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffRDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffRDX == 0) {
@@ -1984,6 +2066,9 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
     } else if (huffRDX == 1) {
       huffRDXTable = huffTableO;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffRDXTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffRDY == 0) {
@@ -1991,11 +2076,17 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
     } else if (huffRDY == 1) {
       huffRDYTable = huffTableO;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffRDYTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
     if (huffRSize == 0) {
       huffRSizeTable = huffTableA;
     } else {
+      if (i >= (Guint)codeTables->getLength()) {
+	goto codeTableError;
+      }
       huffRSizeTable =
 	  ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
     }
@@ -2069,18 +2160,20 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
 
   gfree(syms);
 
-  // combine the region bitmap into the page bitmap
-  if (imm) {
-    if (pageH == 0xffffffff && y + h > curPageH) {
-      pageBitmap->expand(y + h, pageDefPixel);
-    }
-    pageBitmap->combine(bitmap, x, y, extCombOp);
-    delete bitmap;
+  if (bitmap) {
+    // combine the region bitmap into the page bitmap
+    if (imm) {
+      if (pageH == 0xffffffff && y + h > curPageH) {
+        pageBitmap->expand(y + h, pageDefPixel);
+      }
+      pageBitmap->combine(bitmap, x, y, extCombOp);
+      delete bitmap;
 
-  // store the region bitmap
-  } else {
-    bitmap->setSegNum(segNum);
-    segments->append(bitmap);
+    // store the region bitmap
+    } else {
+      bitmap->setSegNum(segNum);
+      segments->append(bitmap);
+    }
   }
 
   // clean up the Huffman decoder
@@ -2090,8 +2183,15 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
 
   return;
 
+ codeTableError:
+  error(getPos(), "Missing code table in JBIG2 text region");
+  gfree(codeTables);
+  delete syms;
+  return;
+
  eofError:
   error(getPos(), "Unexpected EOF in JBIG2 stream");
+  return;
 }
 
 JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine,
@@ -2126,6 +2226,10 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine,
 
   // allocate the bitmap
   bitmap = new JBIG2Bitmap(0, w, h);
+  if (!bitmap->isOk()) {
+    delete bitmap;
+    return NULL;
+  }
   if (defPixel) {
     bitmap->clearToOne();
   } else {
@@ -2202,73 +2306,84 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine,
 	  ri = 0;
 	}
 	if (ri) {
+	  GBool decodeSuccess;
 	  if (huff) {
-	    huffDecoder->decodeInt(&rdw, huffRDWTable);
-	    huffDecoder->decodeInt(&rdh, huffRDHTable);
-	    huffDecoder->decodeInt(&rdx, huffRDXTable);
-	    huffDecoder->decodeInt(&rdy, huffRDYTable);
-	    huffDecoder->decodeInt(&bmSize, huffRSizeTable);
+	    decodeSuccess = huffDecoder->decodeInt(&rdw, huffRDWTable);
+	    decodeSuccess = decodeSuccess && huffDecoder->decodeInt(&rdh, huffRDHTable);
+	    decodeSuccess = decodeSuccess && huffDecoder->decodeInt(&rdx, huffRDXTable);
+	    decodeSuccess = decodeSuccess && huffDecoder->decodeInt(&rdy, huffRDYTable);
+	    decodeSuccess = decodeSuccess && huffDecoder->decodeInt(&bmSize, huffRSizeTable);
 	    huffDecoder->reset();
 	    arithDecoder->start();
 	  } else {
-	    arithDecoder->decodeInt(&rdw, iardwStats);
-	    arithDecoder->decodeInt(&rdh, iardhStats);
-	    arithDecoder->decodeInt(&rdx, iardxStats);
-	    arithDecoder->decodeInt(&rdy, iardyStats);
+	    decodeSuccess = arithDecoder->decodeInt(&rdw, iardwStats);
+	    decodeSuccess = decodeSuccess && arithDecoder->decodeInt(&rdh, iardhStats);
+	    decodeSuccess = decodeSuccess && arithDecoder->decodeInt(&rdx, iardxStats);
+	    decodeSuccess = decodeSuccess && arithDecoder->decodeInt(&rdy, iardyStats);
+	  }
+	  
+	  if (decodeSuccess && syms[symID])
+	  {
+	    refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx;
+	    refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy;
+
+	    symbolBitmap =
+	      readGenericRefinementRegion(rdw + syms[symID]->getWidth(),
+					  rdh + syms[symID]->getHeight(),
+					  templ, gFalse, syms[symID],
+					  refDX, refDY, atx, aty);
 	  }
-	  refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx;
-	  refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy;
-
-	  symbolBitmap =
-	    readGenericRefinementRegion(rdw + syms[symID]->getWidth(),
-					rdh + syms[symID]->getHeight(),
-					templ, gFalse, syms[symID],
-					refDX, refDY, atx, aty);
 	  //~ do we need to use the bmSize value here (in Huffman mode)?
 	} else {
 	  symbolBitmap = syms[symID];
 	}
 
-	// combine the symbol bitmap into the region bitmap
-	//~ something is wrong here - refCorner shouldn't degenerate into
-	//~   two cases
-	bw = symbolBitmap->getWidth() - 1;
-	bh = symbolBitmap->getHeight() - 1;
-	if (transposed) {
-	  switch (refCorner) {
-	  case 0: // bottom left
-	    bitmap->combine(symbolBitmap, tt, s, combOp);
-	    break;
-	  case 1: // top left
-	    bitmap->combine(symbolBitmap, tt, s, combOp);
-	    break;
-	  case 2: // bottom right
-	    bitmap->combine(symbolBitmap, tt - bw, s, combOp);
-	    break;
-	  case 3: // top right
-	    bitmap->combine(symbolBitmap, tt - bw, s, combOp);
-	    break;
+	if (symbolBitmap) {
+	  // combine the symbol bitmap into the region bitmap
+	  //~ something is wrong here - refCorner shouldn't degenerate into
+	  //~   two cases
+	  bw = symbolBitmap->getWidth() - 1;
+	  bh = symbolBitmap->getHeight() - 1;
+	  if (transposed) {
+	    switch (refCorner) {
+	    case 0: // bottom left
+	      bitmap->combine(symbolBitmap, tt, s, combOp);
+	      break;
+	    case 1: // top left
+	      bitmap->combine(symbolBitmap, tt, s, combOp);
+	      break;
+	    case 2: // bottom right
+	      bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+	      break;
+	    case 3: // top right
+	      bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+	      break;
+	    }
+	    s += bh;
+	  } else {
+	    switch (refCorner) {
+	    case 0: // bottom left
+	      bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+	      break;
+	    case 1: // top left
+	      bitmap->combine(symbolBitmap, s, tt, combOp);
+	      break;
+	    case 2: // bottom right
+	      bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+	      break;
+	    case 3: // top right
+	      bitmap->combine(symbolBitmap, s, tt, combOp);
+	      break;
+	    }
+	    s += bw;
 	  }
-	  s += bh;
-	} else {
-	  switch (refCorner) {
-	  case 0: // bottom left
-	    bitmap->combine(symbolBitmap, s, tt - bh, combOp);
-	    break;
-	  case 1: // top left
-	    bitmap->combine(symbolBitmap, s, tt, combOp);
-	    break;
-	  case 2: // bottom right
-	    bitmap->combine(symbolBitmap, s, tt - bh, combOp);
-	    break;
-	  case 3: // top right
-	    bitmap->combine(symbolBitmap, s, tt, combOp);
-	    break;
+	  if (ri) {
+	    delete symbolBitmap;
 	  }
-	  s += bw;
-	}
-	if (ri) {
-	  delete symbolBitmap;
+	} else {
+	  // NULL symbolBitmap only happens on error
+	  delete bitmap;
+	  return NULL;
 	}
       }
 
@@ -2558,7 +2673,9 @@ void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm,
 
   // read the bitmap
   bitmap = readGenericBitmap(mmr, w, h, templ, tpgdOn, gFalse,
-			     NULL, atx, aty, mmr ? 0 : length - 18);
+			     NULL, atx, aty, mmr ? length - 18 : 0);
+  if (!bitmap)
+    return;
 
   // combine the region bitmap into the page bitmap
   if (imm) {
@@ -2580,6 +2697,43 @@ void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm,
   error(getPos(), "Unexpected EOF in JBIG2 stream");
 }
 
+inline void JBIG2Stream::mmrAddPixels(int a1, int blackPixels,
+				      int *codingLine, int *a0i, int w) {
+  if (a1 > codingLine[*a0i]) {
+    if (a1 > w) {
+      error(getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1);
+      a1 = w;
+    }
+    if ((*a0i & 1) ^ blackPixels) {
+      ++*a0i;
+    }
+    codingLine[*a0i] = a1;
+  }
+}
+
+inline void JBIG2Stream::mmrAddPixelsNeg(int a1, int blackPixels,
+					 int *codingLine, int *a0i, int w) {
+  if (a1 > codingLine[*a0i]) {
+    if (a1 > w) {
+      error(getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1);
+      a1 = w;
+    }
+    if ((*a0i & 1) ^ blackPixels) {
+      ++*a0i;
+    }
+    codingLine[*a0i] = a1;
+  } else if (a1 < codingLine[*a0i]) {
+    if (a1 < 0) {
+      error(getPos(), "Invalid JBIG2 MMR code");
+      a1 = 0;
+    }
+    while (*a0i > 0 && a1 <= codingLine[*a0i - 1]) {
+      --*a0i;
+    }
+    codingLine[*a0i] = a1;
+  }
+}
+
 JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
 					    int templ, GBool tpgdOn,
 					    GBool useSkip, JBIG2Bitmap *skip,
@@ -2592,9 +2746,13 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
   JBIG2BitmapPtr atPtr0 = {0}, atPtr1 = {0}, atPtr2 = {0}, atPtr3 = {0};
   int *refLine, *codingLine;
   int code1, code2, code3;
-  int x, y, a0, pix, i, refI, codingI;
+  int x, y, a0i, b1i, blackPixels, pix, i;
 
   bitmap = new JBIG2Bitmap(0, w, h);
+  if (!bitmap->isOk()) {
+    delete bitmap;
+    return NULL;
+  }
   bitmap->clearToZero();
 
   //----- MMR decode
@@ -2602,9 +2760,18 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
   if (mmr) {
 
     mmrDecoder->reset();
+    if (w > INT_MAX - 2) {
+      error(getPos(), "Bad width in JBIG2 generic bitmap");
+      // force a call to gmalloc(-1), which will throw an exception
+      w = -3;
+    }
+    // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = w
+    // ---> max codingLine size = w + 1
+    // refLine has one extra guard entry at the end
+    // ---> max refLine size = w + 2
+    codingLine = (int *)gmallocn(w + 1, sizeof(int));
     refLine = (int *)gmallocn(w + 2, sizeof(int));
-    codingLine = (int *)gmallocn(w + 2, sizeof(int));
-    codingLine[0] = codingLine[1] = w;
+    codingLine[0] = w;
 
     for (y = 0; y < h; ++y) {
 
@@ -2612,128 +2779,157 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
       for (i = 0; codingLine[i] < w; ++i) {
 	refLine[i] = codingLine[i];
       }
-      refLine[i] = refLine[i + 1] = w;
+      refLine[i++] = w;
+      refLine[i] = w;
 
       // decode a line
-      refI = 0;     // b1 = refLine[refI]
-      codingI = 0;  // a1 = codingLine[codingI]
-      a0 = 0;
-      do {
+      codingLine[0] = 0;
+      a0i = 0;
+      b1i = 0;
+      blackPixels = 0;
+      // invariant:
+      // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1] <= w
+      // exception at left edge:
+      //   codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible
+      // exception at right edge:
+      //   refLine[b1i] = refLine[b1i+1] = w is possible
+      while (codingLine[a0i] < w) {
 	code1 = mmrDecoder->get2DCode();
 	switch (code1) {
 	case twoDimPass:
-	  if (refLine[refI] < w) {
-	    a0 = refLine[refI + 1];
-	    refI += 2;
-	  }
-	  break;
+          mmrAddPixels(refLine[b1i + 1], blackPixels, codingLine, &a0i, w);
+          if (refLine[b1i + 1] < w) {
+            b1i += 2;
+          }
+          break;
 	case twoDimHoriz:
-	  if (codingI & 1) {
-	    code1 = 0;
-	    do {
-	      code1 += code3 = mmrDecoder->getBlackCode();
-	    } while (code3 >= 64);
-	    code2 = 0;
-	    do {
-	      code2 += code3 = mmrDecoder->getWhiteCode();
-	    } while (code3 >= 64);
-	  } else {
-	    code1 = 0;
-	    do {
-	      code1 += code3 = mmrDecoder->getWhiteCode();
-	    } while (code3 >= 64);
-	    code2 = 0;
-	    do {
-	      code2 += code3 = mmrDecoder->getBlackCode();
-	    } while (code3 >= 64);
-	  }
-	  if (code1 > 0 || code2 > 0) {
-	    a0 = codingLine[codingI++] = a0 + code1;
-	    a0 = codingLine[codingI++] = a0 + code2;
-	    while (refLine[refI] <= a0 && refLine[refI] < w) {
-	      refI += 2;
-	    }
-	  }
-	  break;
-	case twoDimVert0:
-	  a0 = codingLine[codingI++] = refLine[refI];
-	  if (refLine[refI] < w) {
-	    ++refI;
-	  }
-	  break;
-	case twoDimVertR1:
-	  a0 = codingLine[codingI++] = refLine[refI] + 1;
-	  if (refLine[refI] < w) {
-	    ++refI;
-	    while (refLine[refI] <= a0 && refLine[refI] < w) {
-	      refI += 2;
-	    }
-	  }
-	  break;
-	case twoDimVertR2:
-	  a0 = codingLine[codingI++] = refLine[refI] + 2;
-	  if (refLine[refI] < w) {
-	    ++refI;
-	    while (refLine[refI] <= a0 && refLine[refI] < w) {
-	      refI += 2;
-	    }
-	  }
-	  break;
+          code1 = code2 = 0;
+          if (blackPixels) {
+            do {
+              code1 += code3 = mmrDecoder->getBlackCode();
+            } while (code3 >= 64);
+            do {
+              code2 += code3 = mmrDecoder->getWhiteCode();
+            } while (code3 >= 64);
+          } else {
+            do {
+              code1 += code3 = mmrDecoder->getWhiteCode();
+            } while (code3 >= 64);
+            do {
+              code2 += code3 = mmrDecoder->getBlackCode();
+            } while (code3 >= 64);
+          }
+          mmrAddPixels(codingLine[a0i] + code1, blackPixels,
+		       codingLine, &a0i, w);
+          if (codingLine[a0i] < w) {
+            mmrAddPixels(codingLine[a0i] + code2, blackPixels ^ 1,
+			 codingLine, &a0i, w);
+          }
+          while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+            b1i += 2;
+          }
+          break;
 	case twoDimVertR3:
-	  a0 = codingLine[codingI++] = refLine[refI] + 3;
-	  if (refLine[refI] < w) {
-	    ++refI;
-	    while (refLine[refI] <= a0 && refLine[refI] < w) {
-	      refI += 2;
-	    }
-	  }
-	  break;
-	case twoDimVertL1:
-	  a0 = codingLine[codingI++] = refLine[refI] - 1;
-	  if (refI > 0) {
-	    --refI;
-	  } else {
-	    ++refI;
-	  }
-	  while (refLine[refI] <= a0 && refLine[refI] < w) {
-	    refI += 2;
-	  }
-	  break;
-	case twoDimVertL2:
-	  a0 = codingLine[codingI++] = refLine[refI] - 2;
-	  if (refI > 0) {
-	    --refI;
-	  } else {
-	    ++refI;
-	  }
-	  while (refLine[refI] <= a0 && refLine[refI] < w) {
-	    refI += 2;
-	  }
-	  break;
+          mmrAddPixels(refLine[b1i] + 3, blackPixels, codingLine, &a0i, w);
+          blackPixels ^= 1;
+          if (codingLine[a0i] < w) {
+            ++b1i;
+            while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+              b1i += 2;
+            }
+          }
+          break;
+	case twoDimVertR2:
+          mmrAddPixels(refLine[b1i] + 2, blackPixels, codingLine, &a0i, w);
+          blackPixels ^= 1;
+          if (codingLine[a0i] < w) {
+            ++b1i;
+            while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+              b1i += 2;
+            }
+          }
+          break;
+	case twoDimVertR1:
+          mmrAddPixels(refLine[b1i] + 1, blackPixels, codingLine, &a0i, w);
+          blackPixels ^= 1;
+          if (codingLine[a0i] < w) {
+            ++b1i;
+            while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+              b1i += 2;
+            }
+          }
+          break;
+	case twoDimVert0:
+          mmrAddPixels(refLine[b1i], blackPixels, codingLine, &a0i, w);
+          blackPixels ^= 1;
+          if (codingLine[a0i] < w) {
+            ++b1i;
+            while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+              b1i += 2;
+            }
+          }
+          break;
 	case twoDimVertL3:
-	  a0 = codingLine[codingI++] = refLine[refI] - 3;
-	  if (refI > 0) {
-	    --refI;
-	  } else {
-	    ++refI;
-	  }
-	  while (refLine[refI] <= a0 && refLine[refI] < w) {
-	    refI += 2;
-	  }
-	  break;
+          mmrAddPixelsNeg(refLine[b1i] - 3, blackPixels, codingLine, &a0i, w);
+          blackPixels ^= 1;
+          if (codingLine[a0i] < w) {
+            if (b1i > 0) {
+              --b1i;
+            } else {
+              ++b1i;
+            }
+            while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+              b1i += 2;
+            }
+          }
+          break;
+	case twoDimVertL2:
+          mmrAddPixelsNeg(refLine[b1i] - 2, blackPixels, codingLine, &a0i, w);
+          blackPixels ^= 1;
+          if (codingLine[a0i] < w) {
+            if (b1i > 0) {
+              --b1i;
+            } else {
+              ++b1i;
+            }
+            while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+              b1i += 2;
+            }
+          }
+          break;
+	case twoDimVertL1:
+          mmrAddPixelsNeg(refLine[b1i] - 1, blackPixels, codingLine, &a0i, w);
+          blackPixels ^= 1;
+          if (codingLine[a0i] < w) {
+            if (b1i > 0) {
+              --b1i;
+            } else {
+              ++b1i;
+            }
+            while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+              b1i += 2;
+            }
+          }
+          break;
+	case EOF:
+          mmrAddPixels(w, 0, codingLine, &a0i, w);
+          break;
 	default:
 	  error(getPos(), "Illegal code in JBIG2 MMR bitmap data");
+          mmrAddPixels(w, 0, codingLine, &a0i, w);
 	  break;
 	}
-      } while (a0 < w);
-      codingLine[codingI++] = w;
+      }
 
       // convert the run lengths to a bitmap line
       i = 0;
-      while (codingLine[i] < w) {
+      while (1) {
 	for (x = codingLine[i]; x < codingLine[i+1]; ++x) {
 	  bitmap->setPixel(x, y);
 	}
+	if (codingLine[i+1] >= w || codingLine[i+2] >= w) {
+	  break;
+	}
 	i += 2;
       }
     }
@@ -2781,7 +2977,9 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
 	  ltp = !ltp;
 	}
 	if (ltp) {
-	  bitmap->duplicateRow(y, y-1);
+	  if (y > 0) {
+	    bitmap->duplicateRow(y, y-1);
+	  }
 	  continue;
 	}
       }
@@ -3047,6 +3245,11 @@ JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h,
   int x, y, pix;
 
   bitmap = new JBIG2Bitmap(0, w, h);
+  if (!bitmap->isOk())
+  {
+    delete bitmap;
+    return NULL;
+  }
   bitmap->clearToZero();
 
   // set up the typical row context
@@ -3087,6 +3290,10 @@ JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h,
 	tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2);
 	tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
 	tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+      } else {
+	tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy
+	tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0;
+	tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0;
       }
 
       for (x = 0; x < w; ++x) {
@@ -3158,6 +3365,10 @@ JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h,
 	tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2);
 	tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
 	tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+      } else {
+	tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy
+	tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0;
+	tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0;
       }
 
       for (x = 0; x < w; ++x) {
@@ -3223,6 +3434,12 @@ void JBIG2Stream::readPageInfoSeg(Guint length) {
   }
   pageBitmap = new JBIG2Bitmap(0, pageW, curPageH);
 
+  if (!pageBitmap->isOk()) {
+    delete pageBitmap;
+    pageBitmap = NULL;
+    return;
+  }
+  
   // default pixel value
   if (pageDefPixel) {
     pageBitmap->clearToOne();
diff --git a/poppler/JBIG2Stream.h b/poppler/JBIG2Stream.h
index 7a73938..ca1fee7 100644
--- a/poppler/JBIG2Stream.h
+++ b/poppler/JBIG2Stream.h
@@ -76,6 +76,10 @@ private:
 			     Guint *refSegs, Guint nRefSegs);
   void readGenericRegionSeg(Guint segNum, GBool imm,
 			    GBool lossless, Guint length);
+  void mmrAddPixels(int a1, int blackPixels,
+		    int *codingLine, int *a0i, int w);
+  void mmrAddPixelsNeg(int a1, int blackPixels,
+		       int *codingLine, int *a0i, int w);
   JBIG2Bitmap *readGenericBitmap(GBool mmr, int w, int h,
 				 int templ, GBool tpgdOn,
 				 GBool useSkip, JBIG2Bitmap *skip,
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 91e1d04..98adb7c 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -16,7 +16,7 @@
 //
 // Copyright (C) 2005-2008 Jeff Muizelaar <jeff@infidigm.net>
 // Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
-// Copyright (C) 2005 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005, 2009 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2005 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
 // Copyright (C) 2006-2008 Carlos Garcia Campos <carlosgc@gnome.org>
 // Copyright (C) 2008 Carl Worth <cworth@cworth.org>
@@ -611,7 +611,7 @@ void CairoOutputDev::beginString(GfxState *state, GooString *s)
   if (!currentFont)
     return;
 
-  glyphs = (cairo_glyph_t *) gmalloc (len * sizeof (cairo_glyph_t));
+  glyphs = (cairo_glyph_t *) gmallocn (len, sizeof (cairo_glyph_t));
   glyphCount = 0;
 }
 
@@ -1461,7 +1461,7 @@ void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref,
 
   int row_stride = (maskWidth + 3) & ~3;
   unsigned char *maskBuffer;
-  maskBuffer = (unsigned char *)gmalloc (row_stride * maskHeight);
+  maskBuffer = (unsigned char *)gmallocn (row_stride, maskHeight);
   unsigned char *maskDest;
   cairo_surface_t *maskImage;
   cairo_pattern_t *maskPattern;
@@ -1497,7 +1497,7 @@ void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref,
   cairo_matrix_t matrix;
   int is_identity_transform;
 
-  buffer = (unsigned char *)gmalloc (width * height * 4);
+  buffer = (unsigned char *)gmallocn3 (width, height, 4);
 
   /* TODO: Do we want to cache these? */
   imgStr = new ImageStream(str, width,
@@ -1586,7 +1586,7 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s
 
   int row_stride = (maskWidth + 3) & ~3;
   unsigned char *maskBuffer;
-  maskBuffer = (unsigned char *)gmalloc (row_stride * maskHeight);
+  maskBuffer = (unsigned char *)gmallocn (row_stride, maskHeight);
   unsigned char *maskDest;
   cairo_surface_t *maskImage;
   cairo_pattern_t *maskPattern;
@@ -1613,7 +1613,7 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s
   cairo_matrix_t maskMatrix;
   int is_identity_transform;
 
-  buffer = (unsigned char *)gmalloc (width * height * 4);
+  buffer = (unsigned char *)gmallocn3 (width, height, 4);
 
   /* TODO: Do we want to cache these? */
   imgStr = new ImageStream(str, width,
@@ -1705,7 +1705,7 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   cairo_matrix_t matrix;
   int is_identity_transform;
   
-  buffer = (unsigned char *)gmalloc (width * height * 4);
+  buffer = (unsigned char *)gmallocn3 (width, height, 4);
 
   /* TODO: Do we want to cache these? */
   imgStr = new ImageStream(str, width,
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index 97d622c..6cf2aea 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -11,7 +11,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2006 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006, 2009 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com>
 //
 // To see a description of the changes please see the Changelog file that
@@ -62,13 +62,13 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
   }
   rowSize += rowPad - 1;
   rowSize -= rowSize % rowPad;
-  data = (SplashColorPtr)gmalloc(rowSize * height);
+  data = (SplashColorPtr)gmallocn(rowSize, height);
   if (!topDown) {
     data += (height - 1) * rowSize;
     rowSize = -rowSize;
   }
   if (alphaA) {
-    alpha = (Guchar *)gmalloc(width * height);
+    alpha = (Guchar *)gmallocn(width, height);
   } else {
     alpha = NULL;
   }
diff --git a/goo/gmem.cc b/goo/gmem.cc
index 298d5dd..af3e19e 100644
--- a/goo/gmem.cc
+++ b/goo/gmem.cc
@@ -216,6 +216,29 @@ void *gmallocn_checkoverflow(int nObjs, int objSize) GMEM_EXCEP {
   return gmalloc(n);
 }
 
+inline static void *gmallocn3(int a, int b, int c, bool checkoverflow) GMEM_EXCEP {
+  int n = a * b;
+  if (b <= 0 || a < 0 || a >= INT_MAX / b) {
+#if USE_EXCEPTIONS
+    throw GMemException();
+#else
+    fprintf(stderr, "Bogus memory allocation size\n");
+    if (checkoverflow) return NULL;
+    else exit(1);
+#endif
+  }
+  if (checkoverflow) return gmallocn_checkoverflow(n, c);
+  else return gmallocn(n, c);
+}
+
+void *gmallocn3(int a, int b, int c) GMEM_EXCEP {
+  return gmallocn3(a, b, c, false);
+}
+
+void *gmallocn3_checkoverflow(int a, int b, int c) GMEM_EXCEP {
+  return gmallocn3(a, b, c, true);
+}
+
 void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP {
   int n;
 
diff --git a/goo/gmem.h b/goo/gmem.h
index 96d834d..0c16b01 100644
--- a/goo/gmem.h
+++ b/goo/gmem.h
@@ -72,6 +72,8 @@ extern void *grealloc_checkoverflow(size_t size) GMEM_EXCEP;
  */
 extern void *gmallocn(int nObjs, int objSize) GMEM_EXCEP;
 extern void *gmallocn_checkoverflow(int nObjs, int objSize) GMEM_EXCEP;
+extern void *gmallocn3(int a, int b, int c) GMEM_EXCEP;
+extern void *gmallocn3_checkoverflow(int a, int b, int c) GMEM_EXCEP;
 extern void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP;
 extern void *greallocn_checkoverflow(void *p, int nObjs, int objSize) GMEM_EXCEP;
 
openSUSE Build Service is sponsored by