Bug 1050342. Fix a case where the fast huffman decoder in libjpeg-turbo can produce different results depending on how data is fed to it. r=seth
authorNoel Gordon <noel.gordon@gmail.com>
Wed, 09 Mar 2016 17:56:35 -0600
changeset 287980 d8190cbce7b0b188ec678da1a1ec1a190c5da636
parent 287979 ae6d62d54d7d87765be28691b25055d6e07fadcd
child 287981 82073af0177dab32d1049cf067f6057a4de0ff54
push id30071
push usercbook@mozilla.com
push dateThu, 10 Mar 2016 10:51:55 +0000
treeherdermozilla-central@dd1abe874252 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseth
bugs1050342
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1050342. Fix a case where the fast huffman decoder in libjpeg-turbo can produce different results depending on how data is fed to it. r=seth This change comes from the blink repo https://codereview.appspot.com/229430043/ and is unlikely to be accepted upstream into libjpeg-turbo.
media/libjpeg/1050342.diff
media/libjpeg/MOZCHANGES
media/libjpeg/jdhuff.c
media/libjpeg/jdhuff.h
media/update-libjpeg.sh
new file mode 100644
--- /dev/null
+++ b/media/libjpeg/1050342.diff
@@ -0,0 +1,120 @@
+Bug 1050342. Fix a case where the fast huffman decoder in libjpeg-turbo can produce different results depending on how data is fed to it.
+
+This change comes from the blink repo https://codereview.appspot.com/229430043/ and is unlikely to be accepted upstream into libjpeg-turbo.
+
+diff --git jdhuff.c jdhuff.c
+--- jdhuff.c
++++ jdhuff.c
+@@ -661,34 +661,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
+   ASSIGN_STATE(state, entropy->saved);
+ 
+   for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+     JBLOCKROW block = MCU_data[blkn];
+     d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
+     d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
+     register int s, k, r, l;
+ 
+-    HUFF_DECODE_FAST(s, l, dctbl);
++    HUFF_DECODE_FAST(s, l, dctbl, slow_decode_mcu);
+     if (s) {
+       FILL_BIT_BUFFER_FAST
+       r = GET_BITS(s);
+       s = HUFF_EXTEND(r, s);
+     }
+ 
+     if (entropy->dc_needed[blkn]) {
+       int ci = cinfo->MCU_membership[blkn];
+       s += state.last_dc_val[ci];
+       state.last_dc_val[ci] = s;
+       (*block)[0] = (JCOEF) s;
+     }
+ 
+     if (entropy->ac_needed[blkn]) {
+ 
+       for (k = 1; k < DCTSIZE2; k++) {
+-        HUFF_DECODE_FAST(s, l, actbl);
++        HUFF_DECODE_FAST(s, l, actbl, slow_decode_mcu);
+         r = s >> 4;
+         s &= 15;
+ 
+         if (s) {
+           k += r;
+           FILL_BIT_BUFFER_FAST
+           r = GET_BITS(s);
+           s = HUFF_EXTEND(r, s);
+@@ -697,33 +697,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
+           if (r != 15) break;
+           k += 15;
+         }
+       }
+ 
+     } else {
+ 
+       for (k = 1; k < DCTSIZE2; k++) {
+-        HUFF_DECODE_FAST(s, l, actbl);
++        HUFF_DECODE_FAST(s, l, actbl, slow_decode_mcu);
+         r = s >> 4;
+         s &= 15;
+ 
+         if (s) {
+           k += r;
+           FILL_BIT_BUFFER_FAST
+           DROP_BITS(s);
+         } else {
+           if (r != 15) break;
+           k += 15;
+         }
+       }
+     }
+   }
+ 
+   if (cinfo->unread_marker != 0) {
++slow_decode_mcu:
+     cinfo->unread_marker = 0;
+     return FALSE;
+   }
+ 
+   br_state.bytes_in_buffer -= (buffer - br_state.next_input_byte);
+   br_state.next_input_byte = buffer;
+   BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+   ASSIGN_STATE(entropy->saved, state);
+diff --git jdhuff.h jdhuff.h
+--- jdhuff.h
++++ jdhuff.h
+@@ -200,32 +200,34 @@ EXTERN(boolean) jpeg_fill_bit_buffer
+   } else { \
+ slowlabel: \
+     if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
+         { failaction; } \
+     get_buffer = state.get_buffer; bits_left = state.bits_left; \
+   } \
+ }
+ 
+-#define HUFF_DECODE_FAST(s,nb,htbl) \
++#define HUFF_DECODE_FAST(s,nb,htbl,slowlabel) \
+   FILL_BIT_BUFFER_FAST; \
+   s = PEEK_BITS(HUFF_LOOKAHEAD); \
+   s = htbl->lookup[s]; \
+   nb = s >> HUFF_LOOKAHEAD; \
+   /* Pre-execute the common case of nb <= HUFF_LOOKAHEAD */ \
+   DROP_BITS(nb); \
+   s = s & ((1 << HUFF_LOOKAHEAD) - 1); \
+   if (nb > HUFF_LOOKAHEAD) { \
+     /* Equivalent of jpeg_huff_decode() */ \
+     /* Don't use GET_BITS() here because we don't want to modify bits_left */ \
+     s = (get_buffer >> bits_left) & ((1 << (nb)) - 1); \
+     while (s > htbl->maxcode[nb]) { \
+       s <<= 1; \
+       s |= GET_BITS(1); \
+       nb++; \
+     } \
+-    s = htbl->pub->huffval[ (int) (s + htbl->valoffset[nb]) & 0xFF ]; \
++    if (nb > 16) \
++      goto slowlabel; \
++    s = htbl->pub->huffval[ (int) (s + htbl->valoffset[nb]) ]; \
+   }
+ 
+ /* Out-of-line case for Huffman code fetching */
+ EXTERN(int) jpeg_huff_decode
+         (bitread_working_state * state, register bit_buf_type get_buffer,
+          register int bits_left, d_derived_tbl * htbl, int min_bits);
--- a/media/libjpeg/MOZCHANGES
+++ b/media/libjpeg/MOZCHANGES
@@ -3,16 +3,19 @@ To upgrade to a new revision of libjpeg-
 * Check out libjpeg-turbo from git:
 
     $ git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git
 
 * In a clean clone of mozilla-central, run the update script (tag defaults to HEAD):
 
     $ ./media/update-libjpeg.sh /path/to/libjpeg-turbo [tag]
 
+  and fix up any rejects from applying the Mozilla specific patches at the end
+  of that script.
+
 * Since libjpeg-turbo normally creates jconfig.h and jconfigint.h at build time
   and we use pre-generated versions, changes to jconfig.h.in and jconfigint.h.in
   should be looked for and noted for later inclusion.
 
 * Now look through the new files and rm any which are npotb.  When I upgraded
   to libjpeg-turbo 1.1.0, the only files I kept which didn't match
 
     *.c  *.h *.asm *.inc
--- a/media/libjpeg/jdhuff.c
+++ b/media/libjpeg/jdhuff.c
@@ -661,34 +661,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
   ASSIGN_STATE(state, entropy->saved);
 
   for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
     JBLOCKROW block = MCU_data[blkn];
     d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
     d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
     register int s, k, r, l;
 
-    HUFF_DECODE_FAST(s, l, dctbl);
+    HUFF_DECODE_FAST(s, l, dctbl, slow_decode_mcu);
     if (s) {
       FILL_BIT_BUFFER_FAST
       r = GET_BITS(s);
       s = HUFF_EXTEND(r, s);
     }
 
     if (entropy->dc_needed[blkn]) {
       int ci = cinfo->MCU_membership[blkn];
       s += state.last_dc_val[ci];
       state.last_dc_val[ci] = s;
       (*block)[0] = (JCOEF) s;
     }
 
     if (entropy->ac_needed[blkn]) {
 
       for (k = 1; k < DCTSIZE2; k++) {
-        HUFF_DECODE_FAST(s, l, actbl);
+        HUFF_DECODE_FAST(s, l, actbl, slow_decode_mcu);
         r = s >> 4;
         s &= 15;
 
         if (s) {
           k += r;
           FILL_BIT_BUFFER_FAST
           r = GET_BITS(s);
           s = HUFF_EXTEND(r, s);
@@ -697,33 +697,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
           if (r != 15) break;
           k += 15;
         }
       }
 
     } else {
 
       for (k = 1; k < DCTSIZE2; k++) {
-        HUFF_DECODE_FAST(s, l, actbl);
+        HUFF_DECODE_FAST(s, l, actbl, slow_decode_mcu);
         r = s >> 4;
         s &= 15;
 
         if (s) {
           k += r;
           FILL_BIT_BUFFER_FAST
           DROP_BITS(s);
         } else {
           if (r != 15) break;
           k += 15;
         }
       }
     }
   }
 
   if (cinfo->unread_marker != 0) {
+slow_decode_mcu:
     cinfo->unread_marker = 0;
     return FALSE;
   }
 
   br_state.bytes_in_buffer -= (buffer - br_state.next_input_byte);
   br_state.next_input_byte = buffer;
   BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
   ASSIGN_STATE(entropy->saved, state);
--- a/media/libjpeg/jdhuff.h
+++ b/media/libjpeg/jdhuff.h
@@ -200,32 +200,34 @@ EXTERN(boolean) jpeg_fill_bit_buffer
   } else { \
 slowlabel: \
     if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
         { failaction; } \
     get_buffer = state.get_buffer; bits_left = state.bits_left; \
   } \
 }
 
-#define HUFF_DECODE_FAST(s,nb,htbl) \
+#define HUFF_DECODE_FAST(s,nb,htbl,slowlabel) \
   FILL_BIT_BUFFER_FAST; \
   s = PEEK_BITS(HUFF_LOOKAHEAD); \
   s = htbl->lookup[s]; \
   nb = s >> HUFF_LOOKAHEAD; \
   /* Pre-execute the common case of nb <= HUFF_LOOKAHEAD */ \
   DROP_BITS(nb); \
   s = s & ((1 << HUFF_LOOKAHEAD) - 1); \
   if (nb > HUFF_LOOKAHEAD) { \
     /* Equivalent of jpeg_huff_decode() */ \
     /* Don't use GET_BITS() here because we don't want to modify bits_left */ \
     s = (get_buffer >> bits_left) & ((1 << (nb)) - 1); \
     while (s > htbl->maxcode[nb]) { \
       s <<= 1; \
       s |= GET_BITS(1); \
       nb++; \
     } \
-    s = htbl->pub->huffval[ (int) (s + htbl->valoffset[nb]) & 0xFF ]; \
+    if (nb > 16) \
+      goto slowlabel; \
+    s = htbl->pub->huffval[ (int) (s + htbl->valoffset[nb]) ]; \
   }
 
 /* Out-of-line case for Huffman code fetching */
 EXTERN(int) jpeg_huff_decode
         (bitread_working_state * state, register bit_buf_type get_buffer,
          register int bits_left, d_derived_tbl * htbl, int min_bits);
--- a/media/update-libjpeg.sh
+++ b/media/update-libjpeg.sh
@@ -22,8 +22,9 @@ cp win/jsimdcfg.inc simd/
 revert_files="jconfig.h jconfigint.h moz.build Makefile.in MOZCHANGES mozilla.diff simd/jsimdcfg.inc"
 if test -d ${topsrcdir}/.hg; then
     hg revert --no-backup $revert_files
 elif test -d ${topsrcdir}/.git; then
     git checkout HEAD -- $revert_files
 fi
 
 patch -p0 -i mozilla.diff
+patch -p0 -i 1050342.diff