/src/icu/icu4c/source/test/fuzzer/calendar_fuzzer.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
14 | 4.64k | icu::TimeZone* CreateRandomTimeZone(uint16_t rnd) { |
15 | 4.64k | icu::Locale und("und"); |
16 | 4.64k | UErrorCode status = U_ZERO_ERROR; |
17 | 4.64k | std::unique_ptr<icu::StringEnumeration> enumeration( |
18 | 4.64k | icu::TimeZone::createEnumeration(status)); |
19 | 4.64k | if (U_SUCCESS(status)) { |
20 | 4.64k | int32_t count = enumeration->count(status); |
21 | 4.64k | if (U_SUCCESS(status)) { |
22 | 4.64k | int32_t i = rnd % count; |
23 | 4.64k | const icu::UnicodeString* id = nullptr; |
24 | 1.38M | do { |
25 | 1.38M | id = enumeration->snext(status); |
26 | 1.38M | } while (U_SUCCESS(status) && --i > 0); |
27 | 4.64k | if (U_SUCCESS(status)) { |
28 | 4.64k | return icu::TimeZone::createTimeZone(*id); |
29 | 4.64k | } |
30 | 4.64k | } |
31 | 4.64k | } |
32 | 0 | return icu::TimeZone::getGMT()->clone(); |
33 | 4.64k | } |
34 | 4.64k | const char* GetRandomCalendarType(uint8_t rnd) { |
35 | 4.64k | icu::Locale und("und"); |
36 | 4.64k | UErrorCode status = U_ZERO_ERROR; |
37 | 4.64k | std::unique_ptr<icu::StringEnumeration> enumeration( |
38 | 4.64k | icu::Calendar::getKeywordValuesForLocale("calendar", und, false, status)); |
39 | 4.64k | const char* type = ""; |
40 | 4.64k | if (U_SUCCESS(status)) { |
41 | 4.64k | int32_t count = enumeration->count(status); |
42 | 4.64k | if (U_SUCCESS(status)) { |
43 | 4.64k | int32_t i = rnd % count; |
44 | 36.6k | do { |
45 | 36.6k | type = enumeration->next(nullptr, status); |
46 | 36.6k | } while (U_SUCCESS(status) && --i > 0); |
47 | 4.64k | } |
48 | 4.64k | } |
49 | 4.64k | type = uloc_toUnicodeLocaleType("ca", type); |
50 | 4.64k | return type; |
51 | 4.64k | } |
52 | | |
53 | 4.65k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
54 | 4.65k | uint16_t rnd; |
55 | | // Set the limit for the test data to 100 bytes to avoid timeout for a |
56 | | // very long list of operations. |
57 | 4.65k | if (size > 100) { size = 100; } |
58 | 4.65k | if (size < 2*sizeof(rnd) + 1) return 0; |
59 | 4.64k | icu::StringPiece fuzzData(reinterpret_cast<const char *>(data), size); |
60 | | // Byte 0 and 1 randomly select a TimeZone |
61 | 4.64k | std::memcpy(&rnd, fuzzData.data(), sizeof(rnd)); |
62 | 4.64k | fuzzData.remove_prefix(sizeof(rnd)); |
63 | 4.64k | std::unique_ptr<icu::TimeZone> timeZone(CreateRandomTimeZone(rnd)); |
64 | | |
65 | | // Byte 1 and 2 randomly select a Locale |
66 | 4.64k | std::memcpy(&rnd, fuzzData.data(), sizeof(rnd)); |
67 | 4.64k | fuzzData.remove_prefix(sizeof(rnd)); |
68 | 4.64k | icu::Locale locale = GetRandomLocale(rnd); |
69 | | |
70 | | // Byte 4 randomly select a Calendar type |
71 | 4.64k | const char* type = GetRandomCalendarType(*fuzzData.data()); |
72 | 4.64k | fuzzData.remove_prefix(1); |
73 | | |
74 | 4.64k | UErrorCode status = U_ZERO_ERROR; |
75 | 4.64k | icu::LocaleBuilder bld; |
76 | 4.64k | bld.setLocale(locale); |
77 | 4.64k | bld.setUnicodeLocaleKeyword("ca", type); |
78 | 4.64k | locale = bld.build(status); |
79 | 4.64k | if (U_FAILURE(status)) return 0; |
80 | 4.64k | std::unique_ptr<icu::Calendar> cal( |
81 | 4.64k | icu::Calendar::createInstance(*timeZone, locale, status)); |
82 | 4.64k | printf("locale = %s\n", locale.getName()); |
83 | 4.64k | if (U_FAILURE(status)) return 0; |
84 | 4.64k | cal->clear(); |
85 | | |
86 | 4.64k | int32_t amount; |
87 | 4.64k | double time; |
88 | 16.5k | while (fuzzData.length() > 2 + static_cast<int32_t>(sizeof(time))) { |
89 | 11.8k | UCalendarDateFields field = static_cast<UCalendarDateFields>( |
90 | 11.8k | (*fuzzData.data()) % UCAL_FIELD_COUNT); |
91 | 11.8k | fuzzData.remove_prefix(1); |
92 | | |
93 | 11.8k | uint8_t command = *fuzzData.data(); |
94 | 11.8k | fuzzData.remove_prefix(1); |
95 | | |
96 | 11.8k | std::memcpy(&time, fuzzData.data(), sizeof(time)); |
97 | 11.8k | std::memcpy(&amount, fuzzData.data(), sizeof(amount)); |
98 | 11.8k | fuzzData.remove_prefix(sizeof(time)); |
99 | | |
100 | 11.8k | status = U_ZERO_ERROR; |
101 | 11.8k | switch (command % 7) { |
102 | 331 | case 0: |
103 | 331 | printf("setTime(%f)\n", time); |
104 | 331 | cal->setTime(time, status); |
105 | 331 | break; |
106 | 561 | case 1: |
107 | 561 | printf("getTime()\n"); |
108 | 561 | cal->getTime(status); |
109 | 561 | break; |
110 | 2.80k | case 2: |
111 | 2.80k | printf("set(%d, %d)\n", field, amount); |
112 | 2.80k | cal->set(field, amount); |
113 | 2.80k | break; |
114 | 1.81k | case 3: |
115 | 1.81k | printf("add(%d, %d)\n", field, amount); |
116 | 1.81k | cal->add(field, amount, status); |
117 | 1.81k | break; |
118 | 3.33k | case 4: |
119 | 3.33k | printf("roll(%d, %d)\n", field, amount); |
120 | 3.33k | cal->roll(field, amount, status); |
121 | 3.33k | break; |
122 | 2.66k | case 5: |
123 | 2.66k | printf("fieldDifference(%f, %d)\n", time, field); |
124 | 2.66k | cal->fieldDifference(time, field, status); |
125 | 2.66k | break; |
126 | 382 | case 6: |
127 | 382 | printf("get(%d)\n", field); |
128 | 382 | cal->get(field, status); |
129 | 382 | break; |
130 | 0 | default: |
131 | 0 | break; |
132 | 11.8k | } |
133 | 11.8k | } |
134 | | |
135 | 4.64k | return EXIT_SUCCESS; |
136 | 4.64k | } |