Coverage Report

Created: 2025-12-28 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jansson/test/ossfuzz/json_load_dump_fuzzer.cc
Line
Count
Source
1
#include <stdint.h>
2
#include <stdlib.h>
3
#include <sys/types.h>
4
#include <inttypes.h>
5
6
#include "jansson.h"
7
8
static int enable_diags;
9
10
#define FUZZ_DEBUG(FMT, ...)                                                  \
11
32.0k
        if (enable_diags)                                                     \
12
32.0k
        {                                                                     \
13
0
          fprintf(stderr, FMT, ##__VA_ARGS__);                                \
14
0
          fprintf(stderr, "\n");                                              \
15
0
        }
16
17
18
static int json_dump_counter(const char *buffer, size_t size, void *data)
19
7.96M
{
20
7.96M
  uint64_t *counter = reinterpret_cast<uint64_t *>(data);
21
7.96M
  *counter += size;
22
7.96M
  return 0;
23
7.96M
}
24
25
26
14.6k
#define NUM_COMMAND_BYTES  (sizeof(size_t) + sizeof(size_t) + 1)
27
28
#define FUZZ_DUMP_CALLBACK 0x00
29
5.78k
#define FUZZ_DUMP_STRING   0x01
30
31
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
32
7.31k
{
33
7.31k
  json_error_t error;
34
7.31k
  unsigned char dump_mode;
35
36
  // Enable or disable diagnostics based on the FUZZ_VERBOSE environment flag.
37
7.31k
  enable_diags = (getenv("FUZZ_VERBOSE") != NULL);
38
39
7.31k
  FUZZ_DEBUG("Input data length: %zd", size);
40
41
7.31k
  if (size < NUM_COMMAND_BYTES)
42
7
  {
43
7
    return 0;
44
7
  }
45
46
  // Use the first sizeof(size_t) bytes as load flags.
47
7.30k
  size_t load_flags = *(const size_t*)data;
48
7.30k
  data += sizeof(size_t);
49
50
7.30k
  FUZZ_DEBUG("load_flags: 0x%zx\n"
51
7.30k
             "& JSON_REJECT_DUPLICATES =  0x%zx\n"
52
7.30k
             "& JSON_DECODE_ANY =         0x%zx\n"
53
7.30k
             "& JSON_DISABLE_EOF_CHECK =  0x%zx\n"
54
7.30k
             "& JSON_DECODE_INT_AS_REAL = 0x%zx\n"
55
7.30k
             "& JSON_ALLOW_NUL =          0x%zx\n",
56
7.30k
             load_flags,
57
0
             load_flags & JSON_REJECT_DUPLICATES,
58
0
             load_flags & JSON_DECODE_ANY,
59
0
             load_flags & JSON_DISABLE_EOF_CHECK,
60
0
             load_flags & JSON_DECODE_INT_AS_REAL,
61
0
             load_flags & JSON_ALLOW_NUL);
62
63
  // Use the next sizeof(size_t) bytes as dump flags.
64
7.30k
  size_t dump_flags = *(const size_t*)data;
65
7.30k
  data += sizeof(size_t);
66
67
7.30k
  FUZZ_DEBUG("dump_flags: 0x%zx\n"
68
7.30k
             "& JSON_MAX_INDENT =     0x%zx\n"
69
7.30k
             "& JSON_COMPACT =        0x%zx\n"
70
7.30k
             "& JSON_ENSURE_ASCII =   0x%zx\n"
71
7.30k
             "& JSON_SORT_KEYS =      0x%zx\n"
72
7.30k
             "& JSON_PRESERVE_ORDER = 0x%zx\n"
73
7.30k
             "& JSON_ENCODE_ANY =     0x%zx\n"
74
7.30k
             "& JSON_ESCAPE_SLASH =   0x%zx\n"
75
7.30k
             "& JSON_REAL_PRECISION = 0x%zx\n"
76
7.30k
             "& JSON_EMBED =          0x%zx\n",
77
7.30k
             dump_flags,
78
0
             dump_flags & JSON_MAX_INDENT,
79
0
             dump_flags & JSON_COMPACT,
80
0
             dump_flags & JSON_ENSURE_ASCII,
81
0
             dump_flags & JSON_SORT_KEYS,
82
0
             dump_flags & JSON_PRESERVE_ORDER,
83
0
             dump_flags & JSON_ENCODE_ANY,
84
0
             dump_flags & JSON_ESCAPE_SLASH,
85
0
             ((dump_flags >> 11) & 0x1F) << 11,
86
0
             dump_flags & JSON_EMBED);
87
88
  // Use the next byte as the dump mode.
89
7.30k
  dump_mode = data[0];
90
7.30k
  data++;
91
92
7.30k
  FUZZ_DEBUG("dump_mode: 0x%x", (unsigned int)dump_mode);
93
94
  // Remove the command bytes from the size total.
95
7.30k
  size -= NUM_COMMAND_BYTES;
96
97
  // Attempt to load the remainder of the data with the given load flags.
98
7.30k
  const char* text = reinterpret_cast<const char *>(data);
99
7.30k
  json_t* jobj = json_loadb(text, size, load_flags, &error);
100
101
7.30k
  if (jobj == NULL)
102
1.52k
  {
103
1.52k
    return 0;
104
1.52k
  }
105
106
5.78k
  if (dump_mode & FUZZ_DUMP_STRING)
107
2.99k
  {
108
    // Dump as a string. Remove indents so that we don't run out of memory.
109
2.99k
    char *out = json_dumps(jobj, dump_flags & ~JSON_MAX_INDENT);
110
2.99k
    if (out != NULL)
111
2.62k
    {
112
2.62k
      free(out);
113
2.62k
    }
114
2.99k
  }
115
2.79k
  else
116
2.79k
  {
117
    // Default is callback mode.
118
    //
119
    // Attempt to dump the loaded json object with the given dump flags.
120
2.79k
    uint64_t counter = 0;
121
122
2.79k
    json_dump_callback(jobj, json_dump_counter, &counter, dump_flags);
123
2.79k
    FUZZ_DEBUG("Counter function counted %" PRIu64 " bytes.", counter);
124
2.79k
  }
125
126
5.78k
  if (jobj)
127
5.78k
  {
128
5.78k
    json_decref(jobj);
129
5.78k
  }
130
131
5.78k
  return 0;
132
7.30k
}