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