diff --git a/icu4c/source/test/fuzzer/Makefile.in b/icu4c/source/test/fuzzer/Makefile.in index 372db3ba7ba..8cd23cdf6d6 100644 --- a/icu4c/source/test/fuzzer/Makefile.in +++ b/icu4c/source/test/fuzzer/Makefile.in @@ -40,6 +40,7 @@ FUZZER_TARGETS = \ collator_rulebased_fuzzer \ converter_fuzzer date_format_fuzzer \ date_time_pattern_generator_fuzzer \ + decimal_format_symbols_fuzzer \ dtfmtsym_fuzzer \ list_format_fuzzer locale_fuzzer \ locale_morph_fuzzer \ diff --git a/icu4c/source/test/fuzzer/decimal_format_symbols_fuzzer.cpp b/icu4c/source/test/fuzzer/decimal_format_symbols_fuzzer.cpp new file mode 100644 index 00000000000..9b1f1aa1373 --- /dev/null +++ b/icu4c/source/test/fuzzer/decimal_format_symbols_fuzzer.cpp @@ -0,0 +1,95 @@ +// © 2025 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +// Fuzzer for DecimalFormatSymbols::DecimalFormatSymbols. + +#include +#include +#include +#include +#include +#include "fuzzer_utils.h" +#include "unicode/dcfmtsym.h" +#include "unicode/unum.h" +#include "uassert.h" + +IcuEnvironment* env = new IcuEnvironment(); + +void testMethods( + const icu::DecimalFormatSymbols& dfs, + icu::DecimalFormatSymbols::ENumberFormatSymbol symbol, + UCurrencySpacing spacing, + int32_t digit) { + dfs.getLocale(); + dfs.getSymbol(symbol); + dfs.getConstSymbol(symbol); + dfs.getCurrencyPattern(); + dfs.getNumberingSystemName(); + dfs.isCustomCurrencySymbol(); + dfs.isCustomIntlCurrencySymbol(); + dfs.getCodePointZero(); + dfs.getConstDigitSymbol(digit); + UErrorCode status = U_ZERO_ERROR; + dfs.getPatternForCurrencySpacing(spacing, true, status); + dfs.getPatternForCurrencySpacing(spacing, false, status); + +} +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + UErrorCode status = U_ZERO_ERROR; + if (size < sizeof(uint16_t)) { + return 0; + } + uint16_t rnd = *(reinterpret_cast(data)); + const icu::Locale& locale = GetRandomLocale(rnd); + data = data + sizeof(uint16_t); + size = size - sizeof(uint16_t); + + if (size < sizeof(uint16_t)) { + return 0; + } + uint16_t rnd2 = *(reinterpret_cast(data)); + std::unique_ptr ns(CreateRandomNumberingSystem(rnd2, status)); + U_ASSERT(U_SUCCESS(status)); + data = data + sizeof(uint16_t); + size = size - sizeof(uint16_t); + + if (size < sizeof(int32_t)) { + return 0; + } + int32_t digit = *(reinterpret_cast(data)); + data = data + sizeof(int32_t); + size = size - sizeof(int32_t); + + if (size < sizeof(uint8_t)) { + return 0; + } + icu::DecimalFormatSymbols::ENumberFormatSymbol symbol = + static_cast( + *data % icu::DecimalFormatSymbols::ENumberFormatSymbol::kFormatSymbolCount); + data = data + sizeof(uint8_t); + size = size - sizeof(uint8_t); + + if (size < sizeof(uint8_t)) { + return 0; + } + UCurrencySpacing spacing = + static_cast( + *data % UCurrencySpacing::UNUM_CURRENCY_SPACING_COUNT); + data = data + sizeof(uint8_t); + size = size - sizeof(uint8_t); + + size_t unistr_size = size/2; + std::unique_ptr fuzzbuff(new char16_t[unistr_size]); + std::memcpy(fuzzbuff.get(), data, unistr_size * 2); + + icu::UnicodeString fuzzstr(false, fuzzbuff.get(), unistr_size); + icu::DecimalFormatSymbols dfs1(locale, status); + U_ASSERT(U_SUCCESS(status)); + testMethods(dfs1, symbol, spacing, digit); + + icu::DecimalFormatSymbols dfs2(locale, *ns, status); + U_ASSERT(U_SUCCESS(status)); + testMethods(dfs2, symbol, spacing, digit); + + return 0; +} diff --git a/icu4c/source/test/fuzzer/fuzzer_utils.h b/icu4c/source/test/fuzzer/fuzzer_utils.h index 8a4ed4714b4..0a16f0e4054 100644 --- a/icu4c/source/test/fuzzer/fuzzer_utils.h +++ b/icu4c/source/test/fuzzer/fuzzer_utils.h @@ -7,6 +7,8 @@ #include #include "unicode/locid.h" +#include "unicode/numsys.h" +#include "unicode/strenum.h" struct IcuEnvironment { IcuEnvironment() { @@ -21,4 +23,20 @@ const icu::Locale& GetRandomLocale(uint16_t rnd) { return locales[rnd % num_locales]; } +const icu::NumberingSystem* CreateRandomNumberingSystem(uint16_t rnd, UErrorCode &status) { + std::unique_ptr se(icu::NumberingSystem::getAvailableNames(status)); + if (U_FAILURE(status)) return nullptr; + int32_t count = se->count(status); + if (U_FAILURE(status)) return nullptr; + int32_t index = rnd % count; + se->reset(status); + for (int32_t i = 0; i < index - 1; i++, se->next(nullptr, status)) { + // empty + } + const char* name = se->next(nullptr, status); + if (U_FAILURE(status)) return nullptr; + return icu::NumberingSystem::createInstanceByName(name, status); +} + + #endif // FUZZER_UTILS_H_