xref: /third_party/skia/fuzz/FuzzPathop.cpp (revision cb93a386)
1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "fuzz/Fuzz.h"
9#include "fuzz/FuzzCommon.h"
10#include "include/core/SkPath.h"
11#include "include/core/SkRect.h"
12#include "include/pathops/SkPathOps.h"
13
14const uint8_t MAX_OPS = 20;
15
16DEF_FUZZ(Pathop, fuzz) {
17
18    uint8_t choice;
19    fuzz->nextRange(&choice, 0, 4);
20    switch (choice) {
21        case 0: {
22            uint8_t ops;
23            fuzz->nextRange(&ops, 0, MAX_OPS);
24            SkOpBuilder builder;
25            for (uint8_t i = 0; i < ops && !fuzz->exhausted(); i++) {
26                SkPath path;
27                FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
28                SkPathFillType ft;
29                fuzz->nextRange(&ft, 0, (int)SkPathFillType::kInverseEvenOdd);
30                path.setFillType(ft);
31
32                SkPathOp op;
33                fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp);
34                builder.add(path, op);
35            }
36
37            SkPath result;
38            builder.resolve(&result);
39            break;
40        }
41        case 1: {
42            SkPath path;
43            FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
44            SkPathFillType ft;
45            fuzz->nextRange(&ft, 0, (int)SkPathFillType::kInverseEvenOdd);
46            path.setFillType(ft);
47
48            SkPath result;
49            bool isSame;
50            fuzz->next(&isSame);
51            if (isSame) {
52                result = path;
53            }
54            Simplify(path, &result);
55            break;
56        }
57        case 2: {
58            SkPath path;
59            FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
60            SkPathFillType ft;
61            fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd);
62            path.setFillType(ft);
63
64            SkPath path2;
65            FuzzEvilPath(fuzz, &path2, SkPath::Verb::kDone_Verb);
66            fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd);
67            path.setFillType(ft);
68
69            SkPathOp op;
70            fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp);
71
72            SkPath result;
73            uint8_t pickOutput;
74            fuzz->nextRange(&pickOutput, 0, 2);
75            if (pickOutput == 1) {
76                result = path;
77            } else if (pickOutput == 2) {
78                result = path2;
79            }
80            Op(path, path2, op, &result);
81            break;
82        }
83        case 3: {
84            SkPath path;
85            FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
86            SkPathFillType ft;
87            fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd);
88            path.setFillType(ft);
89
90            SkPath result;
91            bool isSame;
92            fuzz->next(&isSame);
93            if (isSame) {
94                result = path;
95            }
96            AsWinding(path, &result);
97            break;
98        }
99        case 4: {
100            SkPath path;
101            FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
102            SkPathFillType ft;
103            fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd);
104            path.setFillType(ft);
105
106            SkRect result;
107            TightBounds(path, &result);
108            break;
109        }
110        default: {
111            SkASSERT(false);
112            break;
113        }
114    }
115}
116
117
118const int kLastOp = SkPathOp::kReverseDifference_SkPathOp;
119
120void BuildPath(Fuzz* fuzz, SkPath* path) {
121    while (!fuzz->exhausted()) {
122    // Use a uint8_t to conserve bytes.  This makes our "fuzzed bytes footprint"
123    // smaller, which leads to more efficient fuzzing.
124    uint8_t operation;
125    fuzz->next(&operation);
126    SkScalar a,b,c,d,e,f;
127
128    switch (operation % (SkPath::Verb::kDone_Verb + 1)) {
129      case SkPath::Verb::kMove_Verb:
130        if (fuzz->remaining() < (2*sizeof(SkScalar))) {
131            fuzz->deplete();
132            return;
133        }
134        fuzz->next(&a, &b);
135        path->moveTo(a, b);
136        break;
137
138      case SkPath::Verb::kLine_Verb:
139        if (fuzz->remaining() < (2*sizeof(SkScalar))) {
140            fuzz->deplete();
141            return;
142        }
143        fuzz->next(&a, &b);
144        path->lineTo(a, b);
145        break;
146
147      case SkPath::Verb::kQuad_Verb:
148        if (fuzz->remaining() < (4*sizeof(SkScalar))) {
149            fuzz->deplete();
150            return;
151        }
152        fuzz->next(&a, &b, &c, &d);
153        path->quadTo(a, b, c, d);
154        break;
155
156      case SkPath::Verb::kConic_Verb:
157        if (fuzz->remaining() < (5*sizeof(SkScalar))) {
158            fuzz->deplete();
159            return;
160        }
161        fuzz->next(&a, &b, &c, &d, &e);
162        path->conicTo(a, b, c, d, e);
163        break;
164
165      case SkPath::Verb::kCubic_Verb:
166        if (fuzz->remaining() < (6*sizeof(SkScalar))) {
167            fuzz->deplete();
168            return;
169        }
170        fuzz->next(&a, &b, &c, &d, &e, &f);
171        path->cubicTo(a, b, c, d, e, f);
172        break;
173
174      case SkPath::Verb::kClose_Verb:
175        path->close();
176        break;
177
178      case SkPath::Verb::kDone_Verb:
179        // In this case, simply exit.
180        return;
181    }
182  }
183}
184
185DEF_FUZZ(LegacyChromiumPathop, fuzz) {
186    // See https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/skia_pathop_fuzzer.cc
187    SkOpBuilder builder;
188    while (!fuzz->exhausted()) {
189        SkPath path;
190        uint8_t op;
191        fuzz->next(&op);
192        if (fuzz->exhausted()) {
193            break;
194        }
195
196        BuildPath(fuzz, &path);
197        builder.add(path, static_cast<SkPathOp>(op % (kLastOp + 1)));
198    }
199
200    SkPath result;
201    builder.resolve(&result);
202}
203