xref: /aosp_15_r20/external/skia/fuzz/FuzzCommon.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 #include "include/core/SkColorFilter.h"
11 #include "include/core/SkData.h"
12 #include "include/effects/SkBlenders.h"
13 #include "src/core/SkPathPriv.h"
14 
15 using namespace skia_private;
16 
17 // We don't always want to test NaNs and infinities.
fuzz_nice_float(Fuzz * fuzz,float * f)18 static void fuzz_nice_float(Fuzz* fuzz, float* f) {
19     float v;
20     fuzz->next(&v);
21     constexpr float kLimit = 1.0e35f;  // FLT_MAX?
22     *f = (v == v && v <= kLimit && v >= -kLimit) ? v : 0.0f;
23 }
24 
25 template <typename... Args>
fuzz_nice_float(Fuzz * fuzz,float * f,Args...rest)26 static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
27     fuzz_nice_float(fuzz, f);
28     fuzz_nice_float(fuzz, rest...);
29 }
30 
fuzz_nice_rect(Fuzz * fuzz,SkRect * r)31 static void fuzz_nice_rect(Fuzz* fuzz, SkRect* r) {
32     fuzz_nice_float(fuzz, &r->fLeft, &r->fTop, &r->fRight, &r->fBottom);
33     r->sort();
34 }
35 
36 // allows some float values for path points
FuzzNicePath(Fuzz * fuzz,SkPath * path,int maxOps)37 void FuzzNicePath(Fuzz* fuzz, SkPath* path, int maxOps) {
38     if (maxOps <= 0 || fuzz->exhausted() || path->countPoints() > 100000) {
39         return;
40     }
41     uint8_t fillType;
42     fuzz->nextRange(&fillType, 0, (uint8_t)SkPathFillType::kInverseEvenOdd);
43     path->setFillType((SkPathFillType)fillType);
44     uint8_t numOps;
45     fuzz->nextRange(&numOps, 0, maxOps);
46     for (uint8_t i = 0; i < numOps; ++i) {
47         // When we start adding the path to itself, the fuzzer can make an
48         // exponentially long path, which causes timeouts.
49         if (path->countPoints() > 100000) {
50             return;
51         }
52         // How many items in the switch statement below.
53         constexpr uint8_t MAX_PATH_OPERATION = 32;
54         uint8_t op;
55         fuzz->nextRange(&op, 0, MAX_PATH_OPERATION);
56         bool test;
57         SkPath p;
58         SkMatrix m;
59         SkRRect rr;
60         SkRect r;
61         SkPathDirection dir;
62         unsigned int ui;
63         SkScalar a, b, c, d, e, f;
64         switch (op) {
65             case 0:
66                 fuzz_nice_float(fuzz, &a, &b);
67                 path->moveTo(a, b);
68                 break;
69             case 1:
70                 fuzz_nice_float(fuzz, &a, &b);
71                 path->rMoveTo(a, b);
72                 break;
73             case 2:
74                 fuzz_nice_float(fuzz, &a, &b);
75                 path->lineTo(a, b);
76                 break;
77             case 3:
78                 fuzz_nice_float(fuzz, &a, &b);
79                 path->rLineTo(a, b);
80                 break;
81             case 4:
82                 fuzz_nice_float(fuzz, &a, &b, &c, &d);
83                 path->quadTo(a, b, c, d);
84                 break;
85             case 5:
86                 fuzz_nice_float(fuzz, &a, &b, &c, &d);
87                 path->rQuadTo(a, b, c, d);
88                 break;
89             case 6:
90                 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
91                 path->conicTo(a, b, c, d, e);
92                 break;
93             case 7:
94                 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
95                 path->rConicTo(a, b, c, d, e);
96                 break;
97             case 8:
98                 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f);
99                 path->cubicTo(a, b, c, d, e, f);
100                 break;
101             case 9:
102                 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f);
103                 path->rCubicTo(a, b, c, d, e, f);
104                 break;
105             case 10:
106                 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
107                 path->arcTo(a, b, c, d, e);
108                 break;
109             case 11:
110                 fuzz_nice_float(fuzz, &a, &b);
111                 fuzz_nice_rect(fuzz, &r);
112                 fuzz->next(&test);
113                 path->arcTo(r, a, b, test);
114                 break;
115             case 12:
116                 path->close();
117                 break;
118             case 13:
119                 fuzz_nice_rect(fuzz, &r);
120                 fuzz->nextRange(&ui, 0, 1);
121                 dir = static_cast<SkPathDirection>(ui);
122                 path->addRect(r, dir);
123                 break;
124             case 14:
125                 fuzz->nextRange(&ui, 0, 1);
126                 dir = static_cast<SkPathDirection>(ui);
127                 fuzz_nice_rect(fuzz, &r);
128                 fuzz->next(&ui);
129                 path->addRect(r, dir, ui);
130                 break;
131             case 15:
132                 fuzz->nextRange(&ui, 0, 1);
133                 dir = static_cast<SkPathDirection>(ui);
134                 fuzz_nice_rect(fuzz, &r);
135                 path->addOval(r, dir);
136                 break;
137             case 16:
138                 fuzz->nextRange(&ui, 0, 1);
139                 dir = static_cast<SkPathDirection>(ui);
140                 fuzz_nice_rect(fuzz, &r);
141                 fuzz->next(&ui);
142                 path->addOval(r, dir, ui);
143                 break;
144             case 17:
145                 fuzz->nextRange(&ui, 0, 1);
146                 dir = static_cast<SkPathDirection>(ui);
147                 fuzz_nice_float(fuzz, &a, &b, &c);
148                 path->addCircle(a, b, c, dir);
149                 break;
150             case 18:
151                 fuzz_nice_rect(fuzz, &r);
152                 fuzz_nice_float(fuzz, &a, &b);
153                 path->addArc(r, a, b);
154                 break;
155             case 19:
156                 fuzz_nice_float(fuzz, &a, &b);
157                 fuzz_nice_rect(fuzz, &r);
158                 fuzz->nextRange(&ui, 0, 1);
159                 dir = static_cast<SkPathDirection>(ui);
160                 path->addRoundRect(r, a, b, dir);
161                 break;
162             case 20:
163                 FuzzNiceRRect(fuzz, &rr);
164                 fuzz->nextRange(&ui, 0, 1);
165                 dir = static_cast<SkPathDirection>(ui);
166                 path->addRRect(rr, dir);
167                 break;
168             case 21:
169                 fuzz->nextRange(&ui, 0, 1);
170                 dir = static_cast<SkPathDirection>(ui);
171                 FuzzNiceRRect(fuzz, &rr);
172                 path->addRRect(rr, dir, ui);
173                 break;
174             case 22: {
175                 fuzz->nextRange(&ui, 0, 1);
176                 SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui);
177                 FuzzNiceMatrix(fuzz, &m);
178                 FuzzNicePath(fuzz, &p, maxOps-1);
179                 path->addPath(p, m, mode);
180                 break;
181             }
182             case 23: {
183                 fuzz->nextRange(&ui, 0, 1);
184                 SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui);
185                 FuzzNiceMatrix(fuzz, &m);
186                 path->addPath(*path, m, mode);
187                 break;
188             }
189             case 24:
190                 FuzzNicePath(fuzz, &p, maxOps-1);
191                 path->reverseAddPath(p);
192                 break;
193             case 25:
194                 path->addPath(*path);
195                 break;
196             case 26:
197                 path->reverseAddPath(*path);
198                 break;
199             case 27:
200                 fuzz_nice_float(fuzz, &a, &b);
201                 path->offset(a, b, path);
202                 break;
203             case 28:
204                 FuzzNicePath(fuzz, &p, maxOps-1);
205                 fuzz_nice_float(fuzz, &a, &b);
206                 p.offset(a, b, path);
207                 break;
208             case 29:
209                 FuzzNiceMatrix(fuzz, &m);
210                 path->transform(m, path);
211                 break;
212             case 30:
213                 FuzzNicePath(fuzz, &p, maxOps-1);
214                 // transform can explode path sizes so skip this op if p too big
215                 if (p.countPoints() <= 100000) {
216                     FuzzNiceMatrix(fuzz, &m);
217                     p.transform(m, path);
218                 }
219                 break;
220             case 31:
221                 fuzz_nice_float(fuzz, &a, &b);
222                 path->setLastPt(a, b);
223                 break;
224             case MAX_PATH_OPERATION:
225                 SkPathPriv::ShrinkToFit(path);
226                 break;
227 
228             default:
229                 SkASSERT(false);
230                 break;
231         }
232         SkASSERTF(       path->isValid(),        "path->isValid() failed at op %d, case %d", i, op);
233     }
234 }
235 
236 // allows all float values for path points
FuzzEvilPath(Fuzz * fuzz,SkPath * path,int last_verb)237 void FuzzEvilPath(Fuzz* fuzz, SkPath* path, int last_verb) {
238   while (!fuzz->exhausted()) {
239     // Use a uint8_t to conserve bytes.  This makes our "fuzzed bytes footprint"
240     // smaller, which leads to more efficient fuzzing.
241     uint8_t operation;
242     fuzz->next(&operation);
243     SkScalar a,b,c,d,e,f;
244 
245     switch (operation % (last_verb + 1)) {
246       case SkPath::Verb::kMove_Verb:
247         fuzz->next(&a, &b);
248         path->moveTo(a, b);
249         break;
250 
251       case SkPath::Verb::kLine_Verb:
252         fuzz->next(&a, &b);
253         path->lineTo(a, b);
254         break;
255 
256       case SkPath::Verb::kQuad_Verb:
257         fuzz->next(&a, &b, &c, &d);
258         path->quadTo(a, b, c, d);
259         break;
260 
261       case SkPath::Verb::kConic_Verb:
262         fuzz->next(&a, &b, &c, &d, &e);
263         path->conicTo(a, b, c, d, e);
264         break;
265 
266       case SkPath::Verb::kCubic_Verb:
267         fuzz->next(&a, &b, &c, &d, &e, &f);
268         path->cubicTo(a, b, c, d, e, f);
269         break;
270 
271       case SkPath::Verb::kClose_Verb:
272         path->close();
273         break;
274 
275       case SkPath::Verb::kDone_Verb:
276         // In this case, simply exit.
277         return;
278     }
279   }
280 }
281 
FuzzNiceRRect(Fuzz * fuzz,SkRRect * rr)282 void FuzzNiceRRect(Fuzz* fuzz, SkRRect* rr) {
283     SkRect r;
284     fuzz_nice_rect(fuzz, &r);
285 
286     SkVector radii[4];
287     for (SkVector& vec : radii) {
288         fuzz->nextRange(&vec.fX, 0.0f, 1.0f);
289         vec.fX *= 0.5f * r.width();
290         fuzz->nextRange(&vec.fY, 0.0f, 1.0f);
291         vec.fY *= 0.5f * r.height();
292     }
293     rr->setRectRadii(r, radii);
294     SkASSERT(rr->isValid());
295 }
296 
FuzzNiceMatrix(Fuzz * fuzz,SkMatrix * m)297 void FuzzNiceMatrix(Fuzz* fuzz, SkMatrix* m) {
298     constexpr int kArrayLength = 9;
299     SkScalar buffer[kArrayLength];
300     int matrixType;
301     fuzz->nextRange(&matrixType, 0, 4);
302     switch (matrixType) {
303         case 0:  // identity
304             *m = SkMatrix::I();
305             return;
306         case 1:  // translate
307             fuzz->nextRange(&buffer[0], -4000.0f, 4000.0f);
308             fuzz->nextRange(&buffer[1], -4000.0f, 4000.0f);
309             *m = SkMatrix::Translate(buffer[0], buffer[1]);
310             return;
311         case 2:  // translate + scale
312             fuzz->nextRange(&buffer[0], -400.0f, 400.0f);
313             fuzz->nextRange(&buffer[1], -400.0f, 400.0f);
314             fuzz->nextRange(&buffer[2], -4000.0f, 4000.0f);
315             fuzz->nextRange(&buffer[3], -4000.0f, 4000.0f);
316             *m = SkMatrix::Scale(buffer[0], buffer[1]);
317             m->postTranslate(buffer[2], buffer[3]);
318             return;
319         case 3:  // affine
320             fuzz->nextN(buffer, 6);
321             m->setAffine(buffer);
322             return;
323         case 4:  // perspective
324             fuzz->nextN(buffer, kArrayLength);
325             m->set9(buffer);
326             return;
327         default:
328             SkASSERT(false);
329             return;
330     }
331 }
332 
FuzzNiceRegion(Fuzz * fuzz,SkRegion * region,int maxN)333 void FuzzNiceRegion(Fuzz* fuzz, SkRegion* region, int maxN) {
334     uint8_t N;
335     fuzz->nextRange(&N, 0, maxN);
336     for (uint8_t i = 0; i < N; ++i) {
337         SkIRect r;
338         SkRegion::Op op;
339         // Avoid the sentinel value used by Region.
340         fuzz->nextRange(&r.fLeft,   -2147483646, 2147483646);
341         fuzz->nextRange(&r.fTop,    -2147483646, 2147483646);
342         fuzz->nextRange(&r.fRight,  -2147483646, 2147483646);
343         fuzz->nextRange(&r.fBottom, -2147483646, 2147483646);
344         r.sort();
345         fuzz->nextEnum(&op, SkRegion::kLastOp);
346         if (!region->op(r, op)) {
347             return;
348         }
349     }
350 }
351 
FuzzCreateValidInputsForRuntimeEffect(SkRuntimeEffect * effect,sk_sp<SkData> & uniformBytes,TArray<SkRuntimeEffect::ChildPtr> & children)352 void FuzzCreateValidInputsForRuntimeEffect(SkRuntimeEffect* effect,
353                                            sk_sp<SkData>& uniformBytes,
354                                            TArray<SkRuntimeEffect::ChildPtr>& children) {
355     // Create storage for our uniforms.
356     uniformBytes = SkData::MakeZeroInitialized(effect->uniformSize());
357     void* uniformData = uniformBytes->writable_data();
358 
359     for (const SkRuntimeEffect::Uniform& u : effect->uniforms()) {
360         // We treat scalars, vectors, matrices and arrays the same. We just figure out how many
361         // uniform slots need to be filled, and write consecutive numbers into those slots.
362         static_assert(sizeof(int) == 4 && sizeof(float) == 4);
363         size_t numFields = u.sizeInBytes() / 4;
364 
365         if (u.type == SkRuntimeEffect::Uniform::Type::kInt ||
366             u.type == SkRuntimeEffect::Uniform::Type::kInt2 ||
367             u.type == SkRuntimeEffect::Uniform::Type::kInt3 ||
368             u.type == SkRuntimeEffect::Uniform::Type::kInt4) {
369             int intVal = 0;
370             while (numFields--) {
371                 // Assign increasing integer values to each slot (0, 1, 2, ...).
372                 *static_cast<int*>(uniformData) = intVal++;
373                 uniformData = static_cast<int*>(uniformData) + 1;
374             }
375         } else {
376             float floatVal = 0.0f;
377             while (numFields--) {
378                 // Assign increasing float values to each slot (0.0, 1.0, 2.0, ...).
379                 *static_cast<float*>(uniformData) = floatVal++;
380                 uniformData = static_cast<float*>(uniformData) + 1;
381             }
382         }
383     }
384 
385     // Create valid children for any requested child effects.
386     children.clear();
387     children.reserve(effect->children().size());
388     for (const SkRuntimeEffect::Child& c : effect->children()) {
389         switch (c.type) {
390             case SkRuntimeEffect::ChildType::kShader:
391                 children.push_back(SkShaders::Color(SK_ColorRED));
392                 break;
393             case SkRuntimeEffect::ChildType::kColorFilter:
394                 children.push_back(SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kModulate));
395                 break;
396             case SkRuntimeEffect::ChildType::kBlender:
397                 children.push_back(SkBlenders::Arithmetic(0.50f, 0.25f, 0.10f, 0.05f, false));
398                 break;
399         }
400     }
401 }
402