Coverage Report

Created: 2025-06-24 06:54

/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
}