Coverage Report

Created: 2024-09-14 07:19

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