[examples][fuzzing] Add an example fuzzer
This CL adds a contrived fuzzer to help demonstrate how one
is written.
Test: fx run-test example_fuzzers_test
fx run-host-tests --names host_fuzzers_test
Change-Id: I1e0040201e48c1b4ae2d727147a4f37fadaa3424
diff --git a/examples/fuzzer/BUILD.gn b/examples/fuzzer/BUILD.gn
new file mode 100644
index 0000000..5d985ce
--- /dev/null
+++ b/examples/fuzzer/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/fuzzing/fuzzer.gni")
+
+group("fuzzer") {
+ testonly = true
+ deps = [
+ ":example_fuzzers",
+ ]
+}
+
+fuzz_package("example_fuzzers") {
+ targets = [ ":baz_fuzzer" ]
+ fuzz_host = true
+}
+
+fuzz_target("baz_fuzzer") {
+ sources = [ "target.cc" ]
+ deps = [ ":baz" ]
+}
+
+source_set("baz") {
+ sources = [ "baz.cc" ]
+ deps = [ "//src/lib/fxl" ]
+}
+
diff --git a/examples/fuzzer/baz.cc b/examples/fuzzer/baz.cc
new file mode 100644
index 0000000..b0a2475
--- /dev/null
+++ b/examples/fuzzer/baz.cc
@@ -0,0 +1,57 @@
+
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "baz.h"
+
+#include <stdlib.h>
+
+#include "src/lib/fxl/strings/split_string.h"
+
+namespace examples {
+namespace fuzzing {
+
+int Baz::Execute(const std::string &commands) {
+ auto lines = fxl::SplitStringCopy(commands, "\n", fxl::kTrimWhitespace, fxl::kSplitWantNonEmpty);
+ for (auto line : lines) {
+ auto tokens = fxl::SplitStringCopy(line, " ", fxl::kTrimWhitespace, fxl::kSplitWantNonEmpty);
+ auto len = tokens.size();
+ if (tokens[0].compare("set") != 0) {
+ continue;
+ }
+ if (len < 3) {
+ return -1;
+ }
+ int bar = atoi(tokens[2].c_str());
+ if (bar == 0) {
+ return -1;
+ }
+ if (tokens[1].compare("foo") == 0) {
+ std::unique_ptr<Foo> foo(new Foo(bar));
+ SetFoo(std::move(foo));
+ } else if (tokens[1].compare("foo") == 0) {
+ SetBar(bar);
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void Baz::SetFoo(std::unique_ptr<Foo> foo) {
+ foo_.reset(foo.get());
+ if (bar_ == nullptr) {
+ bar_ = &foo_->bar_;
+ }
+}
+
+void Baz::SetBar(int bar) {
+ if (bar_ != nullptr) {
+ *bar_ = bar;
+ }
+}
+
+} // namespace fuzzing
+} // namespace examples
+
diff --git a/examples/fuzzer/baz.h b/examples/fuzzer/baz.h
new file mode 100644
index 0000000..b3adf1f
--- /dev/null
+++ b/examples/fuzzer/baz.h
@@ -0,0 +1,39 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+namespace examples {
+namespace fuzzing {
+
+// A Foo doohicky
+struct Foo {
+ int bar_;
+
+ Foo(int bar) : bar_(bar) {}
+ ~Foo() {}
+};
+
+// A Baz thingamajig
+class Baz {
+public:
+ Baz() : foo_(nullptr), bar_(nullptr) {}
+ ~Baz() {}
+
+ int Execute(const std::string &commands);
+
+private:
+ void SetFoo(std::unique_ptr<Foo> foo);
+ void SetBar(int bar);
+
+ std::unique_ptr<Foo> foo_;
+ int *bar_; // Cache bar_ for faster access
+};
+
+} // namespace fuzzing
+} // namespace examples
+
diff --git a/examples/fuzzer/target.cc b/examples/fuzzer/target.cc
new file mode 100644
index 0000000..81cfe0d
--- /dev/null
+++ b/examples/fuzzer/target.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "baz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ std::string input(reinterpret_cast<const char *>(data), size);
+ examples::fuzzing::Baz baz;
+ baz.Execute(input);
+ return 0;
+}