entry.c 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. #include "RyanJsonFuzzer.h"
  2. #include <limits.h>
  3. /**
  4. * @brief LLVM LibFuzzer 主入口
  5. *
  6. * 每轮 Fuzz 迭代都会调用该函数。
  7. *
  8. * 主要流程:
  9. * - 初始化 Fuzzer 状态与随机源。
  10. * - 先执行一次与输入无关的确定性自检。
  11. * - 注册内存 Hook,确保测试过程中资源可控并可回收。
  12. */
  13. int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
  14. {
  15. if (NULL == data) { return 0; }
  16. // RyanJson 各测试入口统一使用 uint32_t 长度,先在入口处做一次收敛。
  17. uint32_t inputSize = (size > (size_t)UINT32_MAX) ? UINT32_MAX : (uint32_t)size;
  18. RyanJsonFuzzerInit(data, inputSize);
  19. // 与输入无关的确定性覆盖只在首轮执行一次,避免拖慢后续 10 万次跑批。
  20. RyanJsonFuzzerSelfTestOnce();
  21. g_fuzzerState.isEnableMemFail = true;
  22. // 用输入奇偶切换 realloc Hook,可稳定覆盖“有/无 realloc”两套资源路径。
  23. assert(RyanJsonTrue ==
  24. RyanJsonInitHooks(RyanJsonFuzzerMalloc, RyanJsonFuzzerFree, 0 != inputSize % 2 ? NULL : RyanJsonFuzzerRealloc));
  25. // 用输入驱动 strict 选项,保证同一份样本在“宽松尾部/严格尾部”两类解析语义下都能逐步积累覆盖。
  26. RyanJson_t pJson = RyanJsonParseOptions((const char *)data, inputSize, 0 != inputSize % 3 ? RyanJsonTrue : RyanJsonFalse, NULL);
  27. if (NULL != pJson)
  28. {
  29. // 执行顺序保持“文本相关 -> 只读访问 -> 原地变异 -> 所有权迁移”。
  30. // 这样前面的 case 更像观察者,后面的 case 再消费和改写树结构,减少互相污染。
  31. RyanJsonFuzzerTestMinify((const char *)data, inputSize);
  32. RyanJsonFuzzerTestParse(pJson, (const char *)data, inputSize);
  33. RyanJsonFuzzerTestGet(pJson, inputSize);
  34. RyanJsonFuzzerTestDuplicate(pJson);
  35. RyanJsonCheckCode(RyanJsonFuzzerTestModify(pJson, inputSize), { goto exit__; });
  36. RyanJsonCheckCode(RyanJsonFuzzerTestCreate(pJson, inputSize), { goto exit__; });
  37. RyanJsonCheckCode(RyanJsonFuzzerTestDelete(pJson, inputSize), { goto exit__; });
  38. RyanJsonCheckCode(RyanJsonFuzzerTestReplace(pJson, inputSize), { goto exit__; });
  39. {
  40. RyanJsonBool_e lastIsEnableMemFail;
  41. RyanJsonFuzzerMemFailPush(lastIsEnableMemFail, RyanJsonFalse);
  42. // detach 会改变树所有权;先复制一份,避免与前面的变异操作互相干扰。
  43. // 这里特意关闭 OOM,是因为我们想验证 detach 语义本身,而不是重复打一遍 Duplicate 的失败路径。
  44. RyanJson_t pJson2 = RyanJsonDuplicate(pJson);
  45. RyanJsonFuzzerMemFailPop(lastIsEnableMemFail);
  46. RyanJsonDelete(pJson);
  47. RyanJsonFuzzerTestDetach(pJson2, inputSize);
  48. RyanJsonDelete(pJson2);
  49. }
  50. }
  51. return 0;
  52. exit__:
  53. RyanJsonDelete(pJson);
  54. return 0;
  55. }