Add in Region SetPath Fuzzer

Also refactor a few things to make it easier to use oss-fuzz.

Bug: skia:
Change-Id: Ie518a6cfc7d57a347b5d09089379f986d33f8b7f
Reviewed-on: https://skia-review.googlesource.com/41740
Commit-Queue: Kevin Lubick <kjlubick@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Kevin Lubick 2018-01-11 10:27:14 -05:00 committed by Skia Commit-Bot
parent b5ef1f9b13
commit 2541edf0c6
7 changed files with 204 additions and 104 deletions

View File

@ -1700,6 +1700,8 @@ if (skia_enable_tools) {
"fuzz/FuzzPathop.cpp",
"fuzz/FuzzScaleToSides.cpp",
"fuzz/fuzz.cpp",
"fuzz/oss_fuzz/FuzzRegionDeserialize.cpp",
"fuzz/oss_fuzz/FuzzRegionSetPath.cpp",
"tools/UrlDataManager.cpp",
"tools/debugger/SkDebugCanvas.cpp",
"tools/debugger/SkDrawCommand.cpp",

View File

@ -14,15 +14,18 @@
#include "SkTypes.h"
#include <cmath>
#include <signal.h>
class Fuzz : SkNoncopyable {
public:
explicit Fuzz(sk_sp<SkData>);
explicit Fuzz(sk_sp<SkData> bytes) : fBytes(bytes), fNextByte(0) {}
// Returns the total number of "random" bytes available.
size_t size();
size_t size() { return fBytes->size(); }
// Returns if there are no bytes remaining for fuzzing.
bool exhausted();
bool exhausted(){
return fBytes->size() == fNextByte;
}
// next() loads fuzzed bytes into the variable passed in by pointer.
// We use this approach instead of T next() because different compilers
@ -47,7 +50,11 @@ public:
template <typename T>
void nextN(T* ptr, int n);
void signalBug(); // Tell afl-fuzz these inputs found a bug.
void signalBug(){
// Tell the fuzzer that these inputs found a bug.
SkDebugf("Signal bug\n");
raise(SIGSEGV);
}
private:
template <typename T>

View File

@ -6,6 +6,7 @@
*/
#include "Fuzz.h"
#include "FuzzCommon.h"
// CORE
#include "SkCanvas.h"
@ -91,83 +92,6 @@ inline T make_fuzz_t(Fuzz* fuzz) {
return t;
}
// We don't always want to test NaNs and infinities.
static void fuzz_nice_float(Fuzz* fuzz, float* f) {
float v;
fuzz->next(&v);
constexpr float kLimit = 1.0e35f; // FLT_MAX?
*f = (v == v && v <= kLimit && v >= -kLimit) ? v : 0.0f;
}
template <typename... Args>
inline void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
fuzz_nice_float(fuzz, f);
fuzz_nice_float(fuzz, rest...);
}
static void fuzz_path(Fuzz* fuzz, SkPath* path, int maxOps) {
if (maxOps < 2) {
maxOps = 2;
}
uint8_t fillType;
fuzz->nextRange(&fillType, 0, (uint8_t)SkPath::kInverseEvenOdd_FillType);
path->setFillType((SkPath::FillType)fillType);
uint8_t numOps;
fuzz->nextRange(&numOps, 2, maxOps);
for (uint8_t i = 0; i < numOps; ++i) {
uint8_t op;
fuzz->nextRange(&op, 0, 6);
SkScalar a, b, c, d, e, f;
switch (op) {
case 0:
fuzz_nice_float(fuzz, &a, &b);
path->moveTo(a, b);
break;
case 1:
fuzz_nice_float(fuzz, &a, &b);
path->lineTo(a, b);
break;
case 2:
fuzz_nice_float(fuzz, &a, &b, &c, &d);
path->quadTo(a, b, c, d);
break;
case 3:
fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
path->conicTo(a, b, c, d, e);
break;
case 4:
fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f);
path->cubicTo(a, b, c, d, e, f);
break;
case 5:
fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
path->arcTo(a, b, c, d, e);
break;
case 6:
path->close();
break;
default:
break;
}
}
}
template <>
inline void Fuzz::next(SkRegion* region) {
uint8_t N;
this->nextRange(&N, 0, 10);
for (uint8_t i = 0; i < N; ++i) {
SkIRect r;
uint8_t op;
this->next(&r);
r.sort();
this->nextRange(&op, 0, (uint8_t)SkRegion::kLastOp);
if (!region->op(r, (SkRegion::Op)op)) {
return;
}
}
}
template <>
inline void Fuzz::next(SkShader::TileMode* m) {
fuzz_enum_range(this, m, 0, SkShader::kTileModeCount - 1);

87
fuzz/FuzzCommon.h Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright 2018 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 "SkPath.h"
#include "SkRegion.h"
// We don't always want to test NaNs and infinities.
static void fuzz_nice_float(Fuzz* fuzz, float* f) {
float v;
fuzz->next(&v);
constexpr float kLimit = 1.0e35f; // FLT_MAX?
*f = (v == v && v <= kLimit && v >= -kLimit) ? v : 0.0f;
}
template <typename... Args>
inline void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
fuzz_nice_float(fuzz, f);
fuzz_nice_float(fuzz, rest...);
}
static void fuzz_path(Fuzz* fuzz, SkPath* path, int maxOps) {
if (maxOps < 2) {
maxOps = 2;
}
uint8_t fillType;
fuzz->nextRange(&fillType, 0, (uint8_t)SkPath::kInverseEvenOdd_FillType);
path->setFillType((SkPath::FillType)fillType);
uint8_t numOps;
fuzz->nextRange(&numOps, 2, maxOps);
for (uint8_t i = 0; i < numOps; ++i) {
uint8_t op;
fuzz->nextRange(&op, 0, 6);
SkScalar a, b, c, d, e, f;
switch (op) {
case 0:
fuzz_nice_float(fuzz, &a, &b);
path->moveTo(a, b);
break;
case 1:
fuzz_nice_float(fuzz, &a, &b);
path->lineTo(a, b);
break;
case 2:
fuzz_nice_float(fuzz, &a, &b, &c, &d);
path->quadTo(a, b, c, d);
break;
case 3:
fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
path->conicTo(a, b, c, d, e);
break;
case 4:
fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f);
path->cubicTo(a, b, c, d, e, f);
break;
case 5:
fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
path->arcTo(a, b, c, d, e);
break;
case 6:
path->close();
break;
default:
break;
}
}
}
template <>
inline void Fuzz::next(SkRegion* region) {
uint8_t N;
this->nextRange(&N, 0, 10);
for (uint8_t i = 0; i < N; ++i) {
SkIRect r;
uint8_t op;
this->next(&r);
r.sort();
this->nextRange(&op, 0, (uint8_t)SkRegion::kLastOp);
if (!region->op(r, (SkRegion::Op)op)) {
return;
}
}
}

View File

@ -35,6 +35,7 @@
#include <signal.h>
#include "sk_tool_utils.h"
DEFINE_string2(bytes, b, "", "A path to a file or a directory. If a file, the "
"contents will be used as the fuzz bytes. If a directory, all files "
"in the directory will be used as fuzz bytes for the fuzzer, one at a "
@ -53,6 +54,7 @@ DEFINE_string2(type, t, "", "How to interpret --bytes, one of:\n"
"path_deserialize\n"
"pipe\n"
"region_deserialize\n"
"region_set_path\n"
"skp\n"
"sksl2glsl\n"
"textblob");
@ -67,6 +69,7 @@ static void fuzz_icc(sk_sp<SkData>);
static void fuzz_img(sk_sp<SkData>, uint8_t, uint8_t);
static void fuzz_path_deserialize(sk_sp<SkData>);
static void fuzz_region_deserialize(sk_sp<SkData>);
static void fuzz_region_set_path(sk_sp<SkData>);
static void fuzz_skp(sk_sp<SkData>);
static void fuzz_skpipe(sk_sp<SkData>);
static void fuzz_textblob_deserialize(sk_sp<SkData>);
@ -136,6 +139,10 @@ static int fuzz_file(const char* path) {
fuzz_region_deserialize(bytes);
return 0;
}
if (0 == strcmp("region_set_path", FLAGS_type[0])) {
fuzz_region_set_path(bytes);
return 0;
}
if (0 == strcmp("pipe", FLAGS_type[0])) {
fuzz_skpipe(bytes);
return 0;
@ -521,23 +528,13 @@ static void fuzz_path_deserialize(sk_sp<SkData> bytes) {
SkDebugf("[terminated] Success! Initialized SkPath.\n");
}
bool FuzzRegionDeserialize(sk_sp<SkData> bytes);
static void fuzz_region_deserialize(sk_sp<SkData> bytes) {
SkRegion region;
if (!region.readFromMemory(bytes->data(), bytes->size())) {
if (!FuzzRegionDeserialize(bytes)) {
SkDebugf("[terminated] Couldn't initialize SkRegion.\n");
return;
}
region.computeRegionComplexity();
region.isComplex();
SkRegion r2;
if (region == r2) {
region.contains(0,0);
} else {
region.contains(1,1);
}
auto s = SkSurface::MakeRasterN32Premul(1024, 1024);
s->getCanvas()->drawRegion(region, SkPaint());
SkDEBUGCODE(region.validate());
SkDebugf("[terminated] Success! Initialized SkRegion.\n");
}
@ -554,6 +551,14 @@ static void fuzz_textblob_deserialize(sk_sp<SkData> bytes) {
SkDebugf("[terminated] Success! Initialized SkTextBlob.\n");
}
void FuzzRegionSetPath(Fuzz* fuzz);
static void fuzz_region_set_path(sk_sp<SkData> bytes) {
Fuzz fuzz(bytes);
FuzzRegionSetPath(&fuzz);
SkDebugf("[terminated] region_set_path didn't crash!\n");
}
static void fuzz_filter_fuzz(sk_sp<SkData> bytes) {
const int BitmapSize = 24;
SkBitmap bitmap;
@ -603,13 +608,3 @@ static void fuzz_sksl2glsl(sk_sp<SkData> bytes) {
SkDebugf("[terminated] Success! Compiled input.\n");
}
#endif
Fuzz::Fuzz(sk_sp<SkData> bytes) : fBytes(bytes), fNextByte(0) {}
void Fuzz::signalBug() { SkDebugf("Signal bug\n"); raise(SIGSEGV); }
size_t Fuzz::size() { return fBytes->size(); }
bool Fuzz::exhausted() {
return fBytes->size() == fNextByte;
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkRegion.h"
#include "SkSurface.h"
bool FuzzRegionDeserialize(sk_sp<SkData> bytes) {
SkRegion region;
if (!region.readFromMemory(bytes->data(), bytes->size())) {
return false;
}
region.computeRegionComplexity();
region.isComplex();
SkRegion r2;
if (region == r2) {
region.contains(0,0);
} else {
region.contains(1,1);
}
auto s = SkSurface::MakeRasterN32Premul(1024, 1024);
s->getCanvas()->drawRegion(region, SkPaint());
SkDEBUGCODE(region.validate());
return true;
}
#if defined(IS_FUZZING_WITH_LIBFUZZER)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
auto bytes = SkData::MakeWithoutCopy(data, size);
FuzzRegionDeserialize(bytes);
return 0;
}
#endif

View File

@ -0,0 +1,46 @@
/*
* Copyright 2018 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 "SkData.h"
#include "SkPath.h"
#include "SkRegion.h"
void FuzzRegionSetPath(Fuzz* fuzz) {
SkPath p;
fuzz_path(fuzz, &p, 1000);
SkRegion r1;
bool initR1;
fuzz->next(&initR1);
if (initR1) {
fuzz->next(&r1);
}
SkRegion r2;
fuzz->next(&r2);
r1.setPath(p, r2);
// Do some follow on computations to make sure region is well-formed.
r1.computeRegionComplexity();
r1.isComplex();
if (r1 == r2) {
r1.contains(0,0);
} else {
r1.contains(1,1);
}
}
#if defined(IS_FUZZING_WITH_LIBFUZZER)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
sk_sp<SkData> bytes(SkData::MakeWithoutCopy(data, size));
Fuzz fuzz(bytes);
FuzzRegionSetPath(&fuzz);
return 0;
}
#endif