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 "SkImageFilter.h"
     16 #include "SkMallocPixelRef.h"
     17 #include "SkOSFile.h"
     18 #include "SkOSPath.h"
     19 #include "SkPaint.h"
     20 #include "SkPath.h"
     21 #include "SkPicture.h"
     22 #include "SkPipe.h"
     23 #include "SkReadBuffer.h"
     24 #include "SkRegion.h"
     25 #include "SkStream.h"
     26 #include "SkSurface.h"
     27 #include "SkTextBlob.h"
     28 
     29 #if SK_SUPPORT_GPU
     30 #include "SkSLCompiler.h"
     31 #endif
     32 
     33 #include <iostream>
     34 #include <signal.h>
     35 #include "sk_tool_utils.h"
     36 
     37 
     38 DEFINE_string2(bytes, b, "", "A path to a file or a directory. If a file, the "
     39         "contents will be used as the fuzz bytes. If a directory, all files "
     40         "in the directory will be used as fuzz bytes for the fuzzer, one at a "
     41         "time.");
     42 DEFINE_string2(name, n, "", "If --type is 'api', fuzz the API with this name.");
     43 DEFINE_string2(dump, d, "", "If not empty, dump 'image*' or 'skp' types as a "
     44         "PNG with this name.");
     45 DEFINE_bool2(verbose, v, false, "Print more information while fuzzing.");
     46 DEFINE_string2(type, t, "", "How to interpret --bytes, one of:\n"
     47                             "api\n"
     48                             "color_deserialize\n"
     49                             "filter_fuzz (equivalent to Chrome's filter_fuzz_stub)\n"
     50                             "icc\n"
     51                             "image_mode\n"
     52                             "image_scale\n"
     53                             "path_deserialize\n"
     54                             "pipe\n"
     55                             "region_deserialize\n"
     56                             "region_set_path\n"
     57                             "skp\n"
     58                             "sksl2glsl\n"
     59                             "textblob");
     60 
     61 static int fuzz_file(const char* path);
     62 static uint8_t calculate_option(SkData*);
     63 
     64 static void fuzz_api(sk_sp<SkData>);
     65 static void fuzz_color_deserialize(sk_sp<SkData>);
     66 static void fuzz_filter_fuzz(sk_sp<SkData>);
     67 static void fuzz_icc(sk_sp<SkData>);
     68 static void fuzz_img(sk_sp<SkData>, uint8_t, uint8_t);
     69 static void fuzz_path_deserialize(sk_sp<SkData>);
     70 static void fuzz_region_deserialize(sk_sp<SkData>);
     71 static void fuzz_region_set_path(sk_sp<SkData>);
     72 static void fuzz_skp(sk_sp<SkData>);
     73 static void fuzz_skpipe(sk_sp<SkData>);
     74 static void fuzz_textblob_deserialize(sk_sp<SkData>);
     75 
     76 #if SK_SUPPORT_GPU
     77 static void fuzz_sksl2glsl(sk_sp<SkData>);
     78 #endif
     79 
     80 int main(int argc, char** argv) {
     81     SkCommandLineFlags::SetUsage("Usage: fuzz -t <type> -b <path/to/file> [-n api-to-fuzz]\n"
     82                                  "--help lists the valid types\n");
     83     SkCommandLineFlags::Parse(argc, argv);
     84 
     85     const char* path = FLAGS_bytes.isEmpty() ? argv[0] : FLAGS_bytes[0];
     86 
     87     if (!sk_isdir(path)) {
     88         return fuzz_file(path);
     89     }
     90 
     91     SkOSFile::Iter it(path);
     92     for (SkString file; it.next(&file); ) {
     93         SkString p = SkOSPath::Join(path, file.c_str());
     94         SkDebugf("Fuzzing %s\n", p.c_str());
     95         int rv = fuzz_file(p.c_str());
     96         if (rv != 0) {
     97             return rv;
     98         }
     99     }
    100     return 0;
    101 }
    102 
    103 static int fuzz_file(const char* path) {
    104     sk_sp<SkData> bytes(SkData::MakeFromFileName(path));
    105     if (!bytes) {
    106         SkDebugf("Could not read %s\n", path);
    107         return 1;
    108     }
    109 
    110     if (!FLAGS_type.isEmpty()) {
    111         if (0 == strcmp("api", FLAGS_type[0])) {
    112             fuzz_api(bytes);
    113             return 0;
    114         }
    115         if (0 == strcmp("color_deserialize", FLAGS_type[0])) {
    116             fuzz_color_deserialize(bytes);
    117             return 0;
    118         }
    119         if (0 == strcmp("icc", FLAGS_type[0])) {
    120             fuzz_icc(bytes);
    121             return 0;
    122         }
    123         if (0 == strcmp("image_scale", FLAGS_type[0])) {
    124             uint8_t option = calculate_option(bytes.get());
    125             fuzz_img(bytes, option, 0);
    126             return 0;
    127         }
    128         if (0 == strcmp("image_mode", FLAGS_type[0])) {
    129             uint8_t option = calculate_option(bytes.get());
    130             fuzz_img(bytes, 0, option);
    131             return 0;
    132         }
    133         if (0 == strcmp("path_deserialize", FLAGS_type[0])) {
    134             fuzz_path_deserialize(bytes);
    135             return 0;
    136         }
    137         if (0 == strcmp("region_deserialize", FLAGS_type[0])) {
    138             fuzz_region_deserialize(bytes);
    139             return 0;
    140         }
    141         if (0 == strcmp("region_set_path", FLAGS_type[0])) {
    142             fuzz_region_set_path(bytes);
    143             return 0;
    144         }
    145         if (0 == strcmp("pipe", FLAGS_type[0])) {
    146             fuzz_skpipe(bytes);
    147             return 0;
    148         }
    149         if (0 == strcmp("skp", FLAGS_type[0])) {
    150             fuzz_skp(bytes);
    151             return 0;
    152         }
    153         if (0 == strcmp("filter_fuzz", FLAGS_type[0])) {
    154             fuzz_filter_fuzz(bytes);
    155             return 0;
    156         }
    157         if (0 == strcmp("textblob", FLAGS_type[0])) {
    158             fuzz_textblob_deserialize(bytes);
    159             return 0;
    160         }
    161 #if SK_SUPPORT_GPU
    162         if (0 == strcmp("sksl2glsl", FLAGS_type[0])) {
    163             fuzz_sksl2glsl(bytes);
    164             return 0;
    165         }
    166 #endif
    167     }
    168     SkCommandLineFlags::PrintUsage();
    169     return 1;
    170 }
    171 
    172 // This adds up the first 1024 bytes and returns it as an 8 bit integer.  This allows afl-fuzz to
    173 // deterministically excercise different paths, or *options* (such as different scaling sizes or
    174 // different image modes) without needing to introduce a parameter.  This way we don't need a
    175 // image_scale1, image_scale2, image_scale4, etc fuzzer, we can just have a image_scale fuzzer.
    176 // Clients are expected to transform this number into a different range, e.g. with modulo (%).
    177 static uint8_t calculate_option(SkData* bytes) {
    178     uint8_t total = 0;
    179     const uint8_t* data = bytes->bytes();
    180     for (size_t i = 0; i < 1024 && i < bytes->size(); i++) {
    181         total += data[i];
    182     }
    183     return total;
    184 }
    185 
    186 static void fuzz_api(sk_sp<SkData> bytes) {
    187     const char* name = FLAGS_name.isEmpty() ? "" : FLAGS_name[0];
    188 
    189     for (auto r = sk_tools::Registry<Fuzzable>::Head(); r; r = r->next()) {
    190         auto fuzzable = r->factory();
    191         if (0 == strcmp(name, fuzzable.name)) {
    192             SkDebugf("Fuzzing %s...\n", fuzzable.name);
    193             Fuzz fuzz(std::move(bytes));
    194             fuzzable.fn(&fuzz);
    195             SkDebugf("[terminated] Success!\n");
    196             return;
    197         }
    198     }
    199 
    200     SkDebugf("When using --type api, please choose an API to fuzz with --name/-n:\n");
    201     for (auto r = sk_tools::Registry<Fuzzable>::Head(); r; r = r->next()) {
    202         auto fuzzable = r->factory();
    203         SkDebugf("\t%s\n", fuzzable.name);
    204     }
    205 }
    206 
    207 static void dump_png(SkBitmap bitmap) {
    208     if (!FLAGS_dump.isEmpty()) {
    209         sk_tool_utils::EncodeImageToFile(FLAGS_dump[0], bitmap, SkEncodedImageFormat::kPNG, 100);
    210         SkDebugf("Dumped to %s\n", FLAGS_dump[0]);
    211     }
    212 }
    213 
    214 static void fuzz_img(sk_sp<SkData> bytes, uint8_t scale, uint8_t mode) {
    215     // We can scale 1x, 2x, 4x, 8x, 16x
    216     scale = scale % 5;
    217     float fscale = (float)pow(2.0f, scale);
    218     SkDebugf("Scaling factor: %f\n", fscale);
    219 
    220     // We have 5 different modes of decoding.
    221     mode = mode % 5;
    222     SkDebugf("Mode: %d\n", mode);
    223 
    224     // This is mostly copied from DMSrcSink's CodecSrc::draw method.
    225     SkDebugf("Decoding\n");
    226     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(bytes));
    227     if (nullptr == codec.get()) {
    228         SkDebugf("[terminated] Couldn't create codec.\n");
    229         return;
    230     }
    231 
    232     SkImageInfo decodeInfo = codec->getInfo();
    233     SkISize size = codec->getScaledDimensions(fscale);
    234     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
    235 
    236     SkBitmap bitmap;
    237     SkCodec::Options options;
    238     options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
    239 
    240     if (!bitmap.tryAllocPixelsFlags(decodeInfo, SkBitmap::kZeroPixels_AllocFlag)) {
    241         SkDebugf("[terminated] Could not allocate memory.  Image might be too large (%d x %d)",
    242                  decodeInfo.width(), decodeInfo.height());
    243         return;
    244     }
    245 
    246     switch (mode) {
    247         case 0: {//kCodecZeroInit_Mode, kCodec_Mode
    248             switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), &options)) {
    249                 case SkCodec::kSuccess:
    250                     SkDebugf("[terminated] Success!\n");
    251                     break;
    252                 case SkCodec::kIncompleteInput:
    253                     SkDebugf("[terminated] Partial Success\n");
    254                     break;
    255                 case SkCodec::kErrorInInput:
    256                     SkDebugf("[terminated] Partial Success with error\n");
    257                     break;
    258                 case SkCodec::kInvalidConversion:
    259                     SkDebugf("Incompatible colortype conversion\n");
    260                     // Crash to allow afl-fuzz to know this was a bug.
    261                     raise(SIGSEGV);
    262                 default:
    263                     SkDebugf("[terminated] Couldn't getPixels.\n");
    264                     return;
    265             }
    266             break;
    267         }
    268         case 1: {//kScanline_Mode
    269             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) {
    270                 SkDebugf("[terminated] Could not start scanline decoder\n");
    271                 return;
    272             }
    273 
    274             void* dst = bitmap.getAddr(0, 0);
    275             size_t rowBytes = bitmap.rowBytes();
    276             uint32_t height = decodeInfo.height();
    277             switch (codec->getScanlineOrder()) {
    278                 case SkCodec::kTopDown_SkScanlineOrder:
    279                 case SkCodec::kBottomUp_SkScanlineOrder:
    280                     // We do not need to check the return value.  On an incomplete
    281                     // image, memory will be filled with a default value.
    282                     codec->getScanlines(dst, height, rowBytes);
    283                     break;
    284             }
    285             SkDebugf("[terminated] Success!\n");
    286             break;
    287         }
    288         case 2: { //kStripe_Mode
    289             const int height = decodeInfo.height();
    290             // This value is chosen arbitrarily.  We exercise more cases by choosing a value that
    291             // does not align with image blocks.
    292             const int stripeHeight = 37;
    293             const int numStripes = (height + stripeHeight - 1) / stripeHeight;
    294 
    295             // Decode odd stripes
    296             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)
    297                     || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) {
    298                 // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
    299                 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
    300                 // to run this test for image types that do not have this scanline ordering.
    301                 SkDebugf("[terminated] Could not start top-down scanline decoder\n");
    302                 return;
    303             }
    304 
    305             for (int i = 0; i < numStripes; i += 2) {
    306                 // Skip a stripe
    307                 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
    308                 codec->skipScanlines(linesToSkip);
    309 
    310                 // Read a stripe
    311                 const int startY = (i + 1) * stripeHeight;
    312                 const int linesToRead = SkTMin(stripeHeight, height - startY);
    313                 if (linesToRead > 0) {
    314                     codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
    315                 }
    316             }
    317 
    318             // Decode even stripes
    319             const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo);
    320             if (SkCodec::kSuccess != startResult) {
    321                 SkDebugf("[terminated] Failed to restart scanline decoder with same parameters.\n");
    322                 return;
    323             }
    324             for (int i = 0; i < numStripes; i += 2) {
    325                 // Read a stripe
    326                 const int startY = i * stripeHeight;
    327                 const int linesToRead = SkTMin(stripeHeight, height - startY);
    328                 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
    329 
    330                 // Skip a stripe
    331                 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
    332                 if (linesToSkip > 0) {
    333                     codec->skipScanlines(linesToSkip);
    334                 }
    335             }
    336             SkDebugf("[terminated] Success!\n");
    337             break;
    338         }
    339         case 3: { //kSubset_Mode
    340             // Arbitrarily choose a divisor.
    341             int divisor = 2;
    342             // Total width/height of the image.
    343             const int W = codec->getInfo().width();
    344             const int H = codec->getInfo().height();
    345             if (divisor > W || divisor > H) {
    346                 SkDebugf("[terminated] Cannot codec subset: divisor %d is too big "
    347                          "with dimensions (%d x %d)\n", divisor, W, H);
    348                 return;
    349             }
    350             // subset dimensions
    351             // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
    352             const int w = SkAlign2(W / divisor);
    353             const int h = SkAlign2(H / divisor);
    354             SkIRect subset;
    355             SkCodec::Options opts;
    356             opts.fSubset = &subset;
    357             SkBitmap subsetBm;
    358             // We will reuse pixel memory from bitmap.
    359             void* pixels = bitmap.getPixels();
    360             // Keep track of left and top (for drawing subsetBm into canvas). We could use
    361             // fscale * x and fscale * y, but we want integers such that the next subset will start
    362             // where the last one ended. So we'll add decodeInfo.width() and height().
    363             int left = 0;
    364             for (int x = 0; x < W; x += w) {
    365                 int top = 0;
    366                 for (int y = 0; y < H; y+= h) {
    367                     // Do not make the subset go off the edge of the image.
    368                     const int preScaleW = SkTMin(w, W - x);
    369                     const int preScaleH = SkTMin(h, H - y);
    370                     subset.setXYWH(x, y, preScaleW, preScaleH);
    371                     // And fscale
    372                     // FIXME: Should we have a version of getScaledDimensions that takes a subset
    373                     // into account?
    374                     decodeInfo = decodeInfo.makeWH(
    375                             SkTMax(1, SkScalarRoundToInt(preScaleW * fscale)),
    376                             SkTMax(1, SkScalarRoundToInt(preScaleH * fscale)));
    377                     size_t rowBytes = decodeInfo.minRowBytes();
    378                     if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes)) {
    379                         SkDebugf("[terminated] Could not install pixels.\n");
    380                         return;
    381                     }
    382                     const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
    383                             &opts);
    384                     switch (result) {
    385                         case SkCodec::kSuccess:
    386                         case SkCodec::kIncompleteInput:
    387                         case SkCodec::kErrorInInput:
    388                             SkDebugf("okay\n");
    389                             break;
    390                         case SkCodec::kInvalidConversion:
    391                             if (0 == (x|y)) {
    392                                 // First subset is okay to return unimplemented.
    393                                 SkDebugf("[terminated] Incompatible colortype conversion\n");
    394                                 return;
    395                             }
    396                             // If the first subset succeeded, a later one should not fail.
    397                             // fall through to failure
    398                         case SkCodec::kUnimplemented:
    399                             if (0 == (x|y)) {
    400                                 // First subset is okay to return unimplemented.
    401                                 SkDebugf("[terminated] subset codec not supported\n");
    402                                 return;
    403                             }
    404                             // If the first subset succeeded, why would a later one fail?
    405                             // fall through to failure
    406                         default:
    407                             SkDebugf("[terminated] subset codec failed to decode (%d, %d, %d, %d) "
    408                                                   "with dimensions (%d x %d)\t error %d\n",
    409                                                   x, y, decodeInfo.width(), decodeInfo.height(),
    410                                                   W, H, result);
    411                             return;
    412                     }
    413                     // translate by the scaled height.
    414                     top += decodeInfo.height();
    415                 }
    416                 // translate by the scaled width.
    417                 left += decodeInfo.width();
    418             }
    419             SkDebugf("[terminated] Success!\n");
    420             break;
    421         }
    422         case 4: { //kAnimated_Mode
    423             std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
    424             if (frameInfos.size() == 0) {
    425                 SkDebugf("[terminated] Not an animated image\n");
    426                 break;
    427             }
    428 
    429             for (size_t i = 0; i < frameInfos.size(); i++) {
    430                 options.fFrameIndex = i;
    431                 auto result = codec->startIncrementalDecode(decodeInfo, bitmap.getPixels(),
    432                         bitmap.rowBytes(), &options);
    433                 if (SkCodec::kSuccess != result) {
    434                     SkDebugf("[terminated] failed to start incremental decode "
    435                              "in frame %d with error %d\n", i, result);
    436                     return;
    437                 }
    438 
    439                 result = codec->incrementalDecode();
    440                 if (result == SkCodec::kIncompleteInput || result == SkCodec::kErrorInInput) {
    441                     SkDebugf("okay\n");
    442                     // Frames beyond this one will not decode.
    443                     break;
    444                 }
    445                 if (result == SkCodec::kSuccess) {
    446                     SkDebugf("okay - decoded frame %d\n", i);
    447                 } else {
    448                     SkDebugf("[terminated] incremental decode failed with "
    449                              "error %d\n", result);
    450                     return;
    451                 }
    452             }
    453             SkDebugf("[terminated] Success!\n");
    454             break;
    455         }
    456         default:
    457             SkDebugf("[terminated] Mode not implemented yet\n");
    458     }
    459 
    460     dump_png(bitmap);
    461 }
    462 
    463 static void fuzz_skp(sk_sp<SkData> bytes) {
    464     SkReadBuffer buf(bytes->data(), bytes->size());
    465     SkDebugf("Decoding\n");
    466     sk_sp<SkPicture> pic(SkPicture::MakeFromBuffer(buf));
    467     if (!pic) {
    468         SkDebugf("[terminated] Couldn't decode as a picture.\n");
    469         return;
    470     }
    471     SkDebugf("Rendering\n");
    472     SkBitmap bitmap;
    473     if (!FLAGS_dump.isEmpty()) {
    474         SkIRect size = pic->cullRect().roundOut();
    475         bitmap.allocN32Pixels(size.width(), size.height());
    476     }
    477     SkCanvas canvas(bitmap);
    478     canvas.drawPicture(pic);
    479     SkDebugf("[terminated] Success! Decoded and rendered an SkPicture!\n");
    480     dump_png(bitmap);
    481 }
    482 
    483 static void fuzz_skpipe(sk_sp<SkData> bytes) {
    484     SkPipeDeserializer d;
    485     SkDebugf("Decoding\n");
    486     sk_sp<SkPicture> pic(d.readPicture(bytes.get()));
    487     if (!pic) {
    488         SkDebugf("[terminated] Couldn't decode picture via SkPipe.\n");
    489         return;
    490     }
    491     SkDebugf("Rendering\n");
    492     SkBitmap bitmap;
    493     SkCanvas canvas(bitmap);
    494     canvas.drawPicture(pic);
    495     SkDebugf("[terminated] Success! Decoded and rendered an SkPicture from SkPipe!\n");
    496 }
    497 
    498 static void fuzz_icc(sk_sp<SkData> bytes) {
    499     sk_sp<SkColorSpace> space(SkColorSpace::MakeICC(bytes->data(), bytes->size()));
    500     if (!space) {
    501         SkDebugf("[terminated] Couldn't decode ICC.\n");
    502         return;
    503     }
    504     SkDebugf("[terminated] Success! Decoded ICC.\n");
    505 }
    506 
    507 static void fuzz_color_deserialize(sk_sp<SkData> bytes) {
    508     sk_sp<SkColorSpace> space(SkColorSpace::Deserialize(bytes->data(), bytes->size()));
    509     if (!space) {
    510         SkDebugf("[terminated] Couldn't deserialize Colorspace.\n");
    511         return;
    512     }
    513     SkDebugf("[terminated] Success! deserialized Colorspace.\n");
    514 }
    515 
    516 static void fuzz_path_deserialize(sk_sp<SkData> bytes) {
    517     SkPath path;
    518     SkReadBuffer buf(bytes->data(), bytes->size());
    519     buf.readPath(&path);
    520     if (!buf.isValid()) {
    521         SkDebugf("[terminated] Couldn't deserialize SkPath.\n");
    522         return;
    523     }
    524 
    525     auto s = SkSurface::MakeRasterN32Premul(1024, 1024);
    526     s->getCanvas()->drawPath(path, SkPaint());
    527     SkDebugf("[terminated] Success! Initialized SkPath.\n");
    528 }
    529 
    530 bool FuzzRegionDeserialize(sk_sp<SkData> bytes);
    531 
    532 static void fuzz_region_deserialize(sk_sp<SkData> bytes) {
    533     if (!FuzzRegionDeserialize(bytes)) {
    534         SkDebugf("[terminated] Couldn't initialize SkRegion.\n");
    535         return;
    536     }
    537     SkDebugf("[terminated] Success! Initialized SkRegion.\n");
    538 }
    539 
    540 static void fuzz_textblob_deserialize(sk_sp<SkData> bytes) {
    541     SkReadBuffer buf(bytes->data(), bytes->size());
    542     auto tb = SkTextBlob::MakeFromBuffer(buf);
    543     if (!buf.isValid()) {
    544         SkDebugf("[terminated] Couldn't deserialize SkTextBlob.\n");
    545         return;
    546     }
    547 
    548     auto s = SkSurface::MakeRasterN32Premul(512, 512);
    549     s->getCanvas()->drawTextBlob(tb, 200, 200, SkPaint());
    550     SkDebugf("[terminated] Success! Initialized SkTextBlob.\n");
    551 }
    552 
    553 void FuzzRegionSetPath(Fuzz* fuzz);
    554 
    555 static void fuzz_region_set_path(sk_sp<SkData> bytes) {
    556     Fuzz fuzz(bytes);
    557     FuzzRegionSetPath(&fuzz);
    558     SkDebugf("[terminated] region_set_path didn't crash!\n");
    559 }
    560 
    561 static void fuzz_filter_fuzz(sk_sp<SkData> bytes) {
    562     const int BitmapSize = 24;
    563     SkBitmap bitmap;
    564     bitmap.allocN32Pixels(BitmapSize, BitmapSize);
    565     SkCanvas canvas(bitmap);
    566     canvas.clear(0x00000000);
    567 
    568     auto flattenable = SkImageFilter::Deserialize(bytes->data(), bytes->size());
    569 
    570     // Adding some info, but the test passed if we got here without any trouble
    571     if (flattenable != nullptr) {
    572         SkDebugf("Valid stream detected.\n");
    573         // Let's see if using the filters can cause any trouble...
    574         SkPaint paint;
    575         paint.setImageFilter(flattenable);
    576         canvas.save();
    577         canvas.clipRect(SkRect::MakeXYWH(
    578             0, 0, SkIntToScalar(BitmapSize), SkIntToScalar(BitmapSize)));
    579 
    580         // This call shouldn't crash or cause ASAN to flag any memory issues
    581         // If nothing bad happens within this call, everything is fine
    582         canvas.drawBitmap(bitmap, 0, 0, &paint);
    583 
    584         SkDebugf("Filter DAG rendered successfully\n");
    585         canvas.restore();
    586     } else {
    587         SkDebugf("Invalid stream detected.\n");
    588     }
    589 
    590     SkDebugf("[terminated] Done\n");
    591 }
    592 
    593 #if SK_SUPPORT_GPU
    594 static void fuzz_sksl2glsl(sk_sp<SkData> bytes) {
    595     SkSL::Compiler compiler;
    596     SkSL::String output;
    597     SkSL::Program::Settings settings;
    598     sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
    599     settings.fCaps = caps.get();
    600     std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
    601                                                           SkSL::String((const char*) bytes->data()),
    602                                                           settings);
    603     if (!program || !compiler.toGLSL(*program, &output)) {
    604         SkDebugf("[terminated] Couldn't compile input.\n");
    605         return;
    606     }
    607     SkDebugf("[terminated] Success! Compiled input.\n");
    608 }
    609 #endif
    610