/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 | } |