Add Legacy fuzz reproducer

Make FuzzEnum always use uint32_t to make it consistent
(we were seeing some Windows setups have underlying type return
int and not unsigned int that we saw on Linux)

Bug: 897455
Change-Id: Ia8c97e59bb498d959a9a30abcb61731f4bd145cf
Reviewed-on: https://skia-review.googlesource.com/c/164240
Reviewed-by: Cary Clark <caryclark@google.com>
Commit-Queue: Kevin Lubick <kjlubick@google.com>
diff --git a/fuzz/Fuzz.h b/fuzz/Fuzz.h
index b27e04d..bfee1b3 100644
--- a/fuzz/Fuzz.h
+++ b/fuzz/Fuzz.h
@@ -27,10 +27,18 @@
     // Returns the total number of "random" bytes available.
     size_t size() { return fBytes->size(); }
     // Returns if there are no bytes remaining for fuzzing.
-    bool exhausted(){
+    bool exhausted() {
         return fBytes->size() == fNextByte;
     }
 
+    size_t remaining() {
+        return fBytes->size() - fNextByte;
+    }
+
+    void deplete() {
+        fNextByte = fBytes->size();
+    }
+
     // next() loads fuzzed bytes into the variable passed in by pointer.
     // We use this approach instead of T next() because different compilers
     // evaluate function parameters in different orders. If fuzz->next()
@@ -124,8 +132,7 @@
 
 template <typename T, typename Min, typename Max>
 inline void Fuzz::nextEnum(T* value, Min rmin, Max rmax) {
-    using U = skstd::underlying_type_t<T>;
-    this->nextRange((U*)value, (U)rmin, (U)rmax);
+    this->nextRange((uint32_t*)value, (uint32_t)rmin, (uint32_t)rmax);
 }
 
 template <typename T>
diff --git a/fuzz/FuzzMain.cpp b/fuzz/FuzzMain.cpp
index 0e095ad..0ba3fc9 100644
--- a/fuzz/FuzzMain.cpp
+++ b/fuzz/FuzzMain.cpp
@@ -234,7 +234,7 @@
     {"api_raster_n32_canvas", "RasterN32Canvas"},
     {"jpeg_encoder", "JPEGEncoder"},
     {"png_encoder", "PNGEncoder"},
-    {"skia_pathop_fuzzer", "Pathop"},
+    {"skia_pathop_fuzzer", "LegacyChromiumPathop"},
     {"webp_encoder", "WEBPEncoder"}
 };
 
diff --git a/fuzz/FuzzPathop.cpp b/fuzz/FuzzPathop.cpp
index fe7b237..7aa229e 100644
--- a/fuzz/FuzzPathop.cpp
+++ b/fuzz/FuzzPathop.cpp
@@ -113,3 +113,90 @@
         }
     }
 }
+
+
+const int kLastOp = SkPathOp::kReverseDifference_SkPathOp;
+
+void BuildPath(Fuzz* fuzz, SkPath* path) {
+    while (!fuzz->exhausted()) {
+    // Use a uint8_t to conserve bytes.  This makes our "fuzzed bytes footprint"
+    // smaller, which leads to more efficient fuzzing.
+    uint8_t operation;
+    fuzz->next(&operation);
+    SkScalar a,b,c,d,e,f;
+
+    switch (operation % (SkPath::Verb::kDone_Verb + 1)) {
+      case SkPath::Verb::kMove_Verb:
+        if (fuzz->remaining() < (2*sizeof(SkScalar))) {
+            fuzz->deplete();
+            return;
+        }
+        fuzz->next(&a, &b);
+        path->moveTo(a, b);
+        break;
+
+      case SkPath::Verb::kLine_Verb:
+        if (fuzz->remaining() < (2*sizeof(SkScalar))) {
+            fuzz->deplete();
+            return;
+        }
+        fuzz->next(&a, &b);
+        path->lineTo(a, b);
+        break;
+
+      case SkPath::Verb::kQuad_Verb:
+        if (fuzz->remaining() < (4*sizeof(SkScalar))) {
+            fuzz->deplete();
+            return;
+        }
+        fuzz->next(&a, &b, &c, &d);
+        path->quadTo(a, b, c, d);
+        break;
+
+      case SkPath::Verb::kConic_Verb:
+        if (fuzz->remaining() < (5*sizeof(SkScalar))) {
+            fuzz->deplete();
+            return;
+        }
+        fuzz->next(&a, &b, &c, &d, &e);
+        path->conicTo(a, b, c, d, e);
+        break;
+
+      case SkPath::Verb::kCubic_Verb:
+        if (fuzz->remaining() < (6*sizeof(SkScalar))) {
+            fuzz->deplete();
+            return;
+        }
+        fuzz->next(&a, &b, &c, &d, &e, &f);
+        path->cubicTo(a, b, c, d, e, f);
+        break;
+
+      case SkPath::Verb::kClose_Verb:
+        path->close();
+        break;
+
+      case SkPath::Verb::kDone_Verb:
+        // In this case, simply exit.
+        return;
+    }
+  }
+}
+
+DEF_FUZZ(LegacyChromiumPathop, fuzz) {
+    // See https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/skia_pathop_fuzzer.cc
+    SkOpBuilder builder;
+    while (!fuzz->exhausted()) {
+        SkPath path;
+        uint8_t op;
+        fuzz->next(&op);
+        if (fuzz->exhausted()) {
+            break;
+        }
+
+        BuildPath(fuzz, &path);
+        builder.add(path, static_cast<SkPathOp>(op % (kLastOp + 1)));
+    }
+
+    SkPath result;
+    builder.resolve(&result);
+}