Home | History | Annotate | Download | only in fuzz
      1 /*
      2  * Copyright 2016 Google Inc.
      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 "SkCanvas.h"
     10 #include "SkCodec.h"
     11 #include "SkCommandLineFlags.h"
     12 #include "SkData.h"
     13 #include "SkImage.h"
     14 #include "SkImageEncoder.h"
     15 #include "SkMallocPixelRef.h"
     16 #include "SkOSFile.h"
     17 #include "SkOSPath.h"
     18 #include "SkPaint.h"
     19 #include "SkPath.h"
     20 #include "SkPicturePriv.h"
     21 #include "SkReadBuffer.h"
     22 #include "SkStream.h"
     23 #include "SkSurface.h"
     24 #include "SkTextBlob.h"
     25 
     26 #include "sk_tool_utils.h"
     27 
     28 #include <iostream>
     29 #include <map>
     30 #include <regex>
     31 #include <signal.h>
     32 
     33 DEFINE_string2(bytes, b, "", "A path to a file or a directory. If a file, the "
     34         "contents will be used as the fuzz bytes. If a directory, all files "
     35         "in the directory will be used as fuzz bytes for the fuzzer, one at a "
     36         "time.");
     37 DEFINE_string2(name, n, "", "If --type is 'api', fuzz the API with this name.");
     38 DEFINE_string2(dump, d, "", "If not empty, dump 'image*' or 'skp' types as a "
     39         "PNG with this name.");
     40 DEFINE_bool2(verbose, v, false, "Print more information while fuzzing.");
     41 
     42 // This cannot be inlined in DEFINE_string2 due to interleaved ifdefs
     43 static constexpr char g_type_message[] = "How to interpret --bytes, one of:\n"
     44                                          "android_codec\n"
     45                                          "animated_image_decode\n"
     46                                          "api\n"
     47                                          "color_deserialize\n"
     48                                          "filter_fuzz (equivalent to Chrome's filter_fuzz_stub)\n"
     49                                          "image_decode\n"
     50                                          "image_decode_incremental\n"
     51                                          "image_mode\n"
     52                                          "image_scale\n"
     53                                          "json\n"
     54                                          "path_deserialize\n"
     55                                          "region_deserialize\n"
     56                                          "region_set_path\n"
     57                                          "skp\n"
     58                                          "sksl2glsl\n"
     59                                          "sksl2metal\n"
     60                                          "sksl2spirv\n"
     61 #if defined(SK_ENABLE_SKOTTIE)
     62                                          "skottie_json\n"
     63 #endif
     64                                          "textblob";
     65 
     66 DEFINE_string2(type, t, "", g_type_message);
     67 
     68 static int fuzz_file(SkString path, SkString type);
     69 static uint8_t calculate_option(SkData*);
     70 static SkString try_auto_detect(SkString path, SkString* name);
     71 
     72 static void fuzz_android_codec(sk_sp<SkData>);
     73 static void fuzz_animated_img(sk_sp<SkData>);
     74 static void fuzz_api(sk_sp<SkData> bytes, SkString name);
     75 static void fuzz_color_deserialize(sk_sp<SkData>);
     76 static void fuzz_filter_fuzz(sk_sp<SkData>);
     77 static void fuzz_image_decode(sk_sp<SkData>);
     78 static void fuzz_image_decode_incremental(sk_sp<SkData>);
     79 static void fuzz_img(sk_sp<SkData>, uint8_t, uint8_t);
     80 static void fuzz_json(sk_sp<SkData>);
     81 static void fuzz_path_deserialize(sk_sp<SkData>);
     82 static void fuzz_region_deserialize(sk_sp<SkData>);
     83 static void fuzz_region_set_path(sk_sp<SkData>);
     84 static void fuzz_skp(sk_sp<SkData>);
     85 static void fuzz_sksl2glsl(sk_sp<SkData>);
     86 static void fuzz_sksl2metal(sk_sp<SkData>);
     87 static void fuzz_sksl2spirv(sk_sp<SkData>);
     88 static void fuzz_textblob_deserialize(sk_sp<SkData>);
     89 
     90 static void print_api_names();
     91 
     92 #if defined(SK_ENABLE_SKOTTIE)
     93 static void fuzz_skottie_json(sk_sp<SkData>);
     94 #endif
     95 
     96 int main(int argc, char** argv) {
     97     SkCommandLineFlags::SetUsage("Usage: fuzz -t <type> -b <path/to/file> [-n api-to-fuzz]\n"
     98                                  "       fuzz -b <path/to/file>\n"
     99                                  "--help lists the valid types. If type is not specified,\n"
    100                                  "fuzz will make a guess based on the name of the file.\n");
    101     SkCommandLineFlags::Parse(argc, argv);
    102 
    103     SkString path = SkString(FLAGS_bytes.isEmpty() ? argv[0] : FLAGS_bytes[0]);
    104     SkString type = SkString(FLAGS_type.isEmpty() ? "" : FLAGS_type[0]);
    105 
    106     if (!sk_isdir(path.c_str())) {
    107         return fuzz_file(path, type);
    108     }
    109 
    110     SkOSFile::Iter it(path.c_str());
    111     for (SkString file; it.next(&file); ) {
    112         SkString p = SkOSPath::Join(path.c_str(), file.c_str());
    113         SkDebugf("Fuzzing %s\n", p.c_str());
    114         int rv = fuzz_file(p, type);
    115         if (rv != 0) {
    116             return rv;
    117         }
    118     }
    119     return 0;
    120 }
    121 
    122 static int fuzz_file(SkString path, SkString type) {
    123     sk_sp<SkData> bytes(SkData::MakeFromFileName(path.c_str()));
    124     if (!bytes) {
    125         SkDebugf("Could not read %s\n", path.c_str());
    126         return 1;
    127     }
    128 
    129     SkString name = SkString(FLAGS_name.isEmpty() ? "" : FLAGS_name[0]);
    130 
    131     if (type.isEmpty()) {
    132         type = try_auto_detect(path, &name);
    133     }
    134 
    135     if (type.isEmpty()) {
    136         SkDebugf("Could not autodetect type of %s\n", path.c_str());
    137         return 1;
    138     }
    139     if (type.equals("android_codec")) {
    140         fuzz_android_codec(bytes);
    141         return 0;
    142     }
    143     if (type.equals("animated_image_decode")) {
    144         fuzz_animated_img(bytes);
    145         return 0;
    146     }
    147     if (type.equals("api")) {
    148         fuzz_api(bytes, name);
    149         return 0;
    150     }
    151     if (type.equals("color_deserialize")) {
    152         fuzz_color_deserialize(bytes);
    153         return 0;
    154     }
    155     if (type.equals("filter_fuzz")) {
    156         fuzz_filter_fuzz(bytes);
    157         return 0;
    158     }
    159     if (type.equals("image_decode")) {
    160         fuzz_image_decode(bytes);
    161         return 0;
    162     }
    163     if (type.equals("image_decode_incremental")) {
    164         fuzz_image_decode_incremental(bytes);
    165         return 0;
    166     }
    167     if (type.equals("image_scale")) {
    168         uint8_t option = calculate_option(bytes.get());
    169         fuzz_img(bytes, option, 0);
    170         return 0;
    171     }
    172     if (type.equals("image_mode")) {
    173         uint8_t option = calculate_option(bytes.get());
    174         fuzz_img(bytes, 0, option);
    175         return 0;
    176     }
    177     if (type.equals("json")) {
    178         fuzz_json(bytes);
    179         return 0;
    180     }
    181     if (type.equals("path_deserialize")) {
    182         fuzz_path_deserialize(bytes);
    183         return 0;
    184     }
    185     if (type.equals("region_deserialize")) {
    186         fuzz_region_deserialize(bytes);
    187         return 0;
    188     }
    189     if (type.equals("region_set_path")) {
    190         fuzz_region_set_path(bytes);
    191         return 0;
    192     }
    193     if (type.equals("pipe")) {
    194         SkDebugf("I would prefer not to.\n");
    195         return 0;
    196     }
    197 #if defined(SK_ENABLE_SKOTTIE)
    198     if (type.equals("skottie_json")) {
    199         fuzz_skottie_json(bytes);
    200         return 0;
    201     }
    202 #endif
    203     if (type.equals("skp")) {
    204         fuzz_skp(bytes);
    205         return 0;
    206     }
    207     if (type.equals("sksl2glsl")) {
    208         fuzz_sksl2glsl(bytes);
    209         return 0;
    210     }
    211     if (type.equals("sksl2metal")) {
    212         fuzz_sksl2metal(bytes);
    213         return 0;
    214     }
    215     if (type.equals("sksl2spirv")) {
    216         fuzz_sksl2spirv(bytes);
    217         return 0;
    218     }
    219     if (type.equals("textblob")) {
    220         fuzz_textblob_deserialize(bytes);
    221         return 0;
    222     }
    223     SkDebugf("Unknown type %s\n", type.c_str());
    224     SkCommandLineFlags::PrintUsage();
    225     return 1;
    226 }
    227 
    228 static std::map<std::string, std::string> cf_api_map = {
    229     {"api_draw_functions", "DrawFunctions"},
    230     {"api_gradients", "Gradients"},
    231     {"api_image_filter", "ImageFilter"},
    232     {"api_mock_gpu_canvas", "MockGPUCanvas"},
    233     {"api_null_canvas", "NullCanvas"},
    234     {"api_path_measure", "PathMeasure"},
    235     {"api_pathop", "Pathop"},
    236     {"api_polyutils", "PolyUtils"},
    237     {"api_raster_n32_canvas", "RasterN32Canvas"},
    238     {"jpeg_encoder", "JPEGEncoder"},
    239     {"png_encoder", "PNGEncoder"},
    240     {"skia_pathop_fuzzer", "LegacyChromiumPathop"},
    241     {"webp_encoder", "WEBPEncoder"}
    242 };
    243 
    244 // maps clusterfuzz/oss-fuzz -> Skia's name
    245 static std::map<std::string, std::string> cf_map = {
    246     {"android_codec", "android_codec"},
    247     {"animated_image_decode", "animated_image_decode"},
    248     {"image_decode", "image_decode"},
    249     {"image_decode_incremental", "image_decode_incremental"},
    250     {"image_filter_deserialize", "filter_fuzz"},
    251     {"image_filter_deserialize_width", "filter_fuzz"},
    252     {"path_deserialize", "path_deserialize"},
    253     {"region_deserialize", "region_deserialize"},
    254     {"region_set_path", "region_set_path"},
    255     {"skjson", "json"},
    256     {"sksl2glsl", "sksl2glsl"},
    257     {"sksl2metal", "sksl2metal"},
    258     {"sksl2spirv", "sksl2spirv"},
    259 #if defined(SK_ENABLE_SKOTTIE)
    260     {"skottie_json", "skottie_json"},
    261 #endif
    262     {"textblob_deserialize", "textblob"}
    263 };
    264 
    265 static SkString try_auto_detect(SkString path, SkString* name) {
    266     std::cmatch m;
    267     std::regex clusterfuzz("clusterfuzz-testcase(-minimized)?-([a-z0-9_]+)-[\\d]+");
    268     std::regex skiafuzzer("(api-)?(\\w+)-[a-f0-9]+");
    269 
    270     if (std::regex_search(path.c_str(), m, clusterfuzz)) {
    271         std::string type = m.str(2);
    272 
    273         if (cf_api_map.find(type) != cf_api_map.end()) {
    274             *name = SkString(cf_api_map[type].c_str());
    275             return SkString("api");
    276         } else {
    277             if (cf_map.find(type) != cf_map.end()) {
    278                 return SkString(cf_map[type].c_str());
    279             }
    280         }
    281     } else if (std::regex_search(path.c_str(), m, skiafuzzer)) {
    282         std::string a1 = m.str(1);
    283         std::string typeOrName = m.str(2);
    284         if (a1.length() > 0) {
    285             // it's an api fuzzer
    286             *name = SkString(typeOrName.c_str());
    287             return SkString("api");
    288         } else {
    289             return SkString(typeOrName.c_str());
    290         }
    291     }
    292 
    293     return SkString("");
    294 }
    295 
    296 void FuzzJSON(sk_sp<SkData> bytes);
    297 
    298 static void fuzz_json(sk_sp<SkData> bytes){
    299     FuzzJSON(bytes);
    300     SkDebugf("[terminated] Done parsing!\n");
    301 }
    302 
    303 #if defined(SK_ENABLE_SKOTTIE)
    304 void FuzzSkottieJSON(sk_sp<SkData> bytes);
    305 
    306 static void fuzz_skottie_json(sk_sp<SkData> bytes){
    307     FuzzSkottieJSON(bytes);
    308     SkDebugf("[terminated] Done animating!\n");
    309 }
    310 #endif
    311 
    312 // This adds up the first 1024 bytes and returns it as an 8 bit integer.  This allows afl-fuzz to
    313 // deterministically excercise different paths, or *options* (such as different scaling sizes or
    314 // different image modes) without needing to introduce a parameter.  This way we don't need a
    315 // image_scale1, image_scale2, image_scale4, etc fuzzer, we can just have a image_scale fuzzer.
    316 // Clients are expected to transform this number into a different range, e.g. with modulo (%).
    317 static uint8_t calculate_option(SkData* bytes) {
    318     uint8_t total = 0;
    319     const uint8_t* data = bytes->bytes();
    320     for (size_t i = 0; i < 1024 && i < bytes->size(); i++) {
    321         total += data[i];
    322     }
    323     return total;
    324 }
    325 
    326 static void print_api_names(){
    327     SkDebugf("When using --type api, please choose an API to fuzz with --name/-n:\n");
    328     for (const Fuzzable& fuzzable : sk_tools::Registry<Fuzzable>::Range()) {
    329         SkDebugf("\t%s\n", fuzzable.name);
    330     }
    331 }
    332 
    333 static void fuzz_api(sk_sp<SkData> bytes, SkString name) {
    334     for (const Fuzzable& fuzzable : sk_tools::Registry<Fuzzable>::Range()) {
    335         if (name.equals(fuzzable.name)) {
    336             SkDebugf("Fuzzing %s...\n", fuzzable.name);
    337             Fuzz fuzz(std::move(bytes));
    338             fuzzable.fn(&fuzz);
    339             SkDebugf("[terminated] Success!\n");
    340             return;
    341         }
    342     }
    343 
    344     print_api_names();
    345 }
    346 
    347 static void dump_png(SkBitmap bitmap) {
    348     if (!FLAGS_dump.isEmpty()) {
    349         sk_tool_utils::EncodeImageToFile(FLAGS_dump[0], bitmap, SkEncodedImageFormat::kPNG, 100);
    350         SkDebugf("Dumped to %s\n", FLAGS_dump[0]);
    351     }
    352 }
    353 
    354 bool FuzzAnimatedImage(sk_sp<SkData> bytes);
    355 
    356 static void fuzz_animated_img(sk_sp<SkData> bytes) {
    357     if (FuzzAnimatedImage(bytes)) {
    358         SkDebugf("[terminated] Success from decoding/drawing animated image!\n");
    359         return;
    360     }
    361     SkDebugf("[terminated] Could not decode or draw animated image.\n");
    362 }
    363 
    364 bool FuzzImageDecode(sk_sp<SkData> bytes);
    365 
    366 static void fuzz_image_decode(sk_sp<SkData> bytes) {
    367     if (FuzzImageDecode(bytes)) {
    368          SkDebugf("[terminated] Success from decoding/drawing image!\n");
    369          return;
    370     }
    371     SkDebugf("[terminated] Could not decode or draw image.\n");
    372 }
    373 
    374 bool FuzzIncrementalImageDecode(sk_sp<SkData> bytes);
    375 
    376 static void fuzz_image_decode_incremental(sk_sp<SkData> bytes) {
    377     if (FuzzIncrementalImageDecode(bytes)) {
    378         SkDebugf("[terminated] Success using incremental decode!\n");
    379         return;
    380     }
    381     SkDebugf("[terminated] Could not incrementally decode and image.\n");
    382 }
    383 
    384 bool FuzzAndroidCodec(sk_sp<SkData> bytes, uint8_t sampleSize);
    385 
    386 static void fuzz_android_codec(sk_sp<SkData> bytes) {
    387     Fuzz fuzz(bytes);
    388     uint8_t sampleSize;
    389     fuzz.nextRange(&sampleSize, 1, 64);
    390     bytes = SkData::MakeSubset(bytes.get(), 1, bytes->size() - 1);
    391     if (FuzzAndroidCodec(bytes, sampleSize)) {
    392         SkDebugf("[terminated] Success on Android Codec sampleSize=%u!\n", sampleSize);
    393         return;
    394     }
    395     SkDebugf("[terminated] Could not use Android Codec sampleSize=%u!\n", sampleSize);
    396 }
    397 
    398 // This is a "legacy" fuzzer that likely does too much. It was based off of how
    399 // DM reads in images. image_decode, image_decode_incremental and android_codec
    400 // are more targeted fuzzers that do a subset of what this one does.
    401 static void fuzz_img(sk_sp<SkData> bytes, uint8_t scale, uint8_t mode) {
    402     // We can scale 1x, 2x, 4x, 8x, 16x
    403     scale = scale % 5;
    404     float fscale = (float)pow(2.0f, scale);
    405     SkDebugf("Scaling factor: %f\n", fscale);
    406 
    407     // We have 5 different modes of decoding.
    408     mode = mode % 5;
    409     SkDebugf("Mode: %d\n", mode);
    410 
    411     // This is mostly copied from DMSrcSink's CodecSrc::draw method.
    412     SkDebugf("Decoding\n");
    413     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(bytes));
    414     if (nullptr == codec.get()) {
    415         SkDebugf("[terminated] Couldn't create codec.\n");
    416         return;
    417     }
    418 
    419     SkImageInfo decodeInfo = codec->getInfo();
    420     SkISize size = codec->getScaledDimensions(fscale);
    421     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
    422 
    423     SkBitmap bitmap;
    424     SkCodec::Options options;
    425     options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
    426 
    427     if (!bitmap.tryAllocPixelsFlags(decodeInfo, SkBitmap::kZeroPixels_AllocFlag)) {
    428         SkDebugf("[terminated] Could not allocate memory.  Image might be too large (%d x %d)",
    429                  decodeInfo.width(), decodeInfo.height());
    430         return;
    431     }
    432 
    433     switch (mode) {
    434         case 0: {//kCodecZeroInit_Mode, kCodec_Mode
    435             switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), &options)) {
    436                 case SkCodec::kSuccess:
    437                     SkDebugf("[terminated] Success!\n");
    438                     break;
    439                 case SkCodec::kIncompleteInput:
    440                     SkDebugf("[terminated] Partial Success\n");
    441                     break;
    442                 case SkCodec::kErrorInInput:
    443                     SkDebugf("[terminated] Partial Success with error\n");
    444                     break;
    445                 case SkCodec::kInvalidConversion:
    446                     SkDebugf("Incompatible colortype conversion\n");
    447                     // Crash to allow afl-fuzz to know this was a bug.
    448                     raise(SIGSEGV);
    449                 default:
    450                     SkDebugf("[terminated] Couldn't getPixels.\n");
    451                     return;
    452             }
    453             break;
    454         }
    455         case 1: {//kScanline_Mode
    456             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) {
    457                 SkDebugf("[terminated] Could not start scanline decoder\n");
    458                 return;
    459             }
    460 
    461             void* dst = bitmap.getAddr(0, 0);
    462             size_t rowBytes = bitmap.rowBytes();
    463             uint32_t height = decodeInfo.height();
    464             // We do not need to check the return value.  On an incomplete
    465             // image, memory will be filled with a default value.
    466             codec->getScanlines(dst, height, rowBytes);
    467             SkDebugf("[terminated] Success!\n");
    468             break;
    469         }
    470         case 2: { //kStripe_Mode
    471             const int height = decodeInfo.height();
    472             // This value is chosen arbitrarily.  We exercise more cases by choosing a value that
    473             // does not align with image blocks.
    474             const int stripeHeight = 37;
    475             const int numStripes = (height + stripeHeight - 1) / stripeHeight;
    476 
    477             // Decode odd stripes
    478             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)
    479                     || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) {
    480                 // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
    481                 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
    482                 // to run this test for image types that do not have this scanline ordering.
    483                 SkDebugf("[terminated] Could not start top-down scanline decoder\n");
    484                 return;
    485             }
    486 
    487             for (int i = 0; i < numStripes; i += 2) {
    488                 // Skip a stripe
    489                 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
    490                 codec->skipScanlines(linesToSkip);
    491 
    492                 // Read a stripe
    493                 const int startY = (i + 1) * stripeHeight;
    494                 const int linesToRead = SkTMin(stripeHeight, height - startY);
    495                 if (linesToRead > 0) {
    496                     codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
    497                 }
    498             }
    499 
    500             // Decode even stripes
    501             const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo);
    502             if (SkCodec::kSuccess != startResult) {
    503                 SkDebugf("[terminated] Failed to restart scanline decoder with same parameters.\n");
    504                 return;
    505             }
    506             for (int i = 0; i < numStripes; i += 2) {
    507                 // Read a stripe
    508                 const int startY = i * stripeHeight;
    509                 const int linesToRead = SkTMin(stripeHeight, height - startY);
    510                 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
    511 
    512                 // Skip a stripe
    513                 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
    514                 if (linesToSkip > 0) {
    515                     codec->skipScanlines(linesToSkip);
    516                 }
    517             }
    518             SkDebugf("[terminated] Success!\n");
    519             break;
    520         }
    521         case 3: { //kSubset_Mode
    522             // Arbitrarily choose a divisor.
    523             int divisor = 2;
    524             // Total width/height of the image.
    525             const int W = codec->getInfo().width();
    526             const int H = codec->getInfo().height();
    527             if (divisor > W || divisor > H) {
    528                 SkDebugf("[terminated] Cannot codec subset: divisor %d is too big "
    529                          "with dimensions (%d x %d)\n", divisor, W, H);
    530                 return;
    531             }
    532             // subset dimensions
    533             // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
    534             const int w = SkAlign2(W / divisor);
    535             const int h = SkAlign2(H / divisor);
    536             SkIRect subset;
    537             SkCodec::Options opts;
    538             opts.fSubset = &subset;
    539             SkBitmap subsetBm;
    540             // We will reuse pixel memory from bitmap.
    541             void* pixels = bitmap.getPixels();
    542             // Keep track of left and top (for drawing subsetBm into canvas). We could use
    543             // fscale * x and fscale * y, but we want integers such that the next subset will start
    544             // where the last one ended. So we'll add decodeInfo.width() and height().
    545             int left = 0;
    546             for (int x = 0; x < W; x += w) {
    547                 int top = 0;
    548                 for (int y = 0; y < H; y+= h) {
    549                     // Do not make the subset go off the edge of the image.
    550                     const int preScaleW = SkTMin(w, W - x);
    551                     const int preScaleH = SkTMin(h, H - y);
    552                     subset.setXYWH(x, y, preScaleW, preScaleH);
    553                     // And fscale
    554                     // FIXME: Should we have a version of getScaledDimensions that takes a subset
    555                     // into account?
    556                     decodeInfo = decodeInfo.makeWH(
    557                             SkTMax(1, SkScalarRoundToInt(preScaleW * fscale)),
    558                             SkTMax(1, SkScalarRoundToInt(preScaleH * fscale)));
    559                     size_t rowBytes = decodeInfo.minRowBytes();
    560                     if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes)) {
    561                         SkDebugf("[terminated] Could not install pixels.\n");
    562                         return;
    563                     }
    564                     const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
    565                             &opts);
    566                     switch (result) {
    567                         case SkCodec::kSuccess:
    568                         case SkCodec::kIncompleteInput:
    569                         case SkCodec::kErrorInInput:
    570                             SkDebugf("okay\n");
    571                             break;
    572                         case SkCodec::kInvalidConversion:
    573                             if (0 == (x|y)) {
    574                                 // First subset is okay to return unimplemented.
    575                                 SkDebugf("[terminated] Incompatible colortype conversion\n");
    576                                 return;
    577                             }
    578                             // If the first subset succeeded, a later one should not fail.
    579                             // fall through to failure
    580                         case SkCodec::kUnimplemented:
    581                             if (0 == (x|y)) {
    582                                 // First subset is okay to return unimplemented.
    583                                 SkDebugf("[terminated] subset codec not supported\n");
    584                                 return;
    585                             }
    586                             // If the first subset succeeded, why would a later one fail?
    587                             // fall through to failure
    588                         default:
    589                             SkDebugf("[terminated] subset codec failed to decode (%d, %d, %d, %d) "
    590                                                   "with dimensions (%d x %d)\t error %d\n",
    591                                                   x, y, decodeInfo.width(), decodeInfo.height(),
    592                                                   W, H, result);
    593                             return;
    594                     }
    595                     // translate by the scaled height.
    596                     top += decodeInfo.height();
    597                 }
    598                 // translate by the scaled width.
    599                 left += decodeInfo.width();
    600             }
    601             SkDebugf("[terminated] Success!\n");
    602             break;
    603         }
    604         case 4: { //kAnimated_Mode
    605             std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
    606             if (frameInfos.size() == 0) {
    607                 SkDebugf("[terminated] Not an animated image\n");
    608                 break;
    609             }
    610 
    611             for (size_t i = 0; i < frameInfos.size(); i++) {
    612                 options.fFrameIndex = i;
    613                 auto result = codec->startIncrementalDecode(decodeInfo, bitmap.getPixels(),
    614                         bitmap.rowBytes(), &options);
    615                 if (SkCodec::kSuccess != result) {
    616                     SkDebugf("[terminated] failed to start incremental decode "
    617                              "in frame %d with error %d\n", i, result);
    618                     return;
    619                 }
    620 
    621                 result = codec->incrementalDecode();
    622                 if (result == SkCodec::kIncompleteInput || result == SkCodec::kErrorInInput) {
    623                     SkDebugf("okay\n");
    624                     // Frames beyond this one will not decode.
    625                     break;
    626                 }
    627                 if (result == SkCodec::kSuccess) {
    628                     SkDebugf("okay - decoded frame %d\n", i);
    629                 } else {
    630                     SkDebugf("[terminated] incremental decode failed with "
    631                              "error %d\n", result);
    632                     return;
    633                 }
    634             }
    635             SkDebugf("[terminated] Success!\n");
    636             break;
    637         }
    638         default:
    639             SkDebugf("[terminated] Mode not implemented yet\n");
    640     }
    641 
    642     dump_png(bitmap);
    643 }
    644 
    645 static void fuzz_skp(sk_sp<SkData> bytes) {
    646     SkReadBuffer buf(bytes->data(), bytes->size());
    647     SkDebugf("Decoding\n");
    648     sk_sp<SkPicture> pic(SkPicturePriv::MakeFromBuffer(buf));
    649     if (!pic) {
    650         SkDebugf("[terminated] Couldn't decode as a picture.\n");
    651         return;
    652     }
    653     SkDebugf("Rendering\n");
    654     SkBitmap bitmap;
    655     if (!FLAGS_dump.isEmpty()) {
    656         SkIRect size = pic->cullRect().roundOut();
    657         bitmap.allocN32Pixels(size.width(), size.height());
    658     }
    659     SkCanvas canvas(bitmap);
    660     canvas.drawPicture(pic);
    661     SkDebugf("[terminated] Success! Decoded and rendered an SkPicture!\n");
    662     dump_png(bitmap);
    663 }
    664 
    665 static void fuzz_color_deserialize(sk_sp<SkData> bytes) {
    666     sk_sp<SkColorSpace> space(SkColorSpace::Deserialize(bytes->data(), bytes->size()));
    667     if (!space) {
    668         SkDebugf("[terminated] Couldn't deserialize Colorspace.\n");
    669         return;
    670     }
    671     SkDebugf("[terminated] Success! deserialized Colorspace.\n");
    672 }
    673 
    674 void FuzzPathDeserialize(SkReadBuffer& buf);
    675 
    676 static void fuzz_path_deserialize(sk_sp<SkData> bytes) {
    677     SkReadBuffer buf(bytes->data(), bytes->size());
    678     FuzzPathDeserialize(buf);
    679     SkDebugf("[terminated] path_deserialize didn't crash!\n");
    680 }
    681 
    682 bool FuzzRegionDeserialize(sk_sp<SkData> bytes);
    683 
    684 static void fuzz_region_deserialize(sk_sp<SkData> bytes) {
    685     if (!FuzzRegionDeserialize(bytes)) {
    686         SkDebugf("[terminated] Couldn't initialize SkRegion.\n");
    687         return;
    688     }
    689     SkDebugf("[terminated] Success! Initialized SkRegion.\n");
    690 }
    691 
    692 void FuzzTextBlobDeserialize(SkReadBuffer& buf);
    693 
    694 static void fuzz_textblob_deserialize(sk_sp<SkData> bytes) {
    695     SkReadBuffer buf(bytes->data(), bytes->size());
    696     FuzzTextBlobDeserialize(buf);
    697     SkDebugf("[terminated] textblob didn't crash!\n");
    698 }
    699 
    700 void FuzzRegionSetPath(Fuzz* fuzz);
    701 
    702 static void fuzz_region_set_path(sk_sp<SkData> bytes) {
    703     Fuzz fuzz(bytes);
    704     FuzzRegionSetPath(&fuzz);
    705     SkDebugf("[terminated] region_set_path didn't crash!\n");
    706 }
    707 
    708 void FuzzImageFilterDeserialize(sk_sp<SkData> bytes);
    709 
    710 static void fuzz_filter_fuzz(sk_sp<SkData> bytes) {
    711     FuzzImageFilterDeserialize(bytes);
    712     SkDebugf("[terminated] filter_fuzz didn't crash!\n");
    713 }
    714 
    715 bool FuzzSKSL2GLSL(sk_sp<SkData> bytes);
    716 
    717 static void fuzz_sksl2glsl(sk_sp<SkData> bytes) {
    718     if (FuzzSKSL2GLSL(bytes)) {
    719         SkDebugf("[terminated] Success! Compiled input to GLSL.\n");
    720     } else {
    721         SkDebugf("[terminated] Could not compile input to GLSL.\n");
    722     }
    723 }
    724 
    725 bool FuzzSKSL2SPIRV(sk_sp<SkData> bytes);
    726 
    727 static void fuzz_sksl2spirv(sk_sp<SkData> bytes) {
    728     if (FuzzSKSL2SPIRV(bytes)) {
    729         SkDebugf("[terminated] Success! Compiled input to SPIRV.\n");
    730     } else {
    731         SkDebugf("[terminated] Could not compile input to SPIRV.\n");
    732     }
    733 }
    734 
    735 bool FuzzSKSL2Metal(sk_sp<SkData> bytes);
    736 
    737 static void fuzz_sksl2metal(sk_sp<SkData> bytes) {
    738     if (FuzzSKSL2Metal(bytes)) {
    739         SkDebugf("[terminated] Success! Compiled input to Metal.\n");
    740     } else {
    741         SkDebugf("[terminated] Could not compile input to Metal.\n");
    742     }
    743 }
    744