Avoid premature decoding completion in CJBig2_ArithDecoder. BUG=chromium:947622 Change-Id: Iec70a876fa6a00fab424807dd8118b8eb512dda6 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/52712 Reviewed-by: Nicolás Peña Moreno <npm@chromium.org> Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp b/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp index 45cca11..8d3fc5a 100644 --- a/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp +++ b/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp
@@ -52,7 +52,7 @@ } CJBig2_ArithDecoder::CJBig2_ArithDecoder(CJBig2_BitStream* pStream) - : m_Complete(false), m_FinishedStream(false), m_pStream(pStream) { + : m_pStream(pStream) { m_B = m_pStream->getCurByte_arith(); m_C = (m_B ^ 0xff) << 16; BYTEIN(); @@ -86,17 +86,26 @@ } void CJBig2_ArithDecoder::BYTEIN() { - unsigned char B1; if (m_B == 0xff) { - B1 = m_pStream->getNextByte_arith(); + unsigned char B1 = m_pStream->getNextByte_arith(); if (B1 > 0x8f) { m_CT = 8; - // If we are here, it means that we have finished decoding data (see JBIG2 - // spec, Section E.3.4). If we arrive here a second time, we're looping, - // so complete decoding. - if (m_FinishedStream) - m_Complete = true; - m_FinishedStream = true; + + switch (m_State) { + case StreamState::kDataAvailable: + // Finished decoding data (see JBIG2 spec, Section E.3.4). + m_State = StreamState::kDecodingFinished; + break; + case StreamState::kDecodingFinished: + // Allow one more call in the finished state. https://crbug.com/947622 + m_State = StreamState::kLooping; + break; + case StreamState::kLooping: + // Looping state detected. Mark decoding as complete to bail out. + // https://crbug.com/767156 + m_Complete = true; + break; + } } else { m_pStream->incByteIdx(); m_B = B1;
diff --git a/core/fxcodec/jbig2/JBig2_ArithDecoder.h b/core/fxcodec/jbig2/JBig2_ArithDecoder.h index c2fed50..9731ac6 100644 --- a/core/fxcodec/jbig2/JBig2_ArithDecoder.h +++ b/core/fxcodec/jbig2/JBig2_ArithDecoder.h
@@ -46,11 +46,17 @@ bool IsComplete() const { return m_Complete; } private: + enum class StreamState : uint8_t { + kDataAvailable, + kDecodingFinished, + kLooping, + }; + void BYTEIN(); void ReadValueA(); - bool m_Complete; - bool m_FinishedStream; + bool m_Complete = false; + StreamState m_State = StreamState::kDataAvailable; uint8_t m_B; unsigned int m_C; unsigned int m_A;