validate deserialized path verbs

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>
This commit is contained in:
Mike Reed 2017-01-03 13:58:21 -05:00 committed by Skia Commit-Bot
parent b0b625b796
commit e3374d6893
2 changed files with 108 additions and 0 deletions

View 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

View 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) {