1 // © 2023 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3
4 // Fuzzer for ICU Calendar.
5
6 #include <cstring>
7
8 #include "fuzzer_utils.h"
9
10 #include "unicode/calendar.h"
11 #include "unicode/localebuilder.h"
12 #include "unicode/locid.h"
13
CreateRandomTimeZone(uint16_t rnd)14 icu::TimeZone* CreateRandomTimeZone(uint16_t rnd) {
15 icu::Locale und("und");
16 UErrorCode status = U_ZERO_ERROR;
17 std::unique_ptr<icu::StringEnumeration> enumeration(
18 icu::TimeZone::createEnumeration(status));
19 if (U_SUCCESS(status)) {
20 int32_t count = enumeration->count(status);
21 if (U_SUCCESS(status)) {
22 int32_t i = rnd % count;
23 const icu::UnicodeString* id = nullptr;
24 do {
25 id = enumeration->snext(status);
26 } while (U_SUCCESS(status) && --i > 0);
27 if (U_SUCCESS(status)) {
28 return icu::TimeZone::createTimeZone(*id);
29 }
30 }
31 }
32 return icu::TimeZone::getGMT()->clone();
33 }
GetRandomCalendarType(uint8_t rnd)34 const char* GetRandomCalendarType(uint8_t rnd) {
35 icu::Locale und("und");
36 UErrorCode status = U_ZERO_ERROR;
37 std::unique_ptr<icu::StringEnumeration> enumeration(
38 icu::Calendar::getKeywordValuesForLocale("calendar", und, false, status));
39 const char* type = "";
40 if (U_SUCCESS(status)) {
41 int32_t count = enumeration->count(status);
42 if (U_SUCCESS(status)) {
43 int32_t i = rnd % count;
44 do {
45 type = enumeration->next(nullptr, status);
46 } while (U_SUCCESS(status) && --i > 0);
47 }
48 }
49 type = uloc_toUnicodeLocaleType("ca", type);
50 return type;
51 }
52
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)53 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
54 uint16_t rnd;
55 if (size < 2*sizeof(rnd) + 1) return 0;
56 icu::StringPiece fuzzData(reinterpret_cast<const char *>(data), size);
57 // Byte 0 and 1 randomly select a TimeZone
58 std::memcpy(&rnd, fuzzData.data(), sizeof(rnd));
59 fuzzData.remove_prefix(sizeof(rnd));
60 std::unique_ptr<icu::TimeZone> timeZone(CreateRandomTimeZone(rnd));
61
62 // Byte 1 and 2 randomly select a Locale
63 std::memcpy(&rnd, fuzzData.data(), sizeof(rnd));
64 fuzzData.remove_prefix(sizeof(rnd));
65 icu::Locale locale = GetRandomLocale(rnd);
66
67 // Byte 4 randomly select a Calendar type
68 const char* type = GetRandomCalendarType(*fuzzData.data());
69 fuzzData.remove_prefix(1);
70
71 UErrorCode status = U_ZERO_ERROR;
72 icu::LocaleBuilder bld;
73 bld.setLocale(locale);
74 bld.setUnicodeLocaleKeyword("ca", type);
75 locale = bld.build(status);
76 if (U_FAILURE(status)) return 0;
77 std::unique_ptr<icu::Calendar> cal(
78 icu::Calendar::createInstance(*timeZone, locale, status));
79 if (U_FAILURE(status)) return 0;
80 cal->clear();
81
82 int32_t amount;
83 double time;
84 while (fuzzData.length() > 2 + static_cast<int32_t>(sizeof(time))) {
85 UCalendarDateFields field = static_cast<UCalendarDateFields>(
86 (*fuzzData.data()) % UCAL_FIELD_COUNT);
87 fuzzData.remove_prefix(1);
88
89 uint8_t command = *fuzzData.data();
90 fuzzData.remove_prefix(1);
91
92 std::memcpy(&time, fuzzData.data(), sizeof(time));
93 std::memcpy(&amount, fuzzData.data(), sizeof(amount));
94 fuzzData.remove_prefix(sizeof(time));
95
96 status = U_ZERO_ERROR;
97 switch (command % 7) {
98 case 0:
99 printf("setTime(%f)\n", time);
100 cal->setTime(time, status);
101 break;
102 case 1:
103 printf("getTime()\n");
104 cal->getTime(status);
105 break;
106 case 2:
107 printf("set(%d, %d)\n", field, amount);
108 cal->set(field, amount);
109 break;
110 case 3:
111 printf("add(%d, %d)\n", field, amount);
112 cal->add(field, amount, status);
113 break;
114 case 4:
115 printf("roll(%d, %d)\n", field, amount);
116 cal->roll(field, amount, status);
117 break;
118 case 5:
119 printf("fieldDifference(%f, %d)\n", time, field);
120 cal->fieldDifference(time, field, status);
121 break;
122 case 6:
123 printf("get(%d)\n", field);
124 cal->get(field, status);
125 break;
126 default:
127 break;
128 }
129 }
130
131 return EXIT_SUCCESS;
132 }
133