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