From a145861ad1c2650c58dd3ff0dbd92ae6f41f1e1b Mon Sep 17 00:00:00 2001
From: Kaylee Lubick <kjlubick@google.com>
Date: Fri, 5 Jun 2026 20:51:04 +0000
Subject: [PATCH] Reject Slugs that have creationMatrix with perspective

This shouldn't happen during normal use [1] but if the data
is corrupted, there are some assumptions that can can cause
issues, like the ones linked in the bug.

This rejects those and turns one assert into an actual runtime
check to provide defense in depth.

[1] https://github.com/google/skia/blob/9eecbdc30f7da675edab96974b23174a9d521e0c/src/text/gpu/SubRunContainer.cpp#L1578-L1581

Bug: https://issues.chromium.org/issues/520113415
Fixed: 520113415
Change-Id: I6ec23df9a23ea588fa89f7a62dc1f197fe3905fd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1256016
Commit-Queue: Kaylee Lubick <kjlubick@google.com>
Reviewed-by: Thomas Smith <thomsmit@google.com>
---
 src/gpu/ganesh/ops/AtlasTextOp.cpp | 15 ++++--
 src/text/gpu/SubRunContainer.cpp   |  5 ++
 tests/SlugTest.cpp                 | 85 ++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+), 5 deletions(-)

--- a/src/gpu/ganesh/ops/AtlasTextOp.cpp
+++ b/src/gpu/ganesh/ops/AtlasTextOp.cpp
@@ -523,9 +523,17 @@
 
     for (const Geometry* geo = fHead; geo != nullptr; geo = geo->fNext) {
         const sktext::gpu::AtlasSubRun& subRun = geo->fSubRun;
-        SkASSERTF((int) subRun.vertexStride(geo->fDrawMatrix) == vertexStride,
-                  "subRun stride: %d vertex buffer stride: %d\n",
-                  (int)subRun.vertexStride(geo->fDrawMatrix), vertexStride);
+
+		int strideCheck = SkToInt(subRun.vertexStride(geo->fDrawMatrix));
+		if (strideCheck != vertexStride) {
+            // We (unexpectedly) have buffers of different sizes between CPU and GPU. Bail out.
+            SKIA_LOG_D(
+                    "Warning: stride mismatch detected (subrun stride: %d vertex buffer stride: "
+                    "%d). Aborting draw.\n",
+                    strideCheck,
+                    vertexStride);
+            return;
+		}
 
         const int subRunEnd = subRun.glyphCount();
         auto regenerateDelegate = [&](sktext::gpu::GlyphVector* glyphs,
--- a/src/text/gpu/SubRunContainer.cpp
+++ b/src/text/gpu/SubRunContainer.cpp
@@ -169,6 +169,11 @@
 
     SkMatrix creationMatrix;
     buffer.readMatrix(&creationMatrix);
+    // The only valid creationMatrices do not have perspective and many rendering parts assume
+    // they are non-affine, so reject any malformed matrices here.
+    if (!buffer.validate(!creationMatrix.hasPerspective())) {
+        return std::nullopt;
+    }
 
     SkSpan<SkPoint> leftTop = make_points_from_buffer(buffer, alloc);
     if (leftTop.empty()) {
