| // Copyright (c) 2019, Paul Dreik |
| // License: see LICENSE.rst in the fmt root directory |
| |
| #include <fmt/core.h> |
| #include <cstdint> |
| #include <stdexcept> |
| #include <type_traits> |
| #include <vector> |
| |
| #include <fmt/chrono.h> |
| #include "fuzzer_common.h" |
| |
| using fmt_fuzzer::Nfixed; |
| |
| template <typename Item> |
| void invoke_fmt(const uint8_t* Data, std::size_t Size) { |
| constexpr auto N = sizeof(Item); |
| static_assert(N <= Nfixed, "Nfixed is too small"); |
| if (Size <= Nfixed) { |
| return; |
| } |
| const Item item = fmt_fuzzer::assignFromBuf<Item>(Data); |
| Data += Nfixed; |
| Size -= Nfixed; |
| |
| #if FMT_FUZZ_SEPARATE_ALLOCATION |
| // allocates as tight as possible, making it easier to catch buffer overruns. |
| std::vector<char> fmtstringbuffer(Size); |
| std::memcpy(fmtstringbuffer.data(), Data, Size); |
| auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size); |
| #else |
| auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size); |
| #endif |
| |
| #if FMT_FUZZ_FORMAT_TO_STRING |
| std::string message = fmt::format(fmtstring, item); |
| #else |
| fmt::memory_buffer message; |
| fmt::format_to(message, fmtstring, item); |
| #endif |
| } |
| |
| void invoke_fmt_time(const uint8_t* Data, std::size_t Size) { |
| using Item = std::time_t; |
| constexpr auto N = sizeof(Item); |
| static_assert(N <= Nfixed, "Nfixed too small"); |
| if (Size <= Nfixed) { |
| return; |
| } |
| const Item item = fmt_fuzzer::assignFromBuf<Item>(Data); |
| Data += Nfixed; |
| Size -= Nfixed; |
| #if FMT_FUZZ_SEPARATE_ALLOCATION |
| // allocates as tight as possible, making it easier to catch buffer overruns. |
| std::vector<char> fmtstringbuffer(Size); |
| std::memcpy(fmtstringbuffer.data(), Data, Size); |
| auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size); |
| #else |
| auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size); |
| #endif |
| auto* b = std::localtime(&item); |
| if (b) { |
| #if FMT_FUZZ_FORMAT_TO_STRING |
| std::string message = fmt::format(fmtstring, *b); |
| #else |
| fmt::memory_buffer message; |
| fmt::format_to(message, fmtstring, *b); |
| #endif |
| } |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) { |
| if (Size <= 3) { |
| return 0; |
| } |
| |
| const auto first = Data[0]; |
| Data++; |
| Size--; |
| |
| try { |
| switch (first) { |
| case 0: |
| invoke_fmt<bool>(Data, Size); |
| break; |
| case 1: |
| invoke_fmt<char>(Data, Size); |
| break; |
| case 2: |
| invoke_fmt<unsigned char>(Data, Size); |
| break; |
| case 3: |
| invoke_fmt<signed char>(Data, Size); |
| break; |
| case 4: |
| invoke_fmt<short>(Data, Size); |
| break; |
| case 5: |
| invoke_fmt<unsigned short>(Data, Size); |
| break; |
| case 6: |
| invoke_fmt<int>(Data, Size); |
| break; |
| case 7: |
| invoke_fmt<unsigned int>(Data, Size); |
| break; |
| case 8: |
| invoke_fmt<long>(Data, Size); |
| break; |
| case 9: |
| invoke_fmt<unsigned long>(Data, Size); |
| break; |
| case 10: |
| invoke_fmt<float>(Data, Size); |
| break; |
| case 11: |
| invoke_fmt<double>(Data, Size); |
| break; |
| case 12: |
| invoke_fmt<long double>(Data, Size); |
| break; |
| case 13: |
| invoke_fmt_time(Data, Size); |
| break; |
| default: |
| break; |
| } |
| } catch (std::exception& /*e*/) { |
| } |
| return 0; |
| } |