Chromium Code Reviews| Index: fuzz/fuzz.cpp | 
| diff --git a/fuzz/fuzz.cpp b/fuzz/fuzz.cpp | 
| index 343e25b45303527a8a5cbfb5cc33bcebfb747afa..037c3b8a546c807929deeb428e8c26b8eea0e96a 100644 | 
| --- a/fuzz/fuzz.cpp | 
| +++ b/fuzz/fuzz.cpp | 
| @@ -6,33 +6,160 @@ | 
| */ | 
| #include "Fuzz.h" | 
| +#include "SkCanvas.h" | 
| +#include "SkCodec.h" | 
| #include "SkCommandLineFlags.h" | 
| +#include "SkData.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."); | 
| +DEFINE_string2(bytes, b, "", "A path to a file."); | 
| 
 
mtklein
2016/01/20 14:49:06
?  Do they not contain fuzzed bytes any more?
 
kjlubick
2016/01/20 19:21:58
Done.
 
 | 
| DEFINE_string2(match, m, "", "The usual --match, applied to DEF_FUZZ names."); | 
| +DEFINE_string(mode, "api", "How to interpret --bytes, either 'image', 'skp', or 'api'."); | 
| 
 
mtklein
2016/01/20 14:49:06
We may want to make this type, not mode, so that w
 
kjlubick
2016/01/20 19:21:58
Done.
 
 | 
| +DEFINE_string(dump, "", "If not empty, dump 'image' or 'skp' modes as a PNG with this name."); | 
| + | 
| +void printUsage(char*); | 
| 
 
mtklein
2016/01/20 14:49:06
It is a good habit to get into make functions (rea
 
mtklein
2016/01/20 14:49:06
It's another good habit to take your arguments wit
 
kjlubick
2016/01/20 19:21:58
Done.
 
 | 
| +int runSingleTest(SkData*); | 
| 
 
mtklein
2016/01/20 14:49:06
Let's make these more symmetric:
static int fuzz_
 
kjlubick
2016/01/20 19:21:58
Done.
 
 | 
| +int decodeImage(SkData*); | 
| +int decodeSkp(); | 
| + | 
| int main(int argc, char** argv) { | 
| SkCommandLineFlags::Parse(argc, argv); | 
| - if (FLAGS_bytes.isEmpty()) { | 
| 
 
mtklein
2016/01/20 14:49:06
I think you need to rebase your patch.
Are you in
 
kjlubick
2016/01/20 19:21:58
Whoops, just needed a rebase.
 
 | 
| - SkDebugf("Usage: %s -b <path/to/fuzzed.data> [-m pattern]\n", argv[0]); | 
| + if (FLAGS_bytes.isEmpty() || FLAGS_mode.isEmpty()) { | 
| + printUsage(argv[0]); | 
| 
 
mtklein
2016/01/20 14:49:06
You might consider writing this as:
static int us
 
scroggo
2016/01/20 18:46:19
SkCommandLineFlags has a "usage" string, but it on
 
kjlubick
2016/01/20 19:21:57
That would be nice.
 
kjlubick
2016/01/20 19:21:58
Done.
 
 | 
| return 1; | 
| } | 
| + | 
| + if (0 == strcmp(FLAGS_mode[0], "skp")) { | 
| + return decodeSkp(); | 
| + } | 
| + | 
| SkAutoTUnref<SkData> bytes(SkData::NewFromFileName(FLAGS_bytes[0])); | 
| + if (!bytes) { | 
| + SkDebugf("Could not read %s\n", FLAGS_bytes[0]); | 
| + return 2; | 
| + } | 
| + if (0 == strcmp(FLAGS_mode[0], "api")) { | 
| 
 
mtklein
2016/01/20 14:49:06
This is fine, but we probably don't need to be thi
 
kjlubick
2016/01/20 19:21:58
Done, although I'm not sure what the c is for.
 
 | 
| + return runSingleTest(bytes); | 
| + } else if (0 == strcmp(FLAGS_mode[0], "image")) { | 
| + return decodeImage(bytes); | 
| + } | 
| + printUsage(argv[0]); | 
| + return 1; | 
| +} | 
| +void printUsage(char* name) { | 
| + SkDebugf("Usage: %s --mode <mode> -b <path/to/file> [-m pattern]\n", name); | 
| 
 
mtklein
2016/01/20 14:49:07
It seems like this one would be more useful if def
 
kjlubick
2016/01/20 19:21:58
Done.
 
 | 
| +} | 
| + | 
| +int runSingleTest(SkData* bytes) { | 
| for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { | 
| auto fuzzable = r->factory(); | 
| if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, fuzzable.name)) { | 
| SkDebugf("Fuzzing %s...\n", fuzzable.name); | 
| Fuzz fuzz(bytes); | 
| fuzzable.fn(&fuzz); | 
| + return 0; | 
| } | 
| } | 
| return 0; | 
| 
 
mtklein
2016/01/20 14:49:06
1?
 
kjlubick
2016/01/20 19:21:58
Done.
 
 | 
| } | 
| +int decodeImage(SkData* bytes) { | 
| + SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(bytes)); | 
| 
 
mtklein
2016/01/20 14:49:06
This can't really be the easiest way to use SkCode
 
scroggo
2016/01/20 18:46:19
This looks about right. It's complicated in part b
 
kjlubick
2016/01/20 19:21:58
I went over it with scroggo@ yesterday, and this i
 
 | 
| + 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; | 
| + } | 
| + | 
| + | 
| + if (!FLAGS_dump.isEmpty()) { | 
| + SkImageEncoder::EncodeFile(FLAGS_dump[0], bitmap, SkImageEncoder::kPNG_Type, 100); | 
| + SkDebugf("Dumped to %s\n", FLAGS_dump[0]); | 
| + } | 
| + return 0; | 
| +} | 
| + | 
| +static const SkRect kSKPViewport = {0,0, 1000,1000}; | 
| + | 
| +int decodeSkp() { | 
| + SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(FLAGS_bytes[0])); | 
| + 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.clipRect(kSKPViewport); | 
| 
 
mtklein
2016/01/20 14:49:06
Let's not do this?  If we're allocating space for
 
kjlubick
2016/01/20 19:21:58
Done.
 
 | 
| + canvas.drawPicture(pic); | 
| + SkDebugf("Decoded and rendered an SkPicture!\n"); | 
| + if (!FLAGS_dump.isEmpty()) { | 
| + SkImageEncoder::EncodeFile(FLAGS_dump[0], bitmap, SkImageEncoder::kPNG_Type, 100); | 
| 
 
mtklein
2016/01/20 14:49:06
Seems like we've got a bunch of common logic for .
 
kjlubick
2016/01/20 19:21:57
Deduped.
 
 | 
| + SkDebugf("Dumped to %s\n", FLAGS_dump[0]); | 
| + } | 
| + return 0; | 
| +} | 
| Fuzz::Fuzz(SkData* bytes) : fBytes(SkSafeRef(bytes)), fNextByte(0) {} |