shithub: jbig2

Download patch

ref: 7850aaff3651de4a4e7a6be1ac37f61bd9767055
parent: 3e6c1b0670740be3b138228dcc134bf5e6c1eceb
author: Math <[email protected]>
date: Thu Feb 28 19:56:04 EST 2013

Bug 693507: check for out-of-bounds access

Report error in get_next_word() functions on out-of-bounds access and
handling of this error in both arithmetic and huffman decoders.

When decoding a corrupted document, the arithmetic decoder can hit the end
of the Jbig2 stream. The problem was that get_next_word() returned 0 in
that case and that this lead to an infinite loop.

--- a/jbig2.c
+++ b/jbig2.c
@@ -438,8 +438,9 @@
   size_t size;
 } Jbig2WordStreamBuf;
 
-static uint32_t
-jbig2_word_stream_buf_get_next_word(Jbig2WordStream *self, int offset)
+static int
+jbig2_word_stream_buf_get_next_word(Jbig2WordStream *self, int offset,
+  uint32_t *word)
 {
   Jbig2WordStreamBuf *z = (Jbig2WordStreamBuf *)self;
   const byte *data = z->data;
@@ -449,7 +450,7 @@
     result = (data[offset] << 24) | (data[offset + 1] << 16) |
       (data[offset + 2] << 8) | data[offset + 3];
   else if (offset >= z->size)
-    return 0;
+    return -1;
   else
     {
       int i;
@@ -458,7 +459,8 @@
       for (i = 0; i < z->size - offset; i++)
 	result |= data[offset + i] << ((3 - i) << 3);
     }
-  return result;
+  *word = result;
+  return 0;
 }
 
 Jbig2WordStream *
--- a/jbig2_arith.c
+++ b/jbig2_arith.c
@@ -41,6 +41,8 @@
 
   Jbig2WordStream *ws;
   int offset;
+
+  Jbig2Ctx *ctx;
 };
 
 #undef SOFTWARE_CONVENTION
@@ -59,7 +61,7 @@
 
  */
 
-static void
+static int
 jbig2_arith_bytein (Jbig2ArithState *as)
 {
   byte B;
@@ -74,7 +76,12 @@
       if (as->next_word_bytes == 1)
 	{
 	  Jbig2WordStream *ws = as->ws;
-	  as->next_word = ws->get_next_word (ws, as->offset);
+	  if (ws->get_next_word (ws, as->offset, &as->next_word))
+	    {
+	      jbig2_error(as->ctx, JBIG2_SEVERITY_FATAL, -1,
+		"end of jbig2 buffer reached at offset %d", as->offset);
+	      return -1;
+	    }
 	  as->offset += 4;
 	  B1 = (byte)((as->next_word >> 24) & 0xFF);
 	  if (B1 > 0x8F)
@@ -145,7 +152,12 @@
 	{
 	  Jbig2WordStream *ws = as->ws;
 
-	  as->next_word = ws->get_next_word (ws, as->offset);
+	  if (ws->get_next_word (ws, as->offset, &as->next_word))
+	    {
+	      jbig2_error(as->ctx, JBIG2_SEVERITY_FATAL, -1,
+		"end of jbig2 buffer reached at offset %d", as->offset);
+	      return -1;
+	    }
 	  as->offset += 4;
 	  as->next_word_bytes = 4;
 	}
@@ -156,6 +168,7 @@
       as->C += (B << 8);
 #endif
     }
+    return 0;
 }
 
 #if defined(JBIG2_DEBUG) || defined(JBIG2_DEBUG_ARITH)
@@ -185,8 +198,15 @@
   }
 
   result->ws = ws;
+  result->ctx = ctx;
 
-  result->next_word = ws->get_next_word (ws, 0);
+  if (ws->get_next_word (ws, 0, &result->next_word))
+  {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "unable to get first word in jbig2_arith_new");
+      jbig2_free(ctx->allocator, result);
+      return NULL;
+  }
   result->next_word_bytes = 4;
   result->offset = 4;
 
@@ -197,7 +217,11 @@
   result->C = (result->next_word >> 8) & 0xFF0000;
 #endif
 
-  jbig2_arith_bytein (result);
+  if (jbig2_arith_bytein (result))
+  {
+      jbig2_free(ctx->allocator, result);
+      return NULL;
+  }
   result->C <<= 7;
   result->CT -= 7;
   result->A = 0x8000;
@@ -262,19 +286,20 @@
   { 0x5601, 46 ^ 46, 46 ^ 46 }
 };
 
-static void
+static int
 jbig2_arith_renormd (Jbig2ArithState *as)
 {
   /* Figure E.18 */
   do
     {
-      if (as->CT == 0)
-	jbig2_arith_bytein (as);
+      if ((as->CT == 0) && (jbig2_arith_bytein (as) < 0))
+        return -1;
       as->A <<= 1;
       as->C <<= 1;
       as->CT--;
     }
   while ((as->A & 0x8000) == 0);
+  return 0;
 }
 
 bool
@@ -311,7 +336,8 @@
 	      D = cx >> 7;
 	      *pcx ^= pqe->mps_xor;
 	    }
-	  jbig2_arith_renormd (as);
+	  if (jbig2_arith_renormd (as))
+	    return -1;
 	  return D;
 	}
       else
@@ -335,7 +361,8 @@
 	  D = 1 - (cx >> 7);
 	  *pcx ^= pqe->lps_xor;
 	}
-      jbig2_arith_renormd (as);
+      if (jbig2_arith_renormd (as))
+	return -1;
       return D;
     }
 }
@@ -342,8 +369,8 @@
 
 #ifdef TEST
 
-static uint32_t
-test_get_word (Jbig2WordStream *self, int offset)
+static int
+test_get_word (Jbig2WordStream *self, int offset, uint32_t *word)
 {
   byte stream[] = {
     0x84, 0xC7, 0x3B, 0xFC, 0xE1, 0xA1, 0x43, 0x04, 0x02, 0x20, 0x00, 0x00,
@@ -352,10 +379,10 @@
     0x00, 0x00
   };
   if (offset >= sizeof(stream))
-    return 0;
-  else
-    return (stream[offset] << 24) | (stream[offset + 1] << 16) |
-      (stream[offset + 2] << 8) | stream[offset + 3];
+    return -1;
+  *word = (stream[offset] << 24) | (stream[offset + 1] << 16) |
+    (stream[offset + 2] << 8) | stream[offset + 3];
+  return 0;
 }
 
 int
--- a/jbig2_arith_iaid.c
+++ b/jbig2_arith_iaid.c
@@ -86,6 +86,8 @@
   for (i = 0; i < SBSYMCODELEN; i++)
     {
       D = jbig2_arith_decode(as, &IAIDx[PREV]);
+      if (D < 0)
+	return -1;
 #ifdef VERBOSE
       fprintf(stderr, "IAID%x: D = %d\n", PREV, D);
 #endif
--- a/jbig2_arith_int.c
+++ b/jbig2_arith_int.c
@@ -69,28 +69,40 @@
   int i;
 
   S = jbig2_arith_decode(as, &IAx[PREV]);
+  if (S < 0)
+    return -1;
   PREV = (PREV << 1) | S;
 
   bit = jbig2_arith_decode(as, &IAx[PREV]);
+  if (bit < 0)
+    return -1;
   PREV = (PREV << 1) | bit;
   if (bit)
     {
       bit = jbig2_arith_decode(as, &IAx[PREV]);
+      if (bit < 0)
+	return -1;
       PREV = (PREV << 1) | bit;
 
       if (bit)
 	{
 	  bit = jbig2_arith_decode(as, &IAx[PREV]);
+	  if (bit < 0)
+	    return -1;
 	  PREV = (PREV << 1) | bit;
 
 	  if (bit)
 	    {
 	      bit = jbig2_arith_decode(as, &IAx[PREV]);
+	      if (bit < 0)
+		return -1;
 	      PREV = (PREV << 1) | bit;
 
 	      if (bit)
 		{
 		  bit = jbig2_arith_decode(as, &IAx[PREV]);
+	          if (bit < 0)
+		    return -1;
 		  PREV = (PREV << 1) | bit;
 
 		  if (bit)
@@ -132,6 +144,8 @@
   for (i = 0; i < n_tail; i++)
     {
       bit = jbig2_arith_decode(as, &IAx[PREV]);
+      if (bit < 0)
+	return -1;
       PREV = ((PREV << 1) & 511) | (PREV & 256) | bit;
       V = (V << 1) | bit;
     }
--- a/jbig2_generic.c
+++ b/jbig2_generic.c
@@ -103,6 +103,8 @@
 	      bool bit;
 
 	      bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+	      if (bit < 0)
+		return -1;
 	      result |= bit << (7 - x_minor);
 	      CONTEXT = ((CONTEXT & 0x7bf7) << 1) | bit |
 		((line_m1 >> (7 - x_minor)) & 0x10) |
@@ -159,6 +161,8 @@
       CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6],
 	y + params->gbat[7]) << 15;
       bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+      if (bit < 0)
+	return -1;
       jbig2_image_set_pixel(image, x, y, bit);
     }
   }
@@ -217,6 +221,8 @@
 	      bool bit;
 
 	      bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+	      if (bit < 0)
+		return -1;
 	      result |= bit << (7 - x_minor);
 	      CONTEXT = ((CONTEXT & 0xefb) << 1) | bit |
 		((line_m1 >> (8 - x_minor)) & 0x8) |
@@ -285,6 +291,8 @@
 	      bool bit;
 
 	      bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+	      if (bit < 0)
+		return -1;
 	      result |= bit << (7 - x_minor);
 	      CONTEXT = ((CONTEXT & 0x1bd) << 1) | bit |
 		((line_m1 >> (10 - x_minor)) & 0x4) |
@@ -353,6 +361,8 @@
 	      bool bit;
 
 	      bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+	      if (bit < 0)
+		return -1;
 	      result |= bit << (7 - x_minor);
 	      CONTEXT = ((CONTEXT & 0x1b9) << 1) | bit |
 		((line_m1 >> (10 - x_minor)) & 0x8) |
@@ -416,6 +426,8 @@
 	      bool bit;
 
 	      bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+	      if (bit < 0)
+		return -1;
 	      result |= bit << (7 - x_minor);
 	      CONTEXT = ((CONTEXT & 0x1f7) << 1) | bit |
 		((line_m1 >> (10 - x_minor)) & 0x010);
@@ -462,6 +474,8 @@
       CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8;
       CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9;
       bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+      if (bit < 0)
+	return -1;
       jbig2_image_set_pixel(image, x, y, bit);
     }
   }
@@ -498,7 +512,10 @@
 
   for (y = 0; y < GBH; y++)
   {
-    LTP ^= jbig2_arith_decode(as, &GB_stats[0x9B25]);
+    bit = jbig2_arith_decode(as, &GB_stats[0x9B25]);
+    if (bit < 0)
+      return -1;
+    LTP ^= bit;
     if (!LTP) {
       for (x = 0; x < GBW; x++) {
         CONTEXT  = jbig2_image_get_pixel(image, x - 1, y);
@@ -522,6 +539,8 @@
         CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6],
 					y + params->gbat[7]) << 15;
         bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+        if (bit < 0)
+	  return -1;
         jbig2_image_set_pixel(image, x, y, bit);
       }
     } else {
@@ -548,7 +567,10 @@
   int LTP = 0;
 
   for (y = 0; y < GBH; y++) {
-    LTP ^= jbig2_arith_decode(as, &GB_stats[0x0795]);
+    bit = jbig2_arith_decode(as, &GB_stats[0x0795]);
+    if (bit < 0)
+      return -1;
+    LTP ^= bit;
     if (!LTP) {
       for (x = 0; x < GBW; x++) {
         CONTEXT  = jbig2_image_get_pixel(image, x - 1, y);
@@ -566,6 +588,8 @@
         CONTEXT |= jbig2_image_get_pixel(image, x    , y - 2) << 11;
         CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 12;
         bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+        if (bit < 0)
+	  return -1;
         jbig2_image_set_pixel(image, x, y, bit);
       }
     } else {
@@ -592,7 +616,10 @@
   int LTP = 0;
 
   for (y = 0; y < GBH; y++) {
-    LTP ^= jbig2_arith_decode(as, &GB_stats[0xE5]);
+    bit = jbig2_arith_decode(as, &GB_stats[0xE5]);
+    if (bit < 0)
+      return -1;
+    LTP ^= bit;
     if (!LTP) {
       for (x = 0; x < GBW; x++) {
         CONTEXT  = jbig2_image_get_pixel(image, x - 1, y);
@@ -607,6 +634,8 @@
         CONTEXT |= jbig2_image_get_pixel(image, x    , y - 2) << 8;
         CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 9;
         bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+        if (bit < 0)
+	  return -1;
         jbig2_image_set_pixel(image, x, y, bit);
       }
     } else {
@@ -633,7 +662,10 @@
   int LTP = 0;
 
   for (y = 0; y < GBH; y++) {
-    LTP ^= jbig2_arith_decode(as, &GB_stats[0x0195]);
+    bit = jbig2_arith_decode(as, &GB_stats[0x0195]);
+    if (bit < 0)
+      return -1;
+    LTP ^= bit;
     if (!LTP) {
       for (x = 0; x < GBW; x++) {
         CONTEXT  = jbig2_image_get_pixel(image, x - 1, y);
@@ -648,6 +680,8 @@
         CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8;
         CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9;
         bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
+        if (bit < 0)
+	  return -1;
         jbig2_image_set_pixel(image, x, y, bit);
       }
     } else {
--- a/jbig2_huffman.c
+++ b/jbig2_huffman.c
@@ -52,11 +52,25 @@
   uint32_t next_word;
   int offset_bits;
   int offset;
+  int offset_limit;
 
   Jbig2WordStream *ws;
+  Jbig2Ctx *ctx;
 };
 
 
+static uint32_t
+huff_get_next_word(Jbig2HuffmanState *hs, int offset)
+{
+  uint32_t word = 0;
+  Jbig2WordStream *ws = hs->ws;
+  if ((ws->get_next_word (ws, offset, &word)) &&
+      ((hs->offset_limit == 0) || (offset < hs->offset_limit)))
+      hs->offset_limit = offset;
+  return word;
+}
+
+
 /** Allocate and initialize a new huffman coding state
  *  the returned pointer can simply be freed; this does
  *  not affect the associated Jbig2WordStream.
@@ -71,9 +85,11 @@
   if (result != NULL) {
       result->offset = 0;
       result->offset_bits = 0;
-      result->this_word = ws->get_next_word (ws, 0);
-      result->next_word = ws->get_next_word (ws, 4);
+      result->offset_limit = 0;
       result->ws = ws;
+      result->ctx = ctx;
+      result->this_word = huff_get_next_word(result, 0);
+      result->next_word = huff_get_next_word(result, 4);
   } else {
       jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
           "failed to allocate new huffman coding state");
@@ -168,10 +184,9 @@
   }
 
   if (hs->offset_bits >= 32) {
-    Jbig2WordStream *ws = hs->ws;
     hs->this_word = hs->next_word;
     hs->offset += 4;
-    hs->next_word = ws->get_next_word (ws, hs->offset + 4);
+    hs->next_word = huff_get_next_word(hs, hs->offset + 4);
     hs->offset_bits -= 32;
     if (hs->offset_bits) {
       hs->this_word = (hs->this_word << hs->offset_bits) |
@@ -184,8 +199,6 @@
  */
 void jbig2_huffman_advance(Jbig2HuffmanState *hs, int offset)
 {
-  Jbig2WordStream *ws = hs->ws;
-
   hs->offset += offset & ~3;
   hs->offset_bits += (offset & 3) << 3;
   if (hs->offset_bits >= 32) {
@@ -192,8 +205,8 @@
     hs->offset += 4;
     hs->offset_bits -= 32;
   }
-  hs->this_word = ws->get_next_word (ws, hs->offset);
-  hs->next_word = ws->get_next_word (ws, hs->offset + 4);
+  hs->this_word = huff_get_next_word(hs, hs->offset);
+  hs->next_word = huff_get_next_word(hs, hs->offset + 4);
   if (hs->offset_bits > 0)
     hs->this_word = (hs->this_word << hs->offset_bits) |
 	(hs->next_word >> (32 - hs->offset_bits));
@@ -212,11 +225,18 @@
  * without decoding against a table
  */
 int32_t
-jbig2_huffman_get_bits (Jbig2HuffmanState *hs, const int bits)
+jbig2_huffman_get_bits (Jbig2HuffmanState *hs, const int bits, int *err)
 {
   uint32_t this_word = hs->this_word;
   int32_t result;
 
+  if (hs->offset_limit && hs->offset >= hs->offset_limit) {
+    jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, -1,
+      "end of jbig2 buffer reached at offset %d", hs->offset);
+    *err = -1;
+    return -1;
+  }
+
   result = this_word >> (32 - bits);
   hs->offset_bits += bits;
   if (hs->offset_bits >= 32) {
@@ -223,7 +243,7 @@
     hs->offset += 4;
     hs->offset_bits -= 32;
     hs->this_word = hs->next_word;
-    hs->next_word = hs->ws->get_next_word(hs->ws, hs->offset + 4);
+    hs->next_word = huff_get_next_word(hs, hs->offset + 4);
     if (hs->offset_bits) {
       hs->this_word = (hs->this_word << hs->offset_bits) |
 	(hs->next_word >> (32 - hs->offset_bits));
@@ -250,6 +270,14 @@
   int RANGELEN;
   int32_t result;
 
+  if (hs->offset_limit && hs->offset >= hs->offset_limit) {
+    jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, -1,
+      "end of Jbig2WordStream reached at offset %d", hs->offset);
+    if (oob)
+      *oob = -1;
+    return -1;
+  }
+
   for (;;)
     {
       int log_table_size = table->log_table_size;
@@ -270,10 +298,9 @@
       offset_bits += PREFLEN;
       if (offset_bits >= 32)
 	{
-	  Jbig2WordStream *ws = hs->ws;
 	  this_word = next_word;
 	  hs->offset += 4;
-	  next_word = ws->get_next_word (ws, hs->offset + 4);
+	  next_word = huff_get_next_word(hs, hs->offset + 4);
 	  offset_bits -= 32;
 	  hs->next_word = next_word;
 	  PREFLEN = offset_bits;
@@ -303,10 +330,9 @@
       offset_bits += RANGELEN;
       if (offset_bits >= 32)
 	{
-	  Jbig2WordStream *ws = hs->ws;
 	  this_word = next_word;
 	  hs->offset += 4;
-	  next_word = ws->get_next_word (ws, hs->offset + 4);
+	  next_word = huff_get_next_word(hs, hs->offset + 4);
 	  offset_bits -= 32;
 	  hs->next_word = next_word;
 	  RANGELEN = offset_bits;
@@ -681,17 +707,17 @@
 const byte	test_stream[] = { 0xe9, 0xcb, 0xf4, 0x00 };
 const byte	test_tabindex[] = { 4, 2, 2, 1 };
 
-static uint32_t
-test_get_word (Jbig2WordStream *self, int offset)
+static int
+test_get_word (Jbig2WordStream *self, int offset, uint32_t *word)
 {
 	/* assume test_stream[] is at least 4 bytes */
 	if (offset+3 > sizeof(test_stream))
-		return 0;
-	else
-		return ( (test_stream[offset] << 24) |
-				 (test_stream[offset+1] << 16) |
-				 (test_stream[offset+2] << 8) |
-				 (test_stream[offset+3]) );
+		return -1;
+	*word = ( (test_stream[offset] << 24) |
+			 (test_stream[offset+1] << 16) |
+			 (test_stream[offset+2] << 8) |
+			 (test_stream[offset+3]) );
+	return 0;
 }
 
 int
@@ -1956,13 +1982,15 @@
     test_huffmancodes_t *h;
 } test_stream_t;
 
-static uint32_t
-test_get_word(Jbig2WordStream *self, int offset)
+static int
+test_get_word(Jbig2WordStream *self, int offset, uint32_t *word)
 {
     uint32_t val = 0;
     test_stream_t *st = (test_stream_t *)self;
     if (st != NULL) {
         if (st->h != NULL) {
+            if (offset >= st->h->input_len)
+                return -1;
             if (offset   < st->h->input_len) {
                 val |= (st->h->input[offset]   << 24);
             }
@@ -1977,7 +2005,8 @@
             }
         }
     }
-    return val;
+    *word = val;
+    return 0;
 }
 
 int
--- a/jbig2_huffman.h
+++ b/jbig2_huffman.h
@@ -76,7 +76,7 @@
 		   const Jbig2HuffmanTable *table, bool *oob);
 
 int32_t
-jbig2_huffman_get_bits (Jbig2HuffmanState *hs, const int bits);
+jbig2_huffman_get_bits (Jbig2HuffmanState *hs, const int bits, int *err);
 
 #ifdef JBIG2_DEBUG
 void jbig2_dump_huffman_state(Jbig2HuffmanState *hs);
--- a/jbig2_priv.h
+++ b/jbig2_priv.h
@@ -184,7 +184,7 @@
 typedef struct _Jbig2WordStream Jbig2WordStream;
 
 struct _Jbig2WordStream {
-  uint32_t (*get_next_word) (Jbig2WordStream *self, int offset);
+  int (*get_next_word) (Jbig2WordStream *self, int offset, uint32_t *word);
 };
 
 Jbig2WordStream *
--- a/jbig2_refinement.c
+++ b/jbig2_refinement.c
@@ -86,6 +86,8 @@
       CONTEXT |= jbig2_image_get_pixel(ref, x-dx+params->grat[2],
 	y-dy+params->grat[3]) << 12;
       bit = jbig2_arith_decode(as, &GR_stats[CONTEXT]);
+      if (bit < 0)
+        return -1;
       jbig2_image_set_pixel(image, x, y, bit);
     }
   }
@@ -136,6 +138,8 @@
       CONTEXT |= jbig2_image_get_pixel(ref, x-dx-1, y-dy+0) << 8;
       CONTEXT |= jbig2_image_get_pixel(ref, x-dx+0, y-dy-1) << 9;
       bit = jbig2_arith_decode(as, &GR_stats[CONTEXT]);
+      if (bit < 0)
+        return -1;
       jbig2_image_set_pixel(image, x, y, bit);
     }
   }
@@ -215,6 +219,8 @@
 	bool bit;
 
 	bit = jbig2_arith_decode(as, &GR_stats[CONTEXT]);
+	if (bit < 0)
+	  return -1;
 	result |= bit << (7 - x_minor);
 	CONTEXT = ((CONTEXT & 0x0d6) << 1) | bit |
 	  ((line_m1 >> (9 - x_minor)) & 0x002) |
--- a/jbig2_symbol_dict.c
+++ b/jbig2_symbol_dict.c
@@ -564,10 +564,11 @@
 		      int code1 = 0;
 		      int code2 = 0;
 		      int code3 = 0;
+		      int code4 = 0;
 
 		      /* 6.5.8.2.2 (2, 3, 4, 5) */
 		      if (params->SDHUFF) {
-		          ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN);
+		          ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN, &code4);
 		          RDX = jbig2_huffman_get(hs, SDHUFFRDX, &code1);
 		          RDY = jbig2_huffman_get(hs, SDHUFFRDX, &code2);
 		          BMSIZE = jbig2_huffman_get(hs, SBHUFFRSIZE, &code3);
@@ -578,7 +579,7 @@
 		          code3 = jbig2_arith_int_decode(IARDY, as, &RDY);
 		      }
 
-		      if ((code1 < 0) || (code2 < 0) || (code3 < 0))
+		      if ((code1 < 0) || (code2 < 0) || (code3 < 0) || (code4 < 0))
 		      {
 		          code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL,
 		              segment->number, "failed to decode data");
--- a/jbig2_text.c
+++ b/jbig2_text.c
@@ -112,7 +112,9 @@
 
 	/* parse and build the runlength code huffman table */
 	for (index = 0; index < 35; index++) {
-	  runcodelengths[index].PREFLEN = jbig2_huffman_get_bits(hs, 4);
+	  runcodelengths[index].PREFLEN = jbig2_huffman_get_bits(hs, 4, &code);
+	  if (code < 0)
+	    goto cleanup1;
 	  runcodelengths[index].RANGELEN = 0;
 	  runcodelengths[index].RANGELOW = index;
 	  jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
@@ -162,9 +164,12 @@
 	    } else {
 	      len = 0; /* code == 33 or 34 */
 	    }
-	    if (code == 32) range = jbig2_huffman_get_bits(hs, 2) + 3;
-	    else if (code == 33) range = jbig2_huffman_get_bits(hs, 3) + 3;
-	    else if (code == 34) range = jbig2_huffman_get_bits(hs, 7) + 11;
+	    err = 0;
+	    if (code == 32) range = jbig2_huffman_get_bits(hs, 2, &err) + 3;
+	    else if (code == 33) range = jbig2_huffman_get_bits(hs, 3, &err) + 3;
+	    else if (code == 34) range = jbig2_huffman_get_bits(hs, 7, &err) + 11;
+	    if (err < 0)
+	      goto cleanup1;
 	  }
 	  jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
 	    "  read runcode%d at index %d (length %d range %d)", code, index, len, range);
@@ -274,11 +279,11 @@
 	    if (params->SBSTRIPS == 1) {
 		CURT = 0;
 	    } else if (params->SBHUFF) {
-		CURT = jbig2_huffman_get_bits(hs, params->LOGSBSTRIPS);
+		CURT = jbig2_huffman_get_bits(hs, params->LOGSBSTRIPS, &code);
 	    } else {
 		code = jbig2_arith_int_decode(params->IAIT, as, &CURT);
-                if (code < 0) goto cleanup2;
 	    }
+	    if (code < 0) goto cleanup2;
 	    T = STRIPT + CURT;
 
 	    /* (3b.iv) / 6.4.10 - decode the symbol id */
@@ -311,11 +316,11 @@
 	    }
 	    if (params->SBREFINE) {
 	      if (params->SBHUFF) {
-		RI = jbig2_huffman_get_bits(hs, 1);
+		RI = jbig2_huffman_get_bits(hs, 1, &code);
 	      } else {
 		code = jbig2_arith_int_decode(params->IARI, as, &RI);
-        if (code < 0) goto cleanup2;
 	      }
+	      if (code < 0) goto cleanup2;
 	    } else {
 		RI = 0;
 	    }