1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
// © 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;
// Set the limit for the test data to 100 bytes to avoid timeout for a
// very long list of operations.
if (size > 100) { size = 100; }
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));
printf("locale = %s\n", locale.getName());
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;
}
|