Avoid infinite loop caused by floating-point loop counter.

When a floating-point loop counter is incremented/decreased by an amount
that is too small to change its value given its precision, the loop will
get stuck and cause the process to hang.

This CL changes vcgen_dash::calc_dash_start() to decrease `ds` by a
multiple of the total dash length first, so that `ds` won't be too big
to cause an infinite loop.

Bug: pdfium:1822
Change-Id: I3750f8f59260df2c06fd734edce4d57535db8e12
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/93071
Commit-Queue: Nigi <nigi@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/testing/resources/pixel/bug_1822.in b/testing/resources/pixel/bug_1822.in
new file mode 100644
index 0000000..4075bb7
--- /dev/null
+++ b/testing/resources/pixel/bug_1822.in
@@ -0,0 +1,34 @@
+{{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 4 0 R
+  /MediaBox [0 0 400 400]
+>>
+endobj
+{{object 4 0}} <<
+  {{streamlen}}
+>>
+stream
+[1.8 1.8] 96636760 d
+1 i
+100 300 m
+200 300 l
+S
+endstream
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_1822_expected.pdf.0.png b/testing/resources/pixel/bug_1822_expected.pdf.0.png
new file mode 100644
index 0000000..913f33f
--- /dev/null
+++ b/testing/resources/pixel/bug_1822_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_1822_expected_skia.pdf.0.png b/testing/resources/pixel/bug_1822_expected_skia.pdf.0.png
new file mode 100644
index 0000000..2467b79
--- /dev/null
+++ b/testing/resources/pixel/bug_1822_expected_skia.pdf.0.png
Binary files differ
diff --git a/third_party/agg23/0012-infinite-loop.patch b/third_party/agg23/0012-infinite-loop.patch
new file mode 100644
index 0000000..ce1b690
--- /dev/null
+++ b/third_party/agg23/0012-infinite-loop.patch
@@ -0,0 +1,25 @@
+diff --git a/third_party/agg23/agg_vcgen_dash.cpp b/third_party/agg23/agg_vcgen_dash.cpp
+index f690760b0..d44fca178 100644
+--- a/third_party/agg23/agg_vcgen_dash.cpp
++++ b/third_party/agg23/agg_vcgen_dash.cpp
+@@ -18,8 +18,11 @@
+ //
+ //----------------------------------------------------------------------------
+ 
++#include <cmath>
++
+ #include "agg_shorten_path.h"
+ #include "agg_vcgen_dash.h"
++#include "third_party/base/check_op.h"
+ 
+ namespace pdfium
+ {
+@@ -60,6 +63,8 @@ void vcgen_dash::dash_start(float ds)
+ }
+ void vcgen_dash::calc_dash_start(float ds)
+ {
++    DCHECK_GT(m_total_dash_len, 0);
++    ds -= floor(ds / m_total_dash_len) * m_total_dash_len;
+     m_curr_dash = 0;
+     m_curr_dash_start = 0;
+     while(ds > 0) {
diff --git a/third_party/agg23/README.pdfium b/third_party/agg23/README.pdfium
index dd11888..645eb20 100644
--- a/third_party/agg23/README.pdfium
+++ b/third_party/agg23/README.pdfium
@@ -28,3 +28,4 @@
 0009-infinite-loop.patch: avoid hang in agg_math_stroke.h
 0010-math.patch: includes <math.h>
 0011-path-storage-move-ctor.patch: Add a move ctor for path_storage.
+0012-infinite-loop.patch: Fix an infinite loop in calc_dash_start().
diff --git a/third_party/agg23/agg_vcgen_dash.cpp b/third_party/agg23/agg_vcgen_dash.cpp
index f690760..d44fca1 100644
--- a/third_party/agg23/agg_vcgen_dash.cpp
+++ b/third_party/agg23/agg_vcgen_dash.cpp
@@ -18,8 +18,11 @@
 //
 //----------------------------------------------------------------------------
 
+#include <cmath>
+
 #include "agg_shorten_path.h"
 #include "agg_vcgen_dash.h"
+#include "third_party/base/check_op.h"
 
 namespace pdfium
 {
@@ -60,6 +63,8 @@
 }
 void vcgen_dash::calc_dash_start(float ds)
 {
+    DCHECK_GT(m_total_dash_len, 0);
+    ds -= floor(ds / m_total_dash_len) * m_total_dash_len;
     m_curr_dash = 0;
     m_curr_dash_start = 0;
     while(ds > 0) {