From 5cf5ec1adbd2332b3cc289b5b1f5ca8324275fc3 Mon Sep 17 00:00:00 2001 From: Frank Tang Date: Wed, 13 Dec 2023 17:23:11 -0800 Subject: [PATCH] ICU-22549 Add TimeZoneNames fuzzer --- icu4c/source/i18n/tznames_impl.cpp | 18 ++++-- icu4c/source/test/fuzzer/Makefile.in | 1 + .../test/fuzzer/time_zone_names_fuzzer.cpp | 63 +++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 icu4c/source/test/fuzzer/time_zone_names_fuzzer.cpp diff --git a/icu4c/source/i18n/tznames_impl.cpp b/icu4c/source/i18n/tznames_impl.cpp index 8e52fd90a682..536e90117cef 100644 --- a/icu4c/source/i18n/tznames_impl.cpp +++ b/icu4c/source/i18n/tznames_impl.cpp @@ -1303,11 +1303,16 @@ static void mergeTimeZoneKey(const UnicodeString& mzID, char* result) { ZNames* TimeZoneNamesImpl::loadMetaZoneNames(const UnicodeString& mzID, UErrorCode& status) { if (U_FAILURE(status)) { return nullptr; } - U_ASSERT(mzID.length() <= ZID_KEY_MAX - MZ_PREFIX_LEN); + if (mzID.length() > ZID_KEY_MAX - MZ_PREFIX_LEN) { + status = U_INTERNAL_PROGRAM_ERROR; + return nullptr; + } char16_t mzIDKey[ZID_KEY_MAX + 1]; mzID.extract(mzIDKey, ZID_KEY_MAX + 1, status); - U_ASSERT(U_SUCCESS(status)); // already checked length above + if (U_FAILURE(status)) { + return nullptr; + } mzIDKey[mzID.length()] = 0; void* mznames = uhash_get(fMZNamesMap, mzIDKey); @@ -1331,7 +1336,10 @@ TimeZoneNamesImpl::loadMetaZoneNames(const UnicodeString& mzID, UErrorCode& stat ZNames* TimeZoneNamesImpl::loadTimeZoneNames(const UnicodeString& tzID, UErrorCode& status) { if (U_FAILURE(status)) { return nullptr; } - U_ASSERT(tzID.length() <= ZID_KEY_MAX); + if (tzID.length() > ZID_KEY_MAX) { + status = U_INTERNAL_PROGRAM_ERROR; + return nullptr; + } char16_t tzIDKey[ZID_KEY_MAX + 1]; int32_t tzIDKeyLen = tzID.extract(tzIDKey, ZID_KEY_MAX + 1, status); @@ -2248,7 +2256,9 @@ TZDBTimeZoneNames::getMetaZoneNames(const UnicodeString& mzID, UErrorCode& statu char16_t mzIDKey[ZID_KEY_MAX + 1]; mzID.extract(mzIDKey, ZID_KEY_MAX + 1, status); - U_ASSERT(status == U_ZERO_ERROR); // already checked length above + if (U_FAILURE(status)) { + return nullptr; + } mzIDKey[mzID.length()] = 0; static UMutex gTZDBNamesMapLock; diff --git a/icu4c/source/test/fuzzer/Makefile.in b/icu4c/source/test/fuzzer/Makefile.in index a8b28540e325..0fd18ef0b7a2 100644 --- a/icu4c/source/test/fuzzer/Makefile.in +++ b/icu4c/source/test/fuzzer/Makefile.in @@ -47,6 +47,7 @@ FUZZER_TARGETS = \ relative_date_time_formatter_fuzzer \ rule_based_break_iterator_fuzzer \ timezone_create_fuzzer \ + time_zone_names_fuzzer \ ucasemap_fuzzer \ uloc_canonicalize_fuzzer \ uloc_for_language_tag_fuzzer \ diff --git a/icu4c/source/test/fuzzer/time_zone_names_fuzzer.cpp b/icu4c/source/test/fuzzer/time_zone_names_fuzzer.cpp new file mode 100644 index 000000000000..d10481f1de6d --- /dev/null +++ b/icu4c/source/test/fuzzer/time_zone_names_fuzzer.cpp @@ -0,0 +1,63 @@ +// © 2023 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +// Fuzzer for TimeZoneNames. + +#include + +#include "fuzzer_utils.h" + +#include "unicode/tznames.h" +#include "unicode/locid.h" + +void TestNames(icu::TimeZoneNames* names, const icu::UnicodeString& text, UDate date, UTimeZoneNameType type) { + UErrorCode status = U_ZERO_ERROR; + std::unique_ptr enumeration( + names->getAvailableMetaZoneIDs(status)); + status = U_ZERO_ERROR; + enumeration.reset( + names->getAvailableMetaZoneIDs(text, status)); + icu::UnicodeString output; + names->getMetaZoneID(text, date, output); + names->getMetaZoneDisplayName(text, type, output); + names->getTimeZoneDisplayName(text, type, output); + names->getExemplarLocationName(text, output); + names->getDisplayName(text, type, date, output); +} +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + uint16_t rnd; + UDate date; + + UTimeZoneNameType type; + if (size < sizeof(rnd) + sizeof(date) + sizeof(type)) return 0; + icu::StringPiece fuzzData(reinterpret_cast(data), size); + + std::memcpy(&rnd, fuzzData.data(), sizeof(rnd)); + icu::Locale locale = GetRandomLocale(rnd); + fuzzData.remove_prefix(sizeof(rnd)); + + std::memcpy(&date, fuzzData.data(), sizeof(date)); + fuzzData.remove_prefix(sizeof(date)); + + std::memcpy(&type, fuzzData.data(), sizeof(type)); + fuzzData.remove_prefix(sizeof(type)); + + size_t len = fuzzData.size() / sizeof(char16_t); + icu::UnicodeString text(false, reinterpret_cast(fuzzData.data()), len); + + UErrorCode status = U_ZERO_ERROR; + std::unique_ptr names( + icu::TimeZoneNames::createInstance(locale, status)); + if (U_SUCCESS(status)) { + TestNames(names.get(), text, date, type); + } + + status = U_ZERO_ERROR; + names.reset( + icu::TimeZoneNames::createTZDBInstance(locale, status)); + if (U_SUCCESS(status)) { + TestNames(names.get(), text, date, type); + } + + return EXIT_SUCCESS; +}