Fix mask overflow caused by edge drift

BUG=skia:

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4797

Change-Id: Ica1568b67c1e1ce4aae2bdaba2c5b1f2155d1382
Reviewed-on: https://skia-review.googlesource.com/4797
Reviewed-by: Cary Clark <caryclark@google.com>
diff --git a/src/core/SkAnalyticEdge.h b/src/core/SkAnalyticEdge.h
index 0081286..a55ab2a 100644
--- a/src/core/SkAnalyticEdge.h
+++ b/src/core/SkAnalyticEdge.h
@@ -44,7 +44,7 @@
 
     static inline SkFixed snapY(SkFixed y, int accuracy = kDefaultAccuracy) {
         // This approach is safer than left shift, round, then right shift
-        return (y + (SK_Fixed1 >> (accuracy + 1))) >> (16 - accuracy) << (16 - accuracy);
+        return ((unsigned)y + (SK_Fixed1 >> (accuracy + 1))) >> (16 - accuracy) << (16 - accuracy);
     }
 
     // Update fX, fY of this edge so fY = y
diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp
index 8bfe7bb..47d2dcc 100644
--- a/src/core/SkScan_AAAPath.cpp
+++ b/src/core/SkScan_AAAPath.cpp
@@ -1204,8 +1204,18 @@
 
     if (!path.isInverseFillType() && path.isConvex()) {
         SkASSERT(count >= 2);   // convex walker does not handle missing right edges
+        SkFixed leftBound = SkIntToFixed(rect.fLeft);
+        SkFixed rightBound = SkIntToFixed(rect.fRight);
+        if (isUsingMask) {
+            // If we're using mask, then we have to limit the bound within the path bounds.
+            // Otherwise, the edge drift may access an invalid address inside the mask.
+            SkIRect ir;
+            path.getBounds().roundOut(&ir);
+            leftBound = SkTMax(leftBound, SkIntToFixed(ir.fLeft));
+            rightBound = SkTMin(rightBound, SkIntToFixed(ir.fRight));
+        }
         aaa_walk_convex_edges(&headEdge, blitter, start_y, stop_y,
-                              rect.fLeft << 16, rect.fRight << 16, isUsingMask);
+                              leftBound, rightBound, isUsingMask);
     } else {
         SkFAIL("Concave AAA is not yet implemented!");
     }
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index 85bd804..f064a16 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -198,6 +198,24 @@
     canvas->drawRectCoords(0, 0, 250, 250, paint);
 }
 
+static void test_mask_overflow() {
+    auto surface(SkSurface::MakeRasterN32Premul(500, 500));
+    SkCanvas* canvas = surface->getCanvas();
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    SkPath path;
+    path.moveTo(SkBits2Float(0x43e28000), SkBits2Float(0x43aa8000));  // 453, 341
+    path.lineTo(SkBits2Float(0x43de6000), SkBits2Float(0x43aa8000));  // 444.75f, 341
+    // 440.47f, 341, 437, 344.47f, 437, 348.75f
+    path.cubicTo(SkBits2Float(0x43dc3c29), SkBits2Float(0x43aa8000),
+            SkBits2Float(0x43da8000), SkBits2Float(0x43ac3c29),
+            SkBits2Float(0x43da8000), SkBits2Float(0x43ae6000));
+    path.lineTo(SkBits2Float(0x43da8000), SkBits2Float(0x43b18000));  // 437, 355
+    path.lineTo(SkBits2Float(0x43e28000), SkBits2Float(0x43b18000));  // 453, 355
+    path.lineTo(SkBits2Float(0x43e28000), SkBits2Float(0x43aa8000));  // 453, 341
+    canvas->drawPath(path, paint);
+}
+
 /**
  * In debug mode, this path was causing an assertion to fail in
  * SkPathStroker::preJoinTo() and, in Release, the use of an unitialized value.
@@ -4359,6 +4377,7 @@
     test_fuzz_crbug_662952(reporter);
     test_fuzz_crbug_662730(reporter);
     test_fuzz_crbug_662780();
+    test_mask_overflow();
 
     SkTSize<SkScalar>::Make(3,4);