Coverage Report

Created: 2024-05-20 07:14

/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.73M
static void fuzz_nice_float(Fuzz* fuzz, float* f) {
19
3.73M
    float v;
20
3.73M
    fuzz->next(&v);
21
3.73M
    constexpr float kLimit = 1.0e35f;  // FLT_MAX?
22
3.73M
    *f = (v == v && v <= kLimit && v >= -kLimit) ? v : 0.0f;
23
3.73M
}
24
25
template <typename... Args>
26
2.01M
static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
27
2.01M
    fuzz_nice_float(fuzz, f);
28
2.01M
    fuzz_nice_float(fuzz, rest...);
29
2.01M
}
FuzzCommon.cpp:void fuzz_nice_float<float*, float*, float*>(Fuzz*, float*, float*, float*, float*)
Line
Count
Source
26
119k
static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
27
119k
    fuzz_nice_float(fuzz, f);
28
119k
    fuzz_nice_float(fuzz, rest...);
29
119k
}
FuzzCommon.cpp:void fuzz_nice_float<float*>(Fuzz*, float*, float*)
Line
Count
Source
26
1.71M
static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
27
1.71M
    fuzz_nice_float(fuzz, f);
28
1.71M
    fuzz_nice_float(fuzz, rest...);
29
1.71M
}
FuzzCommon.cpp:void fuzz_nice_float<float*, float*, float*, float*>(Fuzz*, float*, float*, float*, float*, float*)
Line
Count
Source
26
37.3k
static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
27
37.3k
    fuzz_nice_float(fuzz, f);
28
37.3k
    fuzz_nice_float(fuzz, rest...);
29
37.3k
}
FuzzCommon.cpp:void fuzz_nice_float<float*, float*, float*, float*, float*>(Fuzz*, float*, float*, float*, float*, float*, float*)
Line
Count
Source
26
17.8k
static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
27
17.8k
    fuzz_nice_float(fuzz, f);
28
17.8k
    fuzz_nice_float(fuzz, rest...);
29
17.8k
}
FuzzCommon.cpp:void fuzz_nice_float<float*, float*>(Fuzz*, float*, float*, float*)
Line
Count
Source
26
127k
static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
27
127k
    fuzz_nice_float(fuzz, f);
28
127k
    fuzz_nice_float(fuzz, rest...);
29
127k
}
30
31
70.2k
static void fuzz_nice_rect(Fuzz* fuzz, SkRect* r) {
32
70.2k
    fuzz_nice_float(fuzz, &r->fLeft, &r->fTop, &r->fRight, &r->fBottom);
33
70.2k
    r->sort();
34
70.2k
}
35
36
// allows some float values for path points
37
102k
void FuzzNicePath(Fuzz* fuzz, SkPath* path, int maxOps) {
38
102k
    if (maxOps <= 0 || fuzz->exhausted() || path->countPoints() > 100000) {
39
3.46k
        return;
40
3.46k
    }
41
98.6k
    uint8_t fillType;
42
98.6k
    fuzz->nextRange(&fillType, 0, (uint8_t)SkPathFillType::kInverseEvenOdd);
43
98.6k
    path->setFillType((SkPathFillType)fillType);
44
98.6k
    uint8_t numOps;
45
98.6k
    fuzz->nextRange(&numOps, 0, maxOps);
46
2.62M
    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.52M
        if (path->countPoints() > 100000) {
50
1.44k
            return;
51
1.44k
        }
52
        // How many items in the switch statement below.
53
2.52M
        constexpr uint8_t MAX_PATH_OPERATION = 32;
54
2.52M
        uint8_t op;
55
2.52M
        fuzz->nextRange(&op, 0, MAX_PATH_OPERATION);
56
2.52M
        bool test;
57
2.52M
        SkPath p;
58
2.52M
        SkMatrix m;
59
2.52M
        SkRRect rr;
60
2.52M
        SkRect r;
61
2.52M
        SkPathDirection dir;
62
2.52M
        unsigned int ui;
63
2.52M
        SkScalar a, b, c, d, e, f;
64
2.52M
        switch (op) {
65
1.47M
            case 0:
66
1.47M
                fuzz_nice_float(fuzz, &a, &b);
67
1.47M
                path->moveTo(a, b);
68
1.47M
                break;
69
19.3k
            case 1:
70
19.3k
                fuzz_nice_float(fuzz, &a, &b);
71
19.3k
                path->rMoveTo(a, b);
72
19.3k
                break;
73
8.68k
            case 2:
74
8.68k
                fuzz_nice_float(fuzz, &a, &b);
75
8.68k
                path->lineTo(a, b);
76
8.68k
                break;
77
10.1k
            case 3:
78
10.1k
                fuzz_nice_float(fuzz, &a, &b);
79
10.1k
                path->rLineTo(a, b);
80
10.1k
                break;
81
5.85k
            case 4:
82
5.85k
                fuzz_nice_float(fuzz, &a, &b, &c, &d);
83
5.85k
                path->quadTo(a, b, c, d);
84
5.85k
                break;
85
5.66k
            case 5:
86
5.66k
                fuzz_nice_float(fuzz, &a, &b, &c, &d);
87
5.66k
                path->rQuadTo(a, b, c, d);
88
5.66k
                break;
89
7.04k
            case 6:
90
7.04k
                fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
91
7.04k
                path->conicTo(a, b, c, d, e);
92
7.04k
                break;
93
5.10k
            case 7:
94
5.10k
                fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
95
5.10k
                path->rConicTo(a, b, c, d, e);
96
5.10k
                break;
97
11.3k
            case 8:
98
11.3k
                fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f);
99
11.3k
                path->cubicTo(a, b, c, d, e, f);
100
11.3k
                break;
101
6.50k
            case 9:
102
6.50k
                fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f);
103
6.50k
                path->rCubicTo(a, b, c, d, e, f);
104
6.50k
                break;
105
7.29k
            case 10:
106
7.29k
                fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
107
7.29k
                path->arcTo(a, b, c, d, e);
108
7.29k
                break;
109
13.4k
            case 11:
110
13.4k
                fuzz_nice_float(fuzz, &a, &b);
111
13.4k
                fuzz_nice_rect(fuzz, &r);
112
13.4k
                fuzz->next(&test);
113
13.4k
                path->arcTo(r, a, b, test);
114
13.4k
                break;
115
15.1k
            case 12:
116
15.1k
                path->close();
117
15.1k
                break;
118
5.61k
            case 13:
119
5.61k
                fuzz_nice_rect(fuzz, &r);
120
5.61k
                fuzz->nextRange(&ui, 0, 1);
121
5.61k
                dir = static_cast<SkPathDirection>(ui);
122
5.61k
                path->addRect(r, dir);
123
5.61k
                break;
124
5.29k
            case 14:
125
5.29k
                fuzz->nextRange(&ui, 0, 1);
126
5.29k
                dir = static_cast<SkPathDirection>(ui);
127
5.29k
                fuzz_nice_rect(fuzz, &r);
128
5.29k
                fuzz->next(&ui);
129
5.29k
                path->addRect(r, dir, ui);
130
5.29k
                break;
131
6.04k
            case 15:
132
6.04k
                fuzz->nextRange(&ui, 0, 1);
133
6.04k
                dir = static_cast<SkPathDirection>(ui);
134
6.04k
                fuzz_nice_rect(fuzz, &r);
135
6.04k
                path->addOval(r, dir);
136
6.04k
                break;
137
5.92k
            case 16:
138
5.92k
                fuzz->nextRange(&ui, 0, 1);
139
5.92k
                dir = static_cast<SkPathDirection>(ui);
140
5.92k
                fuzz_nice_rect(fuzz, &r);
141
5.92k
                fuzz->next(&ui);
142
5.92k
                path->addOval(r, dir, ui);
143
5.92k
                break;
144
8.77k
            case 17:
145
8.77k
                fuzz->nextRange(&ui, 0, 1);
146
8.77k
                dir = static_cast<SkPathDirection>(ui);
147
8.77k
                fuzz_nice_float(fuzz, &a, &b, &c);
148
8.77k
                path->addCircle(a, b, c, dir);
149
8.77k
                break;
150
7.18k
            case 18:
151
7.18k
                fuzz_nice_rect(fuzz, &r);
152
7.18k
                fuzz_nice_float(fuzz, &a, &b);
153
7.18k
                path->addArc(r, a, b);
154
7.18k
                break;
155
10.5k
            case 19:
156
10.5k
                fuzz_nice_float(fuzz, &a, &b);
157
10.5k
                fuzz_nice_rect(fuzz, &r);
158
10.5k
                fuzz->nextRange(&ui, 0, 1);
159
10.5k
                dir = static_cast<SkPathDirection>(ui);
160
10.5k
                path->addRoundRect(r, a, b, dir);
161
10.5k
                break;
162
4.19k
            case 20:
163
4.19k
                FuzzNiceRRect(fuzz, &rr);
164
4.19k
                fuzz->nextRange(&ui, 0, 1);
165
4.19k
                dir = static_cast<SkPathDirection>(ui);
166
4.19k
                path->addRRect(rr, dir);
167
4.19k
                break;
168
6.84k
            case 21:
169
6.84k
                fuzz->nextRange(&ui, 0, 1);
170
6.84k
                dir = static_cast<SkPathDirection>(ui);
171
6.84k
                FuzzNiceRRect(fuzz, &rr);
172
6.84k
                path->addRRect(rr, dir, ui);
173
6.84k
                break;
174
4.35k
            case 22: {
175
4.35k
                fuzz->nextRange(&ui, 0, 1);
176
4.35k
                SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui);
177
4.35k
                FuzzNiceMatrix(fuzz, &m);
178
4.35k
                FuzzNicePath(fuzz, &p, maxOps-1);
179
4.35k
                path->addPath(p, m, mode);
180
4.35k
                break;
181
0
            }
182
7.45k
            case 23: {
183
7.45k
                fuzz->nextRange(&ui, 0, 1);
184
7.45k
                SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui);
185
7.45k
                FuzzNiceMatrix(fuzz, &m);
186
7.45k
                path->addPath(*path, m, mode);
187
7.45k
                break;
188
0
            }
189
31.8k
            case 24:
190
31.8k
                FuzzNicePath(fuzz, &p, maxOps-1);
191
31.8k
                path->reverseAddPath(p);
192
31.8k
                break;
193
20.5k
            case 25:
194
20.5k
                path->addPath(*path);
195
20.5k
                break;
196
23.4k
            case 26:
197
23.4k
                path->reverseAddPath(*path);
198
23.4k
                break;
199
6.11k
            case 27:
200
6.11k
                fuzz_nice_float(fuzz, &a, &b);
201
6.11k
                path->offset(a, b, path);
202
6.11k
                break;
203
28.0k
            case 28:
204
28.0k
                FuzzNicePath(fuzz, &p, maxOps-1);
205
28.0k
                fuzz_nice_float(fuzz, &a, &b);
206
28.0k
                p.offset(a, b, path);
207
28.0k
                break;
208
4.49k
            case 29:
209
4.49k
                FuzzNiceMatrix(fuzz, &m);
210
4.49k
                path->transform(m, path);
211
4.49k
                break;
212
9.98k
            case 30:
213
9.98k
                FuzzNicePath(fuzz, &p, maxOps-1);
214
                // transform can explode path sizes so skip this op if p too big
215
9.98k
                if (p.countPoints() <= 100000) {
216
9.77k
                    FuzzNiceMatrix(fuzz, &m);
217
9.77k
                    p.transform(m, path);
218
9.77k
                }
219
9.98k
                break;
220
6.85k
            case 31:
221
6.85k
                fuzz_nice_float(fuzz, &a, &b);
222
6.85k
                path->setLastPt(a, b);
223
6.85k
                break;
224
731k
            case MAX_PATH_OPERATION:
225
731k
                SkPathPriv::ShrinkToFit(path);
226
731k
                break;
227
228
0
            default:
229
0
                SkASSERT(false);
230
0
                break;
231
2.52M
        }
232
2.52M
        SkASSERTF(       path->isValid(),        "path->isValid() failed at op %d, case %d", i, op);
233
2.52M
    }
234
98.6k
}
235
236
// allows all float values for path points
237
32.4k
void FuzzEvilPath(Fuzz* fuzz, SkPath* path, int last_verb) {
238
422k
  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
408k
    uint8_t operation;
242
408k
    fuzz->next(&operation);
243
408k
    SkScalar a,b,c,d,e,f;
244
245
408k
    switch (operation % (last_verb + 1)) {
246
26.5k
      case SkPath::Verb::kMove_Verb:
247
26.5k
        fuzz->next(&a, &b);
248
26.5k
        path->moveTo(a, b);
249
26.5k
        break;
250
251
75.5k
      case SkPath::Verb::kLine_Verb:
252
75.5k
        fuzz->next(&a, &b);
253
75.5k
        path->lineTo(a, b);
254
75.5k
        break;
255
256
59.7k
      case SkPath::Verb::kQuad_Verb:
257
59.7k
        fuzz->next(&a, &b, &c, &d);
258
59.7k
        path->quadTo(a, b, c, d);
259
59.7k
        break;
260
261
31.5k
      case SkPath::Verb::kConic_Verb:
262
31.5k
        fuzz->next(&a, &b, &c, &d, &e);
263
31.5k
        path->conicTo(a, b, c, d, e);
264
31.5k
        break;
265
266
24.2k
      case SkPath::Verb::kCubic_Verb:
267
24.2k
        fuzz->next(&a, &b, &c, &d, &e, &f);
268
24.2k
        path->cubicTo(a, b, c, d, e, f);
269
24.2k
        break;
270
271
172k
      case SkPath::Verb::kClose_Verb:
272
172k
        path->close();
273
172k
        break;
274
275
18.2k
      case SkPath::Verb::kDone_Verb:
276
        // In this case, simply exit.
277
18.2k
        return;
278
408k
    }
279
408k
  }
280
32.4k
}
281
282
16.1k
void FuzzNiceRRect(Fuzz* fuzz, SkRRect* rr) {
283
16.1k
    SkRect r;
284
16.1k
    fuzz_nice_rect(fuzz, &r);
285
286
16.1k
    SkVector radii[4];
287
64.5k
    for (SkVector& vec : radii) {
288
64.5k
        fuzz->nextRange(&vec.fX, 0.0f, 1.0f);
289
64.5k
        vec.fX *= 0.5f * r.width();
290
64.5k
        fuzz->nextRange(&vec.fY, 0.0f, 1.0f);
291
64.5k
        vec.fY *= 0.5f * r.height();
292
64.5k
    }
293
16.1k
    rr->setRectRadii(r, radii);
294
16.1k
    SkASSERT(rr->isValid());
295
16.1k
}
296
297
41.8k
void FuzzNiceMatrix(Fuzz* fuzz, SkMatrix* m) {
298
41.8k
    constexpr int kArrayLength = 9;
299
41.8k
    SkScalar buffer[kArrayLength];
300
41.8k
    int matrixType;
301
41.8k
    fuzz->nextRange(&matrixType, 0, 4);
302
41.8k
    switch (matrixType) {
303
20.5k
        case 0:  // identity
304
20.5k
            *m = SkMatrix::I();
305
20.5k
            return;
306
542
        case 1:  // translate
307
542
            fuzz->nextRange(&buffer[0], -4000.0f, 4000.0f);
308
542
            fuzz->nextRange(&buffer[1], -4000.0f, 4000.0f);
309
542
            *m = SkMatrix::Translate(buffer[0], buffer[1]);
310
542
            return;
311
947
        case 2:  // translate + scale
312
947
            fuzz->nextRange(&buffer[0], -400.0f, 400.0f);
313
947
            fuzz->nextRange(&buffer[1], -400.0f, 400.0f);
314
947
            fuzz->nextRange(&buffer[2], -4000.0f, 4000.0f);
315
947
            fuzz->nextRange(&buffer[3], -4000.0f, 4000.0f);
316
947
            *m = SkMatrix::Scale(buffer[0], buffer[1]);
317
947
            m->postTranslate(buffer[2], buffer[3]);
318
947
            return;
319
1.20k
        case 3:  // affine
320
1.20k
            fuzz->nextN(buffer, 6);
321
1.20k
            m->setAffine(buffer);
322
1.20k
            return;
323
18.6k
        case 4:  // perspective
324
18.6k
            fuzz->nextN(buffer, kArrayLength);
325
18.6k
            m->set9(buffer);
326
18.6k
            return;
327
0
        default:
328
0
            SkASSERT(false);
329
0
            return;
330
41.8k
    }
331
41.8k
}
FuzzNiceMatrix(Fuzz*, SkMatrix*)
Line
Count
Source
297
41.8k
void FuzzNiceMatrix(Fuzz* fuzz, SkMatrix* m) {
298
41.8k
    constexpr int kArrayLength = 9;
299
41.8k
    SkScalar buffer[kArrayLength];
300
41.8k
    int matrixType;
301
41.8k
    fuzz->nextRange(&matrixType, 0, 4);
302
41.8k
    switch (matrixType) {
303
20.5k
        case 0:  // identity
304
20.5k
            *m = SkMatrix::I();
305
20.5k
            return;
306
542
        case 1:  // translate
307
542
            fuzz->nextRange(&buffer[0], -4000.0f, 4000.0f);
308
542
            fuzz->nextRange(&buffer[1], -4000.0f, 4000.0f);
309
542
            *m = SkMatrix::Translate(buffer[0], buffer[1]);
310
542
            return;
311
947
        case 2:  // translate + scale
312
947
            fuzz->nextRange(&buffer[0], -400.0f, 400.0f);
313
947
            fuzz->nextRange(&buffer[1], -400.0f, 400.0f);
314
947
            fuzz->nextRange(&buffer[2], -4000.0f, 4000.0f);
315
947
            fuzz->nextRange(&buffer[3], -4000.0f, 4000.0f);
316
947
            *m = SkMatrix::Scale(buffer[0], buffer[1]);
317
947
            m->postTranslate(buffer[2], buffer[3]);
318
947
            return;
319
1.20k
        case 3:  // affine
320
1.20k
            fuzz->nextN(buffer, 6);
321
1.20k
            m->setAffine(buffer);
322
1.20k
            return;
323
18.6k
        case 4:  // perspective
324
18.6k
            fuzz->nextN(buffer, kArrayLength);
325
18.6k
            m->set9(buffer);
326
18.6k
            return;
327
0
        default:
328
0
            SkASSERT(false);
329
0
            return;
330
41.8k
    }
331
41.8k
}
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
104k
    for (uint8_t i = 0; i < N; ++i) {
337
93.4k
        SkIRect r;
338
93.4k
        SkRegion::Op op;
339
        // Avoid the sentinel value used by Region.
340
93.4k
        fuzz->nextRange(&r.fLeft,   -2147483646, 2147483646);
341
93.4k
        fuzz->nextRange(&r.fTop,    -2147483646, 2147483646);
342
93.4k
        fuzz->nextRange(&r.fRight,  -2147483646, 2147483646);
343
93.4k
        fuzz->nextRange(&r.fBottom, -2147483646, 2147483646);
344
93.4k
        r.sort();
345
93.4k
        fuzz->nextEnum(&op, SkRegion::kLastOp);
346
93.4k
        if (!region->op(r, op)) {
347
2.40k
            return;
348
2.40k
        }
349
93.4k
    }
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
}