Add simple SmallVec fuzzer.

Bug: 159350083
Test: Run fuzzer.
Change-Id: Idf943890eefd9aa2ec38f86d1cc5fba7d02bb072
diff --git a/fuzzing/orphans/smallvec/Android.bp b/fuzzing/orphans/smallvec/Android.bp
new file mode 100644
index 0000000..b676df0
--- /dev/null
+++ b/fuzzing/orphans/smallvec/Android.bp
@@ -0,0 +1,14 @@
+rust_fuzz {
+    name: "smallvec_fuzzer",
+    srcs: ["smallvec_fuzzer.rs"],
+    proc_macros: ["libnum_derive"],
+    rustlibs: [
+        "libarbitrary",
+        "libnum_traits",
+        "libsmallvec",
+    ],
+    fuzz_config: {
+        fuzz_on_haiku_device: true,
+        fuzz_on_haiku_host: true,
+    },
+}
diff --git a/fuzzing/orphans/smallvec/smallvec_fuzzer.rs b/fuzzing/orphans/smallvec/smallvec_fuzzer.rs
new file mode 100644
index 0000000..be96564
--- /dev/null
+++ b/fuzzing/orphans/smallvec/smallvec_fuzzer.rs
@@ -0,0 +1,134 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#![allow(missing_docs)]
+#![no_main]
+#![feature(bench_black_box)]
+
+use libfuzzer_sys::arbitrary::Arbitrary;
+use libfuzzer_sys::fuzz_target;
+use smallvec::{Array, SmallVec};
+
+// Avoid allocating too much memory and crashing the fuzzer.
+const MAX_SIZE_MODIFIER: usize = 1024;
+
+#[derive(Arbitrary, Clone, Debug, PartialEq)]
+enum Data {
+    A,
+    B,
+    Int { val: u8 },
+    Str { s: String },
+}
+
+#[derive(Arbitrary, Debug)]
+struct FuzzInfo {
+    inline_size: Size,
+    commands: Vec<Command>,
+}
+
+#[derive(Arbitrary, Debug)]
+enum Size {
+    One,
+    Two,
+    Three,
+    Four,
+    Five,
+}
+
+#[derive(Arbitrary, Debug)]
+enum Command {
+    Push { value: Data },
+    Pop,
+    Insert { index: usize, element: Data },
+    Remove { index: usize },
+    SwapRemove { index: usize },
+    Drain,
+    Clear,
+    Reserve { additional: usize },
+    ReserveExact { additional: usize },
+    ShrinkToFit,
+    Truncate { len: usize },
+    Grow { new_cap: usize },
+    Dedup,
+    Resize { len: usize, value: Data },
+}
+
+fuzz_target!(|info: FuzzInfo| {
+    match info.inline_size {
+        Size::One => do_fuzz::<[Data; 1]>(info.commands),
+        Size::Two => do_fuzz::<[Data; 2]>(info.commands),
+        Size::Three => do_fuzz::<[Data; 3]>(info.commands),
+        Size::Four => do_fuzz::<[Data; 4]>(info.commands),
+        Size::Five => do_fuzz::<[Data; 5]>(info.commands),
+    }
+});
+
+fn do_fuzz<T: Array<Item = Data>>(commands: Vec<Command>) {
+    let mut vec = SmallVec::<T>::new();
+    for command in commands {
+        match command {
+            Command::Push { value } => {
+                vec.push(value);
+            }
+            Command::Pop => {
+                vec.pop();
+            }
+            Command::Insert { index, element } => {
+                if index < vec.len() {
+                    vec.insert(index, element);
+                }
+            }
+            Command::Remove { index } => {
+                if index < vec.len() {
+                    vec.remove(index);
+                }
+            }
+            Command::SwapRemove { index } => {
+                if index < vec.len() {
+                    vec.remove(index);
+                }
+            }
+            Command::Drain => {
+                std::hint::black_box(vec.drain(..).count());
+            }
+            Command::Clear => {
+                vec.clear();
+            }
+            Command::Reserve { additional } => {
+                vec.reserve(additional % MAX_SIZE_MODIFIER);
+            }
+            Command::ReserveExact { additional } => {
+                vec.reserve_exact(additional % MAX_SIZE_MODIFIER);
+            }
+            Command::ShrinkToFit => {
+                vec.shrink_to_fit();
+            }
+            Command::Truncate { len } => {
+                vec.truncate(len);
+            }
+            Command::Grow { new_cap } => {
+                let new_cap = new_cap % MAX_SIZE_MODIFIER;
+                if new_cap >= vec.len() {
+                    vec.grow(new_cap);
+                }
+            }
+            Command::Dedup => {
+                vec.dedup();
+            }
+            Command::Resize { len, value } => {
+                vec.resize(len % MAX_SIZE_MODIFIER, value);
+            }
+        }
+    }
+}