xref: /aosp_15_r20/external/icu/icu4c/source/test/fuzzer/calendar_fuzzer.cpp (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
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     // Set the limit for the test data to 1000 bytes to avoid timeout for a
56     // very long list of operations.
57     if (size > 1000) { size = 1000; }
58     if (size < 2*sizeof(rnd) + 1) return 0;
59     icu::StringPiece fuzzData(reinterpret_cast<const char *>(data), size);
60     // Byte 0 and 1 randomly select a TimeZone
61     std::memcpy(&rnd, fuzzData.data(), sizeof(rnd));
62     fuzzData.remove_prefix(sizeof(rnd));
63     std::unique_ptr<icu::TimeZone> timeZone(CreateRandomTimeZone(rnd));
64 
65     // Byte 1 and 2 randomly select a Locale
66     std::memcpy(&rnd, fuzzData.data(), sizeof(rnd));
67     fuzzData.remove_prefix(sizeof(rnd));
68     icu::Locale locale = GetRandomLocale(rnd);
69 
70     // Byte 4 randomly select a Calendar type
71     const char* type = GetRandomCalendarType(*fuzzData.data());
72     fuzzData.remove_prefix(1);
73 
74     UErrorCode status = U_ZERO_ERROR;
75     icu::LocaleBuilder bld;
76     bld.setLocale(locale);
77     bld.setUnicodeLocaleKeyword("ca", type);
78     locale = bld.build(status);
79     if (U_FAILURE(status)) return 0;
80     std::unique_ptr<icu::Calendar> cal(
81         icu::Calendar::createInstance(*timeZone, locale, status));
82     printf("locale = %s\n", locale.getName());
83     if (U_FAILURE(status)) return 0;
84     cal->clear();
85 
86     int32_t amount;
87     double time;
88     while (fuzzData.length() > 2 + static_cast<int32_t>(sizeof(time))) {
89         UCalendarDateFields field = static_cast<UCalendarDateFields>(
90             (*fuzzData.data()) % UCAL_FIELD_COUNT);
91         fuzzData.remove_prefix(1);
92 
93         uint8_t command = *fuzzData.data();
94         fuzzData.remove_prefix(1);
95 
96         std::memcpy(&time, fuzzData.data(), sizeof(time));
97         std::memcpy(&amount, fuzzData.data(), sizeof(amount));
98         fuzzData.remove_prefix(sizeof(time));
99 
100         status = U_ZERO_ERROR;
101         switch (command % 7) {
102             case 0:
103                 printf("setTime(%f)\n", time);
104                 cal->setTime(time, status);
105                 break;
106             case 1:
107                 printf("getTime()\n");
108                 cal->getTime(status);
109                 break;
110             case 2:
111                 printf("set(%d, %d)\n", field, amount);
112                 cal->set(field, amount);
113                 break;
114             case 3:
115                 printf("add(%d, %d)\n", field, amount);
116                 cal->add(field, amount, status);
117                 break;
118             case 4:
119                 printf("roll(%d, %d)\n", field, amount);
120                 cal->roll(field, amount, status);
121                 break;
122             case 5:
123                 printf("fieldDifference(%f, %d)\n", time, field);
124                 cal->fieldDifference(time, field, status);
125                 break;
126             case 6:
127                 printf("get(%d)\n", field);
128                 cal->get(field, status);
129                 break;
130             default:
131                 break;
132         }
133     }
134 
135     return EXIT_SUCCESS;
136 }
137