• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2023 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 // Fuzzer for ICU PluralRules.
5 
6 #include <cstring>
7 
8 #include "fuzzer_utils.h"
9 
10 #include "unicode/plurrule.h"
11 #include "unicode/locid.h"
12 
13 
TestPluralRules(icu::PluralRules * pp,int32_t number,double dbl,UErrorCode & status)14 void TestPluralRules(icu::PluralRules* pp, int32_t number, double dbl,  UErrorCode& status) {
15     if (U_FAILURE(status)) {
16         return;
17     }
18     pp->select(number);
19     pp->select(dbl);
20 }
21 
TestPluralRulesWithLocale(const icu::Locale & locale,int32_t number,double dbl,UPluralType type,UErrorCode & status)22 void TestPluralRulesWithLocale(
23     const icu::Locale& locale, int32_t number, double dbl,  UPluralType type, UErrorCode& status) {
24     if (U_FAILURE(status)) {
25         return;
26     }
27     std::unique_ptr<icu::PluralRules> pp(icu::PluralRules::forLocale(locale, status));
28     TestPluralRules(pp.get(), number, dbl, status);
29 
30     status = U_ZERO_ERROR;
31     pp.reset(icu::PluralRules::forLocale(locale, type, status));
32     TestPluralRules(pp.get(), number, dbl, status);
33 
34     type = static_cast<UPluralType>(
35         static_cast<int>(type) % (static_cast<int>(UPLURAL_TYPE_COUNT)));
36 
37     status = U_ZERO_ERROR;
38     pp.reset(icu::PluralRules::forLocale(locale, type, status));
39     TestPluralRules(pp.get(), number, dbl, status);
40 }
41 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)42 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
43     uint16_t rnd;
44     int32_t number;
45     double dbl;
46     UPluralType  type;
47     if (size > 5000) {
48         size = 5000;
49     }
50     if (size < sizeof(rnd) + sizeof(number) + sizeof(dbl) + sizeof(type)) return 0;
51     icu::StringPiece fuzzData(reinterpret_cast<const char *>(data), size);
52 
53     std::memcpy(&rnd, fuzzData.data(), sizeof(rnd));
54     icu::Locale locale = GetRandomLocale(rnd);
55     fuzzData.remove_prefix(sizeof(rnd));
56 
57     std::memcpy(&number, fuzzData.data(), sizeof(number));
58     fuzzData.remove_prefix(sizeof(number));
59 
60     std::memcpy(&dbl, fuzzData.data(), sizeof(dbl));
61     fuzzData.remove_prefix(sizeof(dbl));
62 
63     std::memcpy(&type, fuzzData.data(), sizeof(type));
64     fuzzData.remove_prefix(sizeof(type));
65 
66     size_t len = fuzzData.size() / sizeof(char16_t);
67     icu::UnicodeString text(false, reinterpret_cast<const char16_t*>(fuzzData.data()), len);
68 
69     UErrorCode status = U_ZERO_ERROR;
70     std::unique_ptr<icu::PluralRules> pp(
71         icu::PluralRules::createRules(text, status));
72     TestPluralRules(pp.get(), number, dbl, status);
73 
74     status = U_ZERO_ERROR;
75     TestPluralRulesWithLocale(locale, number, dbl, type, status);
76 
77     std::string str(fuzzData.data(), fuzzData.size()); // ensure null-terminate
78                                                        // by std::string c_str
79     icu::Locale locale2(str.c_str());
80 
81     status = U_ZERO_ERROR;
82     TestPluralRulesWithLocale(locale2, number, dbl, type, status);
83     return EXIT_SUCCESS;
84 }
85