Add fuzzers for libutils classes

Adds fuzzers for BitSet, FileMap, String8, String16, and Vector.
Test: Ran fuzzers on Android Pixel 3a. Aggregate coverage was 1.2% (this is far lower than true coverage due to shared libraries being counted)

Change-Id: I739216fe88afa51dc2f73b857da91116853382f0

Removed unneeded cflags, moved libbase to defaults

Test: Built Android.bp successfully

Signed-off-by: Dylan Katz <[email protected]>
Change-Id: I739216fe88afa51dc2f73b857da91116853382f0
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 2dbfb70..0f7044a 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -175,8 +175,8 @@
     ],
 
     shared_libs: [
-         "libutils",
-         "libbacktrace",
+        "libutils",
+        "libbacktrace",
     ],
 
     target: {
@@ -194,6 +194,45 @@
     },
 }
 
+cc_defaults {
+    name: "libutils_fuzz_defaults",
+    host_supported: true,
+    shared_libs: [
+        "libutils",
+        "libbase",
+    ],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_bitset",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["BitSet_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_filemap",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["FileMap_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_string8",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["String8_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_string16",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["String16_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_vector",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["Vector_fuzz.cpp"],
+}
+
 cc_test {
     name: "libutils_test",
     host_supported: true,
diff --git a/libutils/BitSet_fuzz.cpp b/libutils/BitSet_fuzz.cpp
new file mode 100644
index 0000000..2e6043c
--- /dev/null
+++ b/libutils/BitSet_fuzz.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 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.
+ */
+#include <functional>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/BitSet.h"
+static constexpr uint8_t MAX_OPERATIONS = 50;
+
+// We need to handle both 32 and 64 bit bitsets, so we use a function template
+// here. Sadly, std::function can't be generic, so we generate a vector of
+// std::functions using this function.
+template <typename T>
+std::vector<std::function<void(T, uint32_t)>> getOperationsForType() {
+    return {
+            [](T bs, uint32_t val) -> void { bs.markBit(val); },
+            [](T bs, uint32_t val) -> void { bs.valueForBit(val); },
+            [](T bs, uint32_t val) -> void { bs.hasBit(val); },
+            [](T bs, uint32_t val) -> void { bs.clearBit(val); },
+            [](T bs, uint32_t val) -> void { bs.getIndexOfBit(val); },
+            [](T bs, uint32_t) -> void { bs.clearFirstMarkedBit(); },
+            [](T bs, uint32_t) -> void { bs.markFirstUnmarkedBit(); },
+            [](T bs, uint32_t) -> void { bs.clearLastMarkedBit(); },
+            [](T bs, uint32_t) -> void { bs.clear(); },
+            [](T bs, uint32_t) -> void { bs.count(); },
+            [](T bs, uint32_t) -> void { bs.isEmpty(); },
+            [](T bs, uint32_t) -> void { bs.isFull(); },
+            [](T bs, uint32_t) -> void { bs.firstMarkedBit(); },
+            [](T bs, uint32_t) -> void { bs.lastMarkedBit(); },
+    };
+}
+
+// Our operations for 32 and 64 bit bitsets
+static const std::vector<std::function<void(android::BitSet32, uint32_t)>> thirtyTwoBitOps =
+        getOperationsForType<android::BitSet32>();
+static const std::vector<std::function<void(android::BitSet64, uint32_t)>> sixtyFourBitOps =
+        getOperationsForType<android::BitSet64>();
+
+void runOperationFor32Bit(android::BitSet32 bs, uint32_t bit, uint8_t operation) {
+    thirtyTwoBitOps[operation](bs, bit);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    uint32_t thirty_two_base = dataProvider.ConsumeIntegral<uint32_t>();
+    uint64_t sixty_four_base = dataProvider.ConsumeIntegral<uint64_t>();
+    android::BitSet32 b1 = android::BitSet32(thirty_two_base);
+    android::BitSet64 b2 = android::BitSet64(sixty_four_base);
+
+    size_t opsRun = 0;
+    while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+        uint32_t bit = dataProvider.ConsumeIntegral<uint32_t>();
+        uint8_t op = dataProvider.ConsumeIntegral<uint8_t>();
+        thirtyTwoBitOps[op % thirtyTwoBitOps.size()](b1, bit);
+        sixtyFourBitOps[op % sixtyFourBitOps.size()](b2, bit);
+    }
+    return 0;
+}
diff --git a/libutils/FileMap_fuzz.cpp b/libutils/FileMap_fuzz.cpp
new file mode 100644
index 0000000..d800564
--- /dev/null
+++ b/libutils/FileMap_fuzz.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 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.
+ */
+#include <iostream>
+
+#include "android-base/file.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/FileMap.h"
+
+static constexpr uint16_t MAX_STR_SIZE = 256;
+static constexpr uint8_t MAX_FILENAME_SIZE = 32;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    TemporaryFile tf;
+    // Generate file contents
+    std::string contents = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE);
+    // If we have string contents, dump them into the file.
+    // Otherwise, just leave it as an empty file.
+    if (contents.length() > 0) {
+        const char* bytes = contents.c_str();
+        android::base::WriteStringToFd(bytes, tf.fd);
+    }
+    android::FileMap m;
+    // Generate create() params
+    std::string orig_name = dataProvider.ConsumeRandomLengthString(MAX_FILENAME_SIZE);
+    size_t length = dataProvider.ConsumeIntegralInRange<size_t>(1, SIZE_MAX);
+    off64_t offset = dataProvider.ConsumeIntegralInRange<off64_t>(1, INT64_MAX);
+    bool read_only = dataProvider.ConsumeBool();
+    m.create(orig_name.c_str(), tf.fd, offset, length, read_only);
+    m.getDataOffset();
+    m.getFileName();
+    m.getDataLength();
+    m.getDataPtr();
+    int enum_index = dataProvider.ConsumeIntegral<int>();
+    m.advise(static_cast<android::FileMap::MapAdvice>(enum_index));
+    return 0;
+}
diff --git a/libutils/String16_fuzz.cpp b/libutils/String16_fuzz.cpp
new file mode 100644
index 0000000..63c2800
--- /dev/null
+++ b/libutils/String16_fuzz.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2020 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.
+ */
+#include <iostream>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/String16.h"
+static constexpr int MAX_STRING_BYTES = 256;
+static constexpr uint8_t MAX_OPERATIONS = 50;
+
+std::vector<std::function<void(FuzzedDataProvider&, android::String16, android::String16)>>
+        operations = {
+
+                // Bytes and size
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+                    str1.string();
+                }),
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+                    str1.isStaticString();
+                }),
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+                    str1.size();
+                }),
+
+                // Casing
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+                    str1.makeLower();
+                }),
+
+                // Comparison
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+                    str1.startsWith(str2);
+                }),
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+                    str1.contains(str2.string());
+                }),
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+                    str1.compare(str2);
+                }),
+
+                // Append and format
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+                    str1.append(str2);
+                }),
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16 str2) -> void {
+                    int pos = dataProvider.ConsumeIntegralInRange<int>(0, str1.size());
+                    str1.insert(pos, str2.string());
+                }),
+
+                // Find and replace operations
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16) -> void {
+                    char16_t findChar = dataProvider.ConsumeIntegral<char16_t>();
+                    str1.findFirst(findChar);
+                }),
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16) -> void {
+                    char16_t findChar = dataProvider.ConsumeIntegral<char16_t>();
+                    str1.findLast(findChar);
+                }),
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16) -> void {
+                    char16_t findChar = dataProvider.ConsumeIntegral<char16_t>();
+                    char16_t replaceChar = dataProvider.ConsumeIntegral<char16_t>();
+                    str1.replaceAll(findChar, replaceChar);
+                }),
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16) -> void {
+                    size_t len = dataProvider.ConsumeIntegral<size_t>();
+                    size_t begin = dataProvider.ConsumeIntegral<size_t>();
+                    str1.remove(len, begin);
+                }),
+};
+
+void callFunc(uint8_t index, FuzzedDataProvider& dataProvider, android::String16 str1,
+              android::String16 str2) {
+    operations[index](dataProvider, str1, str2);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    // We're generating two char vectors.
+    // First, generate lengths.
+    const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+    const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+
+    // Next, populate the vectors
+    std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
+    std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
+
+    // Get pointers to their data
+    char* char_one = vec.data();
+    char* char_two = vec_two.data();
+
+    // Create UTF16 representations
+    android::String16 str_one_utf16 = android::String16(char_one);
+    android::String16 str_two_utf16 = android::String16(char_two);
+
+    // Run operations against strings
+    int opsRun = 0;
+    while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+        uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+        callFunc(op, dataProvider, str_one_utf16, str_two_utf16);
+    }
+
+    str_one_utf16.remove(0, str_one_utf16.size());
+    str_two_utf16.remove(0, str_two_utf16.size());
+    return 0;
+}
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
new file mode 100644
index 0000000..2adfe98
--- /dev/null
+++ b/libutils/String8_fuzz.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2020 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.
+ */
+#include <functional>
+#include <iostream>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/String8.h"
+
+static constexpr int MAX_STRING_BYTES = 256;
+static constexpr uint8_t MAX_OPERATIONS = 50;
+
+std::vector<std::function<void(FuzzedDataProvider&, android::String8, android::String8)>>
+        operations = {
+
+                // Bytes and size
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.bytes();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.isEmpty();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.length();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.size();
+                },
+
+                // Casing
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.toUpper();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.toLower();
+                },
+
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.removeAll(str2.c_str());
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.compare(str2);
+                },
+
+                // Append and format
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.append(str2);
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.appendFormat(str1.c_str(), str2.c_str());
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.format(str1.c_str(), str2.c_str());
+                },
+
+                // Find operation
+                [](FuzzedDataProvider& dataProvider, android::String8 str1,
+                   android::String8) -> void {
+                    // We need to get a value from our fuzzer here.
+                    int start_index = dataProvider.ConsumeIntegralInRange<int>(0, str1.size());
+                    str1.find(str1.c_str(), start_index);
+                },
+
+                // Path handling
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.getBasePath();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.getPathExtension();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.getPathLeaf();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.getPathDir();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.convertToResPath();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    android::String8 path_out_str = android::String8();
+                    str1.walkPath(&path_out_str);
+                    path_out_str.clear();
+                },
+                [](FuzzedDataProvider& dataProvider, android::String8 str1,
+                   android::String8) -> void {
+                    str1.setPathName(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+                },
+                [](FuzzedDataProvider& dataProvider, android::String8 str1,
+                   android::String8) -> void {
+                    str1.appendPath(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+                },
+};
+
+void callFunc(uint8_t index, FuzzedDataProvider& dataProvider, android::String8 str1,
+              android::String8 str2) {
+    operations[index](dataProvider, str1, str2);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    // Generate vector lengths
+    const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+    const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+    // Populate vectors
+    std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
+    std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
+    // Create UTF-8 pointers
+    android::String8 str_one_utf8 = android::String8(vec.data());
+    android::String8 str_two_utf8 = android::String8(vec_two.data());
+
+    // Run operations against strings
+    int opsRun = 0;
+    while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+        uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+        callFunc(op, dataProvider, str_one_utf8, str_two_utf8);
+    }
+
+    // Just to be extra sure these can be freed, we're going to explicitly clear
+    // them
+    str_one_utf8.clear();
+    str_two_utf8.clear();
+    return 0;
+}
diff --git a/libutils/Vector_fuzz.cpp b/libutils/Vector_fuzz.cpp
new file mode 100644
index 0000000..f6df051
--- /dev/null
+++ b/libutils/Vector_fuzz.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 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.
+ */
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/Vector.h"
+static constexpr uint16_t MAX_VEC_SIZE = 5000;
+
+void runVectorFuzz(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    android::Vector<uint8_t> vec = android::Vector<uint8_t>();
+    // We want to test handling of sizeof as well.
+    android::Vector<uint32_t> vec32 = android::Vector<uint32_t>();
+
+    // We're going to generate two vectors of this size
+    size_t vectorSize = dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+    vec.setCapacity(vectorSize);
+    vec32.setCapacity(vectorSize);
+    for (size_t i = 0; i < vectorSize; i++) {
+        uint8_t count = dataProvider.ConsumeIntegralInRange<uint8_t>(1, 5);
+        vec.insertAt((uint8_t)i, i, count);
+        vec32.insertAt((uint32_t)i, i, count);
+        vec.push_front(i);
+        vec32.push(i);
+    }
+
+    // Now we'll perform some test operations with any remaining data
+    // Index to perform operations at
+    size_t index = dataProvider.ConsumeIntegralInRange<size_t>(0, vec.size());
+    std::vector<uint8_t> remainingVec = dataProvider.ConsumeRemainingBytes<uint8_t>();
+    // Insert an array and vector
+    vec.insertArrayAt(remainingVec.data(), index, remainingVec.size());
+    android::Vector<uint8_t> vecCopy = android::Vector<uint8_t>(vec);
+    vec.insertVectorAt(vecCopy, index);
+    // Same thing for 32 bit vector
+    android::Vector<uint32_t> vec32Copy = android::Vector<uint32_t>(vec32);
+    vec32.insertArrayAt(vec32Copy.array(), index, vec32.size());
+    vec32.insertVectorAt(vec32Copy, index);
+    // Replace single character
+    if (remainingVec.size() > 0) {
+        vec.replaceAt(remainingVec[0], index);
+        vec32.replaceAt(static_cast<uint32_t>(remainingVec[0]), index);
+    } else {
+        vec.replaceAt(0, index);
+        vec32.replaceAt(0, index);
+    }
+    // Add any remaining bytes
+    for (uint8_t i : remainingVec) {
+        vec.add(i);
+        vec32.add(static_cast<uint32_t>(i));
+    }
+    // Shrink capactiy
+    vec.setCapacity(remainingVec.size());
+    vec32.setCapacity(remainingVec.size());
+    // Iterate through each pointer
+    size_t sum = 0;
+    for (auto& it : vec) {
+        sum += it;
+    }
+    for (auto& it : vec32) {
+        sum += it;
+    }
+    // Cleanup
+    vec.clear();
+    vecCopy.clear();
+    vec32.clear();
+    vec32Copy.clear();
+}
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    runVectorFuzz(data, size);
+    return 0;
+}