shithub: jbig2

Download patch

ref: 31e0aec4ef57166e8cbdc549e92435bc487ba9bb
parent: 861e081b86b9e4d6c8bf4ff6231025c7a950f6bf
author: Sebastian Rasmussen <sebras@gmail.com>
date: Mon Apr 23 10:02:46 EDT 2018

jbig2dec: Handle get_next_word() returning error/less than a word.

This includes propagating the error handling to all callers.

--- a/jbig2_arith.c
+++ b/jbig2_arith.c
@@ -61,6 +61,7 @@
 static void
 jbig2_arith_bytein(Jbig2ArithState *as)
 {
+    int new_bytes;
     byte B;
 
     /* invariant: as->next_word_bytes > 0 */
@@ -73,8 +74,10 @@
         if (as->next_word_bytes == 1) {
             Jbig2WordStream *ws = as->ws;
 
-            ws->get_next_word(ws, as->offset, &as->next_word);
-            as->offset += 4;
+            new_bytes = ws->get_next_word(ws, as->offset, &as->next_word);
+            as->next_word_bytes = new_bytes;
+            as->offset += new_bytes;
+
             B1 = (byte)((as->next_word >> 24) & 0xFF);
             if (B1 > 0x8F) {
 #ifdef JBIG2_DEBUG_ARITH
@@ -84,8 +87,9 @@
                 as->C += 0xFF00;
 #endif
                 as->CT = 8;
-                as->next_word = (0xFF00 | B1) << 16;
-                as->next_word_bytes = 2;
+                as->next_word = 0xFF000000 | (as->next_word >> 8);
+                as->next_word_bytes = 4;
+                as->offset--;
             } else {
 #ifdef JBIG2_DEBUG_ARITH
                 fprintf(stderr, "read %02x (a)\n", B);
@@ -96,7 +100,6 @@
                 as->C += B1 << 9;
 #endif
                 as->CT = 7;
-                as->next_word_bytes = 4;
             }
         } else {
             B1 = (byte)((as->next_word >> 16) & 0xFF);
@@ -133,9 +136,9 @@
         if (as->next_word_bytes == 0) {
             Jbig2WordStream *ws = as->ws;
 
-            ws->get_next_word(ws, as->offset, &as->next_word);
-            as->offset += 4;
-            as->next_word_bytes = 4;
+            new_bytes = ws->get_next_word(ws, as->offset, &as->next_word);
+            as->offset += new_bytes;
+            as->next_word_bytes = new_bytes;
         }
         B = (byte)((as->next_word >> 24) & 0xFF);
 #ifdef SOFTWARE_CONVENTION
@@ -162,6 +165,7 @@
 jbig2_arith_new(Jbig2Ctx *ctx, Jbig2WordStream *ws)
 {
     Jbig2ArithState *result;
+    int new_bytes;
 
     result = jbig2_new(ctx, Jbig2ArithState, 1);
     if (result == NULL) {
@@ -171,9 +175,9 @@
 
     result->ws = ws;
 
-    ws->get_next_word(ws, 0, &result->next_word);
-    result->next_word_bytes = 4;
-    result->offset = 4;
+    new_bytes = ws->get_next_word(ws, 0, &result->next_word);
+    result->next_word_bytes = new_bytes;
+    result->offset = new_bytes;
 
     /* Figure E.20 */
 #ifdef SOFTWARE_CONVENTION
@@ -348,7 +352,7 @@
     if (self == NULL || word == NULL)
         return -1;
     if (offset >= sizeof (test_stream))
-        return -1;
+        return 0;
 
     if (offset < sizeof(test_stream)) {
         val |= test_stream[offset] << 24;
--- a/jbig2_huffman.c
+++ b/jbig2_huffman.c
@@ -57,14 +57,14 @@
     Jbig2Ctx *ctx;
 };
 
-static uint32_t
-huff_get_next_word(Jbig2HuffmanState *hs, uint32_t offset)
+static int
+huff_get_next_word(Jbig2HuffmanState *hs, uint32_t offset, uint32_t *word)
 {
-    uint32_t word = 0;
     Jbig2WordStream *ws = hs->ws;
 
-    ws->get_next_word(ws, offset, &word);
-    return word;
+    if (word == NULL)
+        return -1;
+    return ws->get_next_word(ws, offset, word);
 }
 
 /** Allocate and initialize a new huffman coding state
@@ -75,6 +75,7 @@
 jbig2_huffman_new(Jbig2Ctx *ctx, Jbig2WordStream *ws)
 {
     Jbig2HuffmanState *result = NULL;
+    int code;
 
     result = jbig2_new(ctx, Jbig2HuffmanState, 1);
 
@@ -84,8 +85,18 @@
         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);
+        code = huff_get_next_word(result, 0, &result->this_word);
+        if (code < 0) {
+            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed read first huffman word");
+            jbig2_huffman_free(ctx, result);
+            return NULL;
+        }
+        code = huff_get_next_word(result, 4, &result->next_word);
+        if (code < 0) {
+            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed read second huffman word");
+            jbig2_huffman_free(ctx, result);
+            return NULL;
+        }
     } else {
         jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate new huffman coding state");
     }
@@ -170,10 +181,11 @@
 
 /** Skip bits up to the next byte boundary
  */
-void
+int
 jbig2_huffman_skip(Jbig2HuffmanState *hs)
 {
     int bits = hs->offset_bits & 7;
+    int code;
 
     if (bits) {
         bits = 8 - bits;
@@ -184,19 +196,24 @@
     if (hs->offset_bits >= 32) {
         hs->this_word = hs->next_word;
         hs->offset += 4;
-        hs->next_word = huff_get_next_word(hs, hs->offset + 4);
+        code = huff_get_next_word(hs, hs->offset + 4, &hs->next_word);
+        if (code < 0) {
+            return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read next huffman word when skipping");
+        }
         hs->offset_bits -= 32;
         if (hs->offset_bits) {
             hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits));
         }
     }
+    return 0;
 }
 
 /* skip ahead a specified number of bytes in the word stream
  */
-void
+int
 jbig2_huffman_advance(Jbig2HuffmanState *hs, int offset)
 {
+    int code;
     hs->offset += offset & ~3;
     hs->offset_bits += (offset & 3) << 3;
     if (hs->offset_bits >= 32) {
@@ -203,10 +220,17 @@
         hs->offset += 4;
         hs->offset_bits -= 32;
     }
-    hs->this_word = huff_get_next_word(hs, hs->offset);
-    hs->next_word = huff_get_next_word(hs, hs->offset + 4);
+    code = huff_get_next_word(hs, hs->offset, &hs->this_word);
+    if (code < 0) {
+        return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get first huffman word after advancing");
+    }
+    code = huff_get_next_word(hs, hs->offset + 4, &hs->next_word);
+    if (code < 0) {
+        return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get second huffman word after advancing");
+    }
     if (hs->offset_bits > 0)
         hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits));
+    return 0;
 }
 
 /* return the offset of the huffman decode pointer (in bytes)
@@ -226,6 +250,7 @@
 {
     uint32_t this_word = hs->this_word;
     int32_t result;
+    int code;
 
     if (hs->offset_limit && hs->offset >= hs->offset_limit) {
         *err = -1;
@@ -238,7 +263,10 @@
         hs->offset += 4;
         hs->offset_bits -= 32;
         hs->this_word = hs->next_word;
-        hs->next_word = huff_get_next_word(hs, hs->offset + 4);
+        code = huff_get_next_word(hs, hs->offset + 4, &hs->next_word);
+        if (code < 0) {
+            return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get next huffman word");
+        }
         if (hs->offset_bits) {
             hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits));
         } else {
@@ -271,6 +299,7 @@
     for (;;) {
         int log_table_size = table->log_table_size;
         int PREFLEN;
+        int code;
 
         /* SumatraPDF: shifting by the size of the operand is undefined */
         entry = &table->entries[log_table_size > 0 ? this_word >> (32 - log_table_size) : 0];
@@ -287,7 +316,10 @@
         if (offset_bits >= 32) {
             this_word = next_word;
             hs->offset += 4;
-            next_word = huff_get_next_word(hs, hs->offset + 4);
+            code = huff_get_next_word(hs, hs->offset + 4, &next_word);
+            if (code < 0) {
+                return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get next huffman word");
+            }
             offset_bits -= 32;
             hs->next_word = next_word;
             PREFLEN = offset_bits;
@@ -303,6 +335,7 @@
     RANGELEN = entry->RANGELEN;
     if (RANGELEN > 0) {
         int32_t HTOFFSET;
+        int code;
 
         HTOFFSET = this_word >> (32 - RANGELEN);
         if (flags & JBIG2_HUFFMAN_FLAGS_ISLOW)
@@ -314,7 +347,10 @@
         if (offset_bits >= 32) {
             this_word = next_word;
             hs->offset += 4;
-            next_word = huff_get_next_word(hs, hs->offset + 4);
+            code = huff_get_next_word(hs, hs->offset + 4, &next_word);
+            if (code < 0) {
+                return jbig2_error(hs->ctx, JBIG2_SEVERITY_WARNING, -1, "failed to get next huffman word");
+            }
             offset_bits -= 32;
             hs->next_word = next_word;
             RANGELEN = offset_bits;
--- a/jbig2_huffman.h
+++ b/jbig2_huffman.h
@@ -60,9 +60,9 @@
 
 void jbig2_huffman_free(Jbig2Ctx *ctx, Jbig2HuffmanState *hs);
 
-void jbig2_huffman_skip(Jbig2HuffmanState *hs);
+int jbig2_huffman_skip(Jbig2HuffmanState *hs);
 
-void jbig2_huffman_advance(Jbig2HuffmanState *hs, int offset);
+int jbig2_huffman_advance(Jbig2HuffmanState *hs, int offset);
 
 uint32_t jbig2_huffman_offset(Jbig2HuffmanState *hs);
 
--- a/jbig2_symbol_dict.c
+++ b/jbig2_symbol_dict.c
@@ -553,14 +553,15 @@
                         int code2 = 0;
                         int code3 = 0;
                         int code4 = 0;
+                        int code5 = 0;
 
                         /* 6.5.8.2.2 (2, 3, 4, 5) */
                         if (params->SDHUFF) {
-                            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);
-                            jbig2_huffman_skip(hs);
+                            ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN, &code1);
+                            RDX = jbig2_huffman_get(hs, SDHUFFRDX, &code2);
+                            RDY = jbig2_huffman_get(hs, SDHUFFRDX, &code3);
+                            BMSIZE = jbig2_huffman_get(hs, SBHUFFRSIZE, &code4);
+                            code5 = jbig2_huffman_skip(hs);
                         } else {
                             code1 = jbig2_arith_iaid_decode(ctx, IAID, as, (int32_t *) & ID);
                             code2 = jbig2_arith_int_decode(ctx, IARDX, as, &RDX);
@@ -567,11 +568,11 @@
                             code3 = jbig2_arith_int_decode(ctx, IARDY, as, &RDY);
                         }
 
-                        if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0) {
+                        if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0) {
                             code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode data");
                             goto cleanup4;
                         }
-                        if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0) {
+                        if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0) {
                             code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB in single refinement/aggregate coded symbol data");
                             goto cleanup4;
                         }
@@ -615,7 +616,11 @@
                         if (params->SDHUFF) {
                             if (BMSIZE == 0)
                                 BMSIZE = image->height * image->stride;
-                            jbig2_huffman_advance(hs, BMSIZE);
+                            code = jbig2_huffman_advance(hs, BMSIZE);
+                            if (code < 0) {
+                                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding in refinement region");
+                                goto cleanup4;
+                            }
                         }
                     }
                 }
@@ -671,7 +676,10 @@
             }
 
             /* skip any bits before the next byte boundary */
-            jbig2_huffman_skip(hs);
+            code = jbig2_huffman_skip(hs);
+            if (code < 0) {
+                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to skip to next byte when decoding collective bitmap");
+            }
 
             image = jbig2_image_new(ctx, TOTWIDTH, HCHEIGHT);
             if (image == NULL) {
@@ -725,7 +733,12 @@
             }
 
             /* advance past the data we've just read */
-            jbig2_huffman_advance(hs, BMSIZE);
+            code = jbig2_huffman_advance(hs, BMSIZE);
+            if (code < 0) {
+                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding MMR bitmap image");
+                jbig2_image_release(ctx, image);
+                goto cleanup4;
+            }
 
             /* copy the collective bitmap into the symbol dictionary */
             x = 0;
--- a/jbig2_text.c
+++ b/jbig2_text.c
@@ -202,7 +202,12 @@
         symcodeparams.n_lines = SBNUMSYMS;
 
         /* skip to byte boundary */
-        jbig2_huffman_skip(hs);
+        err = jbig2_huffman_skip(hs);
+        if (err < 0)
+        {
+            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to skip to next byte when building huffman table");
+            goto cleanup1;
+        }
 
         /* finally, construct the symbol id huffman table itself */
         SBSYMCODES = jbig2_build_huffman_table(ctx, &symcodeparams);
@@ -383,6 +388,7 @@
                 int code3 = 0;
                 int code4 = 0;
                 int code5 = 0;
+                int code6 = 0;
 
                 /* 6.4.11 (1, 2, 3, 4) */
                 if (!params->SBHUFF) {
@@ -396,15 +402,15 @@
                     RDX = jbig2_huffman_get(hs, params->SBHUFFRDX, &code3);
                     RDY = jbig2_huffman_get(hs, params->SBHUFFRDY, &code4);
                     BMSIZE = jbig2_huffman_get(hs, params->SBHUFFRSIZE, &code5);
-                    jbig2_huffman_skip(hs);
+                    code6 = jbig2_huffman_skip(hs);
                 }
 
-                if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0) {
+                if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0 || code6 < 0) {
                     jbig2_image_release(ctx, IB);
                     code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode data");
                     goto cleanup2;
                 }
-                if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0) {
+                if (code1 > 0 || code2 > 0 || code3 > 0 || code4 > 0 || code5 > 0 || code6 > 0) {
                     jbig2_image_release(ctx, IB);
                     code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "OOB obtained when decoding symbol instance refinement data");
                     goto cleanup2;
@@ -447,7 +453,13 @@
 
                 /* 6.4.11 (7) */
                 if (params->SBHUFF) {
-                    jbig2_huffman_advance(hs, BMSIZE);
+                    code = jbig2_huffman_advance(hs, BMSIZE);
+                    if (code < 0) {
+                        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to advance after huffman decoding refinement region");
+                        jbig2_image_release(ctx, refimage);
+                        jbig2_image_release(ctx, IBO);
+                        goto cleanup2;
+                    }
                 }
             }