[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;
+}