/* * Copyright 2018 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "Fuzz.h" #include "SkBitmap.h" #include "SkImage.h" #include "SkImageInfo.h" #include "SkJpegEncoder.h" #include "SkPixmap.h" #include "SkPngEncoder.h" #include "SkRandom.h" #include "SkWebpEncoder.h" #include "SkOSFile.h" #include // These values were picked arbitrarily to hopefully limit the size of the // serialized SkPixmaps. constexpr int MAX_WIDTH = 512; constexpr int MAX_HEIGHT = 512; static SkBitmap make_fuzzed_bitmap(Fuzz* fuzz) { SkBitmap bm; uint32_t w, h; fuzz->nextRange(&w, 1, MAX_WIDTH); fuzz->nextRange(&h, 1, MAX_HEIGHT); if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(w, h))) { return bm; } uint32_t n = w * h; fuzz->nextN((SkPMColor*)bm.getPixels(), n); return bm; } DEF_FUZZ(PNGEncoder, fuzz) { auto bm = make_fuzzed_bitmap(fuzz); auto opts = SkPngEncoder::Options{}; fuzz->nextRange(&opts.fZLibLevel, 0, 9); SkDynamicMemoryWStream dest; SkPngEncoder::Encode(&dest, bm.pixmap(), opts); } DEF_FUZZ(JPEGEncoder, fuzz) { auto bm = make_fuzzed_bitmap(fuzz); auto opts = SkJpegEncoder::Options{}; fuzz->nextRange(&opts.fQuality, 0, 100); SkDynamicMemoryWStream dest; (void)SkJpegEncoder::Encode(&dest, bm.pixmap(), opts); } DEF_FUZZ(WEBPEncoder, fuzz) { auto bm = make_fuzzed_bitmap(fuzz); auto opts = SkWebpEncoder::Options{}; fuzz->nextRange(&opts.fQuality, 0.0f, 100.0f); bool lossy; fuzz->next(&lossy); if (lossy) { opts.fCompression = SkWebpEncoder::Compression::kLossy; } else { opts.fCompression = SkWebpEncoder::Compression::kLossless; } SkDynamicMemoryWStream dest; (void)SkWebpEncoder::Encode(&dest, bm.pixmap(), opts); } // Not a real fuzz endpoint, but a helper to take in real, good images // and dump out a corpus for this fuzzer. DEF_FUZZ(_MakeEncoderCorpus, fuzz) { auto bytes = fuzz->fBytes; SkDebugf("bytes %d\n", bytes->size()); auto img = SkImage::MakeFromEncoded(bytes); if (nullptr == img.get()) { SkDebugf("invalid image, could not decode\n"); return; } if (img->width() > MAX_WIDTH || img->height() > MAX_HEIGHT) { SkDebugf("Too big (%d x %d)\n", img->width(), img->height()); return; } std::vector dstPixels; int rowBytes = img->width() * 4; dstPixels.resize(img->height() * rowBytes); SkPixmap pm(SkImageInfo::MakeN32Premul(img->width(), img->height()), &dstPixels.front(), rowBytes); if (!img->readPixels(pm, 0, 0)) { SkDebugf("Could not read pixmap\n"); return; } SkString s("./encoded_corpus/enc_"); static SkRandom rand; s.appendU32(rand.nextU()); auto file = sk_fopen(s.c_str(), SkFILE_Flags::kWrite_SkFILE_Flag); if (!file) { SkDebugf("Can't initialize file\n"); return; } auto total = pm.info().bytesPerPixel() * pm.width() * pm.height(); SkDebugf("Writing %d (%d x %d) bytes\n", total, pm.width(), pm.height()); // Write out the size in two bytes since that's what the fuzzer will // read first. uint32_t w = pm.width(); sk_fwrite(&w, sizeof(uint32_t), file); uint32_t h = pm.height(); sk_fwrite(&h, sizeof(uint32_t), file); sk_fwrite(pm.addr(), total, file); sk_fclose(file); }