shithub: jbig2

Download patch

ref: 1fddee262691d23dc283965c0dbe0e0de2c85bf9
parent: f680c2d09d76172f7adee998608a8df0b8d2828c
author: Shailesh Mistry <shailesh.mistry@hotmail.co.uk>
date: Tue Nov 29 15:33:16 EST 2011

Bug 691267: jbig2dec needs to check malloc() return values

This fix checks all return paths to ensure that the appropriate error
is returned on failure from any malloc() call within jbig2dec.

--- a/jbig2.c
+++ b/jbig2.c
@@ -143,11 +143,24 @@
   result->n_segments = 0;
   result->n_segments_max = 16;
   result->segments = jbig2_new(result, Jbig2Segment*, result->n_segments_max);
+  if (result->segments == NULL) {
+    error_callback(error_callback_data, "initial segments allocation failed!",
+        JBIG2_SEVERITY_FATAL, -1);
+    jbig2_free(allocator, result);
+    return result;
+  }
   result->segment_index = 0;
 
   result->current_page = 0;
   result->max_page_index = 4;
   result->pages = jbig2_new(result, Jbig2Page, result->max_page_index);
+  if (result->pages == NULL) {
+    error_callback(error_callback_data, "initial pages allocation failed!",
+        JBIG2_SEVERITY_FATAL, -1);
+    jbig2_free(allocator, result->segments);
+    jbig2_free(allocator, result);
+    return result;
+  }
   {
     int index;
     for (index = 0; index < result->max_page_index; index++) {
@@ -216,6 +229,11 @@
 	buf_size <<= 1;
       while (buf_size < size);
       ctx->buf = jbig2_new(ctx, byte, buf_size);
+      if (ctx->buf == NULL)
+      {
+          return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+              "failed to allocate ctx->buf in jbig2_data_in");
+      }
       ctx->buf_size = buf_size;
       ctx->buf_rd_ix = 0;
       ctx->buf_wr_ix = 0;
@@ -237,6 +255,11 @@
 	    buf_size <<= 1;
 	  while (buf_size < ctx->buf_wr_ix - ctx->buf_rd_ix + size);
 	  buf = jbig2_new(ctx, byte, buf_size);
+      if (buf == NULL)
+      {
+          return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+              "failed to allocate buf in jbig2_data_in");
+      }
 	  memcpy(buf, ctx->buf + ctx->buf_rd_ix,
 		  ctx->buf_wr_ix - ctx->buf_rd_ix);
 	  jbig2_free(ctx->allocator, ctx->buf);
@@ -430,6 +453,12 @@
 jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size_t size)
 {
   Jbig2WordStreamBuf *result = jbig2_new(ctx, Jbig2WordStreamBuf, 1);
+  if (result == NULL)
+  {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "failed to allocate Jbig2WordStreamBuf in jbig2_word_stream_buf_new");
+      return NULL;
+  }
 
   result->super.get_next_word = jbig2_word_stream_buf_get_next_word;
   result->data = data;
--- a/jbig2_arith.c
+++ b/jbig2_arith.c
@@ -181,6 +181,12 @@
   Jbig2ArithState *result;
 
   result = jbig2_new(ctx, Jbig2ArithState, 1);
+  if (result == NULL)
+  {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "failed to allocate Jbig2ArithState in jbig2_arith_new");
+      return result;
+  }
 
   result->ws = ws;
 
--- a/jbig2_arith_iaid.c
+++ b/jbig2_arith_iaid.c
@@ -46,9 +46,24 @@
   Jbig2ArithIaidCtx *result = jbig2_new(ctx, Jbig2ArithIaidCtx, 1);
   int ctx_size = 1 << SBSYMCODELEN;
 
+  if (result == NULL)
+  {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "failed to allocate storage in jbig2_arith_iaid_ctx_new");
+      return result;
+  }
+
   result->SBSYMCODELEN = SBSYMCODELEN;
   result->IAIDx = jbig2_new(ctx, Jbig2ArithCx, ctx_size);
-  memset(result->IAIDx, 0, ctx_size);
+  if (result->IAIDx != NULL)
+  {
+      memset(result->IAIDx, 0, ctx_size);
+  }
+  else
+  {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "failed to allocate symbol ID storage in jbig2_arith_iaid_ctx_new");
+  }
 
   return result;
 }
@@ -86,6 +101,9 @@
 void
 jbig2_arith_iaid_ctx_free(Jbig2Ctx *ctx, Jbig2ArithIaidCtx *iax)
 {
-  jbig2_free(ctx->allocator, iax->IAIDx);
-  jbig2_free(ctx->allocator, iax);
+    if (iax != NULL)
+    {
+        jbig2_free(ctx->allocator, iax->IAIDx);
+        jbig2_free(ctx->allocator, iax);
+    }
 }
--- a/jbig2_arith_int.c
+++ b/jbig2_arith_int.c
@@ -40,7 +40,15 @@
 {
   Jbig2ArithIntCtx *result = jbig2_new(ctx, Jbig2ArithIntCtx, 1);
 
-  memset(result->IAx, 0, sizeof(result->IAx));
+  if (result == NULL)
+  {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "failed to allocate Jbig2ArithIntCtx in jbig2_arith_int_ctx_new");
+  }
+  else
+  {
+      memset(result->IAx, 0, sizeof(result->IAx));
+  }
 
   return result;
 }
--- a/jbig2_generic.c
+++ b/jbig2_generic.c
@@ -769,10 +769,10 @@
   int offset;
   int gbat_bytes = 0;
   Jbig2GenericRegionParams params;
-  int code;
-  Jbig2Image *image;
-  Jbig2WordStream *ws;
-  Jbig2ArithState *as;
+  int code = 0;
+  Jbig2Image *image = NULL;
+  Jbig2WordStream *ws = NULL;
+  Jbig2ArithState *as = NULL;
   Jbig2ArithCx *GB_stats = NULL;
 
   /* 7.4.6 */
@@ -816,7 +816,7 @@
 
   image = jbig2_image_new(ctx, rsi.width, rsi.height);
   if (image == NULL)
-    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
              "unable to allocate generic image");
   jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
     "allocated %d x %d image buffer for region decode results",
@@ -825,29 +825,46 @@
   if (params.MMR)
     {
       code = jbig2_decode_generic_mmr(ctx, segment, &params,
-				      segment_data + offset, segment->data_length - offset,
-				      image);
+          segment_data + offset, segment->data_length - offset, image);
     }
   else
     {
       int stats_size = jbig2_generic_stats_size(ctx, params.GBTEMPLATE);
       GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
+      if (GB_stats == NULL)
+      {
+          code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+              "unable to allocate GB_stats in jbig2_immediate_generic_region");
+          goto cleanup;
+      }
       memset(GB_stats, 0, stats_size);
 
-      ws = jbig2_word_stream_buf_new(ctx,
-				     segment_data + offset,
-				     segment->data_length - offset);
+      ws = jbig2_word_stream_buf_new(ctx, segment_data + offset,
+          segment->data_length - offset);
+      if (ws == NULL)
+      {
+          code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+              "unable to allocate ws in jbig2_immediate_generic_region");
+          goto cleanup;
+      }
       as = jbig2_arith_new(ctx, ws);
+      if (as == NULL)
+      {
+          code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+              "unable to allocate as in jbig2_immediate_generic_region");
+          goto cleanup;
+      }
       code = jbig2_decode_generic_region(ctx, segment, &params,
 					 as, image, GB_stats);
-      jbig2_free(ctx->allocator, as);
-      jbig2_word_stream_buf_free(ctx, ws);
-
-      jbig2_free(ctx->allocator, GB_stats);
     }
 
   jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page],
 			image, rsi.x, rsi.y, JBIG2_COMPOSE_OR);
+
+cleanup:
+  jbig2_free(ctx->allocator, as);
+  jbig2_word_stream_buf_free(ctx, ws);
+  jbig2_free(ctx->allocator, GB_stats);
   jbig2_image_release(ctx, image);
 
   return code;
--- a/jbig2_halftone.c
+++ b/jbig2_halftone.c
@@ -79,6 +79,8 @@
   if (new != NULL) {
     new->patterns = jbig2_new(ctx, Jbig2Image*, N);
     if (new->patterns == NULL) {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "failed to allocate pattern in collective bitmap dictionary");
       jbig2_free(ctx->allocator, new);
       return NULL;
     }
@@ -91,7 +93,7 @@
       new->patterns[i] = jbig2_image_new(ctx, HPW, HPH);
       if (new->patterns[i] == NULL) {
         int j;
-        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1,
             "failed to allocate pattern element image");
         for (j = 0; j < i; j++)
           jbig2_free(ctx->allocator, new->patterns[j]);
@@ -105,6 +107,11 @@
 			  -i * HPW, 0, JBIG2_COMPOSE_REPLACE);
     }
   }
+  else
+  {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "failed to allocate collective bitmap dictionary");
+  }
 
   return new;
 }
@@ -147,16 +154,16 @@
 			     Jbig2ArithCx *GB_stats)
 {
   Jbig2PatternDict *hd = NULL;
-  Jbig2Image *image;
+  Jbig2Image *image = NULL;
   Jbig2GenericRegionParams rparams;
-  int code;
+  int code = 0;
 
   /* allocate the collective image */
   image = jbig2_image_new(ctx,
 	params->HDPW * (params->GRAYMAX + 1), params->HDPH);
   if (image == NULL) {
-    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-	"failed to allocate collective bitmap for halftone dict!");
+    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+        "failed to allocate collective bitmap for halftone dict!");
     return NULL;
   }
 
@@ -175,22 +182,32 @@
   rparams.gbat[7] = -2;
 
   if (params->HDMMR) {
-    code = jbig2_decode_generic_mmr(ctx, segment, &rparams,
-		data, size, image);
+    code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data, size, image);
   } else {
     Jbig2WordStream *ws = jbig2_word_stream_buf_new(ctx, data, size);
-    Jbig2ArithState *as = jbig2_arith_new(ctx, ws);
+    if (ws != NULL)
+    {
+      Jbig2ArithState *as = jbig2_arith_new(ctx, ws);
+      if (as != NULL)
+      {
+        code = jbig2_decode_generic_region(ctx, segment, &rparams,
+            as, image, GB_stats);
+      }
+      else
+      {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+            "failed to allocate storage for as in halftone dict!");
+      }
 
-    code = jbig2_decode_generic_region(ctx, segment, &rparams,
-		as, image, GB_stats);
-
-    jbig2_free(ctx->allocator, as);
-    jbig2_word_stream_buf_free(ctx, ws);
+      jbig2_free(ctx->allocator, as);
+      jbig2_word_stream_buf_free(ctx, ws);
+    }
+    else
+    {
+      code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+          "failed to allocate storage for ws in halftone dict!");
+    }
   }
-  if (code != 0) {
-    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
-	"error decoding collective pattern dictionary bitmap!");
-  }
 
   hd = jbig2_hd_new(ctx, params, image);
   jbig2_image_release(ctx, image);
@@ -240,6 +257,12 @@
     /* allocate and zero arithmetic coding stats */
     int stats_size = jbig2_generic_stats_size(ctx, params.HDTEMPLATE);
     GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
+    if (GB_stats == NULL)
+    {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+          "failed to allocate GB_stats in pattern dictionary");
+      return NULL;
+    }
     memset(GB_stats, 0, stats_size);
   }
 
@@ -269,7 +292,9 @@
 {
   int code = 0;
 
-  /* todo: implement */
+  code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+      "decode a halftone region not yet implemented");
+
   return code;
 }
 
@@ -282,9 +307,9 @@
   int offset = 0;
   Jbig2RegionSegmentInfo region_info;
   Jbig2HalftoneRegionParams params;
-  Jbig2Image *image;
-  Jbig2ArithCx *GB_stats;
-  int code;
+  Jbig2Image *image = NULL;
+  Jbig2ArithCx *GB_stats = NULL;
+  int code = 0;
 
   /* 7.4.5.1 */
   if (segment->data_length < 17) goto too_short;
@@ -345,13 +370,21 @@
     /* allocate and zero arithmetic coding stats */
     int stats_size = jbig2_generic_stats_size(ctx, params.HTEMPLATE);
     GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
+    if (GB_stats == NULL)
+    {
+      return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+          "failed to allocate GB_stats in halftone region");
+    }
     memset(GB_stats, 0, stats_size);
   }
 
   image = jbig2_image_new(ctx, region_info.width, region_info.height);
   if (image == NULL)
-    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-             "unable to allocate halftone image");
+  {
+    jbig2_free(ctx->allocator, GB_stats);
+    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+        "unable to allocate halftone image");
+  }
 
   code = jbig2_decode_halftone_region(ctx, segment, &params,
 		segment_data + offset, segment->data_length - offset,
--- a/jbig2_huffman.c
+++ b/jbig2_huffman.c
@@ -59,7 +59,7 @@
 Jbig2HuffmanState *
 jbig2_huffman_new (Jbig2Ctx *ctx, Jbig2WordStream *ws)
 {
-  Jbig2HuffmanState *result;
+  Jbig2HuffmanState *result = NULL;
 
   result = jbig2_new(ctx, Jbig2HuffmanState, 1);
 
@@ -68,8 +68,10 @@
       result->offset_bits = 0;
       result->this_word = ws->get_next_word (ws, 0);
       result->next_word = ws->get_next_word (ws, 4);
-
       result->ws = ws;
+  } else {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "failed to allocate new huffman coding state");
   }
 
   return result;
@@ -370,8 +372,20 @@
   max_j = 1 << log_table_size;
 
   result = jbig2_new(ctx, Jbig2HuffmanTable, 1);
+  if (result == NULL)
+  {
+    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+        "couldn't allocate result storage in jbig2_build_huffman_table");
+    return NULL;
+  }
   result->log_table_size = log_table_size;
   entries = jbig2_new(ctx, Jbig2HuffmanEntry, max_j);
+  if (entries == NULL)
+  {
+    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+        "couldn't allocate entries storage in jbig2_build_huffman_table");
+    return NULL;
+  }
   result->entries = entries;
 
   LENCOUNT[0] = 0;
--- a/jbig2_image.c
+++ b/jbig2_image.c
@@ -36,7 +36,7 @@
 	image = jbig2_new(ctx, Jbig2Image, 1);
 	if (image == NULL) {
 		jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
-			       "could not allocate image structure");
+            "could not allocate image structure in jbig2_image_new");
 		return NULL;
 	}
 
@@ -43,8 +43,8 @@
 	stride = ((width - 1) >> 3) + 1; /* generate a byte-aligned stride */
 	image->data = jbig2_new(ctx, uint8_t, stride*height);
 	if (image->data == NULL) {
-                jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
-                    "could not allocate image data buffer! [%d bytes]\n", stride*height);
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+            "could not allocate image data buffer! [%d bytes]\n", stride*height);
 		jbig2_free(ctx->allocator, image);
 		return NULL;
 	}
--- a/jbig2_metadata.c
+++ b/jbig2_metadata.c
@@ -37,9 +37,14 @@
         md->keys = jbig2_new(ctx, char*, md->max_entries);
         md->values = jbig2_new(ctx, char*, md->max_entries);
         if (md->keys == NULL || md->values == NULL) {
+            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+                "failed to allocate storage for metadata keys/values");
             jbig2_metadata_free(ctx, md);
             md = NULL;
         }
+    } else {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+            "failed to allocate storage for metadata");
     }
     return md;
 }
--- a/jbig2_page.c
+++ b/jbig2_page.c
@@ -145,7 +145,7 @@
         page->image = jbig2_image_new(ctx, page->width, page->height);
     }
     if (page->image == NULL) {
-        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
             "failed to allocate buffer for page image");
     } else {
 	/* 8.2 (3) fill the page with the default pixel value */
--- a/jbig2_refinement.c
+++ b/jbig2_refinement.c
@@ -393,11 +393,11 @@
   params.DX = 0;
   params.DY = 0;
   {
-    Jbig2WordStream *ws;
-    Jbig2ArithState *as;
+    Jbig2WordStream *ws = NULL;
+    Jbig2ArithState *as = NULL;
     Jbig2ArithCx *GR_stats = NULL;
     int stats_size;
-    Jbig2Image *image;
+    Jbig2Image *image = NULL;
     int code;
 
     image = jbig2_image_new(ctx, rsi.width, rsi.height);
@@ -410,18 +410,34 @@
 
     stats_size = params.GRTEMPLATE ? 1 << 10 : 1 << 13;
     GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
+    if (GR_stats == NULL)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+            "failed to allocate GR-stats in jbig2_refinement_region");
+        goto cleanup;
+    }
     memset(GR_stats, 0, stats_size);
 
     ws = jbig2_word_stream_buf_new(ctx, segment_data + offset,
            segment->data_length - offset);
+    if (ws == NULL)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+            "failed to allocate ws in jbig2_refinement_region");
+        goto cleanup;
+    }
+
     as = jbig2_arith_new(ctx, ws);
+    if (as == NULL)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+            "failed to allocate as in jbig2_refinement_region");
+        goto cleanup;
+    }
+
     code = jbig2_decode_refinement_region(ctx, segment, &params,
                               as, image, GR_stats);
 
-    jbig2_free(ctx->allocator, as);
-    jbig2_word_stream_buf_free(ctx, ws);
-    jbig2_free(ctx->allocator, GR_stats);
-
     if ((segment->flags & 63) == 40) {
         /* intermediate region. save the result for later */
 	segment->result = image;
@@ -434,6 +450,11 @@
           image, rsi.x, rsi.y, rsi.op);
         jbig2_image_release(ctx, image);
     }
+
+cleanup:
+    jbig2_free(ctx->allocator, as);
+    jbig2_word_stream_buf_free(ctx, ws);
+    jbig2_free(ctx->allocator, GR_stats);
   }
 
   return 0;
--- a/jbig2_segment.c
+++ b/jbig2_segment.c
@@ -44,6 +44,12 @@
     return NULL;
 
   result = jbig2_new(ctx, Jbig2Segment, 1);
+  if (result == NULL)
+  {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+          "failed to allocate segment in jbig2_parse_segment_header");
+      return result;
+  }
 
   /* 7.2.2 */
   result->number = jbig2_get_uint32(buf);
@@ -85,6 +91,13 @@
 
       referred_to_segments = jbig2_new(ctx, uint32_t,
         referred_to_segment_count * referred_to_segment_size);
+      if (referred_to_segments == NULL)
+      {
+          jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+              "could not allocate referred_to_segments "
+              "in jbig2_parse_segment_header");
+          return NULL;
+      }
 
       for (i = 0; i < referred_to_segment_count; i++) {
         referred_to_segments[i] =
@@ -197,18 +210,15 @@
 int jbig2_parse_extension_segment(Jbig2Ctx *ctx, Jbig2Segment *segment,
                             const uint8_t *segment_data)
 {
-    uint32_t type;
-    bool reserved, dependent, necessary;
+    uint32_t type = jbig2_get_uint32(segment_data);
+    bool reserved = type & 0x20000000;
+    /* bool dependent = type & 0x40000000; (NYI) */
+    bool necessary = type & 0x80000000;
 
-    type = jbig2_get_uint32(segment_data);
-
-    reserved = type & 0x20000000;
-    dependent = type & 0x40000000;
-    necessary = type & 0x80000000;
-
     if (necessary && !reserved) {
         jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
-            "extension segment is marked 'necessary' but not 'reservered' contrary to spec");
+            "extension segment is marked 'necessary' but "
+            "not 'reservered' contrary to spec");
     }
 
     switch (type) {
--- a/jbig2_symbol_dict.c
+++ b/jbig2_symbol_dict.c
@@ -96,6 +96,8 @@
      new->glyphs = jbig2_new(ctx, Jbig2Image*, n_symbols);
      new->n_symbols = n_symbols;
    } else {
+     jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+         "unable to allocate new empty symbol dict");
      return NULL;
    }
 
@@ -102,6 +104,8 @@
    if (new->glyphs != NULL) {
      memset(new->glyphs, 0, n_symbols*sizeof(Jbig2Image*));
    } else {
+     jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+         "unable to allocate glyphs for new empty symbol dict");
      jbig2_free(ctx->allocator, new);
      return NULL;
    }
@@ -157,6 +161,13 @@
     int dindex = 0;
 
     dicts = jbig2_new(ctx, Jbig2SymbolDict*, n_dicts);
+    if (dicts == NULL)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate referred list of symbol dictionaries");
+        return NULL;
+    }
+
     for (index = 0; index < segment->referred_to_segment_count; index++) {
         rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
         if (rsegment && ((rsegment->flags & 63) == 0)) {
@@ -195,6 +206,9 @@
     for (i = 0; i < n_dicts; i++)
       for (j = 0; j < dicts[i]->n_symbols; j++)
         new->glyphs[k++] = jbig2_image_clone(ctx, dicts[i]->glyphs[j]);
+  } else {
+    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1,
+        "failed to allocate new symbol dictionary");
   }
 
   return new;
@@ -212,8 +226,8 @@
 			 Jbig2ArithCx *GB_stats,
 			 Jbig2ArithCx *GR_stats)
 {
-  Jbig2SymbolDict *SDNEWSYMS;
-  Jbig2SymbolDict *SDEXSYMS;
+  Jbig2SymbolDict *SDNEWSYMS = NULL;
+  Jbig2SymbolDict *SDEXSYMS = NULL;
   int32_t HCHEIGHT;
   uint32_t NSYMSDECODED;
   int32_t SYMWIDTH, TOTWIDTH;
@@ -232,7 +246,7 @@
   Jbig2ArithIntCtx *IARDX = NULL;
   Jbig2ArithIntCtx *IARDY = NULL;
   int code = 0;
-  Jbig2SymbolDict **refagg_dicts;
+  Jbig2SymbolDict **refagg_dicts = NULL;
   int n_refagg_dicts = 1;
 
   Jbig2TextRegionParams *tparams = NULL;
@@ -242,6 +256,12 @@
   NSYMSDECODED = 0;
 
   ws = jbig2_word_stream_buf_new(ctx, data, size);
+  if (ws == NULL)
+  {
+      jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+          "failed to allocate storage in jbig2_decode_symbol_dict");
+      return NULL;
+  }
 
   if (!params->SDHUFF) {
       as = jbig2_arith_new(ctx, ws);
@@ -249,30 +269,53 @@
       IADW = jbig2_arith_int_ctx_new(ctx);
       IAEX = jbig2_arith_int_ctx_new(ctx);
       IAAI = jbig2_arith_int_ctx_new(ctx);
+      if ((as == NULL) || (IADH == NULL) || (IADW == NULL) ||
+          (IAEX == NULL) || (IAAI == NULL))
+      {
+          jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+              "failed to allocate storage for symbol bitmap");
+          goto cleanup1;
+      }
       if (params->SDREFAGG) {
-	  int tmp = params->SDINSYMS->n_symbols + params->SDNUMNEWSYMS;
-	  for (SBSYMCODELEN = 0; (1 << SBSYMCODELEN) < tmp; SBSYMCODELEN++);
-	  IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
-	  IARDX = jbig2_arith_int_ctx_new(ctx);
-	  IARDY = jbig2_arith_int_ctx_new(ctx);
+          int tmp = params->SDINSYMS->n_symbols + params->SDNUMNEWSYMS;
+          for (SBSYMCODELEN = 0; (1 << SBSYMCODELEN) < tmp; SBSYMCODELEN++);
+          IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
+          IARDX = jbig2_arith_int_ctx_new(ctx);
+          IARDY = jbig2_arith_int_ctx_new(ctx);
+          if ((IAID == NULL) || (IARDX == NULL) || (IARDY == NULL))
+          {
+              jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+                  "failed to allocate storage for symbol bitmap");
+              goto cleanup2;
+          }
       }
   } else {
       jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
-	"huffman coded symbol dictionary");
+          "huffman coded symbol dictionary");
       hs = jbig2_huffman_new(ctx, ws);
-      SDHUFFRDX = jbig2_build_huffman_table(ctx,
-				&jbig2_huffman_params_O);
+      SDHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
+      if ( (hs == NULL) || (SDHUFFRDX == NULL))
+      {
+          jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+              "failed to allocate storage for symbol bitmap");
+          goto cleanup2;
+      }
       if (!params->SDREFAGG) {
 	  SDNEWSYMWIDTHS = jbig2_new(ctx, uint32_t, params->SDNUMNEWSYMS);
 	  if (SDNEWSYMWIDTHS == NULL) {
 	    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-		"could not allocate storage for symbol widths");
-	    return NULL;
+            "could not allocate storage for symbol widths");
+	    goto cleanup2;
 	  }
       }
   }
 
   SDNEWSYMS = jbig2_sd_new(ctx, params->SDNUMNEWSYMS);
+  if (SDNEWSYMS == NULL) {
+      jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+          "could not allocate storage for symbols");
+      goto cleanup2;
+  }
 
   /* 6.5.5 (4a) */
   while (NSYMSDECODED < params->SDNUMNEWSYMS) {
@@ -297,10 +340,9 @@
       HCFIRSTSYM = NSYMSDECODED;
 
       if (HCHEIGHT < 0) {
-	  /* todo: mem cleanup */
-	  code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-			   "Invalid HCHEIGHT value");
-          return NULL;
+          code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+              "Invalid HCHEIGHT value");
+          goto cleanup2;
       }
 #ifdef JBIG2_DEBUG
       jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
@@ -312,17 +354,17 @@
       for (;;) {
 	  /* check for broken symbol table */
  	  if (NSYMSDECODED > params->SDNUMNEWSYMS)
-	    {
-	      /* todo: mem cleanup? */
-	      jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
-	        "No OOB signalling end of height class %d", HCHEIGHT);
-	      break;
-	    }
+      {
+          jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+              "No OOB signalling end of height class %d", HCHEIGHT);
+	      goto cleanup4;
+      }
 	  /* 6.5.7 */
 	  if (params->SDHUFF) {
 	      DW = jbig2_huffman_get(hs, params->SDHUFFDW, &code);
 	  } else {
 	      code = jbig2_arith_int_decode(IADW, as, &DW);
+          if (code < 0) goto cleanup4;
 	  }
 
 	  /* 6.5.5 (4c.i) */
@@ -334,11 +376,10 @@
 	  SYMWIDTH = SYMWIDTH + DW;
 	  TOTWIDTH = TOTWIDTH + SYMWIDTH;
 	  if (SYMWIDTH < 0) {
-	      /* todo: mem cleanup */
-              code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-                "Invalid SYMWIDTH value (%d) at symbol %d", SYMWIDTH, NSYMSDECODED+1);
-              return NULL;
-          }
+          code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+              "Invalid SYMWIDTH value (%d) at symbol %d", SYMWIDTH, NSYMSDECODED+1);
+          goto cleanup4;
+      }
 #ifdef JBIG2_DEBUG
 	  jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
             "SYMWIDTH = %d TOTWIDTH = %d", SYMWIDTH, TOTWIDTH);
@@ -364,16 +405,21 @@
 		  memcpy(region_params.gbat, params->sdat, sdat_bytes);
 
 		  image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
+          if (image == NULL)
+          {
+              code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                  "failed to allocate image in jbig2_decode_symbol_dict");
+              goto cleanup4;
+          }
 
 		  code = jbig2_decode_generic_region(ctx, segment, &region_params,
-						     as, image, GB_stats);
-		  /* todo: handle errors */
+              as, image, GB_stats);
+          if (code < 0) goto cleanup4;
 
-                  SDNEWSYMS->glyphs[NSYMSDECODED] = image;
-
+          SDNEWSYMS->glyphs[NSYMSDECODED] = image;
 	      } else {
-                  /* 6.5.8.2 refinement/aggregate symbol */
-                  uint32_t REFAGGNINST;
+          /* 6.5.8.2 refinement/aggregate symbol */
+          uint32_t REFAGGNINST;
 
 		  if (params->SDHUFF) {
 		      REFAGGNINST = jbig2_huffman_get(hs, params->SDHUFFAGGINST, &code);
@@ -382,8 +428,8 @@
 		  }
 		  if (code || (int32_t)REFAGGNINST <= 0) {
 		      code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-			"invalid number of symbols or OOB in aggregate glyph");
-		      return NULL;
+                  "invalid number of symbols or OOB in aggregate glyph");
+		      goto cleanup4;
 		  }
 
 		  jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
@@ -402,7 +448,7 @@
 		          if (refagg_dicts == NULL) {
 			      code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
 			       "Out of memory allocating dictionary array");
-		              return NULL;
+		              goto cleanup4;
 		          }
 		          refagg_dicts[0] = jbig2_sd_new(ctx, params->SDNUMINSYMS + params->SDNUMNEWSYMS);
 		          if (refagg_dicts[0] == NULL) {
@@ -409,7 +455,7 @@
 			      code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
 			       "Out of memory allocating symbol dictionary");
 		              jbig2_free(ctx->allocator, refagg_dicts);
-		              return NULL;
+		              goto cleanup4;
 		          }
 		          refagg_dicts[0]->n_symbols = params->SDNUMINSYMS + params->SDNUMNEWSYMS;
 		          for (i=0;i < params->SDNUMINSYMS;i++)
@@ -423,9 +469,9 @@
 			      "Out of memory creating text region params");
 			      jbig2_sd_release(ctx, refagg_dicts[0]);
 			      jbig2_free(ctx->allocator, refagg_dicts);
-			      return NULL;
+			      goto cleanup4;
 			  }
-    		          if (!params->SDHUFF) {
+              if (!params->SDHUFF) {
 			      /* Values from Table 17, section 6.5.8.2 (2) */
 			      tparams->IADT = jbig2_arith_int_ctx_new(ctx);
 			      tparams->IAFS = jbig2_arith_int_ctx_new(ctx);
@@ -468,14 +514,14 @@
 		      }
 		      tparams->SBNUMINSTANCES = REFAGGNINST;
 
-      		      image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
+              image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
 		      if (image == NULL) {
-			  code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-			   "Out of memory creating symbol image");
-		          jbig2_free(ctx->allocator, tparams);
-			  jbig2_sd_release(ctx, refagg_dicts[0]);
-		          jbig2_free(ctx->allocator, refagg_dicts);
-		          return NULL;
+                  code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                      "Out of memory creating symbol image");
+                  jbig2_free(ctx->allocator, tparams);
+                  jbig2_sd_release(ctx, refagg_dicts[0]);
+                  jbig2_free(ctx->allocator, refagg_dicts);
+                  goto cleanup4;
 		      }
 
 		      /* multiple symbols are handled as a text region */
@@ -504,16 +550,21 @@
 		      }
 
 		      if (ID >= ninsyms+NSYMSDECODED) {
-			code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-			  "refinement references unknown symbol %d", ID);
-			return NULL;
+                  code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                      "refinement references unknown symbol %d", ID);
+                  goto cleanup4;
 		      }
 
 		      jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
-			"symbol is a refinement of id %d with the refinement applied at (%d,%d)",
-			ID, RDX, RDY);
+                  "symbol is a refinement of id %d with the "
+                  "refinement applied at (%d,%d)", ID, RDX, RDY);
 
 		      image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
+              if (image == NULL) {
+                  code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                      "Out of memory creating symbol image");
+                  goto cleanup4;
+              }
 
 		      /* Table 18 */
 		      rparams.GRTEMPLATE = params->SDRTEMPLATE;
@@ -528,7 +579,6 @@
 		          &rparams, as, image, GR_stats);
 
 		      SDNEWSYMS->glyphs[NSYMSDECODED] = image;
-
 		  }
                }
 
@@ -573,8 +623,7 @@
 	if (code || (BMSIZE < 0)) {
 	  jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
 	    "error decoding size of collective bitmap!");
-	  /* todo: memory cleanup */
-	  return NULL;
+	  goto cleanup4;
 	}
 
 	/* skip any bits before the next byte boundary */
@@ -584,8 +633,7 @@
 	if (image == NULL) {
 	  jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
 	    "could not allocate collective bitmap image!");
-	  /* todo: memory cleanup */
-	  return NULL;
+	  goto cleanup4;
 	}
 
 	if (BMSIZE == 0) {
@@ -619,8 +667,7 @@
 	  if (code) {
 	    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
 	      "error decoding MMR bitmap image!");
-	    /* todo: memory cleanup */
-	    return NULL;
+	    goto cleanup4;
 	  }
 	}
 
@@ -632,8 +679,13 @@
 	for (j = HCFIRSTSYM; j < NSYMSDECODED; j++) {
 	  Jbig2Image *glyph;
 	  glyph = jbig2_image_new(ctx, SDNEWSYMWIDTHS[j], HCHEIGHT);
-	  jbig2_image_compose(ctx, glyph, image,
-		-x, 0, JBIG2_COMPOSE_REPLACE);
+      if (glyph == NULL)
+      {
+          jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+              "failed to copy the collective bitmap into symbol dictionary");
+          goto cleanup4;
+      }
+	  jbig2_image_compose(ctx, glyph, image, -x, 0, JBIG2_COMPOSE_REPLACE);
 	  x += SDNEWSYMWIDTHS[j];
 	  SDNEWSYMS->glyphs[j] = glyph;
 	}
@@ -642,42 +694,16 @@
 
   } /* end of symbol decode loop */
 
-  if (tparams != NULL)
-  {
-      if (!params->SDHUFF)
-      {
-          jbig2_arith_int_ctx_free(ctx, tparams->IADT);
-          jbig2_arith_int_ctx_free(ctx, tparams->IAFS);
-          jbig2_arith_int_ctx_free(ctx, tparams->IADS);
-          jbig2_arith_int_ctx_free(ctx, tparams->IAIT);
-          jbig2_arith_iaid_ctx_free(ctx, tparams->IAID);
-          jbig2_arith_int_ctx_free(ctx, tparams->IARI);
-          jbig2_arith_int_ctx_free(ctx, tparams->IARDW);
-          jbig2_arith_int_ctx_free(ctx, tparams->IARDH);
-          jbig2_arith_int_ctx_free(ctx, tparams->IARDX);
-          jbig2_arith_int_ctx_free(ctx, tparams->IARDY);
-      }
-      else
-      {
-          jbig2_release_huffman_table(ctx, tparams->SBHUFFFS);
-          jbig2_release_huffman_table(ctx, tparams->SBHUFFDS);
-          jbig2_release_huffman_table(ctx, tparams->SBHUFFDT);
-          jbig2_release_huffman_table(ctx, tparams->SBHUFFRDX);
-          jbig2_release_huffman_table(ctx, tparams->SBHUFFRDY);
-          jbig2_release_huffman_table(ctx, tparams->SBHUFFRDW);
-          jbig2_release_huffman_table(ctx, tparams->SBHUFFRDH);
-      }
-      jbig2_free(ctx->allocator, tparams);
-      tparams = NULL;
-      jbig2_sd_release(ctx, refagg_dicts[0]);
-      jbig2_free(ctx->allocator, refagg_dicts);
-  }
-
-  jbig2_free(ctx->allocator, GB_stats);
-
   /* 6.5.10 */
   SDEXSYMS = jbig2_sd_new(ctx, params->SDNUMEXSYMS);
+  if (SDEXSYMS == NULL)
   {
+      jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+          "failed to allocate symbols exported from symbols dictionary");
+      goto cleanup4;
+  }
+  else
+  {
     int i = 0;
     int j = 0;
     int k, m, exflag = 0;
@@ -714,28 +740,56 @@
     }
   }
 
-  jbig2_sd_release(ctx, SDNEWSYMS);
-
-  if (!params->SDHUFF) {
-      jbig2_arith_int_ctx_free(ctx, IADH);
-      jbig2_arith_int_ctx_free(ctx, IADW);
-      jbig2_arith_int_ctx_free(ctx, IAEX);
-      jbig2_arith_int_ctx_free(ctx, IAAI);
-      if (params->SDREFAGG) {
-        jbig2_arith_iaid_ctx_free(ctx, IAID);
-        jbig2_arith_int_ctx_free(ctx, IARDX);
-        jbig2_arith_int_ctx_free(ctx, IARDY);
+cleanup4:
+  if (tparams != NULL)
+  {
+      if (!params->SDHUFF)
+      {
+          jbig2_arith_int_ctx_free(ctx, tparams->IADT);
+          jbig2_arith_int_ctx_free(ctx, tparams->IAFS);
+          jbig2_arith_int_ctx_free(ctx, tparams->IADS);
+          jbig2_arith_int_ctx_free(ctx, tparams->IAIT);
+          jbig2_arith_iaid_ctx_free(ctx, tparams->IAID);
+          jbig2_arith_int_ctx_free(ctx, tparams->IARI);
+          jbig2_arith_int_ctx_free(ctx, tparams->IARDW);
+          jbig2_arith_int_ctx_free(ctx, tparams->IARDH);
+          jbig2_arith_int_ctx_free(ctx, tparams->IARDX);
+          jbig2_arith_int_ctx_free(ctx, tparams->IARDY);
       }
-      jbig2_free(ctx->allocator, as);
-  } else {
-      if (params->SDREFAGG) {
-	jbig2_free(ctx->allocator, SDNEWSYMWIDTHS);
+      else
+      {
+          jbig2_release_huffman_table(ctx, tparams->SBHUFFFS);
+          jbig2_release_huffman_table(ctx, tparams->SBHUFFDS);
+          jbig2_release_huffman_table(ctx, tparams->SBHUFFDT);
+          jbig2_release_huffman_table(ctx, tparams->SBHUFFRDX);
+          jbig2_release_huffman_table(ctx, tparams->SBHUFFRDY);
+          jbig2_release_huffman_table(ctx, tparams->SBHUFFRDW);
+          jbig2_release_huffman_table(ctx, tparams->SBHUFFRDH);
       }
-      jbig2_release_huffman_table(ctx, SDHUFFRDX);
-      jbig2_free(ctx->allocator, hs);
+      jbig2_free(ctx->allocator, tparams);
   }
+  if (refagg_dicts != NULL)
+  {
+      jbig2_sd_release(ctx, refagg_dicts[0]);
+      jbig2_free(ctx->allocator, refagg_dicts);
+  }
+  jbig2_free(ctx->allocator, GB_stats);
 
+cleanup2:
+  jbig2_free(ctx->allocator, SDNEWSYMWIDTHS);
+  jbig2_release_huffman_table(ctx, SDHUFFRDX);
+  jbig2_free(ctx->allocator, hs);
+  jbig2_arith_iaid_ctx_free(ctx, IAID);
+  jbig2_arith_int_ctx_free(ctx, IARDX);
+  jbig2_arith_int_ctx_free(ctx, IARDY);
+
+cleanup1:
   jbig2_word_stream_buf_free(ctx, ws);
+  jbig2_free(ctx->allocator, as);
+  jbig2_arith_int_ctx_free(ctx, IADH);
+  jbig2_arith_int_ctx_free(ctx, IADW);
+  jbig2_arith_int_ctx_free(ctx, IAEX);
+  jbig2_arith_int_ctx_free(ctx, IAAI);
 
   return SDEXSYMS;
 }
@@ -759,6 +813,10 @@
 
   /* 7.4.2.1.1 */
   flags = jbig2_get_uint16(segment_data);
+
+  /* zero params to ease cleanup later */
+  memset(&params, 0, sizeof(Jbig2SymbolDictParams));
+
   params.SDHUFF = flags & 1;
   params.SDREFAGG = (flags >> 1) & 1;
   params.SDTEMPLATE = (flags >> 10) & 3;
@@ -772,12 +830,10 @@
   if (params.SDHUFF) {
     switch ((flags & 0x000c) >> 2) {
       case 0: /* Table B.4 */
-	params.SDHUFFDH = jbig2_build_huffman_table(ctx,
-		                       &jbig2_huffman_params_D);
+	params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_D);
 	break;
       case 1: /* Table B.5 */
-	params.SDHUFFDH = jbig2_build_huffman_table(ctx,
-		                       &jbig2_huffman_params_E);
+	params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_E);
 	break;
       case 3: /* Custom table from referred segment */
         huffman_params = jbig2_find_table(ctx, segment, table_index);
@@ -788,8 +844,6 @@
         params.SDHUFFDH = jbig2_build_huffman_table(ctx, huffman_params);
         ++table_index;
         break;
-        /* FIXME: this function leaks memory when error happens.
-           i.e. not calling jbig2_release_huffman_table() */
       case 2:
       default:
 	return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
@@ -796,20 +850,26 @@
 	    "symbol dictionary specified invalid huffman table");
 	break;
     }
+    if (params.SDHUFFDH == NULL)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate DH huffman table");
+        goto cleanup;
+    }
+
     switch ((flags & 0x0030) >> 4) {
       case 0: /* Table B.2 */
-	params.SDHUFFDW = jbig2_build_huffman_table(ctx,
-		                       &jbig2_huffman_params_B);
+	params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_B);
 	break;
       case 1: /* Table B.3 */
-	params.SDHUFFDW = jbig2_build_huffman_table(ctx,
-		                       &jbig2_huffman_params_C);
+	params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_C);
 	break;
       case 3: /* Custom table from referred segment */
         huffman_params = jbig2_find_table(ctx, segment, table_index);
         if (huffman_params == NULL) {
-            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                 "Custom DW huffman table not found (%d)", table_index);
+            break;
         }
         params.SDHUFFDW = jbig2_build_huffman_table(ctx, huffman_params);
         ++table_index;
@@ -820,34 +880,54 @@
 	    "symbol dictionary specified invalid huffman table");
 	break;
     }
+    if (params.SDHUFFDW == NULL)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate DW huffman table");
+        goto cleanup;
+    }
+
     if (flags & 0x0040) {
         /* Custom table from referred segment */
         huffman_params = jbig2_find_table(ctx, segment, table_index);
         if (huffman_params == NULL) {
-            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                 "Custom BMSIZE huffman table not found (%d)", table_index);
+        } else {
+            params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, huffman_params);
+            ++table_index;
         }
-        params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, huffman_params);
-        ++table_index;
     } else {
 	/* Table B.1 */
-	params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx,
-					&jbig2_huffman_params_A);
+	params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
     }
+    if (params.SDHUFFBMSIZE == NULL)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate BMSIZE huffman table");
+        goto cleanup;
+    }
+
     if (flags & 0x0080) {
         /* Custom table from referred segment */
         huffman_params = jbig2_find_table(ctx, segment, table_index);
         if (huffman_params == NULL) {
-            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                 "Custom REFAGG huffman table not found (%d)", table_index);
+        } else {
+            params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, huffman_params);
+            ++table_index;
         }
-        params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, huffman_params);
-        ++table_index;
     } else {
 	/* Table B.1 */
-	params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx,
-					&jbig2_huffman_params_A);
+	params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
     }
+    if (params.SDHUFFAGGINST == NULL)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate REFAGG huffman table");
+        goto cleanup;
+    }
   }
 
   /* FIXME: there are quite a few of these conditions to check */
@@ -903,10 +983,22 @@
     int n_dicts = jbig2_sd_count_referred(ctx, segment);
     Jbig2SymbolDict **dicts = NULL;
 
-    params.SDINSYMS = NULL;
     if (n_dicts > 0) {
       dicts = jbig2_sd_list_referred(ctx, segment);
+      if (dicts == NULL)
+      {
+          jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+              "failed to allocate dicts in symbol dictionary");
+          goto cleanup;
+      }
       params.SDINSYMS = jbig2_sd_cat(ctx, n_dicts, dicts);
+      if (params.SDINSYMS == NULL)
+      {
+          jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+              "failed to allocate symbol array in symbol dictionary");
+          jbig2_sd_release(ctx, *dicts);
+          goto cleanup;
+      }
     }
     if (params.SDINSYMS != NULL) {
       params.SDNUMINSYMS = params.SDINSYMS->n_symbols;
@@ -918,13 +1010,26 @@
   /* 7.4.2.2 (4) */
   if (!params.SDHUFF) {
       int stats_size = params.SDTEMPLATE == 0 ? 65536 :
-	params.SDTEMPLATE == 1 ? 8192 : 1024;
+          params.SDTEMPLATE == 1 ? 8192 : 1024;
       GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
+      if (GB_stats == NULL)
+      {
+          jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+              "failed to allocate GB_stats in jbig2_symbol_dictionary");
+          goto cleanup;
+      }
       memset(GB_stats, 0, stats_size);
       if (params.SDREFAGG) {
-	stats_size = params.SDRTEMPLATE ? 1 << 10 : 1 << 13;
-	GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
-	memset(GR_stats, 0, stats_size);
+          stats_size = params.SDRTEMPLATE ? 1 << 10 : 1 << 13;
+          GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
+          if (GR_stats == NULL)
+          {
+              jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
+                  "failed to allocate GR_stats in jbig2_symbol_dictionary");
+              jbig2_free(ctx->allocator, GB_stats);
+              goto cleanup;
+          }
+          memset(GR_stats, 0, stats_size);
       }
   }
 
@@ -942,6 +1047,7 @@
   if (segment->result) jbig2_dump_symbol_dict(ctx, segment);
 #endif
 
+cleanup:
   if (params.SDHUFF) {
       jbig2_release_huffman_table(ctx, params.SDHUFFDH);
       jbig2_release_huffman_table(ctx, params.SDHUFFDW);
--- a/jbig2_text.c
+++ b/jbig2_text.c
@@ -71,7 +71,7 @@
     int x,y;
     bool first_symbol;
     uint32_t index, SBNUMSYMS;
-    Jbig2Image *IB;
+    Jbig2Image *IB = NULL;
     Jbig2HuffmanState *hs = NULL;
     Jbig2HuffmanTable *SBSYMCODES = NULL;
     int code = 0;
@@ -85,16 +85,22 @@
         "symbol list contains %d glyphs in %d dictionaries", SBNUMSYMS, n_dicts);
 
     if (params->SBHUFF) {
-	Jbig2HuffmanTable *runcodes;
+	Jbig2HuffmanTable *runcodes = NULL;
 	Jbig2HuffmanParams runcodeparams;
 	Jbig2HuffmanLine runcodelengths[35];
-	Jbig2HuffmanLine *symcodelengths;
+	Jbig2HuffmanLine *symcodelengths = NULL;
 	Jbig2HuffmanParams symcodeparams;
-	int code, err, len, range, r;
+	int err, len, range, r;
 
 	jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
 	  "huffman coded text region");
 	hs = jbig2_huffman_new(ctx, ws);
+    if (hs == NULL)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+            "failed to allocate storage for text region");
+        return -1;
+    }
 
 	/* 7.4.3.1.7 - decode symbol ID Huffman table */
 	/* this is actually part of the segment header, but it is more
@@ -115,7 +121,8 @@
 	if (runcodes == NULL) {
 	  jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
 	    "error constructing symbol id runcode table!");
-	  return -1;
+	  code = -1;
+      goto cleanup1;
 	}
 
 	/* decode the symbol id codelengths using the runlength table */
@@ -123,7 +130,8 @@
 	if (symcodelengths == NULL) {
 	  jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
 	    "memory allocation failure reading symbol ID huffman table!");
-	  return -1;
+	  code = -1;
+      goto cleanup1;
 	}
 	index = 0;
 	while (index < SBNUMSYMS) {
@@ -131,7 +139,8 @@
 	  if (err != 0 || code < 0 || code >= 35) {
 	    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
 	      "error reading symbol ID huffman table!");
-	    return err ? err : -1;
+	    code = err ? err : -1;
+        goto cleanup1;
 	  }
 
 	  if (code < 32) {
@@ -143,8 +152,8 @@
 	      if (index < 1) {
 		jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
 	 	  "error decoding symbol id table: run length with no antecedent!");
-	        /* todo: memory cleanup */
-	        return -1;
+	        code = -1;
+            goto cleanup1;
 	      }
 	    } else {
 	      len = 0; /* code == 33 or 34 */
@@ -183,13 +192,15 @@
 	/* finally, construct the symbol id huffman table itself */
 	SBSYMCODES = jbig2_build_huffman_table(ctx, &symcodeparams);
 
+cleanup1:
 	jbig2_free(ctx->allocator, symcodelengths);
 	jbig2_release_huffman_table(ctx, runcodes);
 
 	if (SBSYMCODES == NULL) {
 	    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-		"could not construct Symbol ID huffman table!");
-	    return -1;
+            "could not construct Symbol ID huffman table!");
+        jbig2_huffman_free(ctx, hs);
+	    return ((code != 0) ? code : -1);
 	}
     }
 
@@ -201,6 +212,7 @@
         STRIPT = jbig2_huffman_get(hs, params->SBHUFFDT, &code);
     } else {
         code = jbig2_arith_int_decode(params->IADT, as, &STRIPT);
+        if (code < 0) goto cleanup2;
     }
 
     /* 6.4.5 (2) */
@@ -215,6 +227,7 @@
             DT = jbig2_huffman_get(hs, params->SBHUFFDT, &code);
         } else {
             code = jbig2_arith_int_decode(params->IADT, as, &DT);
+            if (code < 0) goto cleanup2;
         }
         DT *= params->SBSTRIPS;
         STRIPT += DT;
@@ -229,6 +242,7 @@
 		    DFS = jbig2_huffman_get(hs, params->SBHUFFFS, &code);
 		} else {
 		    code = jbig2_arith_int_decode(params->IAFS, as, &DFS);
+            if (code < 0) goto cleanup2;
 		}
 		FIRSTS += DFS;
 		CURS = FIRSTS;
@@ -254,6 +268,7 @@
 		CURT = jbig2_huffman_get_bits(hs, params->LOGSBSTRIPS);
 	    } else {
 		code = jbig2_arith_int_decode(params->IAIT, as, &CURT);
+        if (code < 0) goto cleanup2;
 	    }
 	    T = STRIPT + CURT;
 
@@ -262,6 +277,7 @@
 		ID = jbig2_huffman_get(hs, SBSYMCODES, &code);
 	    } else {
 		code = jbig2_arith_iaid_decode(params->IAID, as, (int *)&ID);
+        if (code < 0) goto cleanup2;
 	    }
 	    if (ID >= SBNUMSYMS) {
 		return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
@@ -282,6 +298,7 @@
 		RI = jbig2_huffman_get_bits(hs, 1);
 	      } else {
 		code = jbig2_arith_int_decode(params->IARI, as, &RI);
+        if (code < 0) goto cleanup2;
 	      }
 	    } else {
 		RI = 0;
@@ -295,10 +312,16 @@
 
 		/* 6.4.11 (1, 2, 3, 4) */
 		if (!params->SBHUFF) {
-		  code = jbig2_arith_int_decode(params->IARDW, as, &RDW);
-		  code = jbig2_arith_int_decode(params->IARDH, as, &RDH);
-		  code = jbig2_arith_int_decode(params->IARDX, as, &RDX);
-		  code = jbig2_arith_int_decode(params->IARDY, as, &RDY);
+		  int code1 = jbig2_arith_int_decode(params->IARDW, as, &RDW);
+		  int code2 = jbig2_arith_int_decode(params->IARDH, as, &RDH);
+		  int code3 = jbig2_arith_int_decode(params->IARDX, as, &RDX);
+		  int code4 = jbig2_arith_int_decode(params->IARDY, as, &RDY);
+          if ((code1 < 0) || (code2 < 0) || (code3 < 0) || (code4 < 0))
+          {
+              code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                  "failed to decode data");
+              goto cleanup2;
+          }
 		} else {
 		  RDW = jbig2_huffman_get(hs, params->SBHUFFRDW, &code);
 		  RDH = jbig2_huffman_get(hs, params->SBHUFFRDH, &code);
@@ -394,11 +417,12 @@
     }
     /* 6.4.5 (4) */
 
+cleanup2:
     if (params->SBHUFF) {
       jbig2_release_huffman_table(ctx, SBSYMCODES);
     }
 
-    return 0;
+    return code;
 }
 
 /**
@@ -410,10 +434,10 @@
     int offset = 0;
     Jbig2RegionSegmentInfo region_info;
     Jbig2TextRegionParams params;
-    Jbig2Image *image;
-    Jbig2SymbolDict **dicts;
-    int n_dicts;
-    uint16_t flags;
+    Jbig2Image *image = NULL;
+    Jbig2SymbolDict **dicts = NULL;
+    int n_dicts = 0;
+    uint16_t flags = 0;
     uint16_t huffman_flags = 0;
     Jbig2ArithCx *GR_stats = NULL;
     int code = 0;
@@ -420,7 +444,7 @@
     Jbig2WordStream *ws = NULL;
     Jbig2ArithState *as = NULL;
     int table_index = 0;
-    const Jbig2HuffmanParams *huffman_params;
+    const Jbig2HuffmanParams *huffman_params = NULL;
 
     /* 7.4.1 */
     if (segment->data_length < 17)
@@ -435,6 +459,9 @@
     jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
 	"text region header flags 0x%04x", flags);
 
+    /* zero params to ease cleanup later */
+    memset(&params, 0, sizeof(Jbig2TextRegionParams));
+
     params.SBHUFF = flags & 0x0001;
     params.SBREFINE = flags & 0x0002;
     params.LOGSBSTRIPS = (flags & 0x000c) >> 2;
@@ -473,9 +500,6 @@
             params.sbrat[2] = segment_data[offset + 2];
             params.sbrat[3] = segment_data[offset + 3];
             offset += 4;
-	  } else {
-	    /* zero these for the sake of later debug messages */
-	    memset(params.sbrat, 0, sizeof(params.sbrat));
 	  }
       }
 
@@ -485,7 +509,7 @@
 
     if (params.SBHUFF) {
         /* 7.4.3.1.5 - Symbol ID Huffman table */
-	/* ...this is handled in the segment body decoder */
+        /* ...this is handled in the segment body decoder */
 
         /* 7.4.3.1.6 - Other Huffman table selection */
 	switch (huffman_flags & 0x0003) {
@@ -500,20 +524,27 @@
 	  case 3: /* Custom table from referred segment */
             huffman_params = jbig2_find_table(ctx, segment, table_index);
             if (huffman_params == NULL) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                     "Custom FS huffman table not found (%d)", table_index);
+                goto cleanup1;
             }
             params.SBHUFFFS = jbig2_build_huffman_table(ctx, huffman_params);
             ++table_index;
-            /* FIXME: this function leaks memory when error happens.
-               i.e. not calling jbig2_release_huffman_table() */
             break;
 	  case 2: /* invalid */
 	  default:
-	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-		"text region specified invalid FS huffman table");
+	    code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "text region specified invalid FS huffman table");
+        goto cleanup1;
 	    break;
 	}
+    if (params.SBHUFFFS == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate text region specified FS huffman table");
+        goto cleanup1;
+    }
+
 	switch ((huffman_flags & 0x000c) >> 2) {
 	  case 0: /* Table B.8 */
 	    params.SBHUFFDS = jbig2_build_huffman_table(ctx,
@@ -530,13 +561,21 @@
 	  case 3: /* Custom table from referred segment */
             huffman_params = jbig2_find_table(ctx, segment, table_index);
             if (huffman_params == NULL) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                     "Custom DS huffman table not found (%d)", table_index);
+                goto cleanup1;
             }
             params.SBHUFFDS = jbig2_build_huffman_table(ctx, huffman_params);
             ++table_index;
             break;
 	}
+    if (params.SBHUFFDS == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate text region specified DS huffman table");
+        goto cleanup1;
+    }
+
 	switch ((huffman_flags & 0x0030) >> 4) {
 	  case 0: /* Table B.11 */
 	    params.SBHUFFDT = jbig2_build_huffman_table(ctx,
@@ -553,13 +592,21 @@
 	  case 3: /* Custom table from referred segment */
             huffman_params = jbig2_find_table(ctx, segment, table_index);
             if (huffman_params == NULL) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                     "Custom DT huffman table not found (%d)", table_index);
+                goto cleanup1;
             }
             params.SBHUFFDT = jbig2_build_huffman_table(ctx, huffman_params);
             ++table_index;
             break;
 	}
+    if (params.SBHUFFDT == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate text region specified DT huffman table");
+        goto cleanup1;
+    }
+
 	switch ((huffman_flags & 0x00c0) >> 6) {
 	  case 0: /* Table B.14 */
 	    params.SBHUFFRDW = jbig2_build_huffman_table(ctx,
@@ -572,8 +619,9 @@
 	  case 3: /* Custom table from referred segment */
             huffman_params = jbig2_find_table(ctx, segment, table_index);
             if (huffman_params == NULL) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                     "Custom RDW huffman table not found (%d)", table_index);
+                goto cleanup1;
             }
             params.SBHUFFRDW = jbig2_build_huffman_table(ctx, huffman_params);
             ++table_index;
@@ -580,10 +628,18 @@
 	    break;
 	  case 2: /* invalid */
 	  default:
-	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-		"text region specified invalid RDW huffman table");
+	    code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "text region specified invalid RDW huffman table");
+        goto cleanup1;
 	    break;
 	}
+    if (params.SBHUFFRDW == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate text region specified RDW huffman table");
+        goto cleanup1;
+    }
+
 	switch ((huffman_flags & 0x0300) >> 8) {
 	  case 0: /* Table B.14 */
 	    params.SBHUFFRDH = jbig2_build_huffman_table(ctx,
@@ -596,8 +652,9 @@
 	  case 3: /* Custom table from referred segment */
             huffman_params = jbig2_find_table(ctx, segment, table_index);
             if (huffman_params == NULL) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                     "Custom RDH huffman table not found (%d)", table_index);
+                goto cleanup1;
             }
             params.SBHUFFRDH = jbig2_build_huffman_table(ctx, huffman_params);
             ++table_index;
@@ -604,11 +661,19 @@
 	    break;
 	  case 2: /* invalid */
 	  default:
-	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-		"text region specified invalid RDH huffman table");
+	    code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "text region specified invalid RDH huffman table");
+        goto cleanup1;
 	    break;
 	}
-        switch ((huffman_flags & 0x0c00) >> 10) {
+    if (params.SBHUFFRDH == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate text region specified RDH huffman table");
+        goto cleanup1;
+    }
+
+    switch ((huffman_flags & 0x0c00) >> 10) {
 	  case 0: /* Table B.14 */
 	    params.SBHUFFRDX = jbig2_build_huffman_table(ctx,
 			&jbig2_huffman_params_N);
@@ -620,8 +685,9 @@
 	  case 3: /* Custom table from referred segment */
             huffman_params = jbig2_find_table(ctx, segment, table_index);
             if (huffman_params == NULL) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                     "Custom RDX huffman table not found (%d)", table_index);
+                goto cleanup1;
             }
             params.SBHUFFRDX = jbig2_build_huffman_table(ctx, huffman_params);
             ++table_index;
@@ -628,10 +694,18 @@
 	    break;
 	  case 2: /* invalid */
 	  default:
-	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-		"text region specified invalid RDX huffman table");
+	    code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "text region specified invalid RDX huffman table");
+        goto cleanup1;
 	    break;
 	}
+    if (params.SBHUFFRDX == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate text region specified RDX huffman table");
+        goto cleanup1;
+    }
+
 	switch ((huffman_flags & 0x3000) >> 12) {
 	  case 0: /* Table B.14 */
 	    params.SBHUFFRDY = jbig2_build_huffman_table(ctx,
@@ -644,8 +718,9 @@
 	  case 3: /* Custom table from referred segment */
             huffman_params = jbig2_find_table(ctx, segment, table_index);
             if (huffman_params == NULL) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                     "Custom RDY huffman table not found (%d)", table_index);
+                goto cleanup1;
             }
             params.SBHUFFRDY = jbig2_build_huffman_table(ctx, huffman_params);
             ++table_index;
@@ -652,10 +727,18 @@
 	    break;
 	  case 2: /* invalid */
 	  default:
-	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-		"text region specified invalid RDY huffman table");
+	    code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "text region specified invalid RDY huffman table");
+        goto cleanup1;
 	    break;
 	}
+    if (params.SBHUFFRDY == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate text region specified RDY huffman table");
+        goto cleanup1;
+    }
+
 	switch ((huffman_flags & 0x4000) >> 14) {
 	  case 0: /* Table B.1 */
 	    params.SBHUFFRSIZE = jbig2_build_huffman_table(ctx,
@@ -664,13 +747,20 @@
 	  case 1: /* Custom table from referred segment */
             huffman_params = jbig2_find_table(ctx, segment, table_index);
             if (huffman_params == NULL) {
-                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+                code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                     "Custom RSIZE huffman table not found (%d)", table_index);
+                goto cleanup1;
             }
             params.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, huffman_params);
             ++table_index;
 	    break;
 	}
+    if (params.SBHUFFRSIZE == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to allocate text region specified RSIZE huffman table");
+        goto cleanup1;
+    }
 
         if (huffman_flags & 0x8000) {
 	  jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
@@ -691,19 +781,20 @@
     if (n_dicts != 0) {
         dicts = jbig2_sd_list_referred(ctx, segment);
     } else {
-        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-                "text region refers to no symbol dictionaries!");
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "text region refers to no symbol dictionaries!");
+        goto cleanup1;
     }
     if (dicts == NULL) {
-	return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-		"unable to retrive symbol dictionaries!"
-		" previous parsing error?");
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "unable to retrive symbol dictionaries! previous parsing error?");
+        goto cleanup1;
     } else {
 	int index;
 	if (dicts[0] == NULL) {
-	    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING,
-			segment->number,
-                        "unable to find first referenced symbol dictionary!");
+        code =jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
+            "unable to find first referenced symbol dictionary!");
+        goto cleanup1;
 	}
 	for (index = 1; index < n_dicts; index++)
 	    if (dicts[index] == NULL) {
@@ -717,28 +808,30 @@
     if (!params.SBHUFF && params.SBREFINE) {
 	int stats_size = params.SBRTEMPLATE ? 1 << 10 : 1 << 13;
 	GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
+    if (GR_stats == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "could not allocate GR_stats");
+        goto cleanup1;
+    }
 	memset(GR_stats, 0, stats_size);
     }
 
     image = jbig2_image_new(ctx, region_info.width, region_info.height);
     if (image == NULL) {
-      if (!params.SBHUFF && params.SBREFINE) {
-	jbig2_free(ctx->allocator, GR_stats);
-      } else if (params.SBHUFF) {
-	jbig2_release_huffman_table(ctx, params.SBHUFFFS);
-	jbig2_release_huffman_table(ctx, params.SBHUFFDS);
-	jbig2_release_huffman_table(ctx, params.SBHUFFDT);
-	jbig2_release_huffman_table(ctx, params.SBHUFFRDX);
-	jbig2_release_huffman_table(ctx, params.SBHUFFRDY);
-	jbig2_release_huffman_table(ctx, params.SBHUFFRDW);
-	jbig2_release_huffman_table(ctx, params.SBHUFFRDH);
-	jbig2_release_huffman_table(ctx, params.SBHUFFRSIZE);
-      }
-      return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-		"couldn't allocate text region image");
+        code =jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "couldn't allocate text region image");
+        goto cleanup1;
     }
 
     ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset);
+    if (ws == NULL)
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "couldn't allocate text region image");
+        jbig2_image_release(ctx, image);
+        goto cleanup2;
+    }
     if (!params.SBHUFF) {
 	int SBSYMCODELEN, index;
         int SBNUMSYMS = 0;
@@ -747,60 +840,48 @@
 	}
 
 	as = jbig2_arith_new(ctx, ws);
+    params.IADT = jbig2_arith_int_ctx_new(ctx);
+    params.IAFS = jbig2_arith_int_ctx_new(ctx);
+    params.IADS = jbig2_arith_int_ctx_new(ctx);
+    params.IAIT = jbig2_arith_int_ctx_new(ctx);
+    if ((as == NULL) || (params.IADT == NULL) || (params.IAFS == NULL) ||
+        (params.IADS == NULL) || (params.IAIT == NULL))
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "couldn't allocate text region image data");
+        goto cleanup3;
+    }
 
-        params.IADT = jbig2_arith_int_ctx_new(ctx);
-        params.IAFS = jbig2_arith_int_ctx_new(ctx);
-        params.IADS = jbig2_arith_int_ctx_new(ctx);
-        params.IAIT = jbig2_arith_int_ctx_new(ctx);
 	/* Table 31 */
 	for (SBSYMCODELEN = 0; (1 << SBSYMCODELEN) < SBNUMSYMS; SBSYMCODELEN++);
-        params.IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
+    params.IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
 	params.IARI = jbig2_arith_int_ctx_new(ctx);
 	params.IARDW = jbig2_arith_int_ctx_new(ctx);
 	params.IARDH = jbig2_arith_int_ctx_new(ctx);
 	params.IARDX = jbig2_arith_int_ctx_new(ctx);
 	params.IARDY = jbig2_arith_int_ctx_new(ctx);
+    if ((params.IAID == NULL) || (params.IARI == NULL) ||
+        (params.IARDW == NULL) || (params.IARDH == NULL) ||
+        (params.IARDX == NULL) || (params.IARDY == NULL))
+    {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "couldn't allocate text region image data");
+        goto cleanup4;
     }
+    }
 
     code = jbig2_decode_text_region(ctx, segment, &params,
-                (const Jbig2SymbolDict * const *)dicts, n_dicts, image,
-                segment_data + offset, segment->data_length - offset,
+        (const Jbig2SymbolDict * const *)dicts, n_dicts, image,
+        segment_data + offset, segment->data_length - offset,
 		GR_stats, as, as ? NULL : ws);
-
-    if (!params.SBHUFF && params.SBREFINE) {
-	jbig2_free(ctx->allocator, GR_stats);
+    if (code < 0)
+    {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+            "failed to decode text region image data");
+        jbig2_image_release(ctx, image);
+        goto cleanup4;
     }
 
-    if (params.SBHUFF) {
-      jbig2_release_huffman_table(ctx, params.SBHUFFFS);
-      jbig2_release_huffman_table(ctx, params.SBHUFFDS);
-      jbig2_release_huffman_table(ctx, params.SBHUFFDT);
-      jbig2_release_huffman_table(ctx, params.SBHUFFRDX);
-      jbig2_release_huffman_table(ctx, params.SBHUFFRDY);
-      jbig2_release_huffman_table(ctx, params.SBHUFFRDW);
-      jbig2_release_huffman_table(ctx, params.SBHUFFRDH);
-      jbig2_release_huffman_table(ctx, params.SBHUFFRSIZE);
-      jbig2_word_stream_buf_free(ctx, ws);
-    }
-    else {
-	jbig2_arith_int_ctx_free(ctx, params.IADT);
-	jbig2_arith_int_ctx_free(ctx, params.IAFS);
-	jbig2_arith_int_ctx_free(ctx, params.IADS);
-	jbig2_arith_int_ctx_free(ctx, params.IAIT);
-	jbig2_arith_iaid_ctx_free(ctx, params.IAID);
-	jbig2_arith_int_ctx_free(ctx, params.IARI);
-	jbig2_arith_int_ctx_free(ctx, params.IARDW);
-	jbig2_arith_int_ctx_free(ctx, params.IARDH);
-	jbig2_arith_int_ctx_free(ctx, params.IARDX);
-	jbig2_arith_int_ctx_free(ctx, params.IARDY);
-	jbig2_free(ctx->allocator, as);
-	jbig2_word_stream_buf_free(ctx, ws);
-    }
-
-    jbig2_free(ctx->allocator, dicts);
-
-    /* todo: check errors */
-
     if ((segment->flags & 63) == 4) {
         /* we have an intermediate region here. save it for later */
         segment->result = image;
@@ -809,15 +890,51 @@
         jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
             "composing %dx%d decoded text region onto page at (%d, %d)",
             region_info.width, region_info.height, region_info.x, region_info.y);
-	jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image,
-			      region_info.x, region_info.y, region_info.op);
+        jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image,
+            region_info.x, region_info.y, region_info.op);
         jbig2_image_release(ctx, image);
     }
 
-    /* success */
-    return 0;
+cleanup4:
+    if (!params.SBHUFF) {
+        jbig2_arith_iaid_ctx_free(ctx, params.IAID);
+        jbig2_arith_int_ctx_free(ctx, params.IARI);
+        jbig2_arith_int_ctx_free(ctx, params.IARDW);
+        jbig2_arith_int_ctx_free(ctx, params.IARDH);
+        jbig2_arith_int_ctx_free(ctx, params.IARDX);
+        jbig2_arith_int_ctx_free(ctx, params.IARDY);
+    }
 
-    too_short:
-        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
-                    "Segment too short");
+cleanup3:
+    if (!params.SBHUFF) {
+        jbig2_arith_int_ctx_free(ctx, params.IADT);
+        jbig2_arith_int_ctx_free(ctx, params.IAFS);
+        jbig2_arith_int_ctx_free(ctx, params.IADS);
+        jbig2_arith_int_ctx_free(ctx, params.IAIT);
+        jbig2_free(ctx->allocator, as);
+    }
+    jbig2_word_stream_buf_free(ctx, ws);
+
+cleanup2:
+    if (!params.SBHUFF && params.SBREFINE) {
+        jbig2_free(ctx->allocator, GR_stats);
+    }
+
+cleanup1:
+    if (params.SBHUFF) {
+        jbig2_release_huffman_table(ctx, params.SBHUFFFS);
+        jbig2_release_huffman_table(ctx, params.SBHUFFDS);
+        jbig2_release_huffman_table(ctx, params.SBHUFFDT);
+        jbig2_release_huffman_table(ctx, params.SBHUFFRDX);
+        jbig2_release_huffman_table(ctx, params.SBHUFFRDY);
+        jbig2_release_huffman_table(ctx, params.SBHUFFRDW);
+        jbig2_release_huffman_table(ctx, params.SBHUFFRDH);
+        jbig2_release_huffman_table(ctx, params.SBHUFFRSIZE);
+    }
+
+    return code;
+
+too_short:
+    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
+        "Segment too short");
 }