Home | History | Annotate | Download | only in fuzz
      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 
     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 
     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 
     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 
     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.
     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