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/encode/SkJpegEncoder.h" 14#include "include/encode/SkPngEncoder.h" 15#include "include/encode/SkWebpEncoder.h" 16#include "include/utils/SkRandom.h" 17#include "src/core/SkOSFile.h" 18 19#include <vector> 20 21// These values were picked arbitrarily to hopefully limit the size of the 22// serialized SkPixmaps. 23constexpr int MAX_WIDTH = 512; 24constexpr int MAX_HEIGHT = 512; 25 26static 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 39DEF_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 49DEF_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 59DEF_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. 78DEF_FUZZ(_MakeEncoderCorpus, fuzz) { 79 auto bytes = fuzz->fBytes; 80 SkDebugf("bytes %zu\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(nullptr, 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