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