validate deserialized path verbs
authorMike Reed <reed@google.com>
Tue, 3 Jan 2017 18:58:21 +0000 (13:58 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Tue, 3 Jan 2017 19:31:26 +0000 (19:31 +0000)
BUG=676755

Change-Id: Ie9bd70d3a130c53737756587f73c9dce4a6bcb6d
Reviewed-on: https://skia-review.googlesource.com/6529
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Cary Clark <caryclark@google.com>
src/core/SkPathRef.cpp
tests/PathTest.cpp

index ef051f7..55ee991 100644 (file)
@@ -186,6 +186,38 @@ void SkPathRef::CreateTransformedCopy(sk_sp<SkPathRef>* dst,
     SkDEBUGCODE((*dst)->validate();)
 }
 
+// Given the verb array, deduce the required number of pts and conics,
+// or if an invalid verb is encountered, return false.
+static bool deduce_pts_conics(const uint8_t verbs[], int vCount, int* ptCountPtr,
+                              int* conicCountPtr) {
+    int ptCount = 0;
+    int conicCount = 0;
+    for (int i = 0; i < vCount; ++i) {
+        switch (verbs[i]) {
+            case SkPath::kMove_Verb:
+            case SkPath::kLine_Verb:
+                ptCount += 1;
+                break;
+            case SkPath::kConic_Verb:
+                conicCount += 1;
+                // fall-through
+            case SkPath::kQuad_Verb:
+                ptCount += 2;
+                break;
+            case SkPath::kCubic_Verb:
+                ptCount += 3;
+                break;
+            case SkPath::kClose_Verb:
+                break;
+            default:
+                return false;
+        }
+    }
+    *ptCountPtr = ptCount;
+    *conicCountPtr = conicCount;
+    return true;
+}
+
 SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
     SkPathRef* ref = new SkPathRef;
 
@@ -231,6 +263,17 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
         delete ref;
         return nullptr;
     }
+
+    // Check that the verbs are valid, and imply the correct number of pts and conics
+    {
+        int pCount, cCount;
+        if (!deduce_pts_conics(ref->verbsMemBegin(), ref->countVerbs(), &pCount, &cCount) ||
+            pCount != ref->countPoints() || cCount != ref->fConicWeights.count()) {
+            delete ref;
+            return nullptr;
+        }
+    }
+    
     ref->fBoundsIsDirty = false;
 
     // resetToSize clears fSegmentMask and fIsOval
index 9a44d29..2059c36 100644 (file)
@@ -2532,6 +2532,69 @@ static void write_and_read_back(skiatest::Reporter* reporter,
     REPORTER_ASSERT(reporter, origBounds == readBackBounds);
 }
 
+static void test_corrupt_flattening(skiatest::Reporter* reporter) {
+    SkPath path;
+    path.moveTo(1, 2);
+    path.lineTo(1, 2);
+    path.quadTo(1, 2, 3, 4);
+    path.conicTo(1, 2, 3, 4, 0.5f);
+    path.cubicTo(1, 2, 3, 4, 5, 6);
+    uint8_t buffer[1024];
+    SkDEBUGCODE(size_t size =) path.writeToMemory(buffer);
+    SkASSERT(size <= sizeof(buffer));
+    
+    // find where the counts and verbs are stored : from the impl in SkPathRef.cpp
+    int32_t* vCount = (int32_t*)&buffer[16];
+    SkASSERT(*vCount == 5);
+    int32_t* pCount = (int32_t*)&buffer[20];
+    SkASSERT(*pCount == 9);
+    int32_t* cCount = (int32_t*)&buffer[24];
+    SkASSERT(*cCount == 1);
+    uint8_t* verbs = &buffer[28];
+    
+    REPORTER_ASSERT(reporter, path.readFromMemory(buffer, sizeof(buffer)));
+    
+    // check that we detect under/over-flow of counts
+    
+    *vCount += 1;
+    REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer)));
+    *vCount -= 1;   // restore
+    
+    *pCount += 1;
+    REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer)));
+    *pCount -= 2;
+    REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer)));
+    *pCount += 1;   // restore
+    
+    *cCount += 1;
+    REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer)));
+    *cCount -= 2;
+    REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer)));
+    *cCount += 1;   // restore
+    
+    // Check that we detect when the verbs indicate more or fewer pts/conics
+    
+    uint8_t save = verbs[0];
+    SkASSERT(save == SkPath::kCubic_Verb);
+    verbs[0] = SkPath::kQuad_Verb;
+    REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer)));
+    verbs[0] = save;
+    
+    save = verbs[1];
+    SkASSERT(save == SkPath::kConic_Verb);
+    verbs[1] = SkPath::kQuad_Verb;
+    REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer)));
+    verbs[1] = SkPath::kCubic_Verb;
+    REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer)));
+    verbs[1] = save;
+    
+    // Check that we detect invalid verbs
+    save = verbs[1];
+    verbs[1] = 17;
+    REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer)));
+    verbs[1] = save;
+}
+
 static void test_flattening(skiatest::Reporter* reporter) {
     SkPath p;
 
@@ -2580,6 +2643,8 @@ static void test_flattening(skiatest::Reporter* reporter) {
 
         write_and_read_back(reporter, oval);
     }
+
+    test_corrupt_flattening(reporter);
 }
 
 static void test_transform(skiatest::Reporter* reporter) {