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