Chromium Code Reviews| Index: fuzz/fuzz.cpp |
| diff --git a/fuzz/fuzz.cpp b/fuzz/fuzz.cpp |
| index bd7c723c1657e0d67b1c13e106b9398d1d50e4ed..31deb54bff952bb148d1ae2484666a7e54169329 100644 |
| --- a/fuzz/fuzz.cpp |
| +++ b/fuzz/fuzz.cpp |
| @@ -6,30 +6,156 @@ |
| */ |
| #include "Fuzz.h" |
| +#include "SkCanvas.h" |
| +#include "SkCodec.h" |
| #include "SkCommandLineFlags.h" |
| +#include "SkData.h" |
| +#include "SkForceLinking.h" |
| +#include "SkImage.h" |
| +#include "SkImageEncoder.h" |
| +#include "SkMallocPixelRef.h" |
| +#include "SkPicture.h" |
| +#include "SkStream.h" |
| + |
| #include <signal.h> |
| #include <stdlib.h> |
| +#include <cmath> |
| -DEFINE_string2(bytes, b, "", "A path to a file containing fuzzed bytes."); |
| +__SK_FORCE_IMAGE_DECODER_LINKING; |
| + |
| +DEFINE_string2(bytes, b, "", "A path to a file. This can be the fuzz bytes or a binary to parse."); |
| DEFINE_string2(match, m, "", "The usual --match, applied to DEF_FUZZ names."); |
| +DEFINE_string2(type, t, "api", "How to interpret --bytes, either 'image', 'skp', or 'api'."); |
| +DEFINE_string(dump, "", "If not empty, dump 'image' or 'skp' types as a PNG with this name."); |
|
mtklein
2016/01/20 20:15:21
This can probably be string2(dump, d, ...)
kjlubick
2016/01/20 20:32:59
Done.
|
| + |
| +int printUsage(const char* name) { |
|
mtklein
2016/01/20 20:15:21
static int print_usage(const char* name)
kjlubick
2016/01/20 20:32:59
Done.
|
| + SkDebugf("Usage: %s -t <type> -b <path/to/file> [-m pattern]\n", name); |
| + return 1; |
| +} |
| + |
| +static int fuzz_api(SkData*); |
| +static int fuzz_img(SkData*); |
| +static int fuzz_skp(SkData*); |
| + |
| int main(int argc, char** argv) { |
| SkCommandLineFlags::Parse(argc, argv); |
| + if (FLAGS_bytes.isEmpty() || FLAGS_type.isEmpty()) { |
|
mtklein
2016/01/20 20:15:21
if (FLAGS_bytes.isEmpty() || FLAGS_type.isEmpty())
kjlubick
2016/01/20 20:32:59
https://goto.google.com/zvalt
|
| + return printUsage(argv[0]); |
| + } |
| + |
| const char* path = FLAGS_bytes.isEmpty() ? argv[0] : FLAGS_bytes[0]; |
| SkAutoTUnref<SkData> bytes(SkData::NewFromFileName(path)); |
| + if (!bytes) { |
| + SkDebugf("Could not read %s\n", path); |
| + return 2; |
| + } |
| + switch (FLAGS_type[0][0]) { |
| + case 'a': return fuzz_api(bytes); |
| + case 'i': return fuzz_img(bytes); |
| + case 's': return fuzz_skp(bytes); |
| + } |
| + return printUsage(argv[0]); |
| +} |
| +int fuzz_api(SkData* bytes) { |
| for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { |
| auto fuzzable = r->factory(); |
| if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, fuzzable.name)) { |
|
mtklein
2016/01/20 20:15:21
If we're going to run one, we'd better switch this
kjlubick
2016/01/20 20:32:59
How about just API Fuzz?
|
| SkDebugf("Fuzzing %s...\n", fuzzable.name); |
| Fuzz fuzz(bytes); |
| fuzzable.fn(&fuzz); |
| + return 0; |
| } |
| } |
| + SkDebugf("Test %s not found", FLAGS_match[0]); |
| + return 1; |
| +} |
| + |
| +void dumpPng(SkBitmap bitmap) { |
|
mtklein
2016/01/20 20:15:21
static void dump_png(...)
kjlubick
2016/01/20 20:32:59
Done.
|
| + if (!FLAGS_dump.isEmpty()) { |
| + SkImageEncoder::EncodeFile(FLAGS_dump[0], bitmap, SkImageEncoder::kPNG_Type, 100); |
| + SkDebugf("Dumped to %s\n", FLAGS_dump[0]); |
| + } |
| +} |
| + |
| +int fuzz_img(SkData* bytes) { |
| + SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(bytes)); |
| + if (nullptr == codec.get()) { |
| + SkDebugf("Couldn't create codec."); |
| + return 3; |
| + } |
| + |
| + SkImageInfo decodeInfo = codec->getInfo(); |
| + // Construct a color table for the decode if necessary |
| + SkAutoTUnref<SkColorTable> colorTable(nullptr); |
| + SkPMColor* colorPtr = nullptr; |
| + int* colorCountPtr = nullptr; |
| + int maxColors = 256; |
| + if (kIndex_8_SkColorType == decodeInfo.colorType()) { |
| + SkPMColor colors[256]; |
| + colorTable.reset(new SkColorTable(colors, maxColors)); |
| + colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); |
| + colorCountPtr = &maxColors; |
| + } |
| + |
| + SkBitmap bitmap; |
| + SkMallocPixelRef::ZeroedPRFactory zeroFactory; |
| + SkCodec::Options options; |
| + options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; |
| + |
| + if (!bitmap.tryAllocPixels(decodeInfo, &zeroFactory, nullptr)) { |
| + SkDebugf("Could not allocate memory. Image might be too large (%d x %d)", |
| + decodeInfo.width(), decodeInfo.height()); |
| + return 4; |
| + } |
| + |
| + switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), &options, |
| + colorPtr, colorCountPtr)) { |
| + case SkCodec::kSuccess: |
| + SkDebugf("Success!\n"); |
| + break; |
| + case SkCodec::kIncompleteInput: |
| + SkDebugf("Partial Success\n"); |
| + break; |
| + case SkCodec::kInvalidConversion: |
| + SkDebugf("Incompatible colortype conversion"); |
| + return 5; |
| + default: |
| + // Everything else is considered a failure. |
| + SkDebugf("Couldn't getPixels."); |
| + return 6; |
| + } |
| + |
| + dumpPng(bitmap); |
| return 0; |
| } |
| +int fuzz_skp(SkData* bytes) { |
| + SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(bytes)); |
|
mtklein
2016/01/20 20:15:21
SkMemoryStream stream(bytes);
if (!stream.isValid(
kjlubick
2016/01/20 20:32:59
There is no isValid on SkMemoryStream. I guess if
|
| + if (!stream) { |
| + SkDebugf("Couldn't read %s.", FLAGS_bytes[0]); |
| + return 2; |
| + } |
| + SkDebugf("Decoding\n"); |
| + SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream)); |
| + if (!pic) { |
| + SkDebugf("Couldn't decode as a picture.\n"); |
| + return 3; |
| + } |
| + SkDebugf("Rendering\n"); |
| + SkBitmap bitmap; |
| + if (!FLAGS_dump.isEmpty()) { |
| + SkIRect size = pic->cullRect().roundOut(); |
| + bitmap.allocN32Pixels(size.width(), size.height()); |
| + } |
| + SkCanvas canvas(bitmap); |
| + canvas.drawPicture(pic); |
| + SkDebugf("Decoded and rendered an SkPicture!\n"); |
| + dumpPng(bitmap); |
| + return 0; |
| +} |
| Fuzz::Fuzz(SkData* bytes) : fBytes(SkSafeRef(bytes)), fNextByte(0) {} |