blob: 30dc2a944e32bbc8962263be88f48db4a48fe78c [file] [log] [blame]
kjlubicke5654502016-07-19 16:50:03 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#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"
kjlubicke5654502016-07-19 16:50:03 -070013
Kevin Lubick0a5152e2018-10-11 11:20:04 -040014const uint8_t MAX_OPS = 20;
kjlubicke5654502016-07-19 16:50:03 -070015
kjlubicke5654502016-07-19 16:50:03 -070016DEF_FUZZ(Pathop, fuzz) {
kjlubicke5654502016-07-19 16:50:03 -070017
Kevin Lubick0a5152e2018-10-11 11:20:04 -040018 uint8_t choice;
19 fuzz->nextRange(&choice, 0, 4);
20 switch (choice) {
21 case 0: {
Kevin Lubick0a5152e2018-10-11 11:20:04 -040022 uint8_t ops;
23 fuzz->nextRange(&ops, 0, MAX_OPS);
24 SkOpBuilder builder;
Kevin Lubick1f0170c2018-10-23 09:40:32 -040025 for (uint8_t i = 0; i < ops && !fuzz->exhausted(); i++) {
26 SkPath path;
27 FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
Mike Reed7d34dc72019-11-26 12:17:17 -050028 SkPathFillType ft;
29 fuzz->nextRange(&ft, 0, (int)SkPathFillType::kInverseEvenOdd);
Kevin Lubick1f0170c2018-10-23 09:40:32 -040030 path.setFillType(ft);
31
Kevin Lubick0a5152e2018-10-11 11:20:04 -040032 SkPathOp op;
Mike Kleinf88f5ef2018-11-19 12:21:46 -050033 fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp);
Kevin Lubick0a5152e2018-10-11 11:20:04 -040034 builder.add(path, op);
35 }
kjlubicke5654502016-07-19 16:50:03 -070036
Kevin Lubick0a5152e2018-10-11 11:20:04 -040037 SkPath result;
38 builder.resolve(&result);
39 break;
40 }
41 case 1: {
42 SkPath path;
43 FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb);
Mike Reed7d34dc72019-11-26 12:17:17 -050044 SkPathFillType ft;
45 fuzz->nextRange(&ft, 0, (int)SkPathFillType::kInverseEvenOdd);
Kevin Lubick0a5152e2018-10-11 11:20:04 -040046 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);
Mike Reed7d34dc72019-11-26 12:17:17 -050060 SkPathFillType ft;
61 fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd);
Kevin Lubick0a5152e2018-10-11 11:20:04 -040062 path.setFillType(ft);
63
64 SkPath path2;
65 FuzzEvilPath(fuzz, &path2, SkPath::Verb::kDone_Verb);
Mike Reed7d34dc72019-11-26 12:17:17 -050066 fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd);
Kevin Lubick0a5152e2018-10-11 11:20:04 -040067 path.setFillType(ft);
68
69 SkPathOp op;
Mike Kleinf88f5ef2018-11-19 12:21:46 -050070 fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp);
Kevin Lubick0a5152e2018-10-11 11:20:04 -040071
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);
Mike Reed7d34dc72019-11-26 12:17:17 -050086 SkPathFillType ft;
87 fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd);
Kevin Lubick0a5152e2018-10-11 11:20:04 -040088 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);
Mike Reed7d34dc72019-11-26 12:17:17 -0500102 SkPathFillType ft;
103 fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd);
Kevin Lubick0a5152e2018-10-11 11:20:04 -0400104 path.setFillType(ft);
105
106 SkRect result;
107 TightBounds(path, &result);
108 break;
109 }
110 default: {
111 SkASSERT(false);
112 break;
113 }
114 }
kjlubicke5654502016-07-19 16:50:03 -0700115}
Kevin Lubickf84ded22018-10-23 09:28:48 -0400116
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}