Coverage Report

Created: 2024-05-20 07:14

/src/skia/fuzz/FuzzEncoders.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2018 Google LLC
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 "include/core/SkBitmap.h"
10
#include "include/core/SkImage.h"
11
#include "include/core/SkImageInfo.h"
12
#include "include/core/SkPixmap.h"
13
#include "include/core/SkStream.h"
14
#include "include/encode/SkJpegEncoder.h"
15
#include "include/encode/SkPngEncoder.h"
16
#include "include/encode/SkWebpEncoder.h"
17
#include "src/base/SkRandom.h"
18
#include "src/core/SkOSFile.h"
19
20
#include <vector>
21
22
// These values were picked arbitrarily to hopefully limit the size of the
23
// serialized SkPixmaps.
24
constexpr int MAX_WIDTH = 512;
25
constexpr int MAX_HEIGHT = 512;
26
27
11.6k
static SkBitmap make_fuzzed_bitmap(Fuzz* fuzz) {
28
11.6k
    SkBitmap bm;
29
11.6k
    uint32_t w, h;
30
11.6k
    fuzz->nextRange(&w, 1, MAX_WIDTH);
31
11.6k
    fuzz->nextRange(&h, 1, MAX_HEIGHT);
32
11.6k
    if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(w, h))) {
33
314
        return bm;
34
314
    }
35
11.3k
    uint32_t n = w * h;
36
11.3k
    fuzz->nextN((SkPMColor*)bm.getPixels(), n);
37
11.3k
    return bm;
38
11.6k
}
39
40
2.11k
DEF_FUZZ(PNGEncoder, fuzz) {
41
2.11k
    auto bm = make_fuzzed_bitmap(fuzz);
42
43
2.11k
    auto opts = SkPngEncoder::Options{};
44
2.11k
    fuzz->nextRange(&opts.fZLibLevel, 0, 9);
45
46
2.11k
    SkDynamicMemoryWStream dest;
47
2.11k
    SkPngEncoder::Encode(&dest, bm.pixmap(), opts);
48
2.11k
}
49
50
4.79k
DEF_FUZZ(JPEGEncoder, fuzz) {
51
4.79k
    auto bm = make_fuzzed_bitmap(fuzz);
52
53
4.79k
    auto opts = SkJpegEncoder::Options{};
54
4.79k
    fuzz->nextRange(&opts.fQuality, 0, 100);
55
56
4.79k
    SkDynamicMemoryWStream dest;
57
4.79k
    (void)SkJpegEncoder::Encode(&dest, bm.pixmap(), opts);
58
4.79k
}
59
60
4.78k
DEF_FUZZ(WEBPEncoder, fuzz) {
61
4.78k
    auto bm = make_fuzzed_bitmap(fuzz);
62
63
4.78k
    auto opts = SkWebpEncoder::Options{};
64
4.78k
    fuzz->nextRange(&opts.fQuality, 0.0f, 100.0f);
65
4.78k
    bool lossy;
66
4.78k
    fuzz->next(&lossy);
67
4.78k
    if (lossy) {
68
2.98k
        opts.fCompression = SkWebpEncoder::Compression::kLossy;
69
2.98k
    } else {
70
1.79k
        opts.fCompression = SkWebpEncoder::Compression::kLossless;
71
1.79k
    }
72
73
4.78k
    SkDynamicMemoryWStream dest;
74
4.78k
    (void)SkWebpEncoder::Encode(&dest, bm.pixmap(), opts);
75
4.78k
}
76
77
// Not a real fuzz endpoint, but a helper to take in real, good images
78
// and dump out a corpus for this fuzzer.
79
0
DEF_FUZZ(_MakeEncoderCorpus, fuzz) {
80
0
    sk_sp<SkData> bytes = SkData::MakeWithoutCopy(fuzz->fData, fuzz->fSize);
81
0
    SkDebugf("bytes %zu\n", bytes->size());
82
0
    auto img = SkImages::DeferredFromEncodedData(bytes);
83
0
    if (nullptr == img.get()) {
84
0
        SkDebugf("invalid image, could not decode\n");
85
0
        return;
86
0
    }
87
0
    if (img->width() > MAX_WIDTH || img->height() > MAX_HEIGHT) {
88
0
        SkDebugf("Too big (%d x %d)\n", img->width(), img->height());
89
0
        return;
90
0
    }
91
0
    std::vector<int32_t> dstPixels;
92
0
    int rowBytes = img->width() * 4;
93
0
    dstPixels.resize(img->height() * rowBytes);
94
0
    SkPixmap pm(SkImageInfo::MakeN32Premul(img->width(), img->height()),
95
0
        &dstPixels.front(), rowBytes);
96
0
    if (!img->readPixels(nullptr, pm, 0, 0)) {
97
0
        SkDebugf("Could not read pixmap\n");
98
0
        return;
99
0
    }
100
101
0
    SkString s("./encoded_corpus/enc_");
102
0
    static SkRandom rand;
103
0
    s.appendU32(rand.nextU());
104
0
    auto file = sk_fopen(s.c_str(), SkFILE_Flags::kWrite_SkFILE_Flag);
105
0
    if (!file) {
106
0
        SkDebugf("Can't initialize file\n");
107
0
        return;
108
0
    }
109
0
    auto total = pm.info().bytesPerPixel() * pm.width() * pm.height();
110
0
    SkDebugf("Writing %d (%d x %d) bytes\n", total, pm.width(), pm.height());
111
    // Write out the size in two bytes since that's what the fuzzer will
112
    // read first.
113
0
    uint32_t w = pm.width();
114
0
    sk_fwrite(&w, sizeof(uint32_t), file);
115
0
    uint32_t h = pm.height();
116
0
    sk_fwrite(&h, sizeof(uint32_t), file);
117
0
    sk_fwrite(pm.addr(), total, file);
118
0
    sk_fclose(file);
119
0
}