core: update from upstream
Followed instructions from go/nnapi-dep-instructions.
No manual changes / interventions have been made.
$ git merge origin/master --no-ff
$ git push origin HEAD:refs/for/master
BUG=b:177048246
TEST=cq passes
Submitting directly since this repo is not mapped into ChromeOS, but is
used by copybara to populate other repos (libutils, libcutils).
Exempt-From-Owner-Approval: This is a forked repo
Change-Id: I4e1c0c21f26ea8ad409c47646c8617f55c676e6a
GitOrigin-RevId: 15e8363d6289ccf3e60fd8b7bd29e9258ba82493
diff --git a/Android.bp b/Android.bp
index 2dbfb70..1e7cbdb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -15,7 +15,9 @@
cc_library_headers {
name: "libutils_headers",
vendor_available: true,
+ product_available: true,
recovery_available: true,
+ vendor_ramdisk_available: true,
host_supported: true,
native_bridge_supported: true,
apex_available: [
@@ -43,7 +45,13 @@
header_libs: ["libbacktrace_headers"],
export_header_lib_headers: ["libbacktrace_headers"],
},
+ linux_glibc: {
+ header_libs: ["libbacktrace_headers"],
+ export_header_lib_headers: ["libbacktrace_headers"],
+ },
linux_bionic: {
+ header_libs: ["libbacktrace_headers"],
+ export_header_lib_headers: ["libbacktrace_headers"],
enabled: true,
},
windows: {
@@ -55,6 +63,7 @@
cc_defaults {
name: "libutils_defaults",
vendor_available: true,
+ product_available: true,
recovery_available: true,
vndk: {
enabled: true,
@@ -78,6 +87,9 @@
"libcutils",
"liblog",
],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
target: {
android: {
@@ -129,7 +141,6 @@
"JenkinsHash.cpp",
"NativeHandle.cpp",
"Printer.cpp",
- "PropertyMap.cpp",
"RefBase.cpp",
"SharedBuffer.cpp",
"StopWatch.cpp",
@@ -169,14 +180,16 @@
cc_library {
name: "libutilscallstack",
defaults: ["libutils_defaults"],
+ // TODO(b/153609531): remove when no longer needed.
+ native_bridge_supported: true,
srcs: [
"CallStack.cpp",
],
shared_libs: [
- "libutils",
- "libbacktrace",
+ "libutils",
+ "libbacktrace",
],
target: {
@@ -194,6 +207,94 @@
},
}
+cc_defaults {
+ name: "libutils_fuzz_defaults",
+ host_supported: true,
+ shared_libs: [
+ "libutils",
+ "libbase",
+ "liblog",
+ ],
+}
+
+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_fuzz {
+ name: "libutils_fuzz_printer",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["Printer_fuzz.cpp"],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_callstack",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["CallStack_fuzz.cpp"],
+ shared_libs: [
+ "libutilscallstack",
+ ],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_process_callstack",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["ProcessCallStack_fuzz.cpp"],
+ shared_libs: [
+ "libutilscallstack",
+ ],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_stopwatch",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["StopWatch_fuzz.cpp"],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_refbase",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["RefBase_fuzz.cpp"],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_lrucache",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["LruCache_fuzz.cpp"],
+}
+
+cc_fuzz {
+ name: "libutils_fuzz_looper",
+ defaults: ["libutils_fuzz_defaults"],
+ srcs: ["Looper_fuzz.cpp"],
+}
+
cc_test {
name: "libutils_test",
host_supported: true,
@@ -204,9 +305,11 @@
"LruCache_test.cpp",
"Mutex_test.cpp",
"SharedBuffer_test.cpp",
+ "Singleton_test.cpp",
"String8_test.cpp",
"String16_test.cpp",
"StrongPointer_test.cpp",
+ "Timers_test.cpp",
"Unicode_test.cpp",
"Vector_test.cpp",
],
@@ -239,6 +342,11 @@
},
},
+ data_libs: [
+ "libutils_test_singleton1",
+ "libutils_test_singleton2",
+ ],
+
cflags: [
"-Wall",
"-Wextra",
@@ -249,29 +357,10 @@
test_suites: ["device-tests"],
}
-// TODO: the test infrastructure isn't yet capable of running this,
-// so it's broken out into its own test so that the main libutils_tests
-// can be in presubmit even if this can't.
-
-cc_test {
- name: "libutils_singleton_test",
- srcs: ["Singleton_test.cpp"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- shared_libs: ["libbase"],
-
- required: [
- ":libutils_test_singleton1",
- ":libutils_test_singleton2",
- ],
-}
-
cc_test_library {
name: "libutils_test_singleton1",
host_supported: true,
- relative_install_path: "libutils_test",
+ installable: false,
srcs: ["Singleton_test1.cpp"],
cflags: [
"-Wall",
@@ -282,7 +371,7 @@
cc_test_library {
name: "libutils_test_singleton2",
host_supported: true,
- relative_install_path: "libutils_test",
+ installable: false,
srcs: ["Singleton_test2.cpp"],
cflags: [
"-Wall",
diff --git a/BitSet_fuzz.cpp b/BitSet_fuzz.cpp
new file mode 100644
index 0000000..2e6043c
--- /dev/null
+++ b/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/CallStack_fuzz.cpp b/CallStack_fuzz.cpp
new file mode 100644
index 0000000..e89b5b7
--- /dev/null
+++ b/CallStack_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 <memory.h>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/CallStack.h"
+
+static constexpr int MAX_STRING_SIZE = 500;
+static constexpr int MAX_IGNORE_DEPTH = 200;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider(data, size);
+ size_t ignoreDepth = dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_IGNORE_DEPTH);
+ int logPriority = dataProvider.ConsumeIntegral<int>();
+ pid_t tid = dataProvider.ConsumeIntegral<pid_t>();
+ std::string logTag = dataProvider.ConsumeRandomLengthString(MAX_STRING_SIZE);
+ std::string prefix = dataProvider.ConsumeRandomLengthString(MAX_STRING_SIZE);
+
+ const char* logTagChars = logTag.c_str();
+ const char* prefixChars = prefix.c_str();
+
+ android::CallStack::CallStackUPtr callStack = android::CallStack::getCurrent(ignoreDepth);
+ android::CallStack* callstackPtr = callStack.get();
+ android::CallStack::logStack(logTagChars, callstackPtr,
+ static_cast<android_LogPriority>(logPriority));
+ android::CallStack::stackToString(prefixChars);
+
+ callstackPtr->log(logTagChars, static_cast<android_LogPriority>(logPriority), prefixChars);
+ callstackPtr->clear();
+ callstackPtr->getCurrent(ignoreDepth);
+ callstackPtr->log(logTagChars, static_cast<android_LogPriority>(logPriority), prefixChars);
+ callstackPtr->update(ignoreDepth, tid);
+ callstackPtr->log(logTagChars, static_cast<android_LogPriority>(logPriority), prefixChars);
+
+ return 0;
+}
diff --git a/FileMap.cpp b/FileMap.cpp
index 1d899ab..0abb861 100644
--- a/FileMap.cpp
+++ b/FileMap.cpp
@@ -189,7 +189,11 @@
int adjust = offset % mPageSize;
off64_t adjOffset = offset - adjust;
- size_t adjLength = length + adjust;
+ size_t adjLength;
+ if (__builtin_add_overflow(length, adjust, &adjLength)) {
+ ALOGE("adjusted length overflow: length %zu adjust %d", length, adjust);
+ return false;
+ }
int flags = MAP_SHARED;
int prot = PROT_READ;
diff --git a/FileMap_fuzz.cpp b/FileMap_fuzz.cpp
new file mode 100644
index 0000000..d800564
--- /dev/null
+++ b/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/FileMap_test.cpp b/FileMap_test.cpp
index 9f7ce85..fd1c9b0 100644
--- a/FileMap_test.cpp
+++ b/FileMap_test.cpp
@@ -52,3 +52,16 @@
ASSERT_EQ(0u, m.getDataLength());
ASSERT_EQ(offset, m.getDataOffset());
}
+
+TEST(FileMap, offset_overflow) {
+ // Make sure that an end that overflows SIZE_MAX will not abort.
+ // See http://b/156997193.
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ off64_t offset = 200;
+ size_t length = SIZE_MAX;
+
+ android::FileMap m;
+ ASSERT_FALSE(m.create("test", tf.fd, offset, length, true));
+}
diff --git a/FuzzFormatTypes.h b/FuzzFormatTypes.h
new file mode 100644
index 0000000..aa9e503
--- /dev/null
+++ b/FuzzFormatTypes.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#pragma once
+#include <string>
+
+static const std::string kFormatChars = std::string("duoxXfFeEgGaAcsp");
+static constexpr int32_t kMaxFormatFlagValue = INT16_MAX;
+enum FormatChar : uint8_t {
+ SIGNED_DECIMAL = 0,
+ UNSIGNED_DECIMAL = 1,
+ UNSIGNED_OCTAL = 2,
+ UNSIGNED_HEX_LOWER = 3,
+ UNSIGNED_HEX_UPPER = 4,
+ // Uppercase/lowercase floating point impacts 'inf', 'infinity', and 'nan'
+ FLOAT_LOWER = 5,
+ FLOAT_UPPER = 6,
+ // Upper/lower impacts the "e" in exponents.
+ EXPONENT_LOWER = 7,
+ EXPONENT_UPPER = 8,
+ // %g will use %e or %f, whichever is shortest
+ SHORT_EXP_LOWER = 9,
+ // %G will use %E or %F, whichever is shortest
+ SHORT_EXP_UPPER = 10,
+ HEX_FLOAT_LOWER = 11,
+ HEX_FLOAT_UPPER = 12,
+ CHAR = 13,
+ STRING = 14,
+ POINTER = 15,
+ // Used by libfuzzer
+ kMaxValue = POINTER
+};
+
+bool canApplyFlag(FormatChar formatChar, char modifier) {
+ if (modifier == '#') {
+ return formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+ formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+ formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+ formatChar == SHORT_EXP_UPPER;
+ } else if (modifier == '.') {
+ return formatChar == SIGNED_DECIMAL || formatChar == UNSIGNED_DECIMAL ||
+ formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+ formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+ formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+ formatChar == SHORT_EXP_UPPER || formatChar == STRING;
+ }
+ return true;
+}
diff --git a/Looper_fuzz.cpp b/Looper_fuzz.cpp
new file mode 100644
index 0000000..c3ae54e
--- /dev/null
+++ b/Looper_fuzz.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 <sys/select.h>
+
+#include <iostream>
+
+#include <utils/Looper.h>
+
+#include "Looper_test_pipe.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+using android::Looper;
+using android::sp;
+
+// We don't want this to bog down fuzzing
+static constexpr int MAX_POLL_DELAY = 50;
+static constexpr int MAX_OPERATIONS = 500;
+
+void doNothing() {}
+void* doNothingPointer = reinterpret_cast<void*>(doNothing);
+
+static int noopCallback(int, int, void*) {
+ return 0;
+}
+
+std::vector<std::function<void(FuzzedDataProvider*, sp<Looper>, Pipe)>> operations = {
+ [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe) -> void {
+ looper->pollOnce(dataProvider->ConsumeIntegralInRange<int>(0, MAX_POLL_DELAY));
+ },
+ [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe) -> void {
+ looper->pollAll(dataProvider->ConsumeIntegralInRange<int>(0, MAX_POLL_DELAY));
+ },
+ // events and callback are nullptr
+ [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
+ looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
+ dataProvider->ConsumeIntegral<int>(), nullptr, nullptr);
+ },
+ // Events is nullptr
+ [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
+ looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
+ dataProvider->ConsumeIntegral<int>(), noopCallback, nullptr);
+ },
+ // callback is nullptr
+ [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
+ looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
+ dataProvider->ConsumeIntegral<int>(), nullptr, doNothingPointer);
+ },
+ // callback and events both set
+ [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
+ looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
+ dataProvider->ConsumeIntegral<int>(), noopCallback, doNothingPointer);
+ },
+
+ [](FuzzedDataProvider*, sp<Looper> looper, Pipe) -> void { looper->wake(); },
+ [](FuzzedDataProvider*, sp<Looper>, Pipe pipeObj) -> void { pipeObj.writeSignal(); }};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ Pipe pipeObj;
+ FuzzedDataProvider dataProvider(data, size);
+ sp<Looper> looper = new Looper(dataProvider.ConsumeBool());
+
+ size_t opsRun = 0;
+ while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+ uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+ operations[op](&dataProvider, looper, pipeObj);
+ }
+ // Clear our pointer
+ looper.clear();
+ return 0;
+}
diff --git a/Looper_test.cpp b/Looper_test.cpp
index 37bdf05..34f424b 100644
--- a/Looper_test.cpp
+++ b/Looper_test.cpp
@@ -2,12 +2,13 @@
// Copyright 2010 The Android Open Source Project
//
-#include <utils/Looper.h>
-#include <utils/Timers.h>
-#include <utils/StopWatch.h>
#include <gtest/gtest.h>
-#include <unistd.h>
#include <time.h>
+#include <unistd.h>
+#include <utils/Looper.h>
+#include <utils/StopWatch.h>
+#include <utils/Timers.h>
+#include "Looper_test_pipe.h"
#include <utils/threads.h>
@@ -24,41 +25,6 @@
MSG_TEST4 = 4,
};
-class Pipe {
-public:
- int sendFd;
- int receiveFd;
-
- Pipe() {
- int fds[2];
- ::pipe(fds);
-
- receiveFd = fds[0];
- sendFd = fds[1];
- }
-
- ~Pipe() {
- if (sendFd != -1) {
- ::close(sendFd);
- }
-
- if (receiveFd != -1) {
- ::close(receiveFd);
- }
- }
-
- status_t writeSignal() {
- ssize_t nWritten = ::write(sendFd, "*", 1);
- return nWritten == 1 ? 0 : -errno;
- }
-
- status_t readSignal() {
- char buf[1];
- ssize_t nRead = ::read(receiveFd, buf, 1);
- return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
- }
-};
-
class DelayedTask : public Thread {
int mDelayMillis;
diff --git a/Looper_test_pipe.h b/Looper_test_pipe.h
new file mode 100644
index 0000000..77b7b8b
--- /dev/null
+++ b/Looper_test_pipe.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#pragma once
+#include <unistd.h>
+/**
+ * A pipe class for use when testing or fuzzing Looper
+ */
+class Pipe {
+ public:
+ int sendFd;
+ int receiveFd;
+
+ Pipe() {
+ int fds[2];
+ ::pipe(fds);
+
+ receiveFd = fds[0];
+ sendFd = fds[1];
+ }
+
+ ~Pipe() {
+ if (sendFd != -1) {
+ ::close(sendFd);
+ }
+
+ if (receiveFd != -1) {
+ ::close(receiveFd);
+ }
+ }
+
+ android::status_t writeSignal() {
+ ssize_t nWritten = ::write(sendFd, "*", 1);
+ return nWritten == 1 ? 0 : -errno;
+ }
+
+ android::status_t readSignal() {
+ char buf[1];
+ ssize_t nRead = ::read(receiveFd, buf, 1);
+ return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
+ }
+};
diff --git a/LruCache_fuzz.cpp b/LruCache_fuzz.cpp
new file mode 100644
index 0000000..f8bacfc
--- /dev/null
+++ b/LruCache_fuzz.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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/LruCache.h"
+#include "utils/StrongPointer.h"
+
+typedef android::LruCache<size_t, size_t> FuzzCache;
+
+static constexpr uint32_t MAX_CACHE_ENTRIES = 800;
+
+class NoopRemovedCallback : public android::OnEntryRemoved<size_t, size_t> {
+ public:
+ void operator()(size_t&, size_t&) {
+ // noop
+ }
+};
+
+static NoopRemovedCallback callback;
+
+static const std::vector<std::function<void(FuzzedDataProvider*, FuzzCache*)>> operations = {
+ [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->removeOldest(); },
+ [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->peekOldestValue(); },
+ [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->clear(); },
+ [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->size(); },
+ [](FuzzedDataProvider*, FuzzCache* cache) -> void {
+ android::LruCache<size_t, size_t>::Iterator iter(*cache);
+ while (iter.next()) {
+ iter.key();
+ iter.value();
+ }
+ },
+ [](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void {
+ size_t key = dataProvider->ConsumeIntegral<size_t>();
+ size_t val = dataProvider->ConsumeIntegral<size_t>();
+ cache->put(key, val);
+ },
+ [](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void {
+ size_t key = dataProvider->ConsumeIntegral<size_t>();
+ cache->get(key);
+ },
+ [](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void {
+ size_t key = dataProvider->ConsumeIntegral<size_t>();
+ cache->remove(key);
+ },
+ [](FuzzedDataProvider*, FuzzCache* cache) -> void {
+ cache->setOnEntryRemovedListener(&callback);
+ }};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider(data, size);
+ FuzzCache cache(MAX_CACHE_ENTRIES);
+ while (dataProvider.remaining_bytes() > 0) {
+ uint8_t op = dataProvider.ConsumeIntegral<uint8_t>() % operations.size();
+ operations[op](&dataProvider, &cache);
+ }
+
+ return 0;
+}
diff --git a/Printer_fuzz.cpp b/Printer_fuzz.cpp
new file mode 100755
index 0000000..0180d41
--- /dev/null
+++ b/Printer_fuzz.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "android-base/file.h"
+#include "android/log.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/Printer.h"
+#include "utils/String8.h"
+static constexpr int MAX_STR_SIZE = 1000;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider(data, size);
+ android::String8 outStr = android::String8();
+ // Line indent/formatting
+ uint indent = dataProvider.ConsumeIntegral<uint>();
+ std::string prefix = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE);
+ std::string line = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE);
+
+ // Misc properties
+ std::string logTag = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE);
+ android_LogPriority priority =
+ static_cast<android_LogPriority>(dataProvider.ConsumeIntegral<int>());
+ bool ignoreBlankLines = dataProvider.ConsumeBool();
+
+ TemporaryFile tf;
+ android::FdPrinter filePrinter = android::FdPrinter(tf.fd, indent, prefix.c_str());
+ android::String8Printer stringPrinter = android::String8Printer(&outStr);
+ android::PrefixPrinter printer = android::PrefixPrinter(stringPrinter, prefix.c_str());
+ android::LogPrinter logPrinter =
+ android::LogPrinter(logTag.c_str(), priority, prefix.c_str(), ignoreBlankLines);
+
+ printer.printLine(line.c_str());
+ printer.printFormatLine("%s", line.c_str());
+ logPrinter.printLine(line.c_str());
+ logPrinter.printFormatLine("%s", line.c_str());
+ filePrinter.printLine(line.c_str());
+ filePrinter.printFormatLine("%s", line.c_str());
+ return 0;
+}
diff --git a/ProcessCallStack_fuzz.cpp b/ProcessCallStack_fuzz.cpp
new file mode 100644
index 0000000..30136cd
--- /dev/null
+++ b/ProcessCallStack_fuzz.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 <atomic>
+#include <thread>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/ProcessCallStack.h"
+using android::ProcessCallStack;
+
+static constexpr int MAX_NAME_SIZE = 1000;
+static constexpr int MAX_LOG_META_SIZE = 1000;
+static constexpr uint8_t MAX_THREADS = 10;
+
+std::atomic_bool ranCallStackUpdate(false);
+void loop() {
+ while (!ranCallStackUpdate.load()) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+}
+
+void spawnThreads(FuzzedDataProvider* dataProvider) {
+ std::vector<std::thread> threads = std::vector<std::thread>();
+
+ // Get the number of threads to generate
+ uint8_t count = dataProvider->ConsumeIntegralInRange<uint8_t>(1, MAX_THREADS);
+
+ // Generate threads
+ for (uint8_t i = 0; i < count; i++) {
+ std::string threadName =
+ dataProvider->ConsumeRandomLengthString(MAX_NAME_SIZE).append(std::to_string(i));
+ std::thread th = std::thread(loop);
+ pthread_setname_np(th.native_handle(), threadName.c_str());
+ threads.push_back(move(th));
+ }
+
+ // Collect thread information
+ ProcessCallStack callStack = ProcessCallStack();
+ callStack.update();
+
+ // Tell our patiently waiting threads they can be done now.
+ ranCallStackUpdate.store(true);
+
+ std::string logTag = dataProvider->ConsumeRandomLengthString(MAX_LOG_META_SIZE);
+ std::string prefix = dataProvider->ConsumeRandomLengthString(MAX_LOG_META_SIZE);
+ // Both of these, along with dump, all call print() under the hood,
+ // Which is covered by the Printer fuzzer.
+ callStack.log(logTag.c_str());
+ callStack.toString(prefix.c_str());
+
+ // Check size
+ callStack.size();
+
+ // wait for any remaining threads
+ for (auto& thread : threads) {
+ thread.join();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider(data, size);
+ spawnThreads(&dataProvider);
+ return 0;
+}
diff --git a/PropertyMap.cpp b/PropertyMap.cpp
deleted file mode 100644
index f00272a..0000000
--- a/PropertyMap.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-#define LOG_TAG "PropertyMap"
-
-#include <utils/PropertyMap.h>
-
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
-
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-
-namespace android {
-
-static const char* WHITESPACE = " \t\r";
-static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r=";
-
-
-// --- PropertyMap ---
-
-PropertyMap::PropertyMap() {
-}
-
-PropertyMap::~PropertyMap() {
-}
-
-void PropertyMap::clear() {
- mProperties.clear();
-}
-
-void PropertyMap::addProperty(const String8& key, const String8& value) {
- mProperties.add(key, value);
-}
-
-bool PropertyMap::hasProperty(const String8& key) const {
- return mProperties.indexOfKey(key) >= 0;
-}
-
-bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const {
- ssize_t index = mProperties.indexOfKey(key);
- if (index < 0) {
- return false;
- }
-
- outValue = mProperties.valueAt(index);
- return true;
-}
-
-bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const {
- int32_t intValue;
- if (!tryGetProperty(key, intValue)) {
- return false;
- }
-
- outValue = intValue;
- return true;
-}
-
-bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const {
- String8 stringValue;
- if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
- }
-
- char* end;
- int value = strtol(stringValue.string(), & end, 10);
- if (*end != '\0') {
- ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.",
- key.string(), stringValue.string());
- return false;
- }
- outValue = value;
- return true;
-}
-
-bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const {
- String8 stringValue;
- if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
- }
-
- char* end;
- float value = strtof(stringValue.string(), & end);
- if (*end != '\0') {
- ALOGW("Property key '%s' has invalid value '%s'. Expected a float.",
- key.string(), stringValue.string());
- return false;
- }
- outValue = value;
- return true;
-}
-
-void PropertyMap::addAll(const PropertyMap* map) {
- for (size_t i = 0; i < map->mProperties.size(); i++) {
- mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i));
- }
-}
-
-status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
- *outMap = nullptr;
-
- Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
- if (status) {
- ALOGE("Error %d opening property file %s.", status, filename.string());
- } else {
- PropertyMap* map = new PropertyMap();
- if (!map) {
- ALOGE("Error allocating property map.");
- status = NO_MEMORY;
- } else {
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
- Parser parser(map, tokenizer);
- status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
- ALOGD("Parsed property file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
- elapsedTime / 1000000.0);
-#endif
- if (status) {
- delete map;
- } else {
- *outMap = map;
- }
- }
- delete tokenizer;
- }
- return status;
-}
-
-
-// --- PropertyMap::Parser ---
-
-PropertyMap::Parser::Parser(PropertyMap* map, Tokenizer* tokenizer) :
- mMap(map), mTokenizer(tokenizer) {
-}
-
-PropertyMap::Parser::~Parser() {
-}
-
-status_t PropertyMap::Parser::parse() {
- while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
- ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
-#endif
-
- mTokenizer->skipDelimiters(WHITESPACE);
-
- if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
- String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
- if (keyToken.isEmpty()) {
- ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
-
- if (mTokenizer->nextChar() != '=') {
- ALOGE("%s: Expected '=' between property key and value.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
-
- String8 valueToken = mTokenizer->nextToken(WHITESPACE);
- if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) {
- ALOGE("%s: Found reserved character '\\' or '\"' in property value.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- if (!mTokenizer->isEol()) {
- ALOGE("%s: Expected end of line, got '%s'.",
- mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
- return BAD_VALUE;
- }
-
- if (mMap->hasProperty(keyToken)) {
- ALOGE("%s: Duplicate property value for key '%s'.",
- mTokenizer->getLocation().string(), keyToken.string());
- return BAD_VALUE;
- }
-
- mMap->addProperty(keyToken, valueToken);
- }
-
- mTokenizer->nextLine();
- }
- return OK;
-}
-
-} // namespace android
diff --git a/RefBase.cpp b/RefBase.cpp
index ae10789..8e45226 100644
--- a/RefBase.cpp
+++ b/RefBase.cpp
@@ -21,9 +21,9 @@
#include <android-base/macros.h>
-#include <utils/RefBase.h>
+#include <log/log.h>
-#include <utils/CallStack.h>
+#include <utils/RefBase.h>
#include <utils/Mutex.h>
@@ -55,6 +55,17 @@
// case.
#define DEBUG_REFBASE_DESTRUCTION 1
+#if !defined(_WIN32) && !defined(__APPLE__)
+// CallStack is only supported on linux type platforms.
+#define CALLSTACK_ENABLED 1
+#else
+#define CALLSTACK_ENABLED 0
+#endif
+
+#if CALLSTACK_ENABLED
+#include <utils/CallStack.h>
+#endif
+
// ---------------------------------------------------------------------------
namespace android {
@@ -185,7 +196,7 @@
, mRetain(false)
{
}
-
+
~weakref_impl()
{
bool dumpStack = false;
@@ -196,7 +207,7 @@
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
@@ -210,7 +221,7 @@
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG, refs->stack.get());
#endif
refs = refs->next;
@@ -218,7 +229,9 @@
}
if (dumpStack) {
ALOGE("above errors at:");
+#if CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
+#endif
}
}
@@ -261,8 +274,7 @@
renameRefsId(mWeakRefs, old_id, new_id);
}
- void trackMe(bool track, bool retain)
- {
+ void trackMe(bool track, bool retain) {
mTrackEnabled = track;
mRetain = retain;
}
@@ -306,7 +318,7 @@
{
ref_entry* next;
const void* id;
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
CallStack::CallStackUPtr stack;
#endif
int32_t ref;
@@ -323,7 +335,7 @@
// decrement the reference count.
ref->ref = mRef;
ref->id = id;
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
ref->stack = CallStack::getCurrent(2);
#endif
ref->next = *refs;
@@ -335,7 +347,7 @@
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
-
+
ref_entry* const head = *refs;
ref_entry* ref = head;
while (ref != NULL) {
@@ -359,7 +371,9 @@
ref = ref->next;
}
+#if CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
+#endif
}
}
@@ -385,7 +399,7 @@
snprintf(buf, sizeof(buf), "\t%c ID %p (ref %d):\n",
inc, refs->id, refs->ref);
out->append(buf);
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
out->append(CallStack::stackToString("\t\t", refs->stack.get()));
#else
out->append("\t\t(call stacks disabled)");
@@ -412,7 +426,7 @@
{
weakref_impl* const refs = mRefs;
refs->incWeak(id);
-
+
refs->addStrongRef(id);
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
@@ -468,7 +482,7 @@
// TODO: Better document assumptions.
weakref_impl* const refs = mRefs;
refs->incWeak(id);
-
+
refs->addStrongRef(id);
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
@@ -550,7 +564,7 @@
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
incWeak(id);
-
+
weakref_impl* const impl = static_cast<weakref_impl*>(this);
int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);
@@ -567,7 +581,7 @@
// the strong count has changed on us, we need to re-assert our
// situation. curCount was updated by compare_exchange_weak.
}
-
+
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
// we're now in the harder case of either:
// - there never was a strong reference on us
@@ -624,7 +638,7 @@
}
}
}
-
+
impl->addStrongRef(id);
#if PRINT_REFS
@@ -719,7 +733,10 @@
// Treating this as fatal is prone to causing boot loops. For debugging, it's
// better to treat as non-fatal.
ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
+
+#if CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
+#endif
#else
LOG_ALWAYS_FATAL("RefBase: Explicit destruction, weak count = %d", mRefs->mWeak.load());
#endif
diff --git a/RefBase_fuzz.cpp b/RefBase_fuzz.cpp
new file mode 100644
index 0000000..69288b3
--- /dev/null
+++ b/RefBase_fuzz.cpp
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RefBaseFuzz"
+
+#include <thread>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/Log.h"
+#include "utils/RWLock.h"
+#include "utils/RefBase.h"
+#include "utils/StrongPointer.h"
+
+using android::RefBase;
+using android::RWLock;
+using android::sp;
+using android::wp;
+
+static constexpr int kMaxOperations = 100;
+static constexpr int kMaxThreads = 10;
+struct RefBaseSubclass : public RefBase {
+ public:
+ RefBaseSubclass(bool* deletedCheck, RWLock& deletedMtx)
+ : mDeleted(deletedCheck), mRwLock(deletedMtx) {
+ RWLock::AutoWLock lock(mRwLock);
+ *mDeleted = false;
+ extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+ }
+
+ virtual ~RefBaseSubclass() {
+ RWLock::AutoWLock lock(mRwLock);
+ *mDeleted = true;
+ }
+
+ private:
+ bool* mDeleted;
+ android::RWLock& mRwLock;
+};
+
+// A thread-specific state object for ref
+struct RefThreadState {
+ size_t strongCount = 0;
+ size_t weakCount = 0;
+};
+
+RWLock gRefDeletedLock;
+bool gRefDeleted = false;
+bool gHasModifiedRefs = false;
+RefBaseSubclass* ref;
+RefBase::weakref_type* weakRefs;
+
+// These operations don't need locks as they explicitly check per-thread counts before running
+// they also have the potential to write to gRefDeleted, so must not be locked.
+const std::vector<std::function<void(RefThreadState*)>> kUnlockedOperations = {
+ [](RefThreadState* refState) -> void {
+ if (refState->strongCount > 0) {
+ ref->decStrong(nullptr);
+ gHasModifiedRefs = true;
+ refState->strongCount--;
+ }
+ },
+ [](RefThreadState* refState) -> void {
+ if (refState->weakCount > 0) {
+ weakRefs->decWeak(nullptr);
+ gHasModifiedRefs = true;
+ refState->weakCount--;
+ }
+ },
+};
+
+const std::vector<std::function<void(RefThreadState*)>> kMaybeLockedOperations = {
+ // Read-only operations
+ [](RefThreadState*) -> void { ref->getStrongCount(); },
+ [](RefThreadState*) -> void { weakRefs->getWeakCount(); },
+ [](RefThreadState*) -> void { ref->printRefs(); },
+
+ // Read/write operations
+ [](RefThreadState* refState) -> void {
+ ref->incStrong(nullptr);
+ gHasModifiedRefs = true;
+ refState->strongCount++;
+ },
+ [](RefThreadState* refState) -> void {
+ ref->forceIncStrong(nullptr);
+ gHasModifiedRefs = true;
+ refState->strongCount++;
+ },
+ [](RefThreadState* refState) -> void {
+ ref->createWeak(nullptr);
+ gHasModifiedRefs = true;
+ refState->weakCount++;
+ },
+ [](RefThreadState* refState) -> void {
+ // This will increment weak internally, then attempt to
+ // promote it to strong. If it fails, it decrements weak.
+ // If it succeeds, the weak is converted to strong.
+ // Both cases net no weak reference change.
+ if (weakRefs->attemptIncStrong(nullptr)) {
+ refState->strongCount++;
+ gHasModifiedRefs = true;
+ }
+ },
+ [](RefThreadState* refState) -> void {
+ if (weakRefs->attemptIncWeak(nullptr)) {
+ refState->weakCount++;
+ gHasModifiedRefs = true;
+ }
+ },
+ [](RefThreadState* refState) -> void {
+ weakRefs->incWeak(nullptr);
+ gHasModifiedRefs = true;
+ refState->weakCount++;
+ },
+};
+
+void loop(const std::vector<uint8_t>& fuzzOps) {
+ RefThreadState state;
+ uint8_t lockedOpSize = kMaybeLockedOperations.size();
+ uint8_t totalOperationTypes = lockedOpSize + kUnlockedOperations.size();
+ for (auto op : fuzzOps) {
+ auto opVal = op % totalOperationTypes;
+ if (opVal >= lockedOpSize) {
+ kUnlockedOperations[opVal % lockedOpSize](&state);
+ } else {
+ // We only need to lock if we have no strong or weak count
+ bool shouldLock = state.strongCount == 0 && state.weakCount == 0;
+ if (shouldLock) {
+ gRefDeletedLock.readLock();
+ // If ref has deleted itself, we can no longer fuzz on this thread.
+ if (gRefDeleted) {
+ // Unlock since we're exiting the loop here.
+ gRefDeletedLock.unlock();
+ return;
+ }
+ }
+ // Execute the locked operation
+ kMaybeLockedOperations[opVal](&state);
+ // Unlock if we locked.
+ if (shouldLock) {
+ gRefDeletedLock.unlock();
+ }
+ }
+ }
+
+ // Instead of explicitly freeing this, we're going to remove our weak and
+ // strong references.
+ for (; state.weakCount > 0; state.weakCount--) {
+ weakRefs->decWeak(nullptr);
+ }
+
+ // Clean up any strong references
+ for (; state.strongCount > 0; state.strongCount--) {
+ ref->decStrong(nullptr);
+ }
+}
+
+void spawnThreads(FuzzedDataProvider* dataProvider) {
+ std::vector<std::thread> threads = std::vector<std::thread>();
+
+ // Get the number of threads to generate
+ uint8_t count = dataProvider->ConsumeIntegralInRange<uint8_t>(1, kMaxThreads);
+ // Generate threads
+ for (uint8_t i = 0; i < count; i++) {
+ uint8_t opCount = dataProvider->ConsumeIntegralInRange<uint8_t>(1, kMaxOperations);
+ std::vector<uint8_t> threadOperations = dataProvider->ConsumeBytes<uint8_t>(opCount);
+ std::thread tmpThread = std::thread(loop, threadOperations);
+ threads.push_back(move(tmpThread));
+ }
+
+ for (auto& th : threads) {
+ th.join();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ gHasModifiedRefs = false;
+ ref = new RefBaseSubclass(&gRefDeleted, gRefDeletedLock);
+ weakRefs = ref->getWeakRefs();
+ // Since we are modifying flags, (flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK
+ // is true. The destructor for RefBase should clean up weakrefs because of this.
+ FuzzedDataProvider dataProvider(data, size);
+ spawnThreads(&dataProvider);
+ LOG_ALWAYS_FATAL_IF(!gHasModifiedRefs && gRefDeleted, "ref(%p) was prematurely deleted!", ref);
+ // We need to explicitly delete this object
+ // if no refs have been added or deleted.
+ if (!gHasModifiedRefs && !gRefDeleted) {
+ delete ref;
+ }
+ LOG_ALWAYS_FATAL_IF(gHasModifiedRefs && !gRefDeleted,
+ "ref(%p) should be deleted, is it leaking?", ref);
+ return 0;
+}
diff --git a/SharedBuffer_test.cpp b/SharedBuffer_test.cpp
index 33a4e0c..3f960d2 100644
--- a/SharedBuffer_test.cpp
+++ b/SharedBuffer_test.cpp
@@ -23,36 +23,45 @@
#include "SharedBuffer.h"
-TEST(SharedBufferTest, TestAlloc) {
- EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX), "");
- EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer)), "");
+extern "C" void __hwasan_init() __attribute__((weak));
+#define SKIP_WITH_HWASAN \
+ if (&__hwasan_init != 0) GTEST_SKIP()
- // Make sure we don't die here.
- // Check that null is returned, as we are asking for the whole address space.
- android::SharedBuffer* buf =
- android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
- ASSERT_EQ(nullptr, buf);
-
- buf = android::SharedBuffer::alloc(0);
- ASSERT_NE(nullptr, buf);
- ASSERT_EQ(0U, buf->size());
- buf->release();
+TEST(SharedBufferTest, alloc_death) {
+ EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX), "");
+ EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer)), "");
}
-TEST(SharedBufferTest, TestEditResize) {
- android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
- EXPECT_DEATH(buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer)), "");
- buf = android::SharedBuffer::alloc(10);
- EXPECT_DEATH(buf->editResize(SIZE_MAX), "");
+TEST(SharedBufferTest, alloc_null) {
+ // Big enough to fail, not big enough to abort.
+ SKIP_WITH_HWASAN; // hwasan has a 2GiB allocation limit.
+ ASSERT_EQ(nullptr, android::SharedBuffer::alloc(SIZE_MAX / 2));
+}
- buf = android::SharedBuffer::alloc(10);
- // Make sure we don't die here.
- // Check that null is returned, as we are asking for the whole address space.
- buf = buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
- ASSERT_EQ(nullptr, buf);
+TEST(SharedBufferTest, alloc_zero_size) {
+ android::SharedBuffer* buf = android::SharedBuffer::alloc(0);
+ ASSERT_NE(nullptr, buf);
+ ASSERT_EQ(0U, buf->size());
+ buf->release();
+}
- buf = android::SharedBuffer::alloc(10);
- buf = buf->editResize(0);
- ASSERT_EQ(0U, buf->size());
- buf->release();
+TEST(SharedBufferTest, editResize_death) {
+ android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+ EXPECT_DEATH(buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer)), "");
+ buf = android::SharedBuffer::alloc(10);
+ EXPECT_DEATH(buf->editResize(SIZE_MAX), "");
+}
+
+TEST(SharedBufferTest, editResize_null) {
+ // Big enough to fail, not big enough to abort.
+ SKIP_WITH_HWASAN; // hwasan has a 2GiB allocation limit.
+ android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+ ASSERT_EQ(nullptr, buf->editResize(SIZE_MAX / 2));
+}
+
+TEST(SharedBufferTest, editResize_zero_size) {
+ android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+ buf = buf->editResize(0);
+ ASSERT_EQ(0U, buf->size());
+ buf->release();
}
diff --git a/StopWatch_fuzz.cpp b/StopWatch_fuzz.cpp
new file mode 100644
index 0000000..63d8a28
--- /dev/null
+++ b/StopWatch_fuzz.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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/StopWatch.h"
+
+static constexpr int MAX_OPERATIONS = 100;
+static constexpr int MAX_NAME_LEN = 2048;
+
+static const std::vector<std::function<void(android::StopWatch)>> operations = {
+ [](android::StopWatch stopWatch) -> void { stopWatch.reset(); },
+ [](android::StopWatch stopWatch) -> void { stopWatch.lap(); },
+ [](android::StopWatch stopWatch) -> void { stopWatch.elapsedTime(); },
+ [](android::StopWatch stopWatch) -> void { stopWatch.name(); },
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider(data, size);
+ std::string nameStr = dataProvider.ConsumeRandomLengthString(MAX_NAME_LEN);
+ int clockVal = dataProvider.ConsumeIntegral<int>();
+ android::StopWatch stopWatch = android::StopWatch(nameStr.c_str(), clockVal);
+ std::vector<uint8_t> opsToRun = dataProvider.ConsumeRemainingBytes<uint8_t>();
+ int opsRun = 0;
+ for (auto it : opsToRun) {
+ if (opsRun++ >= MAX_OPERATIONS) {
+ break;
+ }
+ it = it % operations.size();
+ operations[it](stopWatch);
+ }
+ return 0;
+}
diff --git a/String16.cpp b/String16.cpp
index d514f29..70bf5a0 100644
--- a/String16.cpp
+++ b/String16.cpp
@@ -441,7 +441,7 @@
mString = getEmptyString();
return OK;
}
- if ((begin+len) > N) len = N-begin;
+ if (len > N || len > N - begin) len = N - begin;
if (begin == 0 && len == N) {
return OK;
}
diff --git a/String16_fuzz.cpp b/String16_fuzz.cpp
new file mode 100644
index 0000000..63c2800
--- /dev/null
+++ b/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/String16_test.cpp b/String16_test.cpp
index f1f24c3..2505f44 100644
--- a/String16_test.cpp
+++ b/String16_test.cpp
@@ -215,4 +215,16 @@
EXPECT_TRUE(tmp.isStaticString());
}
+TEST(String16Test, OverreadUtf8Conversion) {
+ char tmp[] = {'a', static_cast<char>(0xe0), '\0'};
+ String16 another(tmp);
+ EXPECT_TRUE(another.size() == 0);
+}
+
+TEST(String16Test, ValidUtf8Conversion) {
+ String16 another("abcdef");
+ EXPECT_EQ(6U, another.size());
+ EXPECT_STR16EQ(another, u"abcdef");
+}
+
} // namespace android
diff --git a/String8.cpp b/String8.cpp
index d00e39c..3dc2026 100644
--- a/String8.cpp
+++ b/String8.cpp
@@ -309,8 +309,14 @@
n = vsnprintf(nullptr, 0, fmt, tmp_args);
va_end(tmp_args);
- if (n != 0) {
+ if (n < 0) return UNKNOWN_ERROR;
+
+ if (n > 0) {
size_t oldLength = length();
+ if ((size_t)n > SIZE_MAX - 1 ||
+ oldLength > SIZE_MAX - (size_t)n - 1) {
+ return NO_MEMORY;
+ }
char* buf = lockBuffer(oldLength + n);
if (buf) {
vsnprintf(buf + oldLength, n + 1, fmt, args);
@@ -424,7 +430,7 @@
char* buf = lockBuffer(len);
buf += start;
while (length > 0) {
- *buf = tolower(*buf);
+ *buf = static_cast<char>(tolower(*buf));
buf++;
length--;
}
@@ -448,7 +454,7 @@
char* buf = lockBuffer(len);
buf += start;
while (length > 0) {
- *buf = toupper(*buf);
+ *buf = static_cast<char>(toupper(*buf));
buf++;
length--;
}
diff --git a/String8_fuzz.cpp b/String8_fuzz.cpp
new file mode 100644
index 0000000..b02683c
--- /dev/null
+++ b/String8_fuzz.cpp
@@ -0,0 +1,236 @@
+/*
+ * 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 <memory>
+
+#include "FuzzFormatTypes.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/String8.h"
+
+static constexpr int MAX_STRING_BYTES = 256;
+static constexpr uint8_t MAX_OPERATIONS = 50;
+// Interestingly, 2147483614 (INT32_MAX - 33) seems to be the max value that is handled for format
+// flags. Unfortunately we need to use a smaller value so we avoid consuming too much memory.
+
+void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend);
+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();
+ },
+
+ // 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 {
+ const android::String8& constRef(*str2);
+ str1->compare(constRef);
+ },
+
+ // Append and format
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ str1->append(str2->c_str());
+ },
+ [](FuzzedDataProvider* dataProvider, android::String8* str1, android::String8*)
+ -> void { fuzzFormat(dataProvider, str1, dataProvider->ConsumeBool()); },
+
+ // Find operation
+ [](FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8* str2) -> void {
+ // We need to get a value from our fuzzer here.
+ int start_index = dataProvider->ConsumeIntegralInRange<int>(0, str1->size());
+ str1->find(str2->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 {
+ std::shared_ptr<android::String8> path_out_str =
+ std::make_shared<android::String8>();
+ str1->walkPath(path_out_str.get());
+ 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 fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
+ FormatChar formatType = dataProvider->ConsumeEnum<FormatChar>();
+
+ std::string formatString("%");
+ // Width specifier
+ if (dataProvider->ConsumeBool()) {
+ // Left pad with zeroes
+ if (dataProvider->ConsumeBool()) {
+ formatString.push_back('0');
+ }
+ // Right justify (or left justify if negative)
+ int32_t justify = dataProvider->ConsumeIntegralInRange<int32_t>(-kMaxFormatFlagValue,
+ kMaxFormatFlagValue);
+ formatString += std::to_string(justify);
+ }
+
+ // The # specifier only works with o, x, X, a, A, e, E, f, F, g, and G
+ if (canApplyFlag(formatType, '#') && dataProvider->ConsumeBool()) {
+ formatString.push_back('#');
+ }
+
+ // Precision specifier
+ if (canApplyFlag(formatType, '.') && dataProvider->ConsumeBool()) {
+ formatString.push_back('.');
+ formatString +=
+ std::to_string(dataProvider->ConsumeIntegralInRange<int>(0, kMaxFormatFlagValue));
+ }
+
+ formatString.push_back(kFormatChars.at(static_cast<uint8_t>(formatType)));
+
+ switch (formatType) {
+ case SIGNED_DECIMAL: {
+ int val = dataProvider->ConsumeIntegral<int>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), dataProvider->ConsumeIntegral<int>());
+ }
+ break;
+ }
+
+ case UNSIGNED_DECIMAL:
+ case UNSIGNED_OCTAL:
+ case UNSIGNED_HEX_LOWER:
+ case UNSIGNED_HEX_UPPER: {
+ // Unsigned integers for u, o, x, and X
+ uint val = dataProvider->ConsumeIntegral<uint>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case FLOAT_LOWER:
+ case FLOAT_UPPER:
+ case EXPONENT_LOWER:
+ case EXPONENT_UPPER:
+ case SHORT_EXP_LOWER:
+ case SHORT_EXP_UPPER:
+ case HEX_FLOAT_LOWER:
+ case HEX_FLOAT_UPPER: {
+ // Floating points for f, F, e, E, g, G, a, and A
+ float val = dataProvider->ConsumeFloatingPoint<float>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case CHAR: {
+ char val = dataProvider->ConsumeIntegral<char>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case STRING: {
+ std::string val = dataProvider->ConsumeRandomLengthString(MAX_STRING_BYTES);
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val.c_str());
+ } else {
+ str1->format(formatString.c_str(), val.c_str());
+ }
+ break;
+ }
+ case POINTER: {
+ uintptr_t val = dataProvider->ConsumeIntegral<uintptr_t>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+ }
+}
+
+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);
+ operations[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/String8_test.cpp b/String8_test.cpp
index 3947a5f..9efcc6f 100644
--- a/String8_test.cpp
+++ b/String8_test.cpp
@@ -96,4 +96,9 @@
EXPECT_EQ(10U, string8.length());
}
+TEST_F(String8Test, ValidUtf16Conversion) {
+ char16_t tmp[] = u"abcdef";
+ String8 valid = String8(String16(tmp));
+ EXPECT_STREQ(valid, "abcdef");
+}
}
diff --git a/SystemClock.cpp b/SystemClock.cpp
index 73ec1be..9c71141 100644
--- a/SystemClock.cpp
+++ b/SystemClock.cpp
@@ -39,8 +39,15 @@
*/
int64_t uptimeMillis()
{
- int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
- return (int64_t) nanoseconds_to_milliseconds(when);
+ return nanoseconds_to_milliseconds(uptimeNanos());
+}
+
+/*
+ * public static native long uptimeNanos();
+ */
+int64_t uptimeNanos()
+{
+ return systemTime(SYSTEM_TIME_MONOTONIC);
}
/*
diff --git a/SystemClock_test.cpp b/SystemClock_test.cpp
index 5ad060b..7449dad 100644
--- a/SystemClock_test.cpp
+++ b/SystemClock_test.cpp
@@ -29,16 +29,24 @@
TEST(SystemClock, SystemClock) {
auto startUptimeMs = android::uptimeMillis();
+ auto startUptimeNs = android::uptimeNanos();
auto startRealtimeMs = android::elapsedRealtime();
auto startRealtimeNs = android::elapsedRealtimeNano();
ASSERT_GT(startUptimeMs, 0)
<< "uptimeMillis() reported an impossible uptime";
+ ASSERT_GT(startUptimeNs, 0)
+ << "uptimeNanos() reported an impossible uptime";
ASSERT_GE(startRealtimeMs, startUptimeMs)
<< "elapsedRealtime() thinks we've suspended for negative time";
- ASSERT_GE(startRealtimeNs, startUptimeMs * MS_IN_NS)
+ ASSERT_GE(startRealtimeNs, startUptimeNs)
<< "elapsedRealtimeNano() thinks we've suspended for negative time";
+ ASSERT_GE(startUptimeNs, startUptimeMs * MS_IN_NS)
+ << "uptimeMillis() and uptimeNanos() are inconsistent";
+ ASSERT_LT(startUptimeNs, (startUptimeMs + SLACK_MS) * MS_IN_NS)
+ << "uptimeMillis() and uptimeNanos() are inconsistent";
+
ASSERT_GE(startRealtimeNs, startRealtimeMs * MS_IN_NS)
<< "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
ASSERT_LT(startRealtimeNs, (startRealtimeMs + SLACK_MS) * MS_IN_NS)
@@ -51,6 +59,7 @@
ASSERT_EQ(nanosleepErr, 0) << "nanosleep() failed: " << strerror(errno);
auto endUptimeMs = android::uptimeMillis();
+ auto endUptimeNs = android::uptimeNanos();
auto endRealtimeMs = android::elapsedRealtime();
auto endRealtimeNs = android::elapsedRealtimeNano();
@@ -58,6 +67,10 @@
<< "uptimeMillis() advanced too little after nanosleep()";
EXPECT_LT(endUptimeMs - startUptimeMs, SLEEP_MS + SLACK_MS)
<< "uptimeMillis() advanced too much after nanosleep()";
+ EXPECT_GE(endUptimeNs - startUptimeNs, SLEEP_NS)
+ << "uptimeNanos() advanced too little after nanosleep()";
+ EXPECT_LT(endUptimeNs - startUptimeNs, SLEEP_NS + SLACK_NS)
+ << "uptimeNanos() advanced too much after nanosleep()";
EXPECT_GE(endRealtimeMs - startRealtimeMs, SLEEP_MS)
<< "elapsedRealtime() advanced too little after nanosleep()";
EXPECT_LT(endRealtimeMs - startRealtimeMs, SLEEP_MS + SLACK_MS)
@@ -67,6 +80,11 @@
EXPECT_LT(endRealtimeNs - startRealtimeNs, SLEEP_NS + SLACK_NS)
<< "elapsedRealtimeNano() advanced too much after nanosleep()";
+ EXPECT_GE(endUptimeNs, endUptimeMs * MS_IN_NS)
+ << "uptimeMillis() and uptimeNanos() are inconsistent after nanosleep()";
+ EXPECT_LT(endUptimeNs, (endUptimeMs + SLACK_MS) * MS_IN_NS)
+ << "uptimeMillis() and uptimeNanos() are inconsistent after nanosleep()";
+
EXPECT_GE(endRealtimeNs, endRealtimeMs * MS_IN_NS)
<< "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
EXPECT_LT(endRealtimeNs, (endRealtimeMs + SLACK_MS) * MS_IN_NS)
diff --git a/Timers.cpp b/Timers.cpp
index 1172ae7..fd3f4a9 100644
--- a/Timers.cpp
+++ b/Timers.cpp
@@ -20,31 +20,37 @@
#include <utils/Timers.h>
#include <limits.h>
+#include <stdlib.h>
#include <time.h>
-// host linux support requires Linux 2.6.39+
+#include <android-base/macros.h>
+
+static constexpr size_t clock_id_max = 5;
+
+static void checkClockId(int clock) {
+ if (clock < 0 || clock >= clock_id_max) abort();
+}
+
#if defined(__linux__)
-nsecs_t systemTime(int clock)
-{
- static const clockid_t clocks[] = {
- CLOCK_REALTIME,
- CLOCK_MONOTONIC,
- CLOCK_PROCESS_CPUTIME_ID,
- CLOCK_THREAD_CPUTIME_ID,
- CLOCK_BOOTTIME
- };
- struct timespec t;
- t.tv_sec = t.tv_nsec = 0;
+nsecs_t systemTime(int clock) {
+ checkClockId(clock);
+ static constexpr clockid_t clocks[] = {CLOCK_REALTIME, CLOCK_MONOTONIC,
+ CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID,
+ CLOCK_BOOTTIME};
+ static_assert(clock_id_max == arraysize(clocks));
+ timespec t = {};
clock_gettime(clocks[clock], &t);
return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
}
#else
-nsecs_t systemTime(int /*clock*/)
-{
+nsecs_t systemTime(int clock) {
+ // TODO: is this ever called with anything but REALTIME on mac/windows?
+ checkClockId(clock);
+
// Clock support varies widely across hosts. Mac OS doesn't support
- // CLOCK_BOOTTIME, and Windows is windows.
- struct timeval t;
- t.tv_sec = t.tv_usec = 0;
+ // CLOCK_BOOTTIME (and doesn't even have clock_gettime until 10.12).
+ // Windows is windows.
+ timeval t = {};
gettimeofday(&t, nullptr);
return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
}
diff --git a/Timers_test.cpp b/Timers_test.cpp
new file mode 100644
index 0000000..ec0051e
--- /dev/null
+++ b/Timers_test.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 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 <utils/Timers.h>
+
+#include <gtest/gtest.h>
+
+TEST(Timers, systemTime_invalid) {
+ EXPECT_EXIT(systemTime(-1), testing::KilledBySignal(SIGABRT), "");
+ systemTime(SYSTEM_TIME_REALTIME);
+ systemTime(SYSTEM_TIME_MONOTONIC);
+ systemTime(SYSTEM_TIME_PROCESS);
+ systemTime(SYSTEM_TIME_THREAD);
+ systemTime(SYSTEM_TIME_BOOTTIME);
+ EXPECT_EXIT(systemTime(SYSTEM_TIME_BOOTTIME + 1), testing::KilledBySignal(SIGABRT), "");
+}
diff --git a/Unicode.cpp b/Unicode.cpp
index b08e061..843a81a 100644
--- a/Unicode.cpp
+++ b/Unicode.cpp
@@ -162,9 +162,9 @@
if (index >= src_len) {
return -1;
}
- size_t dummy_index;
+ size_t unused_index;
if (next_index == nullptr) {
- next_index = &dummy_index;
+ next_index = &unused_index;
}
size_t num_read;
int32_t ret = utf32_at_internal(src + index, &num_read);
@@ -359,49 +359,6 @@
// UTF-8
// --------------------------------------------------------------------------
-ssize_t utf8_length(const char *src)
-{
- const char *cur = src;
- size_t ret = 0;
- while (*cur != '\0') {
- const char first_char = *cur++;
- if ((first_char & 0x80) == 0) { // ASCII
- ret += 1;
- continue;
- }
- // (UTF-8's character must not be like 10xxxxxx,
- // but 110xxxxx, 1110xxxx, ... or 1111110x)
- if ((first_char & 0x40) == 0) {
- return -1;
- }
-
- int32_t mask, to_ignore_mask;
- size_t num_to_read = 0;
- char32_t utf32 = 0;
- for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
- num_to_read < 5 && (first_char & mask);
- num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
- if ((*cur & 0xC0) != 0x80) { // must be 10xxxxxx
- return -1;
- }
- // 0x3F == 00111111
- utf32 = (utf32 << 6) + (*cur++ & 0x3F);
- }
- // "first_char" must be (110xxxxx - 11110xxx)
- if (num_to_read == 5) {
- return -1;
- }
- to_ignore_mask |= mask;
- utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
- if (utf32 > kUnicodeMaxCodepoint) {
- return -1;
- }
-
- ret += num_to_read;
- }
- return ret;
-}
-
ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
{
if (src == nullptr || src_len == 0) {
diff --git a/Vector_fuzz.cpp b/Vector_fuzz.cpp
new file mode 100644
index 0000000..f6df051
--- /dev/null
+++ b/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;
+}
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h
index 8abfb1a..0fb1a6a 100644
--- a/include/utils/BitSet.h
+++ b/include/utils/BitSet.h
@@ -21,9 +21,12 @@
#include <utils/TypeHelpers.h>
/*
- * Contains some bit manipulation helpers.
+ * A class to provide efficient manipulation of bitsets.
*
- * DO NOT USE: std::bitset<32> or std::bitset<64> preferred
+ * Consider using std::bitset<32> or std::bitset<64> if all you want is a class to do basic bit
+ * manipulation (i.e. AND / OR / XOR / flip / etc). These classes are only needed if you want to
+ * efficiently perform operations like finding the first set bit in a bitset and you want to
+ * avoid using the built-in functions (e.g. __builtin_clz) on std::bitset::to_ulong.
*/
namespace android {
@@ -46,7 +49,9 @@
// Returns the number of marked bits in the set.
inline uint32_t count() const { return count(value); }
- static inline uint32_t count(uint32_t value) { return __builtin_popcountl(value); }
+ static inline uint32_t count(uint32_t value) {
+ return static_cast<uint32_t>(__builtin_popcountl(value));
+ }
// Returns true if the bit set does not contain any marked bits.
inline bool isEmpty() const { return isEmpty(value); }
@@ -128,7 +133,7 @@
}
static inline uint32_t getIndexOfBit(uint32_t value, uint32_t n) {
- return __builtin_popcountl(value & ~(0xffffffffUL >> n));
+ return static_cast<uint32_t>(__builtin_popcountl(value & ~(0xffffffffUL >> n)));
}
inline bool operator== (const BitSet32& other) const { return value == other.value; }
@@ -153,17 +158,17 @@
// input, which is only guaranteed to be 16b, not 32. The compiler should optimize this away.
static inline uint32_t clz_checked(uint32_t value) {
if (sizeof(unsigned int) == sizeof(uint32_t)) {
- return __builtin_clz(value);
+ return static_cast<uint32_t>(__builtin_clz(value));
} else {
- return __builtin_clzl(value);
+ return static_cast<uint32_t>(__builtin_clzl(value));
}
}
static inline uint32_t ctz_checked(uint32_t value) {
if (sizeof(unsigned int) == sizeof(uint32_t)) {
- return __builtin_ctz(value);
+ return static_cast<uint32_t>(__builtin_ctz(value));
} else {
- return __builtin_ctzl(value);
+ return static_cast<uint32_t>(__builtin_ctzl(value));
}
}
};
@@ -188,7 +193,9 @@
// Returns the number of marked bits in the set.
inline uint32_t count() const { return count(value); }
- static inline uint32_t count(uint64_t value) { return __builtin_popcountll(value); }
+ static inline uint32_t count(uint64_t value) {
+ return static_cast<uint32_t>(__builtin_popcountll(value));
+ }
// Returns true if the bit set does not contain any marked bits.
inline bool isEmpty() const { return isEmpty(value); }
@@ -219,26 +226,32 @@
// Result is undefined if all bits are unmarked.
inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); }
- static inline uint32_t firstMarkedBit(uint64_t value) { return __builtin_clzll(value); }
+ static inline uint32_t firstMarkedBit(uint64_t value) {
+ return static_cast<uint32_t>(__builtin_clzll(value));
+ }
// Finds the first unmarked bit in the set.
// Result is undefined if all bits are marked.
inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); }
- static inline uint32_t firstUnmarkedBit(uint64_t value) { return __builtin_clzll(~ value); }
+ static inline uint32_t firstUnmarkedBit(uint64_t value) {
+ return static_cast<uint32_t>(__builtin_clzll(~value));
+ }
// Finds the last marked bit in the set.
// Result is undefined if all bits are unmarked.
inline uint32_t lastMarkedBit() const { return lastMarkedBit(value); }
- static inline uint32_t lastMarkedBit(uint64_t value) { return 63 - __builtin_ctzll(value); }
+ static inline uint32_t lastMarkedBit(uint64_t value) {
+ return static_cast<uint32_t>(63 - __builtin_ctzll(value));
+ }
// Finds the first marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
inline uint32_t clearFirstMarkedBit() { return clearFirstMarkedBit(value); }
static inline uint32_t clearFirstMarkedBit(uint64_t& value) {
- uint64_t n = firstMarkedBit(value);
+ uint32_t n = firstMarkedBit(value);
clearBit(value, n);
return n;
}
@@ -248,7 +261,7 @@
inline uint32_t markFirstUnmarkedBit() { return markFirstUnmarkedBit(value); }
static inline uint32_t markFirstUnmarkedBit(uint64_t& value) {
- uint64_t n = firstUnmarkedBit(value);
+ uint32_t n = firstUnmarkedBit(value);
markBit(value, n);
return n;
}
@@ -258,7 +271,7 @@
inline uint32_t clearLastMarkedBit() { return clearLastMarkedBit(value); }
static inline uint32_t clearLastMarkedBit(uint64_t& value) {
- uint64_t n = lastMarkedBit(value);
+ uint32_t n = lastMarkedBit(value);
clearBit(value, n);
return n;
}
@@ -268,7 +281,7 @@
inline uint32_t getIndexOfBit(uint32_t n) const { return getIndexOfBit(value, n); }
static inline uint32_t getIndexOfBit(uint64_t value, uint32_t n) {
- return __builtin_popcountll(value & ~(0xffffffffffffffffULL >> n));
+ return static_cast<uint32_t>(__builtin_popcountll(value & ~(0xffffffffffffffffULL >> n)));
}
inline bool operator== (const BitSet64& other) const { return value == other.value; }
diff --git a/include/utils/Debug.h b/include/utils/Debug.h
index 96bd70e..c3b9026 100644
--- a/include/utils/Debug.h
+++ b/include/utils/Debug.h
@@ -14,27 +14,9 @@
* limitations under the License.
*/
-#ifndef ANDROID_UTILS_DEBUG_H
-#define ANDROID_UTILS_DEBUG_H
+#pragma once
-#include <stdint.h>
-#include <sys/types.h>
+// Note: new code should use static_assert directly.
-namespace android {
-// ---------------------------------------------------------------------------
-
-#ifdef __cplusplus
-template<bool> struct CompileTimeAssert;
-template<> struct CompileTimeAssert<true> {};
-#define COMPILE_TIME_ASSERT(_exp) \
- template class CompileTimeAssert< (_exp) >;
-#endif
-
-// DO NOT USE: Please use static_assert instead
-#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(_exp) \
- CompileTimeAssert<( _exp )>();
-
-// ---------------------------------------------------------------------------
-} // namespace android
-
-#endif // ANDROID_UTILS_DEBUG_H
+#define COMPILE_TIME_ASSERT static_assert
+#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE static_assert
diff --git a/include/utils/Flattenable.h b/include/utils/Flattenable.h
index 17c5e10..8aa381a 100644
--- a/include/utils/Flattenable.h
+++ b/include/utils/Flattenable.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_UTILS_FLATTENABLE_H
-#define ANDROID_UTILS_FLATTENABLE_H
+#pragma once
// DO NOT USE: please use parcelable instead
// This code is deprecated and will not be supported via AIDL code gen. For data
@@ -25,7 +24,6 @@
#include <string.h>
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/Debug.h>
#include <type_traits>
@@ -217,5 +215,3 @@
};
} // namespace android
-
-#endif /* ANDROID_UTILS_FLATTENABLE_H */
diff --git a/include/utils/PropertyMap.h b/include/utils/PropertyMap.h
deleted file mode 100644
index a9e674f..0000000
--- a/include/utils/PropertyMap.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef _UTILS_PROPERTY_MAP_H
-#define _UTILS_PROPERTY_MAP_H
-
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/Errors.h>
-#include <utils/Tokenizer.h>
-
-namespace android {
-
-/*
- * Provides a mechanism for passing around string-based property key / value pairs
- * and loading them from property files.
- *
- * The property files have the following simple structure:
- *
- * # Comment
- * key = value
- *
- * Keys and values are any sequence of printable ASCII characters.
- * The '=' separates the key from the value.
- * The key and value may not contain whitespace.
- *
- * The '\' character is reserved for escape sequences and is not currently supported.
- * The '"" character is reserved for quoting and is not currently supported.
- * Files that contain the '\' or '"' character will fail to parse.
- *
- * The file must not contain duplicate keys.
- *
- * TODO Support escape sequences and quoted values when needed.
- */
-class PropertyMap {
-public:
- /* Creates an empty property map. */
- PropertyMap();
- ~PropertyMap();
-
- /* Clears the property map. */
- void clear();
-
- /* Adds a property.
- * Replaces the property with the same key if it is already present.
- */
- void addProperty(const String8& key, const String8& value);
-
- /* Returns true if the property map contains the specified key. */
- bool hasProperty(const String8& key) const;
-
- /* Gets the value of a property and parses it.
- * Returns true and sets outValue if the key was found and its value was parsed successfully.
- * Otherwise returns false and does not modify outValue. (Also logs a warning.)
- */
- bool tryGetProperty(const String8& key, String8& outValue) const;
- bool tryGetProperty(const String8& key, bool& outValue) const;
- bool tryGetProperty(const String8& key, int32_t& outValue) const;
- bool tryGetProperty(const String8& key, float& outValue) const;
-
- /* Adds all values from the specified property map. */
- void addAll(const PropertyMap* map);
-
- /* Gets the underlying property map. */
- inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; }
-
- /* Loads a property map from a file. */
- static status_t load(const String8& filename, PropertyMap** outMap);
-
-private:
- class Parser {
- PropertyMap* mMap;
- Tokenizer* mTokenizer;
-
- public:
- Parser(PropertyMap* map, Tokenizer* tokenizer);
- ~Parser();
- status_t parse();
-
- private:
- status_t parseType();
- status_t parseKey();
- status_t parseKeyProperty();
- status_t parseModifier(const String8& token, int32_t* outMetaState);
- status_t parseCharacterLiteral(char16_t* outCharacter);
- };
-
- KeyedVector<String8, String8> mProperties;
-};
-
-} // namespace android
-
-#endif // _UTILS_PROPERTY_MAP_H
diff --git a/include/utils/SystemClock.h b/include/utils/SystemClock.h
index f816fba..892104c 100644
--- a/include/utils/SystemClock.h
+++ b/include/utils/SystemClock.h
@@ -23,6 +23,7 @@
namespace android {
int64_t uptimeMillis();
+int64_t uptimeNanos();
int64_t elapsedRealtime();
int64_t elapsedRealtimeNano();
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index 54ec474..197fc26 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -14,11 +14,7 @@
* limitations under the License.
*/
-//
-// Timer functions.
-//
-#ifndef _LIBS_UTILS_TIMERS_H
-#define _LIBS_UTILS_TIMERS_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -77,11 +73,11 @@
static CONSTEXPR inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
enum {
- SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock
- SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point
- SYSTEM_TIME_PROCESS = 2, // high-resolution per-process clock
- SYSTEM_TIME_THREAD = 3, // high-resolution per-thread clock
- SYSTEM_TIME_BOOTTIME = 4 // same as SYSTEM_TIME_MONOTONIC, but including CPU suspend time
+ SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock
+ SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point
+ SYSTEM_TIME_PROCESS = 2, // high-resolution per-process clock
+ SYSTEM_TIME_THREAD = 3, // high-resolution per-thread clock
+ SYSTEM_TIME_BOOTTIME = 4, // same as SYSTEM_TIME_MONOTONIC, but including CPU suspend time
};
// return the system-time according to the specified clock
@@ -104,5 +100,3 @@
#ifdef __cplusplus
} // extern "C"
#endif
-
-#endif // _LIBS_UTILS_TIMERS_H
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index fc6712d..0087383 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -111,24 +111,6 @@
void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len);
/**
- * Returns the length of "src" when "src" is valid UTF-8 string.
- * Returns 0 if src is NULL or 0-length string. Returns -1 when the source
- * is an invalid string.
- *
- * This function should be used to determine whether "src" is valid UTF-8
- * characters with valid unicode codepoints. "src" must be nul-terminated.
- *
- * If you are going to use other utf8_to_... functions defined in this header
- * with string which may not be valid UTF-8 with valid codepoint (form 0 to
- * 0x10FFFF), you should use this function before calling others, since the
- * other functions do not check whether the string is valid UTF-8 or not.
- *
- * If you do not care whether "src" is valid UTF-8 or not, you should use
- * strlen() as usual, which should be much faster.
- */
-ssize_t utf8_length(const char *src);
-
-/**
* Returns the UTF-16 length of UTF-8 string "src". Returns -1 in case
* it's invalid utf8. No buffer over-read occurs because of bound checks. Using overreadIsFatal you
* can ask to log a message and fail in case the invalid utf8 could have caused an override if no
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index ddf71de..be35ea2 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -23,15 +23,13 @@
#include <log/log.h>
#include <utils/TypeHelpers.h>
#include <utils/VectorImpl.h>
-
-/*
- * Used to blacklist some functions from CFI.
- *
- */
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
+/*
+ * Used to exclude some functions from CFI.
+ */
#if __has_attribute(no_sanitize)
#define UTILS_VECTOR_NO_CFI __attribute__((no_sanitize("cfi")))
#else