summaryrefslogtreecommitdiffstats
path: root/src/fmt/test/fuzzing/one_arg.cpp
blob: 3a1bf5ccb0bc29c2efed3b227177c6a72473600a (plain)
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
// 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, 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, 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, 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;
}