fuzz: signalBug() / signalBoring()
authormtklein <mtklein@chromium.org>
Fri, 15 Jan 2016 13:46:54 +0000 (05:46 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 15 Jan 2016 13:46:54 +0000 (05:46 -0800)
Instead of a single ASSERT macro, this switches to two new methods:
   - signalBug():    tell afl-fuzz there's a bug caused by its inputs (by crashing)
   - signalBoring(): tell afl-fuzz these inputs are not worth testing (by exiting gracefully)

I'm not seeing any effect on fuzz/s when I just always log verbosely.

signalBug() now triggers SIGSEGV rather than SIGABRT.  This should make it work with catchsegv more easily.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1585353002

Review URL: https://codereview.chromium.org/1585353002

fuzz/Fuzz.h
fuzz/FuzzPaeth.cpp
fuzz/fuzz.cpp

index f5083ef8e68ab9b19aa55730ee771d4274405986..0f34ef4b3ef7a36a6dd5a4c84e3f91d8bfe03260 100644 (file)
@@ -11,7 +11,6 @@
 #include "SkData.h"
 #include "SkTRegistry.h"
 #include "SkTypes.h"
-#include <stdlib.h>
 
 class Fuzz : SkNoncopyable {
 public:
@@ -21,7 +20,13 @@ public:
     uint32_t nextU();
     float    nextF();
 
+    void signalBug   ();  // Tell afl-fuzz these inputs found a bug.
+    void signalBoring();  // Tell afl-fuzz these inputs are not worth testing.
+
 private:
+    template <typename T>
+    T nextT();
+
     SkAutoTUnref<SkData> fBytes;
     int fNextByte;
 };
@@ -36,6 +41,4 @@ struct Fuzzable {
     SkTRegistry<Fuzzable> register_##name({#name, fuzz_##name}); \
     static void fuzz_##name(Fuzz* f)
 
-#define ASSERT(cond) do { if (!(cond)) abort(); } while(false)
-
 #endif//Fuzz_DEFINED
index d7c139ce7a32d4cfa34bc97fee799af29124e5d4..dee9ee99143d30dd48d22c2c67198c7bc93c0836 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include "Fuzz.h"
+#include <stdlib.h>
 
 // This really is just an example Fuzz*.cpp file.
 // It tests that two different ways of calculating the Paeth predictor function are equivalent.
@@ -36,5 +37,13 @@ DEF_FUZZ(Paeth, fuzz) {
     auto a = fuzz->nextB(),
          b = fuzz->nextB(),
          c = fuzz->nextB();
-    ASSERT(paeth_alt(a,b,c) == paeth_std(a,b,c));
+    SkDebugf("Paeth(%d,%d,%d)\n", a,b,c);
+
+    if (a == b && b == c) {
+        fuzz->signalBoring();  // Not really boring, just demoing signalBoring().
+    }
+
+    if (paeth_alt(a,b,c) != paeth_std(a,b,c)) {
+        fuzz->signalBug();
+    }
 }
index 929ba7a4cf54dd4d7243d968cb7bfc9182ad7c1c..55f6046f6ebde515d36ebef34073ff5db1e10d1b 100644 (file)
@@ -6,9 +6,14 @@
  */
 
 #include "Fuzz.h"
+#include <stdlib.h>
+#include <signal.h>
 
 int main(int argc, char** argv) {
-    ASSERT(argc > 2);
+    if (argc < 3) {
+        SkDebugf("Usage: %s <fuzz name> <path/to/fuzzed.data>\n", argv[0]);
+        return 1;
+    }
     const char* name = argv[1];
     const char* path = argv[2];
 
@@ -18,6 +23,7 @@ int main(int argc, char** argv) {
     for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) {
         auto fuzzable = r->factory();
         if (0 == strcmp(name, fuzzable.name)) {
+            SkDebugf("Running %s\n", fuzzable.name);
             fuzzable.fn(&fuzz);
             return 0;
         }
@@ -28,19 +34,22 @@ int main(int argc, char** argv) {
 
 Fuzz::Fuzz(SkData* bytes) : fBytes(SkSafeRef(bytes)), fNextByte(0) {}
 
+void Fuzz::signalBug   () { raise(SIGSEGV); }
+void Fuzz::signalBoring() { exit(0); }
+
 template <typename T>
-static T read(const SkData* data, int* next) {
-    ASSERT(sizeof(T) <= data->size());
-    if (*next + sizeof(T) > data->size()) {
-        *next = 0;
+T Fuzz::nextT() {
+    if (fNextByte + sizeof(T) > fBytes->size()) {
+        this->signalBoring();
     }
+
     T val;
-    memcpy(&val, data->bytes() + *next, sizeof(T));
-    *next += sizeof(T);
+    memcpy(&val, fBytes->bytes() + fNextByte, sizeof(T));
+    fNextByte += sizeof(T);
     return val;
 }
 
-uint8_t  Fuzz::nextB() { return read<uint8_t >(fBytes, &fNextByte); }
-uint32_t Fuzz::nextU() { return read<uint32_t>(fBytes, &fNextByte); }
-float    Fuzz::nextF() { return read<float   >(fBytes, &fNextByte); }
+uint8_t  Fuzz::nextB() { return this->nextT<uint8_t >(); }
+uint32_t Fuzz::nextU() { return this->nextT<uint32_t>(); }
+float    Fuzz::nextF() { return this->nextT<float   >(); }