skia2/fuzz/FuzzPathop.cpp
Mike Klein f88f5ef109 simplify nextRange(), fold in nextEnum()
Doesn't look like we need to distinguish these if we just
write them as the simple

   1) load the right number of bytes
   2) clamp to [min,max]

This makes enum fuzzing independent of its underlying type, and may make
it easier to see the mapping from fuzzed byte stream to
nextRange()/nextEnum() values.

Change-Id: I9f785f94f513a0087ad7151b5e7bc14ddbe9314a
Reviewed-on: https://skia-review.googlesource.com/c/171820
Commit-Queue: Mike Klein <mtklein@google.com>
Commit-Queue: Kevin Lubick <kjlubick@google.com>
Auto-Submit: Mike Klein <mtklein@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2018-11-19 18:04:12 +00:00

203 lines
5.5 KiB
C++

/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Fuzz.h"
#include "FuzzCommon.h"
#include "SkPath.h"
#include "SkPathOps.h"
#include "SkRect.h"
const uint8_t MAX_OPS = 20;
DEF_FUZZ(Pathop, fuzz) {
uint8_t choice;
fuzz->nextRange(&choice, 0, 4);
switch (choice) {
case 0: {
uint8_t ops;
fuzz->nextRange(&ops, 0, MAX_OPS);
SkOpBuilder builder;
for (uint8_t i = 0; i < ops && !fuzz->exhausted(); i++) {
SkPath path;
FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
SkPath::FillType ft;
fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
path.setFillType(ft);
SkPathOp op;
fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp);
builder.add(path, op);
}
SkPath result;
builder.resolve(&result);
break;
}
case 1: {
SkPath path;
FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
SkPath::FillType ft;
fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
path.setFillType(ft);
SkPath result;
bool isSame;
fuzz->next(&isSame);
if (isSame) {
result = path;
}
Simplify(path, &result);
break;
}
case 2: {
SkPath path;
FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
SkPath::FillType ft;
fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
path.setFillType(ft);
SkPath path2;
FuzzEvilPath(fuzz, &path2, SkPath::Verb::kDone_Verb);
fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
path.setFillType(ft);
SkPathOp op;
fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp);
SkPath result;
uint8_t pickOutput;
fuzz->nextRange(&pickOutput, 0, 2);
if (pickOutput == 1) {
result = path;
} else if (pickOutput == 2) {
result = path2;
}
Op(path, path2, op, &result);
break;
}
case 3: {
SkPath path;
FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
SkPath::FillType ft;
fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
path.setFillType(ft);
SkPath result;
bool isSame;
fuzz->next(&isSame);
if (isSame) {
result = path;
}
AsWinding(path, &result);
break;
}
case 4: {
SkPath path;
FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
SkPath::FillType ft;
fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
path.setFillType(ft);
SkRect result;
TightBounds(path, &result);
break;
}
default: {
SkASSERT(false);
break;
}
}
}
const int kLastOp = SkPathOp::kReverseDifference_SkPathOp;
void BuildPath(Fuzz* fuzz, SkPath* path) {
while (!fuzz->exhausted()) {
// Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint"
// smaller, which leads to more efficient fuzzing.
uint8_t operation;
fuzz->next(&operation);
SkScalar a,b,c,d,e,f;
switch (operation % (SkPath::Verb::kDone_Verb + 1)) {
case SkPath::Verb::kMove_Verb:
if (fuzz->remaining() < (2*sizeof(SkScalar))) {
fuzz->deplete();
return;
}
fuzz->next(&a, &b);
path->moveTo(a, b);
break;
case SkPath::Verb::kLine_Verb:
if (fuzz->remaining() < (2*sizeof(SkScalar))) {
fuzz->deplete();
return;
}
fuzz->next(&a, &b);
path->lineTo(a, b);
break;
case SkPath::Verb::kQuad_Verb:
if (fuzz->remaining() < (4*sizeof(SkScalar))) {
fuzz->deplete();
return;
}
fuzz->next(&a, &b, &c, &d);
path->quadTo(a, b, c, d);
break;
case SkPath::Verb::kConic_Verb:
if (fuzz->remaining() < (5*sizeof(SkScalar))) {
fuzz->deplete();
return;
}
fuzz->next(&a, &b, &c, &d, &e);
path->conicTo(a, b, c, d, e);
break;
case SkPath::Verb::kCubic_Verb:
if (fuzz->remaining() < (6*sizeof(SkScalar))) {
fuzz->deplete();
return;
}
fuzz->next(&a, &b, &c, &d, &e, &f);
path->cubicTo(a, b, c, d, e, f);
break;
case SkPath::Verb::kClose_Verb:
path->close();
break;
case SkPath::Verb::kDone_Verb:
// In this case, simply exit.
return;
}
}
}
DEF_FUZZ(LegacyChromiumPathop, fuzz) {
// See https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/skia_pathop_fuzzer.cc
SkOpBuilder builder;
while (!fuzz->exhausted()) {
SkPath path;
uint8_t op;
fuzz->next(&op);
if (fuzz->exhausted()) {
break;
}
BuildPath(fuzz, &path);
builder.add(path, static_cast<SkPathOp>(op % (kLastOp + 1)));
}
SkPath result;
builder.resolve(&result);
}