Avoid integer underflow in SkiaState::AdjustClip(). When the current `m_clipIndex` is larger than the given `limit` index, SkiaState::AdjustClip() looks through the index range below the current `m_clipIndex` until it finds a save command to restore. If no save command is found, it reaches an assertion failure due to the index being negative. This CL makes sure `m_clipIndex` is non-negative when using it to access and check command types. If no save command is found, skip restoring and set `m_clipIndex` to 0, so that all commands below index `limit` can be processed later. The added pixel test is a minimized version of the PDF that triggered the assertion failure in crbug.com/1116869. Bug: chromium:1116869 Change-Id: I47a71918c561c1cb121b91f929d3f0f60b3f22e9 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/78570 Reviewed-by: Daniel Hosseinian <dhoss@chromium.org> Commit-Queue: Hui Yingst <nigi@chromium.org>
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp index 972ecf3..4442a65 100644 --- a/core/fxge/skia/fx_skia_device.cpp +++ b/core/fxge/skia/fx_skia_device.cpp
@@ -1242,9 +1242,11 @@ while (m_clipIndex > limit) { do { --m_clipIndex; - DCHECK(m_clipIndex >= 0); - } while (m_commands[m_clipIndex] != Clip::kSave); - m_pDriver->SkiaCanvas()->restore(); + } while (m_clipIndex >= 0 && m_commands[m_clipIndex] != Clip::kSave); + if (m_clipIndex >= 0) + m_pDriver->SkiaCanvas()->restore(); + else + m_clipIndex = 0; } while (m_clipIndex < limit) { if (Clip::kSave == m_commands[m_clipIndex]) {
diff --git a/testing/resources/pixel/bug_1116869.in b/testing/resources/pixel/bug_1116869.in new file mode 100644 index 0000000..d123e38 --- /dev/null +++ b/testing/resources/pixel/bug_1116869.in
@@ -0,0 +1,117 @@ +{{header}} +{{object 1 0}} << + /Type /Catalog + /Pages 2 0 R +>> +endobj +{{object 2 0}} << + /Type /Pages + /Count 1 + /Kids [3 0 R] +>> +endobj +{{object 3 0}} << + /Type /Page + /Parent 2 0 R + /Contents 5 0 R + /MediaBox [0 0 400 400] + /Resources << + /Font << + /F1 4 0 R + >> + /Pattern << + /P1 6 0 R + >> + /XObject << + /X10 9 0 R + >> + >> +>> +endobj +{{object 4 0}} << + /Type /Font + /Subtype /Type1 + /BaseFont /Times-Roman +>> +endobj +{{object 5 0}} << + {{streamlen}} +>> +stream +/X10 Do +endstream +endobj +{{object 6 0}} << + /Type /Pattern + /PatternType 2 + /Shading 7 0 R +>> +endobj +{{object 7 0}} << + /ShadingType 2 + /ColorSpace /DeviceCMYK + /Coords [0.0 0.0 1.0 0.0] + /Extend [true true] + /Function 8 0 R +>> +endobj +{{object 8 0}} << + /FunctionType 0 + /BitsPerSample 1 + /Domain [0.0 1.0] + /Filter /ASCIIHexDecode + /Range [0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0] + /Size [2] + {{streamlen}} +>> +stream +ff +endstream +endobj +{{object 9 0}} << + /Subtype /Form + /Resources << + /ExtGState << + /G7 10 0 R + >> + >> + {{streamlen}} +>> +stream +q +0 0 m +3 31 l +/G7 gs +f +endstream +endobj +{{object 10 0}} << + /SMas << + /G 11 0 R + >> +>> +endobj +{{object 11 0}} << + {{streamlen}} +>> +stream +1 1 2 2 re +W +100 100 200 200 re s +W +0 g +/F1 12 Tf +0 0 60 30 re +W +m 100 100 +130 150 200 200 250 230 c +/Pattern cs +/P1 scn +(ABC) Tj +Q +endstream +endobj +{{xref}} +{{trailer}} +{{startxref}} +%%EOF
diff --git a/testing/resources/pixel/bug_1116869_expected.pdf.0.png b/testing/resources/pixel/bug_1116869_expected.pdf.0.png new file mode 100644 index 0000000..1ff3f1f --- /dev/null +++ b/testing/resources/pixel/bug_1116869_expected.pdf.0.png Binary files differ