Add a fuzzer for UnicodeStringAppendable.
Bug:1009107
Change-Id: I02f55ede8e1afc713141ab95046ebb7a732f12a8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/deps/icu/+/1853110
Reviewed-by: Max Moroz <mmoroz@chromium.org>
diff --git a/fuzzers/BUILD.gn b/fuzzers/BUILD.gn
index 3053d79..07a40c0 100644
--- a/fuzzers/BUILD.gn
+++ b/fuzzers/BUILD.gn
@@ -4,8 +4,8 @@
# ICU fuzzers.
-import("//third_party/icu/config.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
+import("//third_party/icu/config.gni")
# root BUILD depenends on this target. Needed for package discovery
group("fuzzers") {
@@ -93,3 +93,12 @@
]
libfuzzer_options = [ "max_len=10240" ]
}
+
+fuzzer_test("icu_appendable_fuzzer") {
+ sources = [
+ "icu_appendable_fuzzer.cc",
+ ]
+ deps = [
+ ":fuzzer_support",
+ ]
+}
diff --git a/fuzzers/fuzzer_utils.h b/fuzzers/fuzzer_utils.h
index df69966..3572156 100644
--- a/fuzzers/fuzzer_utils.h
+++ b/fuzzers/fuzzer_utils.h
@@ -51,4 +51,13 @@
return icu::UnicodeString::fromUTF32(uchars.data(), uchars.size());
}
+std::vector<char16_t> RandomChar16Array(size_t random_value,
+ const uint8_t* data,
+ size_t size) {
+ std::vector<char16_t> arr;
+ arr.resize(random_value % size * sizeof(uint8_t) / sizeof(char16_t));
+ memcpy(arr.data(), data, arr.size() * sizeof(char16_t) / sizeof(uint8_t));
+ return arr;
+}
+
#endif // THIRD_PARTY_ICU_FUZZERS_FUZZER_UTILS_H_
diff --git a/fuzzers/icu_appendable_fuzzer.cc b/fuzzers/icu_appendable_fuzzer.cc
new file mode 100644
index 0000000..6274242
--- /dev/null
+++ b/fuzzers/icu_appendable_fuzzer.cc
@@ -0,0 +1,77 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <vector>
+#include "third_party/icu/fuzzers/fuzzer_utils.h"
+#include "third_party/icu/source/common/unicode/appendable.h"
+#include "third_party/libFuzzer/src/utils/FuzzedDataProvider.h"
+
+static IcuEnvironment* env = new IcuEnvironment;
+
+constexpr size_t kMaxInitialSize = 64;
+constexpr size_t kMaxReserveSize = 4096;
+constexpr size_t kMaxAppendLength = 64;
+constexpr size_t kMaxAdditionalDesiredSize = 4096;
+
+constexpr size_t kScratchBufSize = 4096;
+char16_t scratch_buf[kScratchBufSize];
+
+enum class AppendableApi {
+ AppendCodeUnit,
+ AppendCodePoint,
+ AppendString,
+ ReserveAppendCapacity,
+ GetAppendBuffer,
+ kMaxValue = GetAppendBuffer
+};
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider provider(data, size);
+ auto str(icu::UnicodeString::fromUTF8(
+ provider.ConsumeRandomLengthString(kMaxInitialSize)));
+ icu::UnicodeStringAppendable strAppendable(str);
+
+ while (provider.remaining_bytes() > 0) {
+ switch (provider.ConsumeEnum<AppendableApi>()) {
+ case AppendableApi::AppendCodeUnit:
+ strAppendable.appendCodeUnit(provider.ConsumeIntegral<char16_t>());
+ break;
+ case AppendableApi::AppendCodePoint:
+ strAppendable.appendCodePoint(provider.ConsumeIntegral<UChar32>());
+ break;
+ case AppendableApi::AppendString: {
+ std::string appendChrs8(
+ provider.ConsumeRandomLengthString(kMaxAppendLength));
+ if (appendChrs8.size() == 0)
+ break;
+ std::vector<char16_t> appendChrs(RandomChar16Array(
+ 2, reinterpret_cast<const uint8_t*>(appendChrs8.data()),
+ appendChrs8.size()));
+ strAppendable.appendString(appendChrs.data(), appendChrs.size());
+ break;
+ }
+ case AppendableApi::ReserveAppendCapacity:
+ strAppendable.reserveAppendCapacity(
+ provider.ConsumeIntegralInRange<int32_t>(0, kMaxReserveSize));
+ break;
+ case AppendableApi::GetAppendBuffer: {
+ int32_t out_capacity;
+ const auto min_capacity =
+ provider.ConsumeIntegralInRange<int32_t>(1, kScratchBufSize);
+ char16_t* out_buffer = strAppendable.getAppendBuffer(
+ min_capacity,
+ min_capacity + provider.ConsumeIntegralInRange<int32_t>(
+ 0, kMaxAdditionalDesiredSize),
+ scratch_buf, kScratchBufSize, &out_capacity);
+ // Write arbitrary value at the end of the buffer.
+ if (out_buffer)
+ out_buffer[out_capacity - 1] = 1;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}