| // © 2023 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| |
| // Fuzzer for ICU Calendar. |
| |
| #include <cstring> |
| |
| #include "fuzzer_utils.h" |
| |
| #include "unicode/calendar.h" |
| #include "unicode/localebuilder.h" |
| #include "unicode/locid.h" |
| |
| icu::TimeZone* CreateRandomTimeZone(uint16_t rnd) { |
| icu::Locale und("und"); |
| UErrorCode status = U_ZERO_ERROR; |
| std::unique_ptr<icu::StringEnumeration> enumeration( |
| icu::TimeZone::createEnumeration(status)); |
| if (U_SUCCESS(status)) { |
| int32_t count = enumeration->count(status); |
| if (U_SUCCESS(status)) { |
| int32_t i = rnd % count; |
| const icu::UnicodeString* id = nullptr; |
| do { |
| id = enumeration->snext(status); |
| } while (U_SUCCESS(status) && --i > 0); |
| if (U_SUCCESS(status)) { |
| return icu::TimeZone::createTimeZone(*id); |
| } |
| } |
| } |
| return icu::TimeZone::getGMT()->clone(); |
| } |
| const char* GetRandomCalendarType(uint8_t rnd) { |
| icu::Locale und("und"); |
| UErrorCode status = U_ZERO_ERROR; |
| std::unique_ptr<icu::StringEnumeration> enumeration( |
| icu::Calendar::getKeywordValuesForLocale("calendar", und, false, status)); |
| const char* type = ""; |
| if (U_SUCCESS(status)) { |
| int32_t count = enumeration->count(status); |
| if (U_SUCCESS(status)) { |
| int32_t i = rnd % count; |
| do { |
| type = enumeration->next(nullptr, status); |
| } while (U_SUCCESS(status) && --i > 0); |
| } |
| } |
| type = uloc_toUnicodeLocaleType("ca", type); |
| return type; |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| uint16_t rnd; |
| if (size < 2*sizeof(rnd) + 1) return 0; |
| icu::StringPiece fuzzData(reinterpret_cast<const char *>(data), size); |
| // Byte 0 and 1 randomly select a TimeZone |
| std::memcpy(&rnd, fuzzData.data(), sizeof(rnd)); |
| fuzzData.remove_prefix(sizeof(rnd)); |
| std::unique_ptr<icu::TimeZone> timeZone(CreateRandomTimeZone(rnd)); |
| |
| // Byte 1 and 2 randomly select a Locale |
| std::memcpy(&rnd, fuzzData.data(), sizeof(rnd)); |
| fuzzData.remove_prefix(sizeof(rnd)); |
| icu::Locale locale = GetRandomLocale(rnd); |
| |
| // Byte 4 randomly select a Calendar type |
| const char* type = GetRandomCalendarType(*fuzzData.data()); |
| fuzzData.remove_prefix(1); |
| |
| UErrorCode status = U_ZERO_ERROR; |
| icu::LocaleBuilder bld; |
| bld.setLocale(locale); |
| bld.setUnicodeLocaleKeyword("ca", type); |
| locale = bld.build(status); |
| if (U_FAILURE(status)) return 0; |
| std::unique_ptr<icu::Calendar> cal( |
| icu::Calendar::createInstance(*timeZone, locale, status)); |
| if (U_FAILURE(status)) return 0; |
| cal->clear(); |
| |
| int32_t amount; |
| double time; |
| while (fuzzData.length() > 2 + static_cast<int32_t>(sizeof(time))) { |
| UCalendarDateFields field = static_cast<UCalendarDateFields>( |
| (*fuzzData.data()) % UCAL_FIELD_COUNT); |
| fuzzData.remove_prefix(1); |
| |
| uint8_t command = *fuzzData.data(); |
| fuzzData.remove_prefix(1); |
| |
| std::memcpy(&time, fuzzData.data(), sizeof(time)); |
| std::memcpy(&amount, fuzzData.data(), sizeof(amount)); |
| fuzzData.remove_prefix(sizeof(time)); |
| |
| status = U_ZERO_ERROR; |
| switch (command % 7) { |
| case 0: |
| printf("setTime(%f)\n", time); |
| cal->setTime(time, status); |
| break; |
| case 1: |
| printf("getTime()\n"); |
| cal->getTime(status); |
| break; |
| case 2: |
| printf("set(%d, %d)\n", field, amount); |
| cal->set(field, amount); |
| break; |
| case 3: |
| printf("add(%d, %d)\n", field, amount); |
| cal->add(field, amount, status); |
| break; |
| case 4: |
| printf("roll(%d, %d)\n", field, amount); |
| cal->roll(field, amount, status); |
| break; |
| case 5: |
| printf("fieldDifference(%f, %d)\n", time, field); |
| cal->fieldDifference(time, field, status); |
| break; |
| case 6: |
| printf("get(%d)\n", field); |
| cal->get(field, status); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| return EXIT_SUCCESS; |
| } |