blob: 657879ea9b13dda890751258345bf6678021f7a3 [file] [log] [blame]
mtklein65e58242016-01-13 12:57:57 -08001/*
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"
kjlubickdba57342016-01-21 05:03:28 -08009#include "SkCanvas.h"
10#include "SkCodec.h"
mtkleinf5e97822016-01-15 06:19:53 -080011#include "SkCommandLineFlags.h"
kjlubickdba57342016-01-21 05:03:28 -080012#include "SkData.h"
kjlubickdba57342016-01-21 05:03:28 -080013#include "SkImage.h"
14#include "SkImageEncoder.h"
15#include "SkMallocPixelRef.h"
Kevin Lubickf80f1152017-01-06 08:26:56 -050016#include "SkOSFile.h"
17#include "SkOSPath.h"
Herb Derbya839fc02017-03-16 12:30:43 -040018#include "SkPaint.h"
Hal Canary62176db2017-02-27 16:42:03 -050019#include "SkPath.h"
kjlubicke5654502016-07-19 16:50:03 -070020#include "SkPicture.h"
Kevin Lubick0d825662018-01-03 14:38:48 -050021#include "SkPipe.h"
Mike Reedfadbfcd2017-12-06 16:09:20 -050022#include "SkReadBuffer.h"
Hal Canary62176db2017-02-27 16:42:03 -050023#include "SkStream.h"
24#include "SkSurface.h"
Kevin Lubickd46e85f2017-11-21 17:13:35 -050025#include "SkTextBlob.h"
Hal Canary62176db2017-02-27 16:42:03 -050026
Ethan Nicholas7ef4b742016-11-11 15:16:46 -050027#if SK_SUPPORT_GPU
kjlubicke7195772016-10-18 10:06:24 -070028#include "SkSLCompiler.h"
Ethan Nicholas7ef4b742016-11-11 15:16:46 -050029#endif
kjlubickdba57342016-01-21 05:03:28 -080030
Hal Canary62176db2017-02-27 16:42:03 -050031#include <iostream>
mtkleina1159422016-01-15 05:46:54 -080032#include <signal.h>
Hal Canarydb683012016-11-23 08:55:18 -070033#include "sk_tool_utils.h"
34
Kevin Lubick2541edf2018-01-11 10:27:14 -050035
Hal Canary62176db2017-02-27 16:42:03 -050036DEFINE_string2(bytes, b, "", "A path to a file or a directory. If a file, the "
37 "contents will be used as the fuzz bytes. If a directory, all files "
38 "in the directory will be used as fuzz bytes for the fuzzer, one at a "
39 "time.");
mtkleind4387ea2016-01-21 06:13:52 -080040DEFINE_string2(name, n, "", "If --type is 'api', fuzz the API with this name.");
Hal Canary62176db2017-02-27 16:42:03 -050041DEFINE_string2(dump, d, "", "If not empty, dump 'image*' or 'skp' types as a "
42 "PNG with this name.");
Kevin Lubick9ff5dc92018-01-09 12:47:33 -050043DEFINE_bool2(verbose, v, false, "Print more information while fuzzing.");
44DEFINE_string2(type, t, "", "How to interpret --bytes, one of:\n"
Kevin Lubick2416f962018-02-12 08:26:39 -050045 "animated_image_decode\n"
Kevin Lubick9ff5dc92018-01-09 12:47:33 -050046 "api\n"
47 "color_deserialize\n"
48 "filter_fuzz (equivalent to Chrome's filter_fuzz_stub)\n"
49 "icc\n"
Kevin Lubick2416f962018-02-12 08:26:39 -050050 "image_decode\n"
Kevin Lubick9ff5dc92018-01-09 12:47:33 -050051 "image_mode\n"
52 "image_scale\n"
53 "path_deserialize\n"
54 "pipe\n"
55 "region_deserialize\n"
Kevin Lubick2541edf2018-01-11 10:27:14 -050056 "region_set_path\n"
Kevin Lubick9ff5dc92018-01-09 12:47:33 -050057 "skp\n"
58 "sksl2glsl\n"
59 "textblob");
kjlubickdba57342016-01-21 05:03:28 -080060
Kevin Lubickf80f1152017-01-06 08:26:56 -050061static int fuzz_file(const char* path);
kjlubick2a42f482016-02-16 16:14:23 -080062static uint8_t calculate_option(SkData*);
kjlubickdba57342016-01-21 05:03:28 -080063
Kevin Lubickf80f1152017-01-06 08:26:56 -050064static void fuzz_api(sk_sp<SkData>);
Kevin Lubickf80f1152017-01-06 08:26:56 -050065static void fuzz_color_deserialize(sk_sp<SkData>);
Kevin Lubickd46e85f2017-11-21 17:13:35 -050066static void fuzz_filter_fuzz(sk_sp<SkData>);
Kevin Lubick0168e042017-02-14 13:12:37 -050067static void fuzz_icc(sk_sp<SkData>);
Kevin Lubick2416f962018-02-12 08:26:39 -050068static void fuzz_img2(sk_sp<SkData>);
69static void fuzz_animated_img(sk_sp<SkData>);
Kevin Lubick0168e042017-02-14 13:12:37 -050070static void fuzz_img(sk_sp<SkData>, uint8_t, uint8_t);
Kevin Lubickf04c50a2017-01-06 13:48:19 -050071static void fuzz_path_deserialize(sk_sp<SkData>);
Kevin Lubickedee1ae2017-02-20 17:47:18 -050072static void fuzz_region_deserialize(sk_sp<SkData>);
Kevin Lubick2541edf2018-01-11 10:27:14 -050073static void fuzz_region_set_path(sk_sp<SkData>);
Kevin Lubick0168e042017-02-14 13:12:37 -050074static void fuzz_skp(sk_sp<SkData>);
Kevin Lubick0d825662018-01-03 14:38:48 -050075static void fuzz_skpipe(sk_sp<SkData>);
Kevin Lubickd46e85f2017-11-21 17:13:35 -050076static void fuzz_textblob_deserialize(sk_sp<SkData>);
Herb Derbya839fc02017-03-16 12:30:43 -040077
Ethan Nicholas7ef4b742016-11-11 15:16:46 -050078#if SK_SUPPORT_GPU
Kevin Lubickf80f1152017-01-06 08:26:56 -050079static void fuzz_sksl2glsl(sk_sp<SkData>);
Ethan Nicholas7ef4b742016-11-11 15:16:46 -050080#endif
mtklein65e58242016-01-13 12:57:57 -080081
82int main(int argc, char** argv) {
Kevin Lubick9ff5dc92018-01-09 12:47:33 -050083 SkCommandLineFlags::SetUsage("Usage: fuzz -t <type> -b <path/to/file> [-n api-to-fuzz]\n"
84 "--help lists the valid types\n");
mtkleinf5e97822016-01-15 06:19:53 -080085 SkCommandLineFlags::Parse(argc, argv);
86
mtkleind0b82342016-01-15 07:56:20 -080087 const char* path = FLAGS_bytes.isEmpty() ? argv[0] : FLAGS_bytes[0];
Kevin Lubickf80f1152017-01-06 08:26:56 -050088
89 if (!sk_isdir(path)) {
90 return fuzz_file(path);
91 }
92
93 SkOSFile::Iter it(path);
94 for (SkString file; it.next(&file); ) {
95 SkString p = SkOSPath::Join(path, file.c_str());
96 SkDebugf("Fuzzing %s\n", p.c_str());
97 int rv = fuzz_file(p.c_str());
98 if (rv != 0) {
99 return rv;
100 }
101 }
102 return 0;
103}
104
105static int fuzz_file(const char* path) {
bungeman38d909e2016-08-02 14:40:46 -0700106 sk_sp<SkData> bytes(SkData::MakeFromFileName(path));
kjlubickdba57342016-01-21 05:03:28 -0800107 if (!bytes) {
108 SkDebugf("Could not read %s\n", path);
Kevin Lubickf80f1152017-01-06 08:26:56 -0500109 return 1;
kjlubickdba57342016-01-21 05:03:28 -0800110 }
mtklein65e58242016-01-13 12:57:57 -0800111
mtkleind4387ea2016-01-21 06:13:52 -0800112 if (!FLAGS_type.isEmpty()) {
Kevin Lubick2416f962018-02-12 08:26:39 -0500113 if (0 == strcmp("animated_image_decode", FLAGS_type[0])) {
114 fuzz_animated_img(bytes);
115 return 0;
116 }
kjlubicke7195772016-10-18 10:06:24 -0700117 if (0 == strcmp("api", FLAGS_type[0])) {
Kevin Lubickf80f1152017-01-06 08:26:56 -0500118 fuzz_api(bytes);
119 return 0;
kjlubicke7195772016-10-18 10:06:24 -0700120 }
121 if (0 == strcmp("color_deserialize", FLAGS_type[0])) {
Kevin Lubickf80f1152017-01-06 08:26:56 -0500122 fuzz_color_deserialize(bytes);
123 return 0;
kjlubicke7195772016-10-18 10:06:24 -0700124 }
125 if (0 == strcmp("icc", FLAGS_type[0])) {
Kevin Lubickf80f1152017-01-06 08:26:56 -0500126 fuzz_icc(bytes);
127 return 0;
kjlubicke7195772016-10-18 10:06:24 -0700128 }
Kevin Lubick2416f962018-02-12 08:26:39 -0500129 if (0 == strcmp("image_decode", FLAGS_type[0])) {
130 fuzz_img2(bytes);
131 return 0;
132 }
kjlubicke7195772016-10-18 10:06:24 -0700133 if (0 == strcmp("image_scale", FLAGS_type[0])) {
Kevin Lubickc9d28292017-11-09 08:12:56 -0500134 uint8_t option = calculate_option(bytes.get());
Kevin Lubickf80f1152017-01-06 08:26:56 -0500135 fuzz_img(bytes, option, 0);
136 return 0;
kjlubicke7195772016-10-18 10:06:24 -0700137 }
138 if (0 == strcmp("image_mode", FLAGS_type[0])) {
Kevin Lubickc9d28292017-11-09 08:12:56 -0500139 uint8_t option = calculate_option(bytes.get());
Kevin Lubickf80f1152017-01-06 08:26:56 -0500140 fuzz_img(bytes, 0, option);
141 return 0;
kjlubicke7195772016-10-18 10:06:24 -0700142 }
Kevin Lubickf04c50a2017-01-06 13:48:19 -0500143 if (0 == strcmp("path_deserialize", FLAGS_type[0])) {
144 fuzz_path_deserialize(bytes);
145 return 0;
146 }
Kevin Lubickedee1ae2017-02-20 17:47:18 -0500147 if (0 == strcmp("region_deserialize", FLAGS_type[0])) {
148 fuzz_region_deserialize(bytes);
149 return 0;
150 }
Kevin Lubick2541edf2018-01-11 10:27:14 -0500151 if (0 == strcmp("region_set_path", FLAGS_type[0])) {
152 fuzz_region_set_path(bytes);
153 return 0;
154 }
Kevin Lubick0d825662018-01-03 14:38:48 -0500155 if (0 == strcmp("pipe", FLAGS_type[0])) {
156 fuzz_skpipe(bytes);
157 return 0;
158 }
kjlubicke7195772016-10-18 10:06:24 -0700159 if (0 == strcmp("skp", FLAGS_type[0])) {
Kevin Lubickf80f1152017-01-06 08:26:56 -0500160 fuzz_skp(bytes);
161 return 0;
kjlubicke7195772016-10-18 10:06:24 -0700162 }
Herb Derbya839fc02017-03-16 12:30:43 -0400163 if (0 == strcmp("filter_fuzz", FLAGS_type[0])) {
164 fuzz_filter_fuzz(bytes);
165 return 0;
166 }
Kevin Lubickd46e85f2017-11-21 17:13:35 -0500167 if (0 == strcmp("textblob", FLAGS_type[0])) {
168 fuzz_textblob_deserialize(bytes);
169 return 0;
170 }
Ethan Nicholas7ef4b742016-11-11 15:16:46 -0500171#if SK_SUPPORT_GPU
kjlubicke7195772016-10-18 10:06:24 -0700172 if (0 == strcmp("sksl2glsl", FLAGS_type[0])) {
Kevin Lubickf80f1152017-01-06 08:26:56 -0500173 fuzz_sksl2glsl(bytes);
174 return 0;
mtkleind4387ea2016-01-21 06:13:52 -0800175 }
Ethan Nicholas7ef4b742016-11-11 15:16:46 -0500176#endif
kjlubickdba57342016-01-21 05:03:28 -0800177 }
Kevin Lubick9ff5dc92018-01-09 12:47:33 -0500178 SkCommandLineFlags::PrintUsage();
179 return 1;
kjlubickdba57342016-01-21 05:03:28 -0800180}
181
kjlubick2a42f482016-02-16 16:14:23 -0800182// This adds up the first 1024 bytes and returns it as an 8 bit integer. This allows afl-fuzz to
183// deterministically excercise different paths, or *options* (such as different scaling sizes or
184// different image modes) without needing to introduce a parameter. This way we don't need a
185// image_scale1, image_scale2, image_scale4, etc fuzzer, we can just have a image_scale fuzzer.
186// Clients are expected to transform this number into a different range, e.g. with modulo (%).
187static uint8_t calculate_option(SkData* bytes) {
188 uint8_t total = 0;
189 const uint8_t* data = bytes->bytes();
190 for (size_t i = 0; i < 1024 && i < bytes->size(); i++) {
191 total += data[i];
192 }
193 return total;
194}
195
Kevin Lubickf80f1152017-01-06 08:26:56 -0500196static void fuzz_api(sk_sp<SkData> bytes) {
mtkleind4387ea2016-01-21 06:13:52 -0800197 const char* name = FLAGS_name.isEmpty() ? "" : FLAGS_name[0];
198
Mike Reedab273fa2017-01-11 13:58:55 -0500199 for (auto r = sk_tools::Registry<Fuzzable>::Head(); r; r = r->next()) {
mtklein65e58242016-01-13 12:57:57 -0800200 auto fuzzable = r->factory();
mtkleind4387ea2016-01-21 06:13:52 -0800201 if (0 == strcmp(name, fuzzable.name)) {
mtkleinf5e97822016-01-15 06:19:53 -0800202 SkDebugf("Fuzzing %s...\n", fuzzable.name);
Kevin Lubick1ac8fd22017-03-01 10:42:45 -0500203 Fuzz fuzz(std::move(bytes));
mtklein65e58242016-01-13 12:57:57 -0800204 fuzzable.fn(&fuzz);
kjlubick47d158e2016-02-01 08:23:50 -0800205 SkDebugf("[terminated] Success!\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500206 return;
mtklein65e58242016-01-13 12:57:57 -0800207 }
208 }
mtkleind4387ea2016-01-21 06:13:52 -0800209
210 SkDebugf("When using --type api, please choose an API to fuzz with --name/-n:\n");
Mike Reedab273fa2017-01-11 13:58:55 -0500211 for (auto r = sk_tools::Registry<Fuzzable>::Head(); r; r = r->next()) {
mtkleind4387ea2016-01-21 06:13:52 -0800212 auto fuzzable = r->factory();
213 SkDebugf("\t%s\n", fuzzable.name);
214 }
kjlubickdba57342016-01-21 05:03:28 -0800215}
216
217static void dump_png(SkBitmap bitmap) {
218 if (!FLAGS_dump.isEmpty()) {
Hal Canarydb683012016-11-23 08:55:18 -0700219 sk_tool_utils::EncodeImageToFile(FLAGS_dump[0], bitmap, SkEncodedImageFormat::kPNG, 100);
kjlubickdba57342016-01-21 05:03:28 -0800220 SkDebugf("Dumped to %s\n", FLAGS_dump[0]);
221 }
222}
223
Kevin Lubick2416f962018-02-12 08:26:39 -0500224void FuzzAnimatedImage(sk_sp<SkData> bytes);
225
226static void fuzz_animated_img(sk_sp<SkData> bytes) {
227 FuzzAnimatedImage(bytes);
228 SkDebugf("[terminated] Didn't crash while decoding/drawing animated image!\n");
229}
230
231void FuzzImage(sk_sp<SkData> bytes);
232
233static void fuzz_img2(sk_sp<SkData> bytes) {
234 FuzzImage(bytes);
235 SkDebugf("[terminated] Didn't crash while decoding/drawing image!\n");
236}
237
Kevin Lubickf80f1152017-01-06 08:26:56 -0500238static void fuzz_img(sk_sp<SkData> bytes, uint8_t scale, uint8_t mode) {
kjlubick2a42f482016-02-16 16:14:23 -0800239 // We can scale 1x, 2x, 4x, 8x, 16x
240 scale = scale % 5;
kjlubick5bd98a22016-02-18 06:27:38 -0800241 float fscale = (float)pow(2.0f, scale);
242 SkDebugf("Scaling factor: %f\n", fscale);
kjlubick2a42f482016-02-16 16:14:23 -0800243
Leon Scroggins IIIc5a83662016-12-08 09:07:56 -0500244 // We have 5 different modes of decoding.
245 mode = mode % 5;
kjlubick2a42f482016-02-16 16:14:23 -0800246 SkDebugf("Mode: %d\n", mode);
247
248 // This is mostly copied from DMSrcSink's CodecSrc::draw method.
kjlubick47d158e2016-02-01 08:23:50 -0800249 SkDebugf("Decoding\n");
Mike Reedede7bac2017-07-23 15:30:02 -0400250 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(bytes));
kjlubickdba57342016-01-21 05:03:28 -0800251 if (nullptr == codec.get()) {
kjlubick47d158e2016-02-01 08:23:50 -0800252 SkDebugf("[terminated] Couldn't create codec.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500253 return;
kjlubickdba57342016-01-21 05:03:28 -0800254 }
255
256 SkImageInfo decodeInfo = codec->getInfo();
kjlubick2a42f482016-02-16 16:14:23 -0800257 SkISize size = codec->getScaledDimensions(fscale);
258 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
259
kjlubickdba57342016-01-21 05:03:28 -0800260 SkBitmap bitmap;
kjlubickdba57342016-01-21 05:03:28 -0800261 SkCodec::Options options;
262 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
263
Mike Reed086a4272017-07-18 10:53:11 -0400264 if (!bitmap.tryAllocPixelsFlags(decodeInfo, SkBitmap::kZeroPixels_AllocFlag)) {
kjlubick47d158e2016-02-01 08:23:50 -0800265 SkDebugf("[terminated] Could not allocate memory. Image might be too large (%d x %d)",
kjlubick2a42f482016-02-16 16:14:23 -0800266 decodeInfo.width(), decodeInfo.height());
Kevin Lubickf80f1152017-01-06 08:26:56 -0500267 return;
kjlubickdba57342016-01-21 05:03:28 -0800268 }
269
kjlubick2a42f482016-02-16 16:14:23 -0800270 switch (mode) {
271 case 0: {//kCodecZeroInit_Mode, kCodec_Mode
Leon Scroggins571b30f2017-07-11 17:35:31 +0000272 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), &options)) {
kjlubick2a42f482016-02-16 16:14:23 -0800273 case SkCodec::kSuccess:
274 SkDebugf("[terminated] Success!\n");
275 break;
276 case SkCodec::kIncompleteInput:
277 SkDebugf("[terminated] Partial Success\n");
278 break;
Leon Scroggins III674a1842017-07-06 12:26:09 -0400279 case SkCodec::kErrorInInput:
280 SkDebugf("[terminated] Partial Success with error\n");
281 break;
kjlubick2a42f482016-02-16 16:14:23 -0800282 case SkCodec::kInvalidConversion:
283 SkDebugf("Incompatible colortype conversion\n");
284 // Crash to allow afl-fuzz to know this was a bug.
285 raise(SIGSEGV);
286 default:
287 SkDebugf("[terminated] Couldn't getPixels.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500288 return;
kjlubick2a42f482016-02-16 16:14:23 -0800289 }
290 break;
291 }
292 case 1: {//kScanline_Mode
Leon Scroggins571b30f2017-07-11 17:35:31 +0000293 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) {
294 SkDebugf("[terminated] Could not start scanline decoder\n");
295 return;
296 }
kjlubick2a42f482016-02-16 16:14:23 -0800297
298 void* dst = bitmap.getAddr(0, 0);
299 size_t rowBytes = bitmap.rowBytes();
300 uint32_t height = decodeInfo.height();
301 switch (codec->getScanlineOrder()) {
302 case SkCodec::kTopDown_SkScanlineOrder:
303 case SkCodec::kBottomUp_SkScanlineOrder:
kjlubick2a42f482016-02-16 16:14:23 -0800304 // We do not need to check the return value. On an incomplete
305 // image, memory will be filled with a default value.
306 codec->getScanlines(dst, height, rowBytes);
307 break;
kjlubick2a42f482016-02-16 16:14:23 -0800308 }
kjlubick47d158e2016-02-01 08:23:50 -0800309 SkDebugf("[terminated] Success!\n");
kjlubickdba57342016-01-21 05:03:28 -0800310 break;
kjlubick2a42f482016-02-16 16:14:23 -0800311 }
312 case 2: { //kStripe_Mode
313 const int height = decodeInfo.height();
314 // This value is chosen arbitrarily. We exercise more cases by choosing a value that
315 // does not align with image blocks.
316 const int stripeHeight = 37;
317 const int numStripes = (height + stripeHeight - 1) / stripeHeight;
318
319 // Decode odd stripes
Leon Scroggins571b30f2017-07-11 17:35:31 +0000320 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)
kjlubick2a42f482016-02-16 16:14:23 -0800321 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) {
322 // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
323 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
324 // to run this test for image types that do not have this scanline ordering.
325 SkDebugf("[terminated] Could not start top-down scanline decoder\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500326 return;
kjlubick2a42f482016-02-16 16:14:23 -0800327 }
328
329 for (int i = 0; i < numStripes; i += 2) {
330 // Skip a stripe
331 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
332 codec->skipScanlines(linesToSkip);
333
334 // Read a stripe
335 const int startY = (i + 1) * stripeHeight;
336 const int linesToRead = SkTMin(stripeHeight, height - startY);
337 if (linesToRead > 0) {
338 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
339 }
340 }
341
342 // Decode even stripes
Leon Scroggins571b30f2017-07-11 17:35:31 +0000343 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo);
kjlubick2a42f482016-02-16 16:14:23 -0800344 if (SkCodec::kSuccess != startResult) {
345 SkDebugf("[terminated] Failed to restart scanline decoder with same parameters.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500346 return;
kjlubick2a42f482016-02-16 16:14:23 -0800347 }
348 for (int i = 0; i < numStripes; i += 2) {
349 // Read a stripe
350 const int startY = i * stripeHeight;
351 const int linesToRead = SkTMin(stripeHeight, height - startY);
352 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
353
354 // Skip a stripe
355 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
356 if (linesToSkip > 0) {
357 codec->skipScanlines(linesToSkip);
358 }
359 }
360 SkDebugf("[terminated] Success!\n");
kjlubickdba57342016-01-21 05:03:28 -0800361 break;
kjlubick2a42f482016-02-16 16:14:23 -0800362 }
363 case 3: { //kSubset_Mode
364 // Arbitrarily choose a divisor.
365 int divisor = 2;
366 // Total width/height of the image.
367 const int W = codec->getInfo().width();
368 const int H = codec->getInfo().height();
369 if (divisor > W || divisor > H) {
370 SkDebugf("[terminated] Cannot codec subset: divisor %d is too big "
371 "with dimensions (%d x %d)\n", divisor, W, H);
Kevin Lubickf80f1152017-01-06 08:26:56 -0500372 return;
kjlubick2a42f482016-02-16 16:14:23 -0800373 }
374 // subset dimensions
375 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
376 const int w = SkAlign2(W / divisor);
377 const int h = SkAlign2(H / divisor);
378 SkIRect subset;
379 SkCodec::Options opts;
380 opts.fSubset = &subset;
381 SkBitmap subsetBm;
382 // We will reuse pixel memory from bitmap.
383 void* pixels = bitmap.getPixels();
384 // Keep track of left and top (for drawing subsetBm into canvas). We could use
385 // fscale * x and fscale * y, but we want integers such that the next subset will start
386 // where the last one ended. So we'll add decodeInfo.width() and height().
387 int left = 0;
388 for (int x = 0; x < W; x += w) {
389 int top = 0;
390 for (int y = 0; y < H; y+= h) {
391 // Do not make the subset go off the edge of the image.
392 const int preScaleW = SkTMin(w, W - x);
393 const int preScaleH = SkTMin(h, H - y);
394 subset.setXYWH(x, y, preScaleW, preScaleH);
395 // And fscale
396 // FIXME: Should we have a version of getScaledDimensions that takes a subset
397 // into account?
398 decodeInfo = decodeInfo.makeWH(
399 SkTMax(1, SkScalarRoundToInt(preScaleW * fscale)),
400 SkTMax(1, SkScalarRoundToInt(preScaleH * fscale)));
401 size_t rowBytes = decodeInfo.minRowBytes();
Leon Scroggins571b30f2017-07-11 17:35:31 +0000402 if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes)) {
kjlubick2a42f482016-02-16 16:14:23 -0800403 SkDebugf("[terminated] Could not install pixels.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500404 return;
kjlubick2a42f482016-02-16 16:14:23 -0800405 }
406 const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
Leon Scroggins571b30f2017-07-11 17:35:31 +0000407 &opts);
kjlubick2a42f482016-02-16 16:14:23 -0800408 switch (result) {
409 case SkCodec::kSuccess:
410 case SkCodec::kIncompleteInput:
Leon Scroggins III674a1842017-07-06 12:26:09 -0400411 case SkCodec::kErrorInInput:
kjlubick2a42f482016-02-16 16:14:23 -0800412 SkDebugf("okay\n");
413 break;
414 case SkCodec::kInvalidConversion:
415 if (0 == (x|y)) {
416 // First subset is okay to return unimplemented.
417 SkDebugf("[terminated] Incompatible colortype conversion\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500418 return;
kjlubick2a42f482016-02-16 16:14:23 -0800419 }
420 // If the first subset succeeded, a later one should not fail.
421 // fall through to failure
422 case SkCodec::kUnimplemented:
423 if (0 == (x|y)) {
424 // First subset is okay to return unimplemented.
425 SkDebugf("[terminated] subset codec not supported\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500426 return;
kjlubick2a42f482016-02-16 16:14:23 -0800427 }
428 // If the first subset succeeded, why would a later one fail?
429 // fall through to failure
430 default:
431 SkDebugf("[terminated] subset codec failed to decode (%d, %d, %d, %d) "
432 "with dimensions (%d x %d)\t error %d\n",
433 x, y, decodeInfo.width(), decodeInfo.height(),
434 W, H, result);
Kevin Lubickf80f1152017-01-06 08:26:56 -0500435 return;
kjlubick2a42f482016-02-16 16:14:23 -0800436 }
437 // translate by the scaled height.
438 top += decodeInfo.height();
439 }
440 // translate by the scaled width.
441 left += decodeInfo.width();
442 }
443 SkDebugf("[terminated] Success!\n");
444 break;
445 }
Leon Scroggins IIIc5a83662016-12-08 09:07:56 -0500446 case 4: { //kAnimated_Mode
447 std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
448 if (frameInfos.size() == 0) {
449 SkDebugf("[terminated] Not an animated image\n");
450 break;
451 }
452
453 for (size_t i = 0; i < frameInfos.size(); i++) {
454 options.fFrameIndex = i;
455 auto result = codec->startIncrementalDecode(decodeInfo, bitmap.getPixels(),
456 bitmap.rowBytes(), &options);
457 if (SkCodec::kSuccess != result) {
458 SkDebugf("[terminated] failed to start incremental decode "
459 "in frame %d with error %d\n", i, result);
Kevin Lubickf80f1152017-01-06 08:26:56 -0500460 return;
Leon Scroggins IIIc5a83662016-12-08 09:07:56 -0500461 }
462
463 result = codec->incrementalDecode();
Leon Scroggins III674a1842017-07-06 12:26:09 -0400464 if (result == SkCodec::kIncompleteInput || result == SkCodec::kErrorInInput) {
Leon Scroggins IIIc5a83662016-12-08 09:07:56 -0500465 SkDebugf("okay\n");
466 // Frames beyond this one will not decode.
467 break;
468 }
469 if (result == SkCodec::kSuccess) {
470 SkDebugf("okay - decoded frame %d\n", i);
471 } else {
472 SkDebugf("[terminated] incremental decode failed with "
473 "error %d\n", result);
Kevin Lubickf80f1152017-01-06 08:26:56 -0500474 return;
Leon Scroggins IIIc5a83662016-12-08 09:07:56 -0500475 }
476 }
477 SkDebugf("[terminated] Success!\n");
478 break;
479 }
kjlubickdba57342016-01-21 05:03:28 -0800480 default:
kjlubick2a42f482016-02-16 16:14:23 -0800481 SkDebugf("[terminated] Mode not implemented yet\n");
kjlubickdba57342016-01-21 05:03:28 -0800482 }
483
484 dump_png(bitmap);
mtklein65e58242016-01-13 12:57:57 -0800485}
486
Kevin Lubickf80f1152017-01-06 08:26:56 -0500487static void fuzz_skp(sk_sp<SkData> bytes) {
Kevin Lubick09757b22017-12-12 12:52:39 -0500488 SkReadBuffer buf(bytes->data(), bytes->size());
kjlubickdba57342016-01-21 05:03:28 -0800489 SkDebugf("Decoding\n");
Kevin Lubick09757b22017-12-12 12:52:39 -0500490 sk_sp<SkPicture> pic(SkPicture::MakeFromBuffer(buf));
kjlubickdba57342016-01-21 05:03:28 -0800491 if (!pic) {
kjlubick47d158e2016-02-01 08:23:50 -0800492 SkDebugf("[terminated] Couldn't decode as a picture.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500493 return;
kjlubickdba57342016-01-21 05:03:28 -0800494 }
495 SkDebugf("Rendering\n");
496 SkBitmap bitmap;
497 if (!FLAGS_dump.isEmpty()) {
498 SkIRect size = pic->cullRect().roundOut();
499 bitmap.allocN32Pixels(size.width(), size.height());
500 }
501 SkCanvas canvas(bitmap);
502 canvas.drawPicture(pic);
kjlubick47d158e2016-02-01 08:23:50 -0800503 SkDebugf("[terminated] Success! Decoded and rendered an SkPicture!\n");
kjlubickdba57342016-01-21 05:03:28 -0800504 dump_png(bitmap);
kjlubickdba57342016-01-21 05:03:28 -0800505}
mtklein65e58242016-01-13 12:57:57 -0800506
Kevin Lubick0d825662018-01-03 14:38:48 -0500507static void fuzz_skpipe(sk_sp<SkData> bytes) {
508 SkPipeDeserializer d;
509 SkDebugf("Decoding\n");
510 sk_sp<SkPicture> pic(d.readPicture(bytes.get()));
511 if (!pic) {
512 SkDebugf("[terminated] Couldn't decode picture via SkPipe.\n");
513 return;
514 }
515 SkDebugf("Rendering\n");
516 SkBitmap bitmap;
517 SkCanvas canvas(bitmap);
518 canvas.drawPicture(pic);
519 SkDebugf("[terminated] Success! Decoded and rendered an SkPicture from SkPipe!\n");
520}
521
Kevin Lubickf80f1152017-01-06 08:26:56 -0500522static void fuzz_icc(sk_sp<SkData> bytes) {
Brian Osman526972e2016-10-24 09:24:02 -0400523 sk_sp<SkColorSpace> space(SkColorSpace::MakeICC(bytes->data(), bytes->size()));
kjlubick897a8e32016-06-09 07:15:12 -0700524 if (!space) {
525 SkDebugf("[terminated] Couldn't decode ICC.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500526 return;
kjlubick897a8e32016-06-09 07:15:12 -0700527 }
528 SkDebugf("[terminated] Success! Decoded ICC.\n");
kjlubick897a8e32016-06-09 07:15:12 -0700529}
530
Kevin Lubickf80f1152017-01-06 08:26:56 -0500531static void fuzz_color_deserialize(sk_sp<SkData> bytes) {
kjlubick3e3c1a52016-06-23 10:49:27 -0700532 sk_sp<SkColorSpace> space(SkColorSpace::Deserialize(bytes->data(), bytes->size()));
533 if (!space) {
534 SkDebugf("[terminated] Couldn't deserialize Colorspace.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500535 return;
kjlubick3e3c1a52016-06-23 10:49:27 -0700536 }
537 SkDebugf("[terminated] Success! deserialized Colorspace.\n");
kjlubick3e3c1a52016-06-23 10:49:27 -0700538}
539
Kevin Lubickf034d112018-02-08 14:31:24 -0500540void FuzzPathDeserialize(SkReadBuffer& buf);
Kevin Lubickc9d28292017-11-09 08:12:56 -0500541
Kevin Lubickf034d112018-02-08 14:31:24 -0500542static void fuzz_path_deserialize(sk_sp<SkData> bytes) {
543 SkReadBuffer buf(bytes->data(), bytes->size());
544 FuzzPathDeserialize(buf);
545 SkDebugf("[terminated] path_deserialize didn't crash!\n");
Kevin Lubickf04c50a2017-01-06 13:48:19 -0500546}
547
Kevin Lubick2541edf2018-01-11 10:27:14 -0500548bool FuzzRegionDeserialize(sk_sp<SkData> bytes);
549
Kevin Lubickedee1ae2017-02-20 17:47:18 -0500550static void fuzz_region_deserialize(sk_sp<SkData> bytes) {
Kevin Lubick2541edf2018-01-11 10:27:14 -0500551 if (!FuzzRegionDeserialize(bytes)) {
Kevin Lubickedee1ae2017-02-20 17:47:18 -0500552 SkDebugf("[terminated] Couldn't initialize SkRegion.\n");
553 return;
554 }
Kevin Lubickedee1ae2017-02-20 17:47:18 -0500555 SkDebugf("[terminated] Success! Initialized SkRegion.\n");
556}
557
Kevin Lubickf034d112018-02-08 14:31:24 -0500558void FuzzTextBlobDeserialize(SkReadBuffer& buf);
559
Kevin Lubickd46e85f2017-11-21 17:13:35 -0500560static void fuzz_textblob_deserialize(sk_sp<SkData> bytes) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500561 SkReadBuffer buf(bytes->data(), bytes->size());
Kevin Lubickf034d112018-02-08 14:31:24 -0500562 FuzzTextBlobDeserialize(buf);
563 SkDebugf("[terminated] textblob didn't crash!\n");
Kevin Lubickd46e85f2017-11-21 17:13:35 -0500564}
565
Kevin Lubick2541edf2018-01-11 10:27:14 -0500566void FuzzRegionSetPath(Fuzz* fuzz);
567
568static void fuzz_region_set_path(sk_sp<SkData> bytes) {
569 Fuzz fuzz(bytes);
570 FuzzRegionSetPath(&fuzz);
571 SkDebugf("[terminated] region_set_path didn't crash!\n");
572}
573
Kevin Lubickf034d112018-02-08 14:31:24 -0500574void FuzzImageFilterDeserialize(sk_sp<SkData> bytes);
575
Herb Derbya839fc02017-03-16 12:30:43 -0400576static void fuzz_filter_fuzz(sk_sp<SkData> bytes) {
Kevin Lubickf034d112018-02-08 14:31:24 -0500577 FuzzImageFilterDeserialize(bytes);
578 SkDebugf("[terminated] filter_fuzz didn't crash!\n");
Herb Derbya839fc02017-03-16 12:30:43 -0400579}
580
Ethan Nicholas7ef4b742016-11-11 15:16:46 -0500581#if SK_SUPPORT_GPU
Kevin Lubickf80f1152017-01-06 08:26:56 -0500582static void fuzz_sksl2glsl(sk_sp<SkData> bytes) {
kjlubicke7195772016-10-18 10:06:24 -0700583 SkSL::Compiler compiler;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400584 SkSL::String output;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500585 SkSL::Program::Settings settings;
586 sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
587 settings.fCaps = caps.get();
588 std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
Brian Osman93ba0a42017-08-14 14:48:10 -0400589 SkSL::String((const char*) bytes->data()),
590 settings);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500591 if (!program || !compiler.toGLSL(*program, &output)) {
kjlubicke7195772016-10-18 10:06:24 -0700592 SkDebugf("[terminated] Couldn't compile input.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500593 return;
kjlubicke7195772016-10-18 10:06:24 -0700594 }
595 SkDebugf("[terminated] Success! Compiled input.\n");
kjlubicke7195772016-10-18 10:06:24 -0700596}
Ethan Nicholas7ef4b742016-11-11 15:16:46 -0500597#endif