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