blob: d75d658d22811c556b326901b68a5680f2b8a4b8 [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();
Brian Osmanea176c62018-04-06 15:28:23 -0400301 // We do not need to check the return value. On an incomplete
302 // image, memory will be filled with a default value.
303 codec->getScanlines(dst, height, rowBytes);
kjlubick47d158e2016-02-01 08:23:50 -0800304 SkDebugf("[terminated] Success!\n");
kjlubickdba57342016-01-21 05:03:28 -0800305 break;
kjlubick2a42f482016-02-16 16:14:23 -0800306 }
307 case 2: { //kStripe_Mode
308 const int height = decodeInfo.height();
309 // This value is chosen arbitrarily. We exercise more cases by choosing a value that
310 // does not align with image blocks.
311 const int stripeHeight = 37;
312 const int numStripes = (height + stripeHeight - 1) / stripeHeight;
313
314 // Decode odd stripes
Leon Scroggins571b30f2017-07-11 17:35:31 +0000315 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)
kjlubick2a42f482016-02-16 16:14:23 -0800316 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) {
317 // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
318 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
319 // to run this test for image types that do not have this scanline ordering.
320 SkDebugf("[terminated] Could not start top-down scanline decoder\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500321 return;
kjlubick2a42f482016-02-16 16:14:23 -0800322 }
323
324 for (int i = 0; i < numStripes; i += 2) {
325 // Skip a stripe
326 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
327 codec->skipScanlines(linesToSkip);
328
329 // Read a stripe
330 const int startY = (i + 1) * stripeHeight;
331 const int linesToRead = SkTMin(stripeHeight, height - startY);
332 if (linesToRead > 0) {
333 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
334 }
335 }
336
337 // Decode even stripes
Leon Scroggins571b30f2017-07-11 17:35:31 +0000338 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo);
kjlubick2a42f482016-02-16 16:14:23 -0800339 if (SkCodec::kSuccess != startResult) {
340 SkDebugf("[terminated] Failed to restart scanline decoder with same parameters.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500341 return;
kjlubick2a42f482016-02-16 16:14:23 -0800342 }
343 for (int i = 0; i < numStripes; i += 2) {
344 // Read a stripe
345 const int startY = i * stripeHeight;
346 const int linesToRead = SkTMin(stripeHeight, height - startY);
347 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
348
349 // Skip a stripe
350 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
351 if (linesToSkip > 0) {
352 codec->skipScanlines(linesToSkip);
353 }
354 }
355 SkDebugf("[terminated] Success!\n");
kjlubickdba57342016-01-21 05:03:28 -0800356 break;
kjlubick2a42f482016-02-16 16:14:23 -0800357 }
358 case 3: { //kSubset_Mode
359 // Arbitrarily choose a divisor.
360 int divisor = 2;
361 // Total width/height of the image.
362 const int W = codec->getInfo().width();
363 const int H = codec->getInfo().height();
364 if (divisor > W || divisor > H) {
365 SkDebugf("[terminated] Cannot codec subset: divisor %d is too big "
366 "with dimensions (%d x %d)\n", divisor, W, H);
Kevin Lubickf80f1152017-01-06 08:26:56 -0500367 return;
kjlubick2a42f482016-02-16 16:14:23 -0800368 }
369 // subset dimensions
370 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
371 const int w = SkAlign2(W / divisor);
372 const int h = SkAlign2(H / divisor);
373 SkIRect subset;
374 SkCodec::Options opts;
375 opts.fSubset = &subset;
376 SkBitmap subsetBm;
377 // We will reuse pixel memory from bitmap.
378 void* pixels = bitmap.getPixels();
379 // Keep track of left and top (for drawing subsetBm into canvas). We could use
380 // fscale * x and fscale * y, but we want integers such that the next subset will start
381 // where the last one ended. So we'll add decodeInfo.width() and height().
382 int left = 0;
383 for (int x = 0; x < W; x += w) {
384 int top = 0;
385 for (int y = 0; y < H; y+= h) {
386 // Do not make the subset go off the edge of the image.
387 const int preScaleW = SkTMin(w, W - x);
388 const int preScaleH = SkTMin(h, H - y);
389 subset.setXYWH(x, y, preScaleW, preScaleH);
390 // And fscale
391 // FIXME: Should we have a version of getScaledDimensions that takes a subset
392 // into account?
393 decodeInfo = decodeInfo.makeWH(
394 SkTMax(1, SkScalarRoundToInt(preScaleW * fscale)),
395 SkTMax(1, SkScalarRoundToInt(preScaleH * fscale)));
396 size_t rowBytes = decodeInfo.minRowBytes();
Leon Scroggins571b30f2017-07-11 17:35:31 +0000397 if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes)) {
kjlubick2a42f482016-02-16 16:14:23 -0800398 SkDebugf("[terminated] Could not install pixels.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500399 return;
kjlubick2a42f482016-02-16 16:14:23 -0800400 }
401 const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
Leon Scroggins571b30f2017-07-11 17:35:31 +0000402 &opts);
kjlubick2a42f482016-02-16 16:14:23 -0800403 switch (result) {
404 case SkCodec::kSuccess:
405 case SkCodec::kIncompleteInput:
Leon Scroggins III674a1842017-07-06 12:26:09 -0400406 case SkCodec::kErrorInInput:
kjlubick2a42f482016-02-16 16:14:23 -0800407 SkDebugf("okay\n");
408 break;
409 case SkCodec::kInvalidConversion:
410 if (0 == (x|y)) {
411 // First subset is okay to return unimplemented.
412 SkDebugf("[terminated] Incompatible colortype conversion\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500413 return;
kjlubick2a42f482016-02-16 16:14:23 -0800414 }
415 // If the first subset succeeded, a later one should not fail.
416 // fall through to failure
417 case SkCodec::kUnimplemented:
418 if (0 == (x|y)) {
419 // First subset is okay to return unimplemented.
420 SkDebugf("[terminated] subset codec not supported\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500421 return;
kjlubick2a42f482016-02-16 16:14:23 -0800422 }
423 // If the first subset succeeded, why would a later one fail?
424 // fall through to failure
425 default:
426 SkDebugf("[terminated] subset codec failed to decode (%d, %d, %d, %d) "
427 "with dimensions (%d x %d)\t error %d\n",
428 x, y, decodeInfo.width(), decodeInfo.height(),
429 W, H, result);
Kevin Lubickf80f1152017-01-06 08:26:56 -0500430 return;
kjlubick2a42f482016-02-16 16:14:23 -0800431 }
432 // translate by the scaled height.
433 top += decodeInfo.height();
434 }
435 // translate by the scaled width.
436 left += decodeInfo.width();
437 }
438 SkDebugf("[terminated] Success!\n");
439 break;
440 }
Leon Scroggins IIIc5a83662016-12-08 09:07:56 -0500441 case 4: { //kAnimated_Mode
442 std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
443 if (frameInfos.size() == 0) {
444 SkDebugf("[terminated] Not an animated image\n");
445 break;
446 }
447
448 for (size_t i = 0; i < frameInfos.size(); i++) {
449 options.fFrameIndex = i;
450 auto result = codec->startIncrementalDecode(decodeInfo, bitmap.getPixels(),
451 bitmap.rowBytes(), &options);
452 if (SkCodec::kSuccess != result) {
453 SkDebugf("[terminated] failed to start incremental decode "
454 "in frame %d with error %d\n", i, result);
Kevin Lubickf80f1152017-01-06 08:26:56 -0500455 return;
Leon Scroggins IIIc5a83662016-12-08 09:07:56 -0500456 }
457
458 result = codec->incrementalDecode();
Leon Scroggins III674a1842017-07-06 12:26:09 -0400459 if (result == SkCodec::kIncompleteInput || result == SkCodec::kErrorInInput) {
Leon Scroggins IIIc5a83662016-12-08 09:07:56 -0500460 SkDebugf("okay\n");
461 // Frames beyond this one will not decode.
462 break;
463 }
464 if (result == SkCodec::kSuccess) {
465 SkDebugf("okay - decoded frame %d\n", i);
466 } else {
467 SkDebugf("[terminated] incremental decode failed with "
468 "error %d\n", result);
Kevin Lubickf80f1152017-01-06 08:26:56 -0500469 return;
Leon Scroggins IIIc5a83662016-12-08 09:07:56 -0500470 }
471 }
472 SkDebugf("[terminated] Success!\n");
473 break;
474 }
kjlubickdba57342016-01-21 05:03:28 -0800475 default:
kjlubick2a42f482016-02-16 16:14:23 -0800476 SkDebugf("[terminated] Mode not implemented yet\n");
kjlubickdba57342016-01-21 05:03:28 -0800477 }
478
479 dump_png(bitmap);
mtklein65e58242016-01-13 12:57:57 -0800480}
481
Kevin Lubickf80f1152017-01-06 08:26:56 -0500482static void fuzz_skp(sk_sp<SkData> bytes) {
Kevin Lubick09757b22017-12-12 12:52:39 -0500483 SkReadBuffer buf(bytes->data(), bytes->size());
kjlubickdba57342016-01-21 05:03:28 -0800484 SkDebugf("Decoding\n");
Kevin Lubick09757b22017-12-12 12:52:39 -0500485 sk_sp<SkPicture> pic(SkPicture::MakeFromBuffer(buf));
kjlubickdba57342016-01-21 05:03:28 -0800486 if (!pic) {
kjlubick47d158e2016-02-01 08:23:50 -0800487 SkDebugf("[terminated] Couldn't decode as a picture.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500488 return;
kjlubickdba57342016-01-21 05:03:28 -0800489 }
490 SkDebugf("Rendering\n");
491 SkBitmap bitmap;
492 if (!FLAGS_dump.isEmpty()) {
493 SkIRect size = pic->cullRect().roundOut();
494 bitmap.allocN32Pixels(size.width(), size.height());
495 }
496 SkCanvas canvas(bitmap);
497 canvas.drawPicture(pic);
kjlubick47d158e2016-02-01 08:23:50 -0800498 SkDebugf("[terminated] Success! Decoded and rendered an SkPicture!\n");
kjlubickdba57342016-01-21 05:03:28 -0800499 dump_png(bitmap);
kjlubickdba57342016-01-21 05:03:28 -0800500}
mtklein65e58242016-01-13 12:57:57 -0800501
Kevin Lubick0d825662018-01-03 14:38:48 -0500502static void fuzz_skpipe(sk_sp<SkData> bytes) {
503 SkPipeDeserializer d;
504 SkDebugf("Decoding\n");
505 sk_sp<SkPicture> pic(d.readPicture(bytes.get()));
506 if (!pic) {
507 SkDebugf("[terminated] Couldn't decode picture via SkPipe.\n");
508 return;
509 }
510 SkDebugf("Rendering\n");
511 SkBitmap bitmap;
512 SkCanvas canvas(bitmap);
513 canvas.drawPicture(pic);
514 SkDebugf("[terminated] Success! Decoded and rendered an SkPicture from SkPipe!\n");
515}
516
Kevin Lubickf80f1152017-01-06 08:26:56 -0500517static void fuzz_icc(sk_sp<SkData> bytes) {
Brian Osman526972e2016-10-24 09:24:02 -0400518 sk_sp<SkColorSpace> space(SkColorSpace::MakeICC(bytes->data(), bytes->size()));
kjlubick897a8e32016-06-09 07:15:12 -0700519 if (!space) {
520 SkDebugf("[terminated] Couldn't decode ICC.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500521 return;
kjlubick897a8e32016-06-09 07:15:12 -0700522 }
523 SkDebugf("[terminated] Success! Decoded ICC.\n");
kjlubick897a8e32016-06-09 07:15:12 -0700524}
525
Kevin Lubickf80f1152017-01-06 08:26:56 -0500526static void fuzz_color_deserialize(sk_sp<SkData> bytes) {
kjlubick3e3c1a52016-06-23 10:49:27 -0700527 sk_sp<SkColorSpace> space(SkColorSpace::Deserialize(bytes->data(), bytes->size()));
528 if (!space) {
529 SkDebugf("[terminated] Couldn't deserialize Colorspace.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500530 return;
kjlubick3e3c1a52016-06-23 10:49:27 -0700531 }
532 SkDebugf("[terminated] Success! deserialized Colorspace.\n");
kjlubick3e3c1a52016-06-23 10:49:27 -0700533}
534
Kevin Lubickf034d112018-02-08 14:31:24 -0500535void FuzzPathDeserialize(SkReadBuffer& buf);
Kevin Lubickc9d28292017-11-09 08:12:56 -0500536
Kevin Lubickf034d112018-02-08 14:31:24 -0500537static void fuzz_path_deserialize(sk_sp<SkData> bytes) {
538 SkReadBuffer buf(bytes->data(), bytes->size());
539 FuzzPathDeserialize(buf);
540 SkDebugf("[terminated] path_deserialize didn't crash!\n");
Kevin Lubickf04c50a2017-01-06 13:48:19 -0500541}
542
Kevin Lubick2541edf2018-01-11 10:27:14 -0500543bool FuzzRegionDeserialize(sk_sp<SkData> bytes);
544
Kevin Lubickedee1ae2017-02-20 17:47:18 -0500545static void fuzz_region_deserialize(sk_sp<SkData> bytes) {
Kevin Lubick2541edf2018-01-11 10:27:14 -0500546 if (!FuzzRegionDeserialize(bytes)) {
Kevin Lubickedee1ae2017-02-20 17:47:18 -0500547 SkDebugf("[terminated] Couldn't initialize SkRegion.\n");
548 return;
549 }
Kevin Lubickedee1ae2017-02-20 17:47:18 -0500550 SkDebugf("[terminated] Success! Initialized SkRegion.\n");
551}
552
Kevin Lubickf034d112018-02-08 14:31:24 -0500553void FuzzTextBlobDeserialize(SkReadBuffer& buf);
554
Kevin Lubickd46e85f2017-11-21 17:13:35 -0500555static void fuzz_textblob_deserialize(sk_sp<SkData> bytes) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500556 SkReadBuffer buf(bytes->data(), bytes->size());
Kevin Lubickf034d112018-02-08 14:31:24 -0500557 FuzzTextBlobDeserialize(buf);
558 SkDebugf("[terminated] textblob didn't crash!\n");
Kevin Lubickd46e85f2017-11-21 17:13:35 -0500559}
560
Kevin Lubick2541edf2018-01-11 10:27:14 -0500561void FuzzRegionSetPath(Fuzz* fuzz);
562
563static void fuzz_region_set_path(sk_sp<SkData> bytes) {
564 Fuzz fuzz(bytes);
565 FuzzRegionSetPath(&fuzz);
566 SkDebugf("[terminated] region_set_path didn't crash!\n");
567}
568
Kevin Lubickf034d112018-02-08 14:31:24 -0500569void FuzzImageFilterDeserialize(sk_sp<SkData> bytes);
570
Herb Derbya839fc02017-03-16 12:30:43 -0400571static void fuzz_filter_fuzz(sk_sp<SkData> bytes) {
Kevin Lubickf034d112018-02-08 14:31:24 -0500572 FuzzImageFilterDeserialize(bytes);
573 SkDebugf("[terminated] filter_fuzz didn't crash!\n");
Herb Derbya839fc02017-03-16 12:30:43 -0400574}
575
Ethan Nicholas7ef4b742016-11-11 15:16:46 -0500576#if SK_SUPPORT_GPU
Kevin Lubickf80f1152017-01-06 08:26:56 -0500577static void fuzz_sksl2glsl(sk_sp<SkData> bytes) {
kjlubicke7195772016-10-18 10:06:24 -0700578 SkSL::Compiler compiler;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400579 SkSL::String output;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500580 SkSL::Program::Settings settings;
581 sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
582 settings.fCaps = caps.get();
583 std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
Brian Osman93ba0a42017-08-14 14:48:10 -0400584 SkSL::String((const char*) bytes->data()),
585 settings);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500586 if (!program || !compiler.toGLSL(*program, &output)) {
kjlubicke7195772016-10-18 10:06:24 -0700587 SkDebugf("[terminated] Couldn't compile input.\n");
Kevin Lubickf80f1152017-01-06 08:26:56 -0500588 return;
kjlubicke7195772016-10-18 10:06:24 -0700589 }
590 SkDebugf("[terminated] Success! Compiled input.\n");
kjlubicke7195772016-10-18 10:06:24 -0700591}
Ethan Nicholas7ef4b742016-11-11 15:16:46 -0500592#endif