Add support for MSVC run-time checks (and control flow guard)

This enables four different options in the compiler, described
below. I also added enough masks to satisfy RTCc when running
all GMs in both 8888 and gl configs.

---

/RTCc - Detects when a value is assigned to a smaller data
type and results in data loss. This happens even when casting.
Masking is required to suppress this.

/RTCs - Various stack-related checks, including uninitialized
data (by initializing locals to a non-zero value), array bounds
checking, and stack pointer corruption that can occur with a
calling convention mismatch.

/RTCu - Reports when a variable is used without having been
initialized. Mostly redundant with compile-time checks.

/guard:cf - This is more of a security option, that computes
all possible targets for indirect calls at compile time, and
verifies that those are the only targets reached at compile
time. Also generates similar logic around switch statements
that turn into jump tables.

Bug: skia:
Change-Id: I7b527af8fd67dec0b6556f38bcd0efc3fd505856
Reviewed-on: https://skia-review.googlesource.com/c/188625
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/gn/BUILD.gn b/gn/BUILD.gn
index 55c344c..9bfa415 100644
--- a/gn/BUILD.gn
+++ b/gn/BUILD.gn
@@ -221,7 +221,7 @@
     ldflags += [ "-Wl,-w" ]
   }
 
-  if (sanitize != "") {
+  if (sanitize != "" && sanitize != "MSVC") {
     # You can either pass the sanitizers directly, e.g. "address,undefined",
     # or pass one of the couple common aliases used by the bots.
     sanitizers = sanitize
@@ -428,7 +428,10 @@
   } else if (is_win) {
     cflags = [ "/Z7" ]
     if (is_clang) {
-      cflags += [ "-mllvm", "-emit-codeview-ghash-section" ]
+      cflags += [
+        "-mllvm",
+        "-emit-codeview-ghash-section",
+      ]
       ldflags = [ "/DEBUG:GHASH" ]
     } else {
       ldflags = [ "/DEBUG:FASTLINK" ]
@@ -483,6 +486,15 @@
   defines = [ "NDEBUG" ]
 }
 
+config("msvc_rtc") {
+  defines = [ "_ALLOW_RTCc_IN_STL" ]
+  cflags = [
+    "/RTCcsu",
+    "/guard:cf",
+  ]
+  ldflags = [ "/guard:cf" ]
+}
+
 config("executable") {
   if (is_android) {
     ldflags = [
diff --git a/gn/BUILDCONFIG.gn b/gn/BUILDCONFIG.gn
index 454334a..d045ddf 100644
--- a/gn/BUILDCONFIG.gn
+++ b/gn/BUILDCONFIG.gn
@@ -238,6 +238,9 @@
   "//gn:warnings_except_public_headers",
   "//gn:extra_flags",
 ]
+if (sanitize == "MSVC") {
+  default_configs += [ "//gn:msvc_rtc" ]
+}
 
 set_defaults("executable") {
   configs = [ "//gn:executable" ] + default_configs
diff --git a/include/private/SkTFitsIn.h b/include/private/SkTFitsIn.h
index 5fdf743..a912f13 100644
--- a/include/private/SkTFitsIn.h
+++ b/include/private/SkTFitsIn.h
@@ -9,9 +9,24 @@
 #define SkTFitsIn_DEFINED
 
 #include <limits>
+#include <stdint.h>
 #include <type_traits>
 
 /**
+ * std::underlying_type is only defined for enums. For integral types, we just want the type.
+ */
+template <typename T, class Enable = void>
+struct sk_strip_enum {
+    typedef T type;
+};
+
+template <typename T>
+struct sk_strip_enum<T, typename std::enable_if<std::is_enum<T>::value>::type> {
+    typedef typename std::underlying_type<T>::type type;
+};
+
+
+/**
  * In C++ an unsigned to signed cast where the source value cannot be represented in the destination
  * type results in an implementation defined destination value. Unlike C, C++ does not allow a trap.
  * This makes "(S)(D)s == s" a possibly useful test. However, there are two cases where this is
@@ -65,10 +80,20 @@
 
     // E.g. (uint8_t)(int8_t) uint8_t(255) == 255, but the int8_t == -1.
     (std::is_signed<D>::value && std::is_unsigned<S>::value && sizeof(D) <= sizeof(S)) ?
-        src <= (S)std::numeric_limits<D>::max() :
+        src <= (S)std::numeric_limits<typename sk_strip_enum<D>::type>::max() :
 
-    // else
-        (S)(D)src == src;
+#if !defined(SK_DEBUG) && !defined(__MSVC_RUNTIME_CHECKS )
+    // Correct (simple) version. This trips up MSVC's /RTCc run-time checking.
+    (S)(D)src == src;
+#else
+    // More complex version that's safe with /RTCc. Used in all debug builds, for coverage.
+    (std::is_signed<S>::value) ?
+        (intmax_t)src >= (intmax_t)std::numeric_limits<typename sk_strip_enum<D>::type>::min() &&
+        (intmax_t)src <= (intmax_t)std::numeric_limits<typename sk_strip_enum<D>::type>::max() :
+
+    // std::is_unsigned<S> ?
+        (uintmax_t)src <= (uintmax_t)std::numeric_limits<typename sk_strip_enum<D>::type>::max();
+#endif
 }
 
 #endif
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 5b70168..af479cc 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -114,10 +114,10 @@
 
     // require that rowBytes fit in 31bits
     int64_t mrb = info.minRowBytes64();
-    if ((int32_t)mrb != mrb) {
+    if (!SkTFitsIn<int32_t>(mrb)) {
         return reset_return_false(this);
     }
-    if ((int64_t)rowBytes != (int32_t)rowBytes) {
+    if (!SkTFitsIn<int32_t>(rowBytes)) {
         return reset_return_false(this);
     }
 
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index 3992b14..7443377 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -293,7 +293,7 @@
 
 // maskBitCount is the number of 1's to place in the mask. It must be in the range between 1 and 8.
 static uint8_t generate_right_mask(int maskBitCount) {
-    return static_cast<uint8_t>(0xFF00U >> maskBitCount);
+    return static_cast<uint8_t>((0xFF00U >> maskBitCount) & 0xFF);
 }
 
 void SkBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
diff --git a/src/core/SkEndian.h b/src/core/SkEndian.h
index 39e5dd8..79c62ca 100644
--- a/src/core/SkEndian.h
+++ b/src/core/SkEndian.h
@@ -28,7 +28,7 @@
     e.g. 0x1234 -> 0x3412
 */
 static inline uint16_t SkEndianSwap16(uint16_t value) {
-    return static_cast<uint16_t>((value >> 8) | (value << 8));
+    return static_cast<uint16_t>((value >> 8) | ((value & 0xFF) << 8));
 }
 
 template<uint16_t N> struct SkTEndianSwap16 {
diff --git a/src/core/SkFDot6.h b/src/core/SkFDot6.h
index d8ad89c..4e949c0 100644
--- a/src/core/SkFDot6.h
+++ b/src/core/SkFDot6.h
@@ -68,7 +68,7 @@
 inline SkFixed SkFDot6Div(SkFDot6 a, SkFDot6 b) {
     SkASSERT(b != 0);
 
-    if (a == (int16_t)a) {
+    if (SkTFitsIn<int16_t>(a)) {
         return SkLeftShift(a, 16) / b;
     } else {
         return SkFixedDiv(a, b);
diff --git a/src/core/SkMipMap.cpp b/src/core/SkMipMap.cpp
index ad2d375..6d05666 100644
--- a/src/core/SkMipMap.cpp
+++ b/src/core/SkMipMap.cpp
@@ -42,7 +42,7 @@
         return (x & ~SK_G16_MASK_IN_PLACE) | ((x & SK_G16_MASK_IN_PLACE) << 16);
     }
     static uint16_t Compact(uint32_t x) {
-        return (x & ~SK_G16_MASK_IN_PLACE) | ((x >> 16) & SK_G16_MASK_IN_PLACE);
+        return ((x & ~SK_G16_MASK_IN_PLACE) & 0xFFFF) | ((x >> 16) & SK_G16_MASK_IN_PLACE);
     }
 };
 
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 86bb2af..e0120dd 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -45,7 +45,7 @@
 DrawType SkPicturePlayback::ReadOpAndSize(SkReadBuffer* reader, uint32_t* size) {
     uint32_t temp = reader->readInt();
     uint32_t op;
-    if (((uint8_t)temp) == temp) {
+    if ((temp & 0xFF) == temp) {
         // old skp file - no size information
         op = temp;
         *size = 0;
diff --git a/src/core/SkResourceCache.cpp b/src/core/SkResourceCache.cpp
index b992c85..d37bce0 100644
--- a/src/core/SkResourceCache.cpp
+++ b/src/core/SkResourceCache.cpp
@@ -52,7 +52,7 @@
                  "namespace_field_must_be_last");
 
     fCount32 = SkToS32(kLocal32s + (dataSize >> 2));
-    fSharedID_lo = (uint32_t)sharedID;
+    fSharedID_lo = (uint32_t)(sharedID & 0xFFFFFFFF);
     fSharedID_hi = (uint32_t)(sharedID >> 32);
     fNamespace = nameSpace;
     // skip unhashed fields when computing the hash
diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp
index 4f98073..e5209a5 100644
--- a/src/core/SkScan_AAAPath.cpp
+++ b/src/core/SkScan_AAAPath.cpp
@@ -636,7 +636,7 @@
         alphas[R-1] = SkFixedMul(last, lastH) >> 9; // triangle alpha
         SkFixed alpha16 = lastH + (dY >> 1); // rectangle plus triangle
         for (int i = R - 2; i > 0; i--) {
-            alphas[i] = alpha16 >> 8;
+            alphas[i] = (alpha16 >> 8) & 0xFF;
             alpha16 += dY;
         }
         alphas[0] = fullAlpha - partialTriangleToAlpha(first, dY);
diff --git a/src/core/SkScan_Antihair.cpp b/src/core/SkScan_Antihair.cpp
index ade4818..542f58e 100644
--- a/src/core/SkScan_Antihair.cpp
+++ b/src/core/SkScan_Antihair.cpp
@@ -112,7 +112,7 @@
         fy += SK_Fixed1/2;
 
         int y = fy >> 16;
-        uint8_t  a = (uint8_t)(fy >> 8);
+        uint8_t  a = (uint8_t)((fy >> 8) & 0xFF);
 
         // lower line
         unsigned ma = SmallDot6Scale(a, mod64);
@@ -136,7 +136,7 @@
         fy += SK_Fixed1/2;
 
         int y = fy >> 16;
-        uint8_t  a = (uint8_t)(fy >> 8);
+        uint8_t  a = (uint8_t)((fy >> 8) & 0xFF);
 
         // lower line
         if (a) {
@@ -159,7 +159,7 @@
         fy += SK_Fixed1/2;
 
         int lower_y = fy >> 16;
-        uint8_t  a = (uint8_t)(fy >> 8);
+        uint8_t  a = (uint8_t)((fy >> 8) & 0xFF);
         unsigned a0 = SmallDot6Scale(255 - a, mod64);
         unsigned a1 = SmallDot6Scale(a, mod64);
         this->getBlitter()->blitAntiV2(x, lower_y - 1, a0, a1);
@@ -174,7 +174,7 @@
         SkBlitter* blitter = this->getBlitter();
         do {
             int lower_y = fy >> 16;
-            uint8_t  a = (uint8_t)(fy >> 8);
+            uint8_t  a = (uint8_t)((fy >> 8) & 0xFF);
             blitter->blitAntiV2(x, lower_y - 1, 255 - a, a);
             fy += dy;
         } while (++x < stopx);
@@ -190,7 +190,7 @@
         fx += SK_Fixed1/2;
 
         int x = fx >> 16;
-        int a = (uint8_t)(fx >> 8);
+        int a = (uint8_t)((fx >> 8) & 0xFF);
 
         unsigned ma = SmallDot6Scale(a, mod64);
         if (ma) {
@@ -210,7 +210,7 @@
         fx += SK_Fixed1/2;
 
         int x = fx >> 16;
-        int a = (uint8_t)(fx >> 8);
+        int a = (uint8_t)((fx >> 8) & 0xFF);
 
         if (a) {
             this->getBlitter()->blitV(x, y, stopy - y, a);
@@ -230,7 +230,7 @@
         fx += SK_Fixed1/2;
 
         int x = fx >> 16;
-        uint8_t a = (uint8_t)(fx >> 8);
+        uint8_t a = (uint8_t)((fx >> 8) & 0xFF);
         this->getBlitter()->blitAntiH2(x - 1, y,
                                        SmallDot6Scale(255 - a, mod64), SmallDot6Scale(a, mod64));
 
@@ -242,7 +242,7 @@
         fx += SK_Fixed1/2;
         do {
             int x = fx >> 16;
-            uint8_t a = (uint8_t)(fx >> 8);
+            uint8_t a = (uint8_t)((fx >> 8) & 0xFF);
             this->getBlitter()->blitAntiH2(x - 1, y, 255 - a, a);
             fx += dx;
         } while (++y < stopy);
diff --git a/src/opts/SkSwizzler_opts.h b/src/opts/SkSwizzler_opts.h
index 82eb7b6..ae1891f 100644
--- a/src/opts/SkSwizzler_opts.h
+++ b/src/opts/SkSwizzler_opts.h
@@ -22,10 +22,10 @@
 
 static void RGBA_to_rgbA_portable(uint32_t* dst, const uint32_t* src, int count) {
     for (int i = 0; i < count; i++) {
-        uint8_t a = src[i] >> 24,
-                b = src[i] >> 16,
-                g = src[i] >>  8,
-                r = src[i] >>  0;
+        uint8_t a = (src[i] >> 24) & 0xFF,
+                b = (src[i] >> 16) & 0xFF,
+                g = (src[i] >>  8) & 0xFF,
+                r = (src[i] >>  0) & 0xFF;
         b = (b*a+127)/255;
         g = (g*a+127)/255;
         r = (r*a+127)/255;
@@ -38,10 +38,10 @@
 
 static void RGBA_to_bgrA_portable(uint32_t* dst, const uint32_t* src, int count) {
     for (int i = 0; i < count; i++) {
-        uint8_t a = src[i] >> 24,
-                b = src[i] >> 16,
-                g = src[i] >>  8,
-                r = src[i] >>  0;
+        uint8_t a = (src[i] >> 24) & 0xFF,
+                b = (src[i] >> 16) & 0xFF,
+                g = (src[i] >>  8) & 0xFF,
+                r = (src[i] >>  0) & 0xFF;
         b = (b*a+127)/255;
         g = (g*a+127)/255;
         r = (r*a+127)/255;
@@ -54,10 +54,10 @@
 
 static void RGBA_to_BGRA_portable(uint32_t* dst, const uint32_t* src, int count) {
     for (int i = 0; i < count; i++) {
-        uint8_t a = src[i] >> 24,
-                b = src[i] >> 16,
-                g = src[i] >>  8,
-                r = src[i] >>  0;
+        uint8_t a = (src[i] >> 24) & 0xFF,
+                b = (src[i] >> 16) & 0xFF,
+                g = (src[i] >>  8) & 0xFF,
+                r = (src[i] >>  0) & 0xFF;
         dst[i] = (uint32_t)a << 24
                | (uint32_t)r << 16
                | (uint32_t)g <<  8
@@ -127,10 +127,10 @@
 
 static void inverted_CMYK_to_RGB1_portable(uint32_t* dst, const uint32_t* src, int count) {
     for (int i = 0; i < count; i++) {
-        uint8_t k = src[i] >> 24,
-                y = src[i] >> 16,
-                m = src[i] >>  8,
-                c = src[i] >>  0;
+        uint8_t k = (src[i] >> 24) & 0xFF,
+                y = (src[i] >> 16) & 0xFF,
+                m = (src[i] >>  8) & 0xFF,
+                c = (src[i] >>  0) & 0xFF;
         // See comments in SkSwizzler.cpp for details on the conversion formula.
         uint8_t b = (y*k+127)/255,
                 g = (m*k+127)/255,
@@ -144,10 +144,10 @@
 
 static void inverted_CMYK_to_BGR1_portable(uint32_t* dst, const uint32_t* src, int count) {
     for (int i = 0; i < count; i++) {
-        uint8_t k = src[i] >> 24,
-                y = src[i] >> 16,
-                m = src[i] >>  8,
-                c = src[i] >>  0;
+        uint8_t k = (src[i] >> 24) & 0xFF,
+                y = (src[i] >> 16) & 0xFF,
+                m = (src[i] >>  8) & 0xFF,
+                c = (src[i] >>  0) & 0xFF;
         uint8_t b = (y*k+127)/255,
                 g = (m*k+127)/255,
                 r = (c*k+127)/255;
diff --git a/src/ports/SkImageEncoder_WIC.cpp b/src/ports/SkImageEncoder_WIC.cpp
index a24fbc7..29f6c59 100644
--- a/src/ports/SkImageEncoder_WIC.cpp
+++ b/src/ports/SkImageEncoder_WIC.cpp
@@ -83,9 +83,9 @@
             uint8_t* dstRow = SkTAddOffset<uint8_t>(pixelStorage.get(), y * rowBytes);
             for (int x = 0; x < bitmap.width(); x++) {
                 uint32_t bgra = *bitmap.getAddr32(x, y);
-                dstRow[0] = (uint8_t) (bgra >>  0);
-                dstRow[1] = (uint8_t) (bgra >>  8);
-                dstRow[2] = (uint8_t) (bgra >> 16);
+                dstRow[0] = (uint8_t) ((bgra >>  0) & 0xFF);
+                dstRow[1] = (uint8_t) ((bgra >>  8) & 0xFF);
+                dstRow[2] = (uint8_t) ((bgra >> 16) & 0xFF);
                 dstRow += 3;
             }
         }
diff --git a/src/utils/SkBase64.cpp b/src/utils/SkBase64.cpp
index cb3396c..e679e0a 100644
--- a/src/utils/SkBase64.cpp
+++ b/src/utils/SkBase64.cpp
@@ -79,10 +79,10 @@
             int one = (uint8_t) (bytes[0] << 2);
             two = bytes[1];
             one |= two >> 4;
-            two = (uint8_t) (two << 4);
+            two = (uint8_t) ((two << 4) & 0xFF);
             three = bytes[2];
             two |= three >> 2;
-            three = (uint8_t) (three << 6);
+            three = (uint8_t) ((three << 6) & 0xFF);
             three |= bytes[3];
             SkASSERT(one < 256 && two < 256 && three < 256);
             *dst = (unsigned char) one;
diff --git a/tests/FitsInTest.cpp b/tests/FitsInTest.cpp
index 5d21b8d..1802477 100644
--- a/tests/FitsInTest.cpp
+++ b/tests/FitsInTest.cpp
@@ -13,6 +13,12 @@
 
 #define TEST(S, s, D, expected) REPORTER_ASSERT(reporter, (SkTFitsIn<D>((S)(s)) == (expected)))
 
+enum TestEnum_t : uint8_t {
+    kFoo,
+    kBar,
+    kBaz,
+};
+
 DEF_TEST(FitsIn, reporter) {
     TEST(uint16_t, 257, int8_t, false);
 
@@ -32,6 +38,9 @@
     TEST(int32_t, -127, uint8_t, false);
     TEST(int32_t, -128, uint8_t, false);
 
+    TEST(uint8_t, 2, TestEnum_t, true);
+    TEST(TestEnum_t, kBar, uint8_t, true);
+
     TEST(int32_t, 1000, int8_t, false);
     TEST(int32_t, 1000, uint8_t, false);
 
diff --git a/tests/GrMemoryPoolTest.cpp b/tests/GrMemoryPoolTest.cpp
index bdc5557..38d68c1 100644
--- a/tests/GrMemoryPoolTest.cpp
+++ b/tests/GrMemoryPoolTest.cpp
@@ -19,10 +19,10 @@
 public:
     A() {}
     virtual void setValues(int v) {
-        fChar = static_cast<char>(v);
+        fChar = static_cast<char>(v & 0xFF);
     }
     virtual bool checkValues(int v) {
-        return fChar == static_cast<char>(v);
+        return fChar == static_cast<char>(v & 0xFF);
     }
     virtual ~A() {}
 
diff --git a/tests/GrSurfaceTest.cpp b/tests/GrSurfaceTest.cpp
index f306d01..6334c40 100644
--- a/tests/GrSurfaceTest.cpp
+++ b/tests/GrSurfaceTest.cpp
@@ -266,8 +266,9 @@
     static constexpr int kSize = 100;
     SkAutoPixmapStorage pixels;
     pixels.alloc(SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
-    fillPixels(&pixels,
-               [](int x, int y) { return (0xFFU << 24) | (x << 16) | (y << 8) | uint8_t(x * y); });
+    fillPixels(&pixels, [](int x, int y) {
+        return (0xFFU << 24) | (x << 16) | (y << 8) | uint8_t((x * y) & 0xFF);
+    });
 
     GrContext* context = context_info.grContext();
     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
diff --git a/tests/GrTRecorderTest.cpp b/tests/GrTRecorderTest.cpp
index a4d9b1f..4765875 100644
--- a/tests/GrTRecorderTest.cpp
+++ b/tests/GrTRecorderTest.cpp
@@ -196,7 +196,9 @@
     }
 
 private:
-    static int ValueAt(uint64_t i) { return static_cast<int>(123456789 + 987654321 * i); }
+    static int ValueAt(uint64_t i) {
+        return static_cast<int>((123456789 + 987654321 * i) & 0xFFFFFFFF);
+    }
     int fLength;
 };
 
diff --git a/tests/MathTest.cpp b/tests/MathTest.cpp
index e733324..2d41118 100644
--- a/tests/MathTest.cpp
+++ b/tests/MathTest.cpp
@@ -522,6 +522,7 @@
 
 template <typename T>
 static void test_divmod(skiatest::Reporter* r) {
+#if !defined(__MSVC_RUNTIME_CHECKS)
     const struct {
         T numer;
         T denom;
@@ -557,6 +558,7 @@
         REPORTER_ASSERT(r, numer/denom == div);
         REPORTER_ASSERT(r, numer%denom == mod);
     }
+#endif
 }
 
 DEF_TEST(divmod_u8, r) {
diff --git a/tests/PathOpsThreadedCommon.h b/tests/PathOpsThreadedCommon.h
index b47af53..32902c8 100644
--- a/tests/PathOpsThreadedCommon.h
+++ b/tests/PathOpsThreadedCommon.h
@@ -55,10 +55,10 @@
 public:
     PathOpsThreadedRunnable(void (*testFun)(PathOpsThreadState*), int a, int b, int c, int d,
             PathOpsThreadedTestRunner* runner) {
-        fState.fA = a;
-        fState.fB = b;
-        fState.fC = c;
-        fState.fD = d;
+        fState.fA = (a & 0xFF);
+        fState.fB = (b & 0xFF);
+        fState.fC = (c & 0xFF);
+        fState.fD = (d & 0xFF);
         fState.fReporter = runner->fReporter;
         fTestFun = testFun;
     }
diff --git a/tests/ProcessorTest.cpp b/tests/ProcessorTest.cpp
index dde1f11..e854d69 100644
--- a/tests/ProcessorTest.cpp
+++ b/tests/ProcessorTest.cpp
@@ -237,7 +237,10 @@
     // Delta must be less than 0.5 to prevent over/underflow issues with the input color
     SkASSERT(delta <= 0.5);
 
-    SkColor color = SkColorSetARGB((uint8_t)i, (uint8_t)j, (uint8_t)(i + j), (uint8_t)(2 * j - i));
+    SkColor color = SkColorSetARGB((uint8_t)(i & 0xFF),
+                                   (uint8_t)(j & 0xFF),
+                                   (uint8_t)((i + j) & 0xFF),
+                                   (uint8_t)((2 * j - i) & 0xFF));
     SkColor4f color4f = SkColor4f::FromColor(color);
     for (int i = 0; i < 4; i++) {
         if (color4f[i] > 0.5) {
@@ -481,6 +484,10 @@
             // written.
             timesToInvokeFactory *= FPFactory::Count() / 2;
         }
+#if defined(__MSVC_RUNTIME_CHECKS)
+        // This test is infuriatingly slow with MSVC runtime checks enabled
+        timesToInvokeFactory = 1;
+#endif
         for (int j = 0; j < timesToInvokeFactory; ++j) {
             fp = FPFactory::MakeIdx(i, &testData);
             if (!fp->instantiate(resourceProvider)) {
diff --git a/tests/SkBase64Test.cpp b/tests/SkBase64Test.cpp
index 30bfbce..39bc1c2 100644
--- a/tests/SkBase64Test.cpp
+++ b/tests/SkBase64Test.cpp
@@ -12,9 +12,10 @@
 
 DEF_TEST(SkBase64, reporter) {
     char all[256];
-    for (int index = 0; index < 256; ++index) {
+    for (int index = 0; index < 255; ++index) {
         all[index] = (signed char) (index + 1);
     }
+    all[255] = 0;
 
     for (int offset = 0; offset < 6; ++offset) {
         size_t length = 256 - offset;
diff --git a/third_party/etc1/etc1.cpp b/third_party/etc1/etc1.cpp
index 65d5140..a150081 100644
--- a/third_party/etc1/etc1.cpp
+++ b/third_party/etc1/etc1.cpp
@@ -480,10 +480,10 @@
 }
 
 static void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) {
-    pOut[0] = (etc1_byte)(d >> 24);
-    pOut[1] = (etc1_byte)(d >> 16);
-    pOut[2] = (etc1_byte)(d >> 8);
-    pOut[3] = (etc1_byte) d;
+    pOut[0] = (etc1_byte) (d >> 24);
+    pOut[1] = (etc1_byte)((d >> 16) & 0xFF);
+    pOut[2] = (etc1_byte)((d >>  8) & 0xFF);
+    pOut[3] = (etc1_byte)((d >>  0) & 0xFF);
 }
 
 // Input is a 4 x 4 square of 3-byte pixels in form R, G, B
diff --git a/third_party/third_party.gni b/third_party/third_party.gni
index ff77ee0..3c1059a 100644
--- a/third_party/third_party.gni
+++ b/third_party/third_party.gni
@@ -55,6 +55,11 @@
     # Official builds don't have warnings to begin with.
     configs -= [ "//gn:warnings" ]
   }
+
+  # Don't want to to deal with this (especially /RTCc)
+  if (sanitize == "MSVC") {
+    configs -= [ "//gn:msvc_rtc" ]
+  }
   if (is_debug) {
     configs += [ "//gn:optimize" ]
   }