File: calendar_fuzzer.cpp

package info (click to toggle)
icu 76.1-4
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 121,296 kB
  • sloc: cpp: 522,712; ansic: 113,387; sh: 4,983; makefile: 4,709; perl: 3,198; python: 2,847; xml: 2,652; sed: 36; lisp: 12
file content (136 lines) | stat: -rw-r--r-- 4,619 bytes parent folder | download | duplicates (8)
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;
}