Catch width overflow in ASAN using int64
authorYuqian Li <liyuqian@google.com>
Mon, 14 Nov 2016 21:45:01 +0000 (16:45 -0500)
committerMike Klein <mtklein@chromium.org>
Mon, 14 Nov 2016 23:08:21 +0000 (23:08 +0000)
This is related with our previous CL:
https://skia-review.googlesource.com/c/4628/

That previous CL fix won't pass the ASAN test (../../../include/core/SkRect.h:72:39: runtime error: signed integer overflow: 1 - -2147483648 cannot be represented in type 'int') so we use int64 in this CL.

BUG=skia:

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

Change-Id: I39f7329c427d49f4be07588f37120722ac9892c2
Reviewed-on: https://skia-review.googlesource.com/4785
Reviewed-by: Mike Reed <reed@google.com>
src/core/SkScan_AAAPath.cpp

index 8ca2fea..3915fea 100644 (file)
@@ -153,8 +153,7 @@ public:
     int getWidth() override { return fClipRect.width(); }
 
     static bool canHandleRect(const SkIRect& bounds) {
-        // The width may overflow signed int, e.g., left = -2147483648, right = 1
-        unsigned width = bounds.width();
+        int width = bounds.width();
         if (width > MaskAdditiveBlitter::kMAX_WIDTH) {
             return false;
         }
@@ -1251,6 +1250,22 @@ static int rect_overflows_short_shift(SkIRect rect, int shift) {
            overflows_short_shift(rect.fBottom, 2);
 }
 
+static bool fitsInsideLimit(const SkRect& r, SkScalar max) {
+    const SkScalar min = -max;
+    return  r.fLeft > min && r.fTop > min &&
+            r.fRight < max && r.fBottom < max;
+}
+
+static bool safeRoundOut(const SkRect& src, SkIRect* dst, int32_t maxInt) {
+    const SkScalar maxScalar = SkIntToScalar(maxInt);
+
+    if (fitsInsideLimit(src, maxScalar)) {
+        src.roundOut(dst);
+        return true;
+    }
+    return false;
+}
+
 void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter,
                          bool forceRLE) {
     if (origClip.isEmpty()) {
@@ -1264,7 +1279,9 @@ void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter
 
     const bool isInverse = path.isInverseFillType();
     SkIRect ir;
-    path.getBounds().roundOut(&ir);
+    if (!safeRoundOut(path.getBounds(), &ir, SK_MaxS32 >> 2)) {
+        return;
+    }
     if (ir.isEmpty()) {
         if (isInverse) {
             blitter->blitRegion(origClip);