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.h"
9 #include "FuzzCommon.h"
10 #include "SkPath.h"
11 #include "SkPathOps.h"
12 #include "SkRect.h"
13
14 const uint8_t MAX_OPS = 20;
15
DEF_FUZZ(Pathop,fuzz)16 DEF_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 SkPath::FillType ft;
29 fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
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 SkPath::FillType ft;
45 fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
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 SkPath::FillType ft;
61 fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
62 path.setFillType(ft);
63
64 SkPath path2;
65 FuzzEvilPath(fuzz, &path2, SkPath::Verb::kDone_Verb);
66 fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
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 SkPath::FillType ft;
87 fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
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 SkPath::FillType ft;
103 fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType);
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
118 const int kLastOp = SkPathOp::kReverseDifference_SkPathOp;
119
BuildPath(Fuzz * fuzz,SkPath * path)120 void 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
DEF_FUZZ(LegacyChromiumPathop,fuzz)185 DEF_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