ref: d2fefa97ec91550a640dd028f8425a5d1443cc9d
parent: f6d326878893dc92b45cbd18e25ab4d2b3a8db73
author: Sebastian Rasmussen <sebras@gmail.com>
date: Sun Sep 15 15:01:05 EDT 2019
Bug 702165: jbig2dec: Treat end of stream as fatal error, and remember errors. * Treat reading beyond end of stream in arithmetic decoder as a fatal error. * Remember previously encountered stream errors in arithmetic decoder. * Ignore trailing bytes after terminating marker code in stream.
--- a/jbig2_arith.c
+++ b/jbig2_arith.c
@@ -56,11 +56,20 @@
static int
jbig2_arith_bytein(Jbig2Ctx *ctx, Jbig2ArithState *as)
{
- int new_bytes;
byte B;
- /* invariant: as->next_word_bytes > 0 */
+ /* Treat both errors and reading beyond end of stream as an error. */
+ if (as->next_word_bytes < 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to read from underlying stream during arithmetic decoding");
+ return -1;
+ }
+ if (as->next_word_bytes == 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to read beyond end of underlying stream during arithmetic decoding");
+ return -1;
+ }
+ /* At this point there is at least one byte in as->next_word. */
+
/* This code confused me no end when I first read it, so a quick note
* to save others (and future me's) from being similarly confused.
* 'next_word' does indeed contain 'next_word_bytes' of valid data
@@ -83,16 +92,23 @@
if (B == 0xFF) {
byte B1;
- if (as->next_word_bytes == 1) {
- Jbig2WordStream *ws = as->ws;
-
- new_bytes = ws->get_next_word(ctx, ws, as->offset, &as->next_word);
- if (new_bytes < 0) {
- return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read from underlying stream during arithmetic decoding");
+ /* next_word_bytes can only be == 1 here, but let's be defensive. */
+ if (as->next_word_bytes <= 1) {
+ as->next_word_bytes = as->ws->get_next_word(ctx, as->ws, as->offset, &as->next_word);
+ if (as->next_word_bytes < 0) {
+ return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to check for marker code due to failure in underlying stream during arithmetic decoding");
}
- as->next_word_bytes = new_bytes;
- as->offset += new_bytes;
+ if (as->next_word_bytes == 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read end of possible terminating marker code, assuming terminating marker code");
+ as->next_word = 0xFF900000;
+ as->next_word_bytes = 2;
+ as->C += 0xFF00;
+ as->CT = 8;
+ return 0;
+ }
+ as->offset += as->next_word_bytes;
+
B1 = (byte)((as->next_word >> 24) & 0xFF);
if (B1 > 0x8F) {
#ifdef JBIG2_DEBUG_ARITH
@@ -100,7 +116,7 @@
#endif
as->CT = 8;
as->next_word = 0xFF000000 | (as->next_word >> 8);
- as->next_word_bytes = 4;
+ as->next_word_bytes = 2;
as->offset--;
} else {
#ifdef JBIG2_DEBUG_ARITH
@@ -131,21 +147,29 @@
#ifdef JBIG2_DEBUG_ARITH
fprintf(stderr, "read %02x\n", B);
#endif
- as->CT = 8;
as->next_word <<= 8;
as->next_word_bytes--;
- if (as->next_word_bytes == 0) {
- Jbig2WordStream *ws = as->ws;
- new_bytes = ws->get_next_word(ctx, ws, as->offset, &as->next_word);
- if (new_bytes < 0) {
+ if (as->next_word_bytes == 0) {
+ as->next_word_bytes = as->ws->get_next_word(ctx, as->ws, as->offset, &as->next_word);
+ if (as->next_word_bytes < 0) {
return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read from underlying stream during arithmetic decoding");
}
- as->offset += new_bytes;
- as->next_word_bytes = new_bytes;
+ if (as->next_word_bytes == 0) {
+ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to find terminating marker code before end of underlying stream, assuming terminating marker code");
+ as->next_word = 0xFF900000;
+ as->next_word_bytes = 2;
+ as->C += 0xFF00;
+ as->CT = 8;
+ return 0;
+ }
+
+ as->offset += as->next_word_bytes;
}
+
B = (byte)((as->next_word >> 24) & 0xFF);
as->C += 0xFF00 - (B << 8);
+ as->CT = 8;
}
return 0;
@@ -159,7 +183,6 @@
jbig2_arith_new(Jbig2Ctx *ctx, Jbig2WordStream *ws)
{
Jbig2ArithState *result;
- int new_bytes;
result = jbig2_new(ctx, Jbig2ArithState, 1);
if (result == NULL) {
@@ -168,15 +191,20 @@
}
result->ws = ws;
+ result->offset = 0;
- new_bytes = ws->get_next_word(ctx, ws, 0, &result->next_word);
- if (new_bytes < 0) {
+ result->next_word_bytes = result->ws->get_next_word(ctx, result->ws, result->offset, &result->next_word);
+ if (result->next_word_bytes < 0) {
jbig2_free(ctx->allocator, result);
- jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to initialize underlying stream of arithmetic decoder");
+ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to initialize underlying stream of arithmetic decoder");
return NULL;
}
- result->next_word_bytes = new_bytes;
- result->offset = new_bytes;
+ if (result->next_word_bytes == 0) {
+ jbig2_free(ctx->allocator, result);
+ jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to read first byte from underlying stream when initializing arithmetic decoder");
+ return NULL;
+ }
+ result->offset += result->next_word_bytes;
/* Figure F.1 */
result->C = (~(result->next_word >> 8)) & 0xFF0000;
--- a/jbig2_huffman.c
+++ b/jbig2_huffman.c
@@ -80,13 +80,13 @@
result->ctx = ctx;
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_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to 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_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to read second huffman word");
jbig2_huffman_free(ctx, result);
return NULL;
}