/src/skia/fuzz/FuzzCommon.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2018 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 | | |
11 | | // We don't always want to test NaNs and infinities. |
12 | 3.59M | static void fuzz_nice_float(Fuzz* fuzz, float* f) { |
13 | 3.59M | float v; |
14 | 3.59M | fuzz->next(&v); |
15 | 3.59M | constexpr float kLimit = 1.0e35f; // FLT_MAX? |
16 | 3.59M | *f = (v == v && v <= kLimit && v >= -kLimit) ? v : 0.0f; |
17 | 3.59M | } |
18 | | |
19 | | template <typename... Args> |
20 | 2.03M | static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) { |
21 | 2.03M | fuzz_nice_float(fuzz, f); |
22 | 2.03M | fuzz_nice_float(fuzz, rest...); |
23 | 2.03M | } FuzzCommon.cpp:void fuzz_nice_float<float*, float*, float*>(Fuzz*, float*, float*, float*, float*) Line | Count | Source | 20 | 201k | static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) { | 21 | 201k | fuzz_nice_float(fuzz, f); | 22 | 201k | fuzz_nice_float(fuzz, rest...); | 23 | 201k | } |
FuzzCommon.cpp:void fuzz_nice_float<float*>(Fuzz*, float*, float*) Line | Count | Source | 20 | 1.55M | static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) { | 21 | 1.55M | fuzz_nice_float(fuzz, f); | 22 | 1.55M | fuzz_nice_float(fuzz, rest...); | 23 | 1.55M | } |
FuzzCommon.cpp:void fuzz_nice_float<float*, float*, float*, float*>(Fuzz*, float*, float*, float*, float*, float*) Line | Count | Source | 20 | 48.4k | static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) { | 21 | 48.4k | fuzz_nice_float(fuzz, f); | 22 | 48.4k | fuzz_nice_float(fuzz, rest...); | 23 | 48.4k | } |
FuzzCommon.cpp:void fuzz_nice_float<float*, float*, float*, float*, float*>(Fuzz*, float*, float*, float*, float*, float*, float*) Line | Count | Source | 20 | 21.8k | static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) { | 21 | 21.8k | fuzz_nice_float(fuzz, f); | 22 | 21.8k | fuzz_nice_float(fuzz, rest...); | 23 | 21.8k | } |
FuzzCommon.cpp:void fuzz_nice_float<float*, float*>(Fuzz*, float*, float*, float*) Line | Count | Source | 20 | 207k | static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) { | 21 | 207k | fuzz_nice_float(fuzz, f); | 22 | 207k | fuzz_nice_float(fuzz, rest...); | 23 | 207k | } |
|
24 | | |
25 | 126k | static void fuzz_nice_rect(Fuzz* fuzz, SkRect* r) { |
26 | 126k | fuzz_nice_float(fuzz, &r->fLeft, &r->fTop, &r->fRight, &r->fBottom); |
27 | 126k | r->sort(); |
28 | 126k | } |
29 | | |
30 | | // allows some float values for path points |
31 | 207k | void FuzzNicePath(Fuzz* fuzz, SkPath* path, int maxOps) { |
32 | 207k | if (maxOps <= 0 || fuzz->exhausted() || path->countPoints() > 100000) { |
33 | 5.51k | return; |
34 | 5.51k | } |
35 | 202k | uint8_t fillType; |
36 | 202k | fuzz->nextRange(&fillType, 0, (uint8_t)SkPathFillType::kInverseEvenOdd); |
37 | 202k | path->setFillType((SkPathFillType)fillType); |
38 | 202k | uint8_t numOps; |
39 | 202k | fuzz->nextRange(&numOps, 0, maxOps); |
40 | 3.09M | for (uint8_t i = 0; i < numOps; ++i) { |
41 | | // When we start adding the path to itself, the fuzzer can make an |
42 | | // exponentially long path, which causes timeouts. |
43 | 2.89M | if (path->countPoints() > 100000) { |
44 | 1.99k | return; |
45 | 1.99k | } |
46 | | // How many items in the switch statement below. |
47 | 2.89M | constexpr uint8_t PATH_OPERATIONS = 32; |
48 | 2.89M | uint8_t op; |
49 | 2.89M | fuzz->nextRange(&op, 0, PATH_OPERATIONS); |
50 | 2.89M | bool test; |
51 | 2.89M | SkPath p; |
52 | 2.89M | SkMatrix m; |
53 | 2.89M | SkRRect rr; |
54 | 2.89M | SkRect r; |
55 | 2.89M | SkPathDirection dir; |
56 | 2.89M | unsigned int ui; |
57 | 2.89M | SkScalar a, b, c, d, e, f; |
58 | 2.89M | switch (op) { |
59 | 1.20M | case 0: |
60 | 1.20M | fuzz_nice_float(fuzz, &a, &b); |
61 | 1.20M | path->moveTo(a, b); |
62 | 1.20M | break; |
63 | 29.4k | case 1: |
64 | 29.4k | fuzz_nice_float(fuzz, &a, &b); |
65 | 29.4k | path->rMoveTo(a, b); |
66 | 29.4k | break; |
67 | 15.3k | case 2: |
68 | 15.3k | fuzz_nice_float(fuzz, &a, &b); |
69 | 15.3k | path->lineTo(a, b); |
70 | 15.3k | break; |
71 | 13.8k | case 3: |
72 | 13.8k | fuzz_nice_float(fuzz, &a, &b); |
73 | 13.8k | path->rLineTo(a, b); |
74 | 13.8k | break; |
75 | 6.32k | case 4: |
76 | 6.32k | fuzz_nice_float(fuzz, &a, &b, &c, &d); |
77 | 6.32k | path->quadTo(a, b, c, d); |
78 | 6.32k | break; |
79 | 19.7k | case 5: |
80 | 19.7k | fuzz_nice_float(fuzz, &a, &b, &c, &d); |
81 | 19.7k | path->rQuadTo(a, b, c, d); |
82 | 19.7k | break; |
83 | 8.22k | case 6: |
84 | 8.22k | fuzz_nice_float(fuzz, &a, &b, &c, &d, &e); |
85 | 8.22k | path->conicTo(a, b, c, d, e); |
86 | 8.22k | break; |
87 | 8.72k | case 7: |
88 | 8.72k | fuzz_nice_float(fuzz, &a, &b, &c, &d, &e); |
89 | 8.72k | path->rConicTo(a, b, c, d, e); |
90 | 8.72k | break; |
91 | 17.2k | case 8: |
92 | 17.2k | fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f); |
93 | 17.2k | path->cubicTo(a, b, c, d, e, f); |
94 | 17.2k | break; |
95 | 4.64k | case 9: |
96 | 4.64k | fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f); |
97 | 4.64k | path->rCubicTo(a, b, c, d, e, f); |
98 | 4.64k | break; |
99 | 9.64k | case 10: |
100 | 9.64k | fuzz_nice_float(fuzz, &a, &b, &c, &d, &e); |
101 | 9.64k | path->arcTo(a, b, c, d, e); |
102 | 9.64k | break; |
103 | 23.0k | case 11: |
104 | 23.0k | fuzz_nice_float(fuzz, &a, &b); |
105 | 23.0k | fuzz_nice_rect(fuzz, &r); |
106 | 23.0k | fuzz->next(&test); |
107 | 23.0k | path->arcTo(r, a, b, test); |
108 | 23.0k | break; |
109 | 19.4k | case 12: |
110 | 19.4k | path->close(); |
111 | 19.4k | break; |
112 | 6.26k | case 13: |
113 | 6.26k | fuzz_nice_rect(fuzz, &r); |
114 | 6.26k | fuzz->nextRange(&ui, 0, 1); |
115 | 6.26k | dir = static_cast<SkPathDirection>(ui); |
116 | 6.26k | path->addRect(r, dir); |
117 | 6.26k | break; |
118 | 2.43k | case 14: |
119 | 2.43k | fuzz->nextRange(&ui, 0, 1); |
120 | 2.43k | dir = static_cast<SkPathDirection>(ui); |
121 | 2.43k | fuzz_nice_rect(fuzz, &r); |
122 | 2.43k | fuzz->next(&ui); |
123 | 2.43k | path->addRect(r, dir, ui); |
124 | 2.43k | break; |
125 | 8.54k | case 15: |
126 | 8.54k | fuzz->nextRange(&ui, 0, 1); |
127 | 8.54k | dir = static_cast<SkPathDirection>(ui); |
128 | 8.54k | fuzz_nice_rect(fuzz, &r); |
129 | 8.54k | path->addOval(r, dir); |
130 | 8.54k | break; |
131 | 13.2k | case 16: |
132 | 13.2k | fuzz->nextRange(&ui, 0, 1); |
133 | 13.2k | dir = static_cast<SkPathDirection>(ui); |
134 | 13.2k | fuzz_nice_rect(fuzz, &r); |
135 | 13.2k | fuzz->next(&ui); |
136 | 13.2k | path->addOval(r, dir, ui); |
137 | 13.2k | break; |
138 | 6.68k | case 17: |
139 | 6.68k | fuzz->nextRange(&ui, 0, 1); |
140 | 6.68k | dir = static_cast<SkPathDirection>(ui); |
141 | 6.68k | fuzz_nice_float(fuzz, &a, &b, &c); |
142 | 6.68k | path->addCircle(a, b, c, dir); |
143 | 6.68k | break; |
144 | 8.48k | case 18: |
145 | 8.48k | fuzz_nice_rect(fuzz, &r); |
146 | 8.48k | fuzz_nice_float(fuzz, &a, &b); |
147 | 8.48k | path->addArc(r, a, b); |
148 | 8.48k | break; |
149 | 16.1k | case 19: |
150 | 16.1k | fuzz_nice_float(fuzz, &a, &b); |
151 | 16.1k | fuzz_nice_rect(fuzz, &r); |
152 | 16.1k | fuzz->nextRange(&ui, 0, 1); |
153 | 16.1k | dir = static_cast<SkPathDirection>(ui); |
154 | 16.1k | path->addRoundRect(r, a, b, dir); |
155 | 16.1k | break; |
156 | 5.21k | case 20: |
157 | 5.21k | FuzzNiceRRect(fuzz, &rr); |
158 | 5.21k | fuzz->nextRange(&ui, 0, 1); |
159 | 5.21k | dir = static_cast<SkPathDirection>(ui); |
160 | 5.21k | path->addRRect(rr, dir); |
161 | 5.21k | break; |
162 | 15.4k | case 21: |
163 | 15.4k | fuzz->nextRange(&ui, 0, 1); |
164 | 15.4k | dir = static_cast<SkPathDirection>(ui); |
165 | 15.4k | FuzzNiceRRect(fuzz, &rr); |
166 | 15.4k | path->addRRect(rr, dir, ui); |
167 | 15.4k | break; |
168 | 7.13k | case 22: { |
169 | 7.13k | fuzz->nextRange(&ui, 0, 1); |
170 | 7.13k | SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui); |
171 | 7.13k | FuzzNiceMatrix(fuzz, &m); |
172 | 7.13k | FuzzNicePath(fuzz, &p, maxOps-1); |
173 | 7.13k | path->addPath(p, m, mode); |
174 | 7.13k | break; |
175 | 0 | } |
176 | 8.46k | case 23: { |
177 | 8.46k | fuzz->nextRange(&ui, 0, 1); |
178 | 8.46k | SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui); |
179 | 8.46k | FuzzNiceMatrix(fuzz, &m); |
180 | 8.46k | path->addPath(*path, m, mode); |
181 | 8.46k | break; |
182 | 0 | } |
183 | 85.1k | case 24: |
184 | 85.1k | FuzzNicePath(fuzz, &p, maxOps-1); |
185 | 85.1k | path->reverseAddPath(p); |
186 | 85.1k | break; |
187 | 22.3k | case 25: |
188 | 22.3k | path->addPath(*path); |
189 | 22.3k | break; |
190 | 29.4k | case 26: |
191 | 29.4k | path->reverseAddPath(*path); |
192 | 29.4k | break; |
193 | 9.73k | case 27: |
194 | 9.73k | fuzz_nice_float(fuzz, &a, &b); |
195 | 9.73k | path->offset(a, b, path); |
196 | 9.73k | break; |
197 | 21.3k | case 28: |
198 | 21.3k | FuzzNicePath(fuzz, &p, maxOps-1); |
199 | 21.3k | fuzz_nice_float(fuzz, &a, &b); |
200 | 21.3k | p.offset(a, b, path); |
201 | 21.3k | break; |
202 | 9.51k | case 29: |
203 | 9.51k | FuzzNiceMatrix(fuzz, &m); |
204 | 9.51k | path->transform(m, path); |
205 | 9.51k | break; |
206 | 29.8k | case 30: |
207 | 29.8k | FuzzNicePath(fuzz, &p, maxOps-1); |
208 | 29.8k | FuzzNiceMatrix(fuzz, &m); |
209 | 29.8k | p.transform(m, path); |
210 | 29.8k | break; |
211 | 4.39k | case 31: |
212 | 4.39k | fuzz_nice_float(fuzz, &a, &b); |
213 | 4.39k | path->setLastPt(a, b); |
214 | 4.39k | break; |
215 | | |
216 | 1.19M | default: |
217 | 1.19M | SkASSERT(false); |
218 | 1.19M | break; |
219 | 2.89M | } |
220 | 2.89M | SkASSERTF( path->isValid(), "path->isValid() failed at op %d, case %d", i, op); |
221 | 2.89M | } |
222 | 202k | } |
223 | | |
224 | | // allows all float values for path points |
225 | 27.7k | void FuzzEvilPath(Fuzz* fuzz, SkPath* path, int last_verb) { |
226 | 373k | while (!fuzz->exhausted()) { |
227 | | // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" |
228 | | // smaller, which leads to more efficient fuzzing. |
229 | 360k | uint8_t operation; |
230 | 360k | fuzz->next(&operation); |
231 | 360k | SkScalar a,b,c,d,e,f; |
232 | | |
233 | 360k | switch (operation % (last_verb + 1)) { |
234 | 26.1k | case SkPath::Verb::kMove_Verb: |
235 | 26.1k | fuzz->next(&a, &b); |
236 | 26.1k | path->moveTo(a, b); |
237 | 26.1k | break; |
238 | | |
239 | 72.8k | case SkPath::Verb::kLine_Verb: |
240 | 72.8k | fuzz->next(&a, &b); |
241 | 72.8k | path->lineTo(a, b); |
242 | 72.8k | break; |
243 | | |
244 | 33.3k | case SkPath::Verb::kQuad_Verb: |
245 | 33.3k | fuzz->next(&a, &b, &c, &d); |
246 | 33.3k | path->quadTo(a, b, c, d); |
247 | 33.3k | break; |
248 | | |
249 | 28.9k | case SkPath::Verb::kConic_Verb: |
250 | 28.9k | fuzz->next(&a, &b, &c, &d, &e); |
251 | 28.9k | path->conicTo(a, b, c, d, e); |
252 | 28.9k | break; |
253 | | |
254 | 19.7k | case SkPath::Verb::kCubic_Verb: |
255 | 19.7k | fuzz->next(&a, &b, &c, &d, &e, &f); |
256 | 19.7k | path->cubicTo(a, b, c, d, e, f); |
257 | 19.7k | break; |
258 | | |
259 | 164k | case SkPath::Verb::kClose_Verb: |
260 | 164k | path->close(); |
261 | 164k | break; |
262 | | |
263 | 14.8k | case SkPath::Verb::kDone_Verb: |
264 | | // In this case, simply exit. |
265 | 14.8k | return; |
266 | 360k | } |
267 | 360k | } |
268 | 27.7k | } |
269 | | |
270 | 48.2k | void FuzzNiceRRect(Fuzz* fuzz, SkRRect* rr) { |
271 | 48.2k | SkRect r; |
272 | 48.2k | fuzz_nice_rect(fuzz, &r); |
273 | | |
274 | 48.2k | SkVector radii[4]; |
275 | 193k | for (SkVector& vec : radii) { |
276 | 193k | fuzz->nextRange(&vec.fX, 0.0f, 1.0f); |
277 | 193k | vec.fX *= 0.5f * r.width(); |
278 | 193k | fuzz->nextRange(&vec.fY, 0.0f, 1.0f); |
279 | 193k | vec.fY *= 0.5f * r.height(); |
280 | 193k | } |
281 | 48.2k | rr->setRectRadii(r, radii); |
282 | 48.2k | SkASSERT(rr->isValid()); |
283 | 48.2k | } |
284 | | |
285 | 127k | void FuzzNiceMatrix(Fuzz* fuzz, SkMatrix* m) { |
286 | 127k | constexpr int kArrayLength = 9; |
287 | 127k | SkScalar buffer[kArrayLength]; |
288 | 127k | int matrixType; |
289 | 127k | fuzz->nextRange(&matrixType, 0, 4); |
290 | 127k | switch (matrixType) { |
291 | 57.4k | case 0: // identity |
292 | 57.4k | *m = SkMatrix::I(); |
293 | 57.4k | return; |
294 | 1.30k | case 1: // translate |
295 | 1.30k | fuzz->nextRange(&buffer[0], -4000.0f, 4000.0f); |
296 | 1.30k | fuzz->nextRange(&buffer[1], -4000.0f, 4000.0f); |
297 | 1.30k | *m = SkMatrix::Translate(buffer[0], buffer[1]); |
298 | 1.30k | return; |
299 | 2.83k | case 2: // translate + scale |
300 | 2.83k | fuzz->nextRange(&buffer[0], -400.0f, 400.0f); |
301 | 2.83k | fuzz->nextRange(&buffer[1], -400.0f, 400.0f); |
302 | 2.83k | fuzz->nextRange(&buffer[2], -4000.0f, 4000.0f); |
303 | 2.83k | fuzz->nextRange(&buffer[3], -4000.0f, 4000.0f); |
304 | 2.83k | *m = SkMatrix::Scale(buffer[0], buffer[1]); |
305 | 2.83k | m->postTranslate(buffer[2], buffer[3]); |
306 | 2.83k | return; |
307 | 1.23k | case 3: // affine |
308 | 1.23k | fuzz->nextN(buffer, 6); |
309 | 1.23k | m->setAffine(buffer); |
310 | 1.23k | return; |
311 | 64.8k | case 4: // perspective |
312 | 64.8k | fuzz->nextN(buffer, kArrayLength); |
313 | 64.8k | m->set9(buffer); |
314 | 64.8k | return; |
315 | 0 | default: |
316 | 0 | SkASSERT(false); |
317 | 0 | return; |
318 | 127k | } |
319 | 127k | } |
320 | | |
321 | 50.1k | void FuzzNiceRegion(Fuzz* fuzz, SkRegion* region, int maxN) { |
322 | 50.1k | uint8_t N; |
323 | 50.1k | fuzz->nextRange(&N, 0, maxN); |
324 | 199k | for (uint8_t i = 0; i < N; ++i) { |
325 | 155k | SkIRect r; |
326 | 155k | SkRegion::Op op; |
327 | | // Avoid the sentinel value used by Region. |
328 | 155k | fuzz->nextRange(&r.fLeft, -2147483646, 2147483646); |
329 | 155k | fuzz->nextRange(&r.fTop, -2147483646, 2147483646); |
330 | 155k | fuzz->nextRange(&r.fRight, -2147483646, 2147483646); |
331 | 155k | fuzz->nextRange(&r.fBottom, -2147483646, 2147483646); |
332 | 155k | r.sort(); |
333 | 155k | fuzz->nextEnum(&op, SkRegion::kLastOp); |
334 | 155k | if (!region->op(r, op)) { |
335 | 6.14k | return; |
336 | 6.14k | } |
337 | 155k | } |
338 | 50.1k | } |