diff options
Diffstat (limited to 'fuzz/FuzzEncoders.cpp')
-rw-r--r-- | fuzz/FuzzEncoders.cpp | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/fuzz/FuzzEncoders.cpp b/fuzz/FuzzEncoders.cpp new file mode 100644 index 0000000000..7ca4a48d9c --- /dev/null +++ b/fuzz/FuzzEncoders.cpp @@ -0,0 +1,118 @@ +/* + * 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 <vector> + +// 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<int32_t> 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); +} |