2
0

json_load_dump_fuzzer.cc 3.8 KB

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