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 
main(int argc,char ** argv)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 
fuzz_file(SkString path,SkString type)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 
try_auto_detect(SkString path,SkString * name)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 
fuzz_json(sk_sp<SkData> bytes)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 
fuzz_skottie_json(sk_sp<SkData> bytes)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 (%).
calculate_option(SkData * bytes)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 
print_api_names()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 
fuzz_api(sk_sp<SkData> bytes,SkString name)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 
dump_png(SkBitmap bitmap)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 
fuzz_animated_img(sk_sp<SkData> bytes)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 
fuzz_image_decode(sk_sp<SkData> bytes)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 
fuzz_image_decode_incremental(sk_sp<SkData> bytes)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 
fuzz_android_codec(sk_sp<SkData> bytes)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.
fuzz_img(sk_sp<SkData> bytes,uint8_t scale,uint8_t mode)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 
fuzz_skp(sk_sp<SkData> bytes)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 
fuzz_color_deserialize(sk_sp<SkData> bytes)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 
fuzz_path_deserialize(sk_sp<SkData> bytes)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 
fuzz_region_deserialize(sk_sp<SkData> bytes)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 
fuzz_textblob_deserialize(sk_sp<SkData> bytes)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 
fuzz_region_set_path(sk_sp<SkData> bytes)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 
fuzz_filter_fuzz(sk_sp<SkData> bytes)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 
fuzz_sksl2glsl(sk_sp<SkData> bytes)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 
fuzz_sksl2spirv(sk_sp<SkData> bytes)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 
fuzz_sksl2metal(sk_sp<SkData> bytes)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