Browse Source

refactor: 持续优化

RyanCW 2 weeks ago
parent
commit
f5f0ad5a3c
10 changed files with 328 additions and 154 deletions
  1. 127 33
      .clang-format
  2. 2 0
      .gitignore
  3. 12 0
      .vscode/settings.json
  4. 2 3
      README.md
  5. 34 13
      RyanJson/RyanJson.c
  6. 22 20
      RyanJson/RyanJsonConfig.h
  7. 6 3
      run_coverage.sh
  8. 42 77
      test/fuzzer/RyanJsonFuzzer.c
  9. 77 1
      test/fuzzer/RyanJsonFuzzer.dict
  10. 4 4
      xmake.lua

+ 127 - 33
.clang-format

@@ -1,46 +1,73 @@
+# SPDX-License-Identifier: Apache-2.0
+#
+# Note: The list of ForEachMacros can be obtained using:
+#
+#    git grep -h '^#define [^[:space:]]*FOR_EACH[^[:space:]]*(' include/ \
+#    | sed "s,^#define \([^[:space:]]*FOR_EACH[^[:space:]]*\)(.*$,  - '\1'," \
+#    | sort | uniq
+#
+# References:
+#   - https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+
 ---
+# 基于 LLVM 的代码风格作为起点,随后覆盖指定字段
 BasedOnStyle: LLVM
 
-# --- 对齐策略 ---
-# 对齐连续宏定义,不跨空行
+# 连续宏定义的对齐方式
+# Enabled: true         -> 启用对齐连续宏定义
+# AcrossComments: true  -> 跨注释也会对齐,适合一组宏中间穿插注释的情况
 AlignConsecutiveMacros:
   Enabled: true
   AcrossComments: true
-  AcrossEmptyLines: false
 
-# 对齐位字段和连续赋值(嵌入式配置常用)
-AlignConsecutiveAssignments:
-  Enabled: true
-  AcrossEmptyLines: false
-AlignConsecutiveBitFields:
-  Enabled: true
-
-# --- 单行短代码压缩策略 ---
+# 是否允许短代码块(如 { ... })出现在单行
 AllowShortBlocksOnASingleLine: true
+
+# 是否允许短 case 标签单行
+# true  -> 允许 `case X: doSomething();`
 AllowShortCaseLabelsOnASingleLine: true
+
+# 是否允许短枚举在一行
+# true  -> 允许短枚举如 `enum { A, B };`
 AllowShortEnumsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: All # 建议显式设为 All
-AllowShortIfStatementsOnASingleLine: AllIfAndElse # 允许 if/else 都在单行
+
+# 是否允许短函数在单行
+AllowShortFunctionsOnASingleLine: true
+
+AllowShortCaseExpressionOnASingleLine: true
+
+# 短 if 语句单行显示策略
+# Always  -> 允许并尽可能保留短 if 语句为单行(包括带 else 的情况)
+# 你希望单行 + 大括号时使用这个选项
+AllowShortIfStatementsOnASingleLine: true
+
+# 是否允许短循环(for/while)单行显示
 AllowShortLoopsOnASingleLine: true
 
-# --- 缩进与制表符 ---
-IndentWidth: 8
-TabWidth: 8  # 必须与 IndentWidth 一致
-UseTab: ForContinuationAndIndentation
-ContinuationIndentWidth: 8
-ConstructorInitializerIndentWidth: 8
+# 属性宏列表,列出在格式化时应视为属性的宏(影响对齐、换行等)
+# 如果代码库使用自定义属性宏,把它们列在这里可以提升格式化准确性
+AttributeMacros:
+  - __aligned
+  - __deprecated
+  - __packed
+  - __printf_like
+  - __syscall
+  - __syscall_always_inline
+  - __subsystem
+
+# 位字段冒号后的空格:After 表示 `int x : 3;` 中冒号后带一个空格(风格选择)
+BitFieldColonSpacing: After
 
-# --- 大括号换行 (重点修正) ---
+# 大括号换行策略:使用 Custom 配合 BraceWrapping 指定细节
+# 你用了 Custom,这意味着下面的 BraceWrapping 字段决定具体行为
 BreakBeforeBraces: Custom
 BraceWrapping:
-  AfterCaseLabel: false
-  AfterClass: true
-  # 改为 MultiLine: 只有当 if 内容本身跨行时,大括号才换行
-  # 这样可以配合 AllowShortIfStatements 保持真正的单行短语句
-  AfterControlStatement: MultiLine 
-  AfterEnum: true
+  AfterCaseLabel: false           # case 标签后不另起行放 {,通常 case: 仍和语句对齐
+  AfterClass: true                # class 后大括号另起行
+  AfterControlStatement: Always   # 控制语句(if/for/while)后通常将 { 放在新行(可被覆盖)
+  AfterEnum: true                 # enum 后另起行
   AfterExternBlock: false
-  AfterFunction: true
+  AfterFunction: true             # 函数体大括号另起行
   AfterNamespace: true
   AfterObjCDeclaration: true
   AfterStruct: true
@@ -49,21 +76,88 @@ BraceWrapping:
   BeforeElse: true
   BeforeLambdaBody: false
   BeforeWhile: false
-  IndentBraces: false
+  IndentBraces: false             # 不单独缩进大括号行
   SplitEmptyFunction: true
   SplitEmptyRecord: true
   SplitEmptyNamespace: true
 
-# --- 细节修正 ---
+# 单行代码的最大列数(换行阈值)
 ColumnLimit: 140
+
+# 构造函数初始化列表的缩进宽度(可针对长列表调整可读性)
+ConstructorInitializerIndentWidth: 8
+
+# 折行缩进宽度(续行缩进)
+ContinuationIndentWidth: 8
+
+# ForEach 宏列表:告诉 clang-format 哪些宏应当当作循环处理(便于格式化块体)
+ForEachMacros:
+  - "ARRAY_FOR_EACH"
+  - "ARRAY_FOR_EACH_PTR"
+  - "FOR_EACH"
+
+# If 宏列表:把 CHECKIF 等宏视为 if 语句(影响括号和后续块处理)
+IfMacros:
+  - "CHECKIF"
+
+# include 文件的分类和排序优先级
+# Regex: 正则匹配,Priority: 数字越小优先级越高(越先放)
+IncludeCategories:
+  - Regex: '^".*\.h"$'
+    Priority: 0
+  - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|limits|locale|math|setjmp|signal|stdarg|stdbool|stddef|stdint|stdio|stdlib|string|tgmath|time|wchar|wctype)\.h>$'
+    Priority: 1
+  - Regex: '^\<Ryan/.*\.h\>$'
+    Priority: 2
+  - Regex: ".*"
+    Priority: 3
+
+# case 标签是否缩进(true 会将 case 缩进到 switch 中)
+# false -> case 与 switch 对齐(你原先设置 false)
 IndentCaseLabels: false
+
+# goto 标签是否缩进(false 表示标签在行首)
 IndentGotoLabels: false
+
+# 缩进宽度(通常与制表符策略配合使用)
+IndentWidth: 8
+
+# 自动插入大括号(即使单语句也插入 { })
+# 这可以避免单行语句因为后续添加语句而引入 bug
 InsertBraces: true
+
+# 文件末尾自动插入换行
 InsertNewlineAtEOF: true
-SortIncludes: Never # 既然你不排序,IncludeCategories 的优先级其实失效了
 
-# 强制在指针符号左侧对齐 (int* p),如果你喜欢嵌入式风格 (int *p),改为 Right
-PointerAlignment: Right 
+# 继承冒号前是否加空格(False 表示不加空格:"class A: public B")
+SpaceBeforeInheritanceColon: False
 
-# 控制语句空格
+# 控制语句后是否加空格(这个值控制 if/for/while 等的格式)
+# ControlStatementsExceptControlMacros -> 控制语句(非宏)前加空格:`if (cond)` 而非 `if(cond)`
 SpaceBeforeParens: ControlStatementsExceptControlMacros
+
+# 包含文件是否自动排序(Never 表示不排序)
+SortIncludes: Never
+
+# 缩进与续行使用制表符策略
+# ForContinuationAndIndentation -> 续行与缩进使用制表符,其他空格仍按规则
+UseTab: ForContinuationAndIndentation
+
+# 对空白敏感的宏列表(多用于预处理器宏展开格式保持)
+WhitespaceSensitiveMacros:
+  - COND_CODE_0
+  - COND_CODE_1
+  - IF_DISABLED
+  - IF_ENABLED
+  - LISTIFY
+  - STRINGIFY
+  - Z_STRINGIFY
+  - DT_FOREACH_PROP_ELEM_SEP
+
+# --------------------------
+# 可选:降低 clang-format 拆行惩罚,使其更倾向于保留短 if/else 单行
+# 下面两个值可以帮助把格式化后的多行 if/else 更可能压缩成单行(仅在 AllowShortIfStatementsOnASingleLine: Always 有效时可用)
+# PenaltyBreakIfElse: 0
+# PenaltyBreakStatement: 0
+
+# 注:上面的 Penalty 设置是可选的,如果你发现 clang-format 依旧不把某些 if/else 压成单行,可以取消注释并试验效果。

+ 2 - 0
.gitignore

@@ -20,3 +20,5 @@ default.profdata
 default.profraw
 test/fuzzer/corpus
 docs
+
+fuzz-*

+ 12 - 0
.vscode/settings.json

@@ -20,6 +20,18 @@
         // "--suppress=constVariablePointer",
         // "--suppress=constParameter",
     ],
+    "files.watcherExclude": {
+        "**/test/fuzzer/corpus/**": true,
+        "./docs": true,
+        "./build": true,
+        "./.xmake": true,
+    },
+    "files.exclude": {
+        "**/test/fuzzer/corpus/**": true,
+        "./docs": true,
+        "./build": true,
+        "./.xmake": true,
+    },
     "files.associations": {
         "*.c": "c",
         "inttypes.h": "c",

+ 2 - 3
README.md

@@ -16,7 +16,7 @@
 #### ✅ 特性亮点
 
 - 💡 **极致内存优化**:在资源受限设备上实现 **40-70% 内存节省**(对比 cJSON),在 RT-Thread 平台 malloc 头部空间为 12 字节时节省约 40%,无 malloc 头部空间可接近 70%。同时保持工业级健壮性,运行速度与 cJSON 基本持平。
-- 🔍 **模糊测试保障**:基于[LLVM Fuzzer](https://llvm.org/docs/LibFuzzer.html) ,千万级数据输入分支覆盖率 **99.9%**,确保在各种非法输入和极端场景下依旧安全。**[点击在线查看覆盖率信息](https://ryan-cw-code.github.io/RyanJson/)** 
+- 🔍 **模糊测试保障**:基于[LLVM Fuzzer](https://llvm.org/docs/LibFuzzer.html) ,上亿级数据输入分支覆盖率 **99.9%**,确保在各种非法输入和极端场景下依旧安全。**[点击在线查看覆盖率信息](https://ryan-cw-code.github.io/RyanJson/)** 
 - 🛡️ **运行时安全分析验证**,使用 **[Sanitizer](https://clang.llvm.org/docs/index.html#sanitizers)** 系列工具,捕获内存越界、Use-after-free、数据竞争、未定义行为、内存泄漏等问题,提升代码健壮性与安全性
 - 📐**高质量代码保障** , 引入 **[clang-tidy](https://clang.llvm.org/extra/clang-tidy/#clang-tidy)** 与 **[Cppcheck](https://cppcheck.sourceforge.io/)** 进行静态分析,实现接近语法级的"**零缺陷**",显著提升可维护性与可读性
 - 🤖  **AI 辅助开发与审查**,结合  **[coderabbitai](https://www.coderabbit.ai)** 、 **[Copilot](https://github.com/features/copilot)** 、**[Gemini Code Assist](https://codeassist.google/)**,在编码与代码审查阶段持续优化代码质量,构建多层安全防线
@@ -125,7 +125,7 @@ typedef struct RyanJsonNode *RyanJson_t;
 
 **[点击在线查看覆盖率信息](https://ryan-cw-code.github.io/RyanJson/)** 
 
-- **千万级测试样本**:[LLVM Fuzzer](https://llvm.org/docs/LibFuzzer.html)  自动生成并执行千万级随机与非法 JSON 输入。
+- **千万级测试样本**:[LLVM Fuzzer](https://llvm.org/docs/LibFuzzer.html)  自动生成并执行上亿级随机与非法 JSON 输入。
 - **覆盖率极高**:分支覆盖率 **99.9%**,无崩溃、无泄漏。
 - **鲁棒性验证**:内存申请失败、扩容失败、非法转义字符、尾随逗号、嵌套过深、随机类型切换。
 - **内存安全验证**:结合 Sanitizer 工具链,确保无泄漏、无悬空指针、无越界。
@@ -335,4 +335,3 @@ RFC 8259 JSON: (322/322)
 
 📧 联系方式:1831931681@qq.com
 
-

+ 34 - 13
RyanJson/RyanJson.c

@@ -2,15 +2,35 @@
 
 #ifdef isEnableFuzzer
 #undef RyanJsonNestingLimit
-#define RyanJsonNestingLimit 150
+#define RyanJsonNestingLimit 350
 
 #undef RyanJsonSnprintf
 #include <stdarg.h>
+#include <time.h>
+
+static uint32_t RyanJsonRandRange(uint32_t min, uint32_t max)
+{
+	// int32_t seedp = (int32_t)time(NULL);
+	// return min + rand_r(&seedp) % (max - min + 1);
+
+	static uint64_t state = 0;
+	// 初始化一次种子
+	if (state == 0) { state = (uint64_t)time(NULL); }
+
+	// Xorshift64* 算法
+	state ^= state >> 12;
+	state ^= state << 25;
+	state ^= state >> 27;
+	uint64_t result = state * 2685821657736338717ULL;
+
+	return min + (uint32_t)(result % (max - min + 1));
+}
+
 static int32_t RyanJsonSnprintf(char *buf, size_t size, const char *fmt, ...)
 {
 	static uint32_t jsonsnprintCount = 1;
 	jsonsnprintCount++;
-	if (jsonsnprintCount % random() % 500 == 0) { return 0; };
+	if (jsonsnprintCount % RyanJsonRandRange(10, 500) == 0) { return 0; };
 
 	va_list args;
 	va_start(args, fmt); // 每 500 次随机触发一次“失败”
@@ -94,7 +114,7 @@ static RyanJsonBool_e parseBufTyrAdvanceCurrentPrt(RyanJsonParseBuffer *parseBuf
 #ifdef isEnableFuzzer
 	static uint32_t count = 0;
 	count++;
-	if (0 == count % random() % 2000) { return RyanJsonFalse; }
+	if (0 == count % RyanJsonRandRange(10, 2000)) { return RyanJsonFalse; }
 #endif
 
 	if (parseBufHasRemainBytes(parseBuf, bytesToAdvance))
@@ -119,11 +139,11 @@ static RyanJsonBool_e parseBufSkipWhitespace(RyanJsonParseBuffer *parseBuf)
 #ifdef isEnableFuzzer
 	static uint32_t count = 0;
 	count++;
-	if (0 == count % random() % 2000) { return RyanJsonFalse; }
+	if (0 == count % RyanJsonRandRange(10, 2000)) { return RyanJsonFalse; }
 #endif
 
 	const uint8_t *cursor = parseBuf->currentPtr;
-	while (*cursor && (' ' == *cursor || '\n' == *cursor || '\r' == *cursor))
+	while (parseBufHasRemain(parseBuf) && *cursor && (' ' == *cursor || '\n' == *cursor || '\r' == *cursor))
 	{
 		RyanJsonCheckReturnFalse(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1));
 		// 更新本地指针以反映 buf->address 的变化(若 parseBufTyrAdvanceCurrentPrt 移动 address)
@@ -554,7 +574,7 @@ static RyanJsonBool_e RyanJsonParseNumber(RyanJsonParseBuffer *parseBuf, char *k
 	RyanJsonBool_e isint = RyanJsonTrue;
 
 	// 处理符号
-	if ('-' == *parseBuf->currentPtr)
+	if (parseBufHasRemain(parseBuf) && '-' == *parseBuf->currentPtr)
 	{
 		sign = -1;
 		RyanJsonCheckReturnFalse(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1));
@@ -562,7 +582,7 @@ static RyanJsonBool_e RyanJsonParseNumber(RyanJsonParseBuffer *parseBuf, char *k
 	}
 
 	// 跳过前导零
-	while ('0' == *parseBuf->currentPtr)
+	while (parseBufHasRemain(parseBuf) && '0' == *parseBuf->currentPtr)
 	{
 		RyanJsonCheckReturnFalse(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1));
 		// 前导0后面不允许跟数组,比如"0123"
@@ -570,19 +590,19 @@ static RyanJsonBool_e RyanJsonParseNumber(RyanJsonParseBuffer *parseBuf, char *k
 	}
 
 	// 整数部分
-	while (*parseBuf->currentPtr >= '0' && *parseBuf->currentPtr <= '9')
+	while (parseBufHasRemain(parseBuf) && *parseBuf->currentPtr >= '0' && *parseBuf->currentPtr <= '9')
 	{
 		number = number * 10.0 + (*parseBuf->currentPtr - '0');
 		RyanJsonCheckReturnFalse(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1));
 	}
 
 	// 小数部分
-	if ('.' == *parseBuf->currentPtr)
+	if (parseBufHasRemain(parseBuf) && '.' == *parseBuf->currentPtr)
 	{
 		RyanJsonCheckReturnFalse(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1));
 		RyanJsonCheckReturnFalse(parseBufHasRemain(parseBuf) && *parseBuf->currentPtr >= '0' && *parseBuf->currentPtr <= '9');
 
-		while (*parseBuf->currentPtr >= '0' && *parseBuf->currentPtr <= '9')
+		while (parseBufHasRemain(parseBuf) && *parseBuf->currentPtr >= '0' && *parseBuf->currentPtr <= '9')
 		{
 			number = number * 10.0 + (*parseBuf->currentPtr - '0');
 			scale--; // 每读一位小数,scale减一
@@ -592,14 +612,15 @@ static RyanJsonBool_e RyanJsonParseNumber(RyanJsonParseBuffer *parseBuf, char *k
 	}
 
 	// 指数部分
-	if (('e' == *parseBuf->currentPtr || 'E' == *parseBuf->currentPtr))
+	if (parseBufHasRemain(parseBuf) && ('e' == *parseBuf->currentPtr || 'E' == *parseBuf->currentPtr))
 	{
 		RyanJsonCheckReturnFalse(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1));
+		RyanJsonCheckReturnFalse(parseBufHasRemain(parseBuf));
 		if ('+' == *parseBuf->currentPtr || '-' == *parseBuf->currentPtr) { e_sign = ('-' == *parseBuf->currentPtr) ? -1 : 1; }
 		RyanJsonCheckReturnFalse(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1));
-		RyanJsonCheckReturnFalse(*parseBuf->currentPtr >= '0' && *parseBuf->currentPtr <= '9');
+		RyanJsonCheckReturnFalse(parseBufHasRemain(parseBuf) && *parseBuf->currentPtr >= '0' && *parseBuf->currentPtr <= '9');
 
-		while (*parseBuf->currentPtr >= '0' && *parseBuf->currentPtr <= '9')
+		while (parseBufHasRemain(parseBuf) && *parseBuf->currentPtr >= '0' && *parseBuf->currentPtr <= '9')
 		{
 			e_scale = e_scale * 10 + (*parseBuf->currentPtr - '0');
 			RyanJsonCheckReturnFalse(RyanJsonTrue == parseBufTyrAdvanceCurrentPrt(parseBuf, 1));

+ 22 - 20
RyanJson/RyanJsonConfig.h

@@ -41,7 +41,9 @@ extern "C" {
 // true 表示支持未对齐访问
 // false 表示不支持未对齐访问
 // UINT8_MAX 标识让RyanJson自动判断,但可能会漏掉支持对齐访问的平台
-#define RyanJsonAlignUnalignedAccessSupported UINT8_MAX
+#ifndef RyanJsonUnalignedAccessSupported
+#define RyanJsonUnalignedAccessSupported UINT8_MAX
+#endif
 
 // 限制解析数组/对象中嵌套的深度
 // RyanJson使用递归 序列化/反序列化 json
@@ -72,73 +74,73 @@ extern "C" {
  * @brief 判断是否支持未对齐访问
  *
  */
-#if UINT8_MAX == RyanJsonAlignUnalignedAccessSupported
-#undef RyanJsonAlignUnalignedAccessSupported
+#if UINT8_MAX == RyanJsonUnalignedAccessSupported
+#undef RyanJsonUnalignedAccessSupported
 
 // Cortex-M0/M0+/M1 属于 ARMv6-M
 #if defined(__ARM_ARCH_6M__)
-#define RyanJsonAlignUnalignedAccessSupported false
+#define RyanJsonUnalignedAccessSupported false
 
 // Cortex-M3/M4/M7 属于 ARMv7-M/EM
 #elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
-#define RyanJsonAlignUnalignedAccessSupported true
+#define RyanJsonUnalignedAccessSupported true
 
 // Cortex-M23/M33 属于 ARMv8-M
 #elif defined(__ARM_ARCH_8M_BASE__) || defined(__ARM_ARCH_8M_MAIN__)
-#define RyanJsonAlignUnalignedAccessSupported true
+#define RyanJsonUnalignedAccessSupported true
 
 // Cortex-A/R 属于 ARMv7-A/R
 #elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)
-#define RyanJsonAlignUnalignedAccessSupported true
+#define RyanJsonUnalignedAccessSupported true
 
 // ARM9/ARM11 等老核
 #elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5E__)
-#define RyanJsonAlignUnalignedAccessSupported false
+#define RyanJsonUnalignedAccessSupported false
 
 // ARMv8-A / ARM64
 #elif defined(__aarch64__) || defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH_9__)
-#define RyanJsonAlignUnalignedAccessSupported true
+#define RyanJsonUnalignedAccessSupported true
 
 // RISC-V MCU 默认不支持未对齐访问
 #elif defined(__riscv)
-#define RyanJsonAlignUnalignedAccessSupported false
+#define RyanJsonUnalignedAccessSupported false
 
 // x86 / x86-64
 #elif defined(__i386__) || defined(__x86_64__)
-#define RyanJsonAlignUnalignedAccessSupported true
+#define RyanJsonUnalignedAccessSupported true
 
 // MIPS
 #elif defined(__mips__)
-#define RyanJsonAlignUnalignedAccessSupported false
+#define RyanJsonUnalignedAccessSupported false
 
 // PowerPC
 #elif defined(__powerpc__) || defined(__ppc__)
-#define RyanJsonAlignUnalignedAccessSupported false
+#define RyanJsonUnalignedAccessSupported false
 
 // SPARC
 #elif defined(__sparc__)
-#define RyanJsonAlignUnalignedAccessSupported false
+#define RyanJsonUnalignedAccessSupported false
 
 // SuperH
 #elif defined(__sh__)
-#define RyanJsonAlignUnalignedAccessSupported false
+#define RyanJsonUnalignedAccessSupported false
 
 // Alpha
 #elif defined(__alpha__)
-#define RyanJsonAlignUnalignedAccessSupported true
+#define RyanJsonUnalignedAccessSupported true
 
 // Itanium
 #elif defined(__ia64__)
-#define RyanJsonAlignUnalignedAccessSupported false
+#define RyanJsonUnalignedAccessSupported false
 
 #else
 // 默认认为不支持未对齐访问
-#define RyanJsonAlignUnalignedAccessSupported false
+#define RyanJsonUnalignedAccessSupported false
 #endif
 
-#endif // UINT8_MAX == RyanJsonAlignUnalignedAccessSupported
+#endif // UINT8_MAX == RyanJsonUnalignedAccessSupported
 
-#if true != RyanJsonAlignUnalignedAccessSupported
+#if true != RyanJsonUnalignedAccessSupported
 #define RyanJsonAlign sizeof(void *)
 #else
 #define RyanJsonAlign sizeof(uint8_t)

+ 6 - 3
run_coverage.sh

@@ -7,10 +7,13 @@ set -e  # 遇到错误立即退出
 ./build/linux/x86/release/RyanJson \
   ./test/fuzzer/corpus \
   -dict=./test/fuzzer/RyanJsonFuzzer.dict \
-  -timeout=2 \
-  -runs=999999 \
+  -timeout=4 \
+  -runs=99999999 \
   -verbosity=0 \
-  -max_len=16384
+  -max_len=8192 \
+  -workers=5 \
+  -jobs=10 \ 
+
 
 # ================================
 # 2. 合并 profile 数据

+ 42 - 77
test/fuzzer/RyanJsonFuzzer.c

@@ -7,7 +7,7 @@
 		goto __exit;                                                                                                               \
 	})
 
-RyanJsonBool_e isadfa = RyanJsonTrue;
+RyanJsonBool_e isEnableRandomMemFail = RyanJsonTrue;
 
 static RyanJsonBool_e RyanJsonFuzzerTestByParseAndPrint(RyanJson_t pJson, const char *data, uint32_t size)
 {
@@ -23,74 +23,48 @@ static RyanJsonBool_e RyanJsonFuzzerTestByParseAndPrint(RyanJson_t pJson, const
 	RyanJsonCheckReturnFalse(NULL != jsonStr && len > 0);
 	RyanJsonFree(jsonStr);
 
+	uint32_t bufLen = len * 3;
+	if (bufLen < size * 2) { bufLen = size * 2; }
+	if (bufLen < 4096) { bufLen = 4096; }
+	char *buf = malloc((size_t)bufLen);
 	{
-		uint32_t bufLen = len * 3;
-		if (bufLen < 8192) { bufLen = 8192; }
-		char *buf = malloc((size_t)bufLen);
-
 		uint32_t len2 = 0;
 		char *jsonStr2 = RyanJsonPrintPreallocated(pJson, buf, bufLen, size % 2 ? RyanJsonFalse : RyanJsonTrue, &len2);
 		// printf("len: %d, len2: %d, str: %s\r\n", len, len2, NULL == jsonStr2 ? "NULL" : jsonStr2);
-		if (buf)
-		{
-			RyanJsonCheckCode(NULL != jsonStr2 && len == len2, {
-				free(buf);
-				return RyanJsonFalse;
-			});
-
+		RyanJsonCheckCode(NULL != jsonStr2 && len == len2, {
 			free(buf);
-		}
+			return RyanJsonFalse;
+		});
 	}
 
+	memcpy(buf, data, (size_t)size);
+	buf[size] = 0;
+	RyanJson_t jsonRoot = RyanJsonParse(buf);
+	RyanJsonCheckCode(NULL != jsonRoot, {
+		free(buf);
+		return RyanJsonFalse;
+	});
+
+    // 测试多次打印结果是否一致
 	{
-		uint32_t bufLen = size * 3;
-		char *buf = malloc((size_t)bufLen);
-		if (buf)
-		{
-			memset(buf, 0, (size_t)bufLen);
-			memcpy(buf, data, (size_t)size);
-			RyanJson_t jsonRoot = RyanJsonParse(buf);
-			RyanJsonCheckCode(NULL != jsonRoot, {
-				free(buf);
-				return RyanJsonFalse;
-			});
+		uint32_t len3 = 0;
+		char *jsonStr3 = RyanJsonPrint(jsonRoot, 100, size % 2 ? RyanJsonFalse : RyanJsonTrue, &len3); // 以带格式方式将数据打印出来
+		RyanJsonCheckCode(NULL != jsonStr3 && len == len3, {
 			free(buf);
-
-			uint32_t len3 = 0;
-			char *jsonStr3 =
-				RyanJsonPrint(jsonRoot, 100, size % 2 ? RyanJsonFalse : RyanJsonTrue, &len3); // 以带格式方式将数据打印出来
-			// printf("len222222222222222222: %d\r\n", len);
-			RyanJsonCheckCode(NULL != jsonStr3 && len == len3, {
-				if (jsonStr3) { RyanJsonFree(jsonStr3); }
-				RyanJsonDelete(jsonRoot);
-				return RyanJsonFalse;
-			});
-
-			RyanJsonFree(jsonStr3);
-
+			if (jsonStr3) { RyanJsonFree(jsonStr3); }
 			RyanJsonDelete(jsonRoot);
-		}
+			return RyanJsonFalse;
+		});
+
+		RyanJsonFree(jsonStr3);
 	}
 
 	{
-		uint32_t bufLen = size * 3;
-		char *buf = malloc((size_t)bufLen);
-		if (buf)
-		{
-			memset(buf, 0, (size_t)bufLen);
-			memcpy(buf, data, (size_t)size);
-			RyanJson_t jsonRoot = RyanJsonParse(buf);
-			RyanJsonCheckCode(NULL != jsonRoot, {
-				free(buf);
-				return RyanJsonFalse;
-			});
-
-			RyanJsonPrintPreallocated(jsonRoot, buf, bufLen / 15, RyanJsonTrue, NULL);
-			free(buf);
-			RyanJsonDelete(jsonRoot);
-		}
+		RyanJsonPrintPreallocated(jsonRoot, buf, bufLen / 15, RyanJsonTrue, NULL);
 	}
 
+	free(buf);
+	RyanJsonDelete(jsonRoot);
 	return RyanJsonTrue;
 }
 
@@ -215,9 +189,8 @@ static RyanJsonBool_e RyanJsonFuzzerTestByForEachChange(RyanJson_t pJson, uint32
 		char *key = malloc(strlen(RyanJsonGetKey(pJson)) + 1);
 		if (key)
 		{
-
-			memset(key, 0, strlen(RyanJsonGetKey(pJson)) + 1);
 			memcpy(key, RyanJsonGetKey(pJson), strlen(RyanJsonGetKey(pJson)));
+			key[strlen(RyanJsonGetKey(pJson))] = 0;
 
 			RyanJsonChangeKey(pJson, "key");
 			RyanJsonChangeKey(pJson, key);
@@ -246,8 +219,8 @@ static RyanJsonBool_e RyanJsonFuzzerTestByForEachChange(RyanJson_t pJson, uint32
 		char *value = malloc(strlen(RyanJsonGetStringValue(pJson)) + 1);
 		if (value)
 		{
-			memset(value, 0, strlen(RyanJsonGetStringValue(pJson)) + 1);
 			memcpy(value, RyanJsonGetStringValue(pJson), strlen(RyanJsonGetStringValue(pJson)));
+			value[strlen(RyanJsonGetStringValue(pJson))] = 0;
 
 			RyanJsonChangeStringValue(pJson, "hello world");
 			RyanJsonChangeStringValue(pJson, value);
@@ -259,16 +232,8 @@ static RyanJsonBool_e RyanJsonFuzzerTestByForEachChange(RyanJson_t pJson, uint32
 	if (RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))
 	{
 		RyanJson_t item;
-		if (RyanJsonIsArray(pJson))
-		{
-			RyanJsonArrayForEach(pJson, item)
-			{ RyanJsonCheckReturnFalse(RyanJsonTrue == RyanJsonFuzzerTestByForEachChange(item, size)); }
-		}
-		else
-		{
-			RyanJsonObjectForEach(pJson, item)
-			{ RyanJsonCheckReturnFalse(RyanJsonTrue == RyanJsonFuzzerTestByForEachChange(item, size)); }
-		}
+		RyanJsonArrayForEach(pJson, item)
+		{ RyanJsonCheckReturnFalse(RyanJsonTrue == RyanJsonFuzzerTestByForEachChange(item, size)); }
 	}
 
 	return RyanJsonTrue;
@@ -457,7 +422,7 @@ static RyanJsonBool_e RyanJsonFuzzerTestByForEachCreate(RyanJson_t pJson, uint32
 static RyanJsonBool_e RyanJsonFuzzerTestByForEachReplace(RyanJson_t pJson, uint32_t size)
 {
 	{
-		isadfa = RyanJsonFalse;
+		isEnableRandomMemFail = RyanJsonFalse;
 		RyanJson_t strItem = RyanJsonCreateString("", "NULL");
 		RyanJsonAssert(RyanJsonFalse == RyanJsonReplaceByKey(NULL, NULL, NULL));
 		RyanJsonAssert(RyanJsonFalse == RyanJsonReplaceByKey(pJson, NULL, NULL));
@@ -487,7 +452,7 @@ static RyanJsonBool_e RyanJsonFuzzerTestByForEachReplace(RyanJson_t pJson, uint3
 		RyanJsonAddItemToObject(objItem, "item", RyanJsonCreateObject());
 		RyanJsonAssert(RyanJsonFalse == RyanJsonReplaceByKey(objItem, "NULL222", strItem));
 		RyanJsonAssert(RyanJsonFalse == RyanJsonReplaceByIndex(objItem, INT32_MAX, strItem));
-		isadfa = RyanJsonTrue;
+		isEnableRandomMemFail = RyanJsonTrue;
 
 		RyanJsonDelete(objItem);
 		RyanJsonDelete(strItem);
@@ -653,10 +618,10 @@ static RyanJsonBool_e RyanJsonFuzzerTestByForEachDelete(RyanJson_t pJson, uint32
 static RyanJsonBool_e RyanJsonFuzzerTestByMinify(const char *data, uint32_t size)
 {
 	char *buf = malloc(size + 100);
-	memset(buf, 0, size + 100);
 	memcpy(buf, data, size);
+	memset(buf + size, 0, 100);
 
-	uint32_t size2 = RyanJsonMinify(buf, size);
+	uint32_t size2 = RyanJsonMinify(buf, (int32_t)size);
 	// 非法情况
 	{
 		RyanJsonCheckReturnFalse(0 == RyanJsonMinify(NULL, 0));
@@ -691,7 +656,7 @@ static void *RyanJsonFuzzerMalloc(size_t size)
 {
 	static int32_t count = 0;
 	count++;
-	if (RyanJsonTrue == isadfa)
+	if (RyanJsonTrue == isEnableRandomMemFail)
 	{
 		if (0 == count % 598) { return NULL; }
 	}
@@ -704,7 +669,7 @@ static void *RyanJsonFuzzerRealloc(void *block, size_t size)
 {
 	static int32_t count = 0;
 	count++;
-	if (RyanJsonTrue == isadfa)
+	if (RyanJsonTrue == isEnableRandomMemFail)
 	{
 		if (0 == count % 508) { return NULL; }
 	}
@@ -752,9 +717,9 @@ int LLVMFuzzerTestOneInput(const char *data, uint32_t size)
 		assert(NULL != parseEndPtr && parseEndPtr - data <= size);
 
 		{
-			isadfa = RyanJsonFalse;
+			isEnableRandomMemFail = RyanJsonFalse;
 			RyanJson_t pJson2 = RyanJsonDuplicate(pJson);
-			isadfa = RyanJsonTrue;
+			isEnableRandomMemFail = RyanJsonTrue;
 			RyanJsonCheckCode(RyanJsonFuzzerTestByForEachDelete(pJson2, size), {
 				RyanJsonDelete(pJson2);
 				goto __exit;
@@ -763,9 +728,9 @@ int LLVMFuzzerTestOneInput(const char *data, uint32_t size)
 		}
 
 		{
-			isadfa = RyanJsonFalse;
+			isEnableRandomMemFail = RyanJsonFalse;
 			RyanJson_t pJson2 = RyanJsonDuplicate(pJson);
-			isadfa = RyanJsonTrue;
+			isEnableRandomMemFail = RyanJsonTrue;
 			RyanJsonCheckCode(RyanJsonFuzzerTestByForEachDetach(pJson2, size), {
 				RyanJsonDelete(pJson2);
 				goto __exit;

+ 77 - 1
test/fuzzer/RyanJsonFuzzer.dict

@@ -40,6 +40,8 @@
 "-"
 "000-000"
 "-0045.12348"
+"0123"
+"0123.123"
 
 # 嵌套结构
 "{\"a\":1}"
@@ -55,6 +57,80 @@
 "{\"user\":{\"id\":123,\"name\":\"Alice\",\"roles\":[\"admin\",\"editor\"]}}"
 "{\"response\":{\"status\":200,\"data\":[{\"id\":1},{\"id\":2}]}}"
 
+# 边界结构
+# 键未加引号
+"{a:1}"
+
+# 缺少冒号
+"{\"a\" 1}"
+
+# 缺少逗号
+"{\"a\":1 \"b\":2}"
+
+# 多余逗号
+"{\"a\":1,}"
+
+# 数组尾逗号
+"[1,2,3,]"
+
+# 空对象错误
+"{,}"
+
+# 空数组错误
+"[,]"
+
+# 未闭合字符串
+"{\"a\":\"value}"
+
+# 单引号字符串
+"{\"a\":'value'}"
+
+# 非法转义
+"{\"a\":\"\\q\"}"
+
+# 非法 Unicode 转义
+"{\"a\":\"\\uZZZZ\"}"
+
+# 位数不足
+"{\"a\":\"\\u12\"}"
+
+# 控制字符
+"{\"a\":\"\\x07\"}"
+
+# 小数点后无数字
+"1."
+
+# 科学计数法错误
+"1e"
+
+# 科学计数法错误
+"1e+"
+
+# 超大指数
+"1e9999"
+
+# 拼写错误
+"True"
+"False"
+"Null"
+"tru"
+"nul"
+
+# 顶层错误
+"string"
+"123"
+"true"
+"null"
+
+# 注释错误:单行
+"// comment"
+"/* block comment */"
+
+# 非 UTF-8 字节流
+"\xC0\xAF"
+"\xFF\xFF"
+"\xFE\xFF"
+
 # 空结构
 "{}"
 "[]"
@@ -126,7 +202,7 @@
 "{\"error\":{\"code\":1234,\"message\":\"Invalid request\"}}"
 "{\"error\":{\"code\":5678,\"message\":\"Timeout\"}}"
 
-# RESTful 复杂响应
+# RESTful 响应
 "{\"status\":200,\"user\":{\"id\":123,\"name\":\"Alice\",\"roles\":[\"admin\",\"editor\"]},\"token\":\"abcdef123456\"}"
 "{\"status\":200,\"config\":{\"theme\":\"dark\",\"language\":\"en\"},\"features\":[\"chat\",\"upload\",\"search\"]}"
 

+ 4 - 4
xmake.lua

@@ -7,9 +7,9 @@ target("RyanJson",function()
     set_plat("linux")
     set_arch("x86")
     set_languages("gnu99") -- 关键!启用 GNU 扩展
-    -- add_defines("isEnableFuzzer")
-    -- add_cxflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true} )
-    -- add_ldflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true} )
+    add_defines("isEnableFuzzer")
+    add_cxflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true} )
+    add_ldflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true} )
 
     set_policy("build.ccache", false)
     -- set_optimize("smallest") -- -Os
@@ -61,7 +61,7 @@ target("RyanJson",function()
 
     -- 编译器警告与静态分析(开发期错误检测,Clang 兼容)
     add_cxflags(
-        "-g3",                  -- 生成调试信息"
+        "-g3",                     -- 生成调试信息"
         "-pedantic",               -- 强制遵循 ISO C 标准
         "-Wall",                   -- 常见警告
         "-Wextra",                 -- 额外警告