File: cmJSONParserFuzzer.cxx

package info (click to toggle)
cmake 4.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 158,704 kB
  • sloc: ansic: 406,077; cpp: 309,512; sh: 4,233; python: 3,696; yacc: 3,109; lex: 1,279; f90: 538; asm: 471; lisp: 375; java: 310; cs: 270; fortran: 239; objc: 215; perl: 213; xml: 198; makefile: 110; javascript: 83; pascal: 63; tcl: 55; php: 25; ruby: 22; sed: 2
file content (107 lines) | stat: -rw-r--r-- 2,627 bytes parent folder | download | duplicates (2)
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
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file LICENSE.rst or https://cmake.org/licensing for details.  */

/*
 * Fuzzer for CMake's JSON parsing (via jsoncpp)
 *
 * CMake parses JSON files for CMakePresets.json, compile_commands.json,
 * and various other configuration files. This fuzzer tests the JSON
 * parser for crashes and undefined behavior.
 *
 * Coverage targets:
 * - JSON value parsing (strings, numbers, booleans, null)
 * - Array and object parsing
 * - Nested structures
 * - Unicode handling
 * - Error recovery
 */

#include <cstddef>
#include <cstdint>
#include <sstream>
#include <string>

#include <cm3p/json/reader.h>
#include <cm3p/json/value.h>

// Limit input size
static constexpr size_t kMaxInputSize = 256 * 1024; // 256KB

// Recursive helper to access all values (exercises accessor code)
static void TraverseValue(Json::Value const& value, int depth = 0)
{
  // Prevent stack overflow on deeply nested structures
  if (depth > 100) {
    return;
  }

  switch (value.type()) {
    case Json::nullValue:
      (void)value.isNull();
      break;
    case Json::intValue:
      (void)value.asInt64();
      break;
    case Json::uintValue:
      (void)value.asUInt64();
      break;
    case Json::realValue:
      (void)value.asDouble();
      break;
    case Json::stringValue:
      (void)value.asString();
      break;
    case Json::booleanValue:
      (void)value.asBool();
      break;
    case Json::arrayValue:
      for (Json::ArrayIndex i = 0; i < value.size() && i < 1000; ++i) {
        TraverseValue(value[i], depth + 1);
      }
      break;
    case Json::objectValue:
      for (auto const& name : value.getMemberNames()) {
        (void)name;
        TraverseValue(value[name], depth + 1);
      }
      break;
  }
}

extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
{
  if (size == 0 || size > kMaxInputSize) {
    return 0;
  }

  std::string input(reinterpret_cast<char const*>(data), size);

  Json::Value root;
  Json::CharReaderBuilder builder;
  std::string errors;

  std::istringstream stream(input);

  // Try parsing with default settings
  bool success = Json::parseFromStream(builder, stream, &root, &errors);

  if (success) {
    // Traverse the parsed structure
    TraverseValue(root);
  }

  // Also try with strict mode
  builder["strictRoot"] = true;
  builder["allowComments"] = false;
  builder["allowTrailingCommas"] = false;

  stream.clear();
  stream.str(input);

  success = Json::parseFromStream(builder, stream, &root, &errors);
  if (success) {
    TraverseValue(root);
  }

  return 0;
}