@ohos-graphics/stability-code-review 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +169 -0
  2. package/SKILL.md +518 -0
  3. package/bin/install.js +165 -0
  4. package/config/rules.yaml +445 -0
  5. package/config/whitelist.yaml +52 -0
  6. package/package.json +40 -0
  7. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_001.md +275 -0
  8. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_002.md +273 -0
  9. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_003.md +305 -0
  10. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_004.md +350 -0
  11. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_005.md +301 -0
  12. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_006.md +320 -0
  13. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_007.md +432 -0
  14. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_008.md +394 -0
  15. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_009.md +425 -0
  16. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_010.md +472 -0
  17. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_011.md +204 -0
  18. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_012.md +210 -0
  19. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_013.md +226 -0
  20. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_014.md +222 -0
  21. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_015.md +256 -0
  22. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_016.md +269 -0
  23. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_017.md +222 -0
  24. package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_018.md +336 -0
  25. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_001.md +414 -0
  26. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_002.md +335 -0
  27. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_003.md +284 -0
  28. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_004.md +313 -0
  29. package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_005.md +364 -0
  30. package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_001.md +142 -0
  31. package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_002.md +222 -0
  32. package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_003.md +383 -0
  33. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_001.md +258 -0
  34. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_002.md +131 -0
  35. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_003.md +220 -0
  36. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_004.md +224 -0
  37. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_005.md +250 -0
  38. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_006.md +153 -0
  39. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_007.md +169 -0
  40. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_008.md +153 -0
  41. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_009.md +144 -0
  42. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_010.md +152 -0
  43. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_011.md +221 -0
  44. package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_012.md +318 -0
  45. package/references/InitializationOrder/StabilityCodeReview_InitializationOrder_001.md +411 -0
  46. package/references/Lifecycle/StabilityCodeReview_Lifecycle_001.md +255 -0
  47. package/references/Lifecycle/StabilityCodeReview_Lifecycle_002.md +177 -0
  48. package/references/MemoryStability/StabilityCodeReview_MemoryStability_001.md +332 -0
  49. package/references/MemoryStability/StabilityCodeReview_MemoryStability_002.md +261 -0
  50. package/references/MemoryStability/StabilityCodeReview_MemoryStability_003.md +428 -0
  51. package/references/MemoryStability/StabilityCodeReview_MemoryStability_004.md +400 -0
  52. package/references/MemoryStability/StabilityCodeReview_MemoryStability_005.md +364 -0
  53. package/references/MemoryStability/StabilityCodeReview_MemoryStability_006.md +359 -0
  54. package/references/MemoryStability/StabilityCodeReview_MemoryStability_007.md +279 -0
  55. package/references/PROBLEM_TEMPLATE.md +65 -0
  56. package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_001.md +380 -0
  57. package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_002.md +437 -0
  58. package/references/REPORT_TEMPLATE.csv +5 -0
  59. package/references/REPORT_TEMPLATE.md +132 -0
  60. package/references/RULE_DEVELOPMENT_GUIDE.md +711 -0
  61. package/references/RULE_INDEX.md +101 -0
  62. package/references/RULE_TEMPLATE.md +192 -0
  63. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_001.md +334 -0
  64. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_002.md +425 -0
  65. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_003.md +420 -0
  66. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_004.md +409 -0
  67. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_005.md +445 -0
  68. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_006.md +384 -0
  69. package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_007.md +395 -0
  70. package/scripts/add-rule.py +423 -0
@@ -0,0 +1,380 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_PerformanceStability_001"
3
+ name: "递归条件未考虑充分导致无限递归"
4
+ category: "性能稳定性"
5
+ severity: "HIGH"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # 递归条件未考虑充分导致无限递归
11
+
12
+ ## 问题描述
13
+
14
+ 递归函数如果没有正确的终止条件或终止条件考虑不充分,在某些输入情况下可能无法终止,导致无限递归、栈溢出和进程崩溃。这类问题隐蔽性强,通常在特定边界条件下触发,严重影响系统稳定性。
15
+
16
+ ## 检测示例
17
+
18
+ ### ❌ 问题代码
19
+
20
+ ```cpp
21
+ // 错误示例1:缺少终止条件
22
+ int CalculateFactorial(int n)
23
+ {
24
+ return n * CalculateFactorial(n - 1); // 危险:无终止条件,永远递归
25
+ }
26
+
27
+ // 错误示例2:终止条件不完整
28
+ int Fibonacci(int n)
29
+ {
30
+ if (n == 0) return 0; // 只考虑了 n==0 的情况
31
+ return Fibonacci(n - 1) + Fibonacci(n - 2); // 危险:n<0 时无限递归
32
+ }
33
+
34
+ // 错误示例3:终止条件永远无法满足
35
+ void ProcessNode(Node* node)
36
+ {
37
+ if (node == nullptr) return;
38
+ ProcessNode(node); // 危险:传入相同节点,无法终止
39
+ }
40
+
41
+ // 错误示例4:终止条件逻辑错误
42
+ int BinarySearch(int* arr, int left, int right, int target)
43
+ {
44
+ if (left >= right) return -1;
45
+ int mid = (left + right) / 2;
46
+ if (arr[mid] == target) return mid;
47
+ if (arr[mid] > target) {
48
+ return BinarySearch(arr, left, mid, target); // 危险:应该是 mid-1
49
+ }
50
+ return BinarySearch(arr, mid, right, target); // 危险:应该是 mid+1
51
+ }
52
+
53
+ // 错误示例5:深度递归无保护
54
+ void TraverseTree(TreeNode* node)
55
+ {
56
+ if (node == nullptr) return;
57
+ Process(node);
58
+ for (auto child : node->children) {
59
+ TraverseTree(child); // 危险:恶意构造的超深树导致栈溢出
60
+ }
61
+ }
62
+ ```
63
+
64
+ ### ✅ 修复方案
65
+
66
+ ```cpp
67
+ // 正确示例1:添加完整的终止条件
68
+ int CalculateFactorial(int n)
69
+ {
70
+ if (n <= 1) return 1; // 安全:明确的终止条件
71
+ return n * CalculateFactorial(n - 1);
72
+ }
73
+
74
+ // 正确示例2:完整的终止条件处理
75
+ int Fibonacci(int n)
76
+ {
77
+ if (n < 0) { // 安全:处理所有边界情况
78
+ LOGE("Invalid input: n must be non-negative");
79
+ return -1;
80
+ }
81
+ if (n <= 1) return n; // 安全:n==0 和 n==1 都终止
82
+ return Fibonacci(n - 1) + Fibonacci(n - 2);
83
+ }
84
+
85
+ // 正确示例3:正确的递归调用
86
+ void ProcessNode(Node* node)
87
+ {
88
+ if (node == nullptr) return;
89
+ Process(node);
90
+ for (auto child : node->children) {
91
+ ProcessNode(child); // 安全:传入子节点
92
+ }
93
+ }
94
+
95
+ // 正确示例4:修正递归逻辑
96
+ int BinarySearch(int* arr, int left, int right, int target)
97
+ {
98
+ if (left > right) return -1; // 安全:正确的终止条件
99
+ int mid = left + (right - left) / 2;
100
+ if (arr[mid] == target) return mid;
101
+ if (arr[mid] > target) {
102
+ return BinarySearch(arr, left, mid - 1, target); // 安全:排除mid
103
+ }
104
+ return BinarySearch(arr, mid + 1, right, target); // 安全:排除mid
105
+ }
106
+
107
+ // 正确示例5:添加深度限制(实际场景的深度值)
108
+ constexpr int MAX_NESTING_DEPTH = 800; // 实际代码中常用的深度限制
109
+ constexpr int RECORD_CMD_MAX_DEPTH = 800;
110
+
111
+ void TraverseTree(TreeNode* node, int depth = 0)
112
+ {
113
+ if (node == nullptr) return;
114
+ if (depth >= MAX_NESTING_DEPTH) { // 安全:深度保护
115
+ LOGE("Tree depth exceeded limit: %d", depth);
116
+ return;
117
+ }
118
+ Process(node);
119
+ for (auto child : node->children) {
120
+ TraverseTree(child, depth + 1);
121
+ }
122
+ }
123
+
124
+ // 正确示例5b:序列化/反序列化深度检查的两种模式
125
+ bool MarshallingData(Data* data, int& recordCmdDepth)
126
+ {
127
+ if (++recordCmdDepth > RECORD_CMD_MAX_DEPTH) { // Marshalling: 先递增再检查
128
+ ROSEN_LOGE("exceed max depth");
129
+ return false;
130
+ }
131
+ // 序列化处理
132
+ return true;
133
+ }
134
+
135
+ bool UnmarshallingData(Parcel& parcel, int depth)
136
+ {
137
+ if (depth >= MAX_NESTING_DEPTH) { // Unmarshalling: 先检查再处理
138
+ LOGE("depth exceeds maximum limit");
139
+ return false;
140
+ }
141
+ // 反序列化处理
142
+ return true;
143
+ }
144
+
145
+ // 正确示例6:使用迭代替代递归
146
+ int FibonacciIterative(int n)
147
+ {
148
+ if (n < 0) return -1;
149
+ if (n <= 1) return n;
150
+
151
+ int prev = 0, curr = 1;
152
+ for (int i = 2; i <= n; i++) {
153
+ int next = prev + curr;
154
+ prev = curr;
155
+ curr = next;
156
+ }
157
+ return curr; // 安全:无递归风险
158
+ }
159
+
160
+ // 正确示例7:使用Visitor模式替代传统递归
161
+ class RenderVisitor {
162
+ public:
163
+ void PrepareChildren(RSRenderNode& node) {
164
+ for (auto& child : *node.GetSortedChildren()) { // 迭代器遍历
165
+ child->Prepare(shared_from_this()); // visitor调用,避免传统递归
166
+ }
167
+ }
168
+
169
+ void PrepareNode(RSRenderNode& node) {
170
+ if (!canvas_) { return; } // 终止条件1:canvas无效
171
+ if (!node.ShouldPaint()) { return; } // 终止条件2:节点不可见
172
+ // 多重终止条件保护
173
+
174
+ PrepareChildren(node); // 所有条件通过后才遍历子节点
175
+ }
176
+ };
177
+ ```
178
+
179
+ ## 检测范围
180
+
181
+ 检查以下递归模式:
182
+
183
+ 1. 函数直接调用自身的直接递归
184
+ 2. 函数通过其他函数间接调用的间接递归
185
+ 3. 递归函数中缺少`return`语句或条件判断
186
+ 4. 递归终止条件只覆盖部分边界情况
187
+ 5. 递归深度未限制的场景
188
+
189
+ ## 检测要点
190
+
191
+ 1. 识别递归函数:函数体中调用自身或形成调用环
192
+ 2. 检查是否存在终止条件:`if`语句中包含`return`
193
+ 3. 检查终止条件是否充分:覆盖所有可能的输入情况
194
+ 4. 检查递归深度限制:是否存在深度保护机制
195
+ 5. 排除NOPROTECT标记的代码
196
+
197
+ ### 实际深度限制值参考
198
+
199
+ 不同场景需要不同的深度限制:
200
+
201
+ - **数据结构遍历**:100-200(简单树结构)
202
+ - **序列化/反序列化**:800-1000(复杂嵌套对象)
203
+ - **实际代码常用值**:MAX_NESTING_DEPTH = 800, RECORD_CMD_MAX_DEPTH = 800
204
+
205
+ **深度检查的两种模式**:
206
+
207
+ - **Marshalling(序列化)**:`if (++depth > MAX_DEPTH)` - 先递增再检查
208
+ - **Unmarshalling(反序列化)**:`if (depth >= MAX_DEPTH)` - 先检查再处理
209
+
210
+ ### Visitor模式替代传统递归
211
+
212
+ 现代C++常用Visitor模式遍历树结构,避免传统递归:
213
+
214
+ - **优势**:
215
+ - 迭代器遍历子节点,自然终止
216
+ - 不使用传统的函数递归调用
217
+ - 通过迭代器终止条件控制深度
218
+
219
+ - **典型模式**:
220
+ ```cpp
221
+ void PrepareChildren(Node& node) {
222
+ for (auto& child : *node.GetChildren()) { // 迭代器
223
+ child->Prepare(visitor); // visitor调用
224
+ }
225
+ }
226
+ ```
227
+
228
+ - **注意**:Visitor模式虽然避免了传统递归,但仍可能形成间接递归(见规则002)
229
+
230
+ ### 多重终止条件保护
231
+
232
+ 实际代码中常使用多重终止条件:
233
+
234
+ - nullptr检查:`if (!canvas_) return;`
235
+ - 有效性检查:`if (!node.IsValid()) return;`
236
+ - 可见性检查:`if (!node.ShouldPaint()) return;`
237
+ - 安全标志检查:`if (isSecurityDisplay_ && ...) return;`
238
+
239
+ 多重条件可以提前终止,避免深度累积。
240
+
241
+ ## 风险流分析(RiskFlow)
242
+
243
+ - **RISK_SOURCE**: 递归函数中终止条件缺失或条件不充分
244
+ - **RISK_TYPE**: 无限递归风险
245
+ - **RISK_PATH**: 递归调用无法终止 → 栈帧持续增长 → 栈空间耗尽 → 栈溢出
246
+ - **IMPACT_POINT**: 进程崩溃,可能导致服务中断或系统不稳定
247
+
248
+ ## 影响分析(ImpactAnalysis)
249
+
250
+ - **Trigger**: 递归函数被调用时,传入参数导致终止条件无法满足
251
+ - **Propagation**: 每次递归调用消耗栈空间,无终止条件下栈帧持续累积,最终耗尽栈空间
252
+ - **Consequence**: 栈溢出导致SIGSEGV信号,进程异常终止,影响服务可用性
253
+ - **Mitigation**: 添加明确的终止条件,限制递归深度,或使用迭代替代递归
254
+
255
+ ## 误报排除
256
+
257
+ | 场景 | 识别特征 | 处理方式 |
258
+ |------|----------|----------|
259
+ | NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
260
+ | 已有终止条件 | 存在 if-return 模式 | 不报 |
261
+ | 已有深度限制 | 存在 depth/MAX_DEPTH 检查 | 不报 |
262
+ | 尾递归优化 | 尾递归形式且编译器支持 | 谨慎报告 |
263
+ | 第三方库 | 位于 third_party 目录 | 白名单排除 |
264
+ | 测试代码 | 位于 test 目录 | 自动跳过 |
265
+ ## 测试用例
266
+
267
+ ### 触发用例(应该报)
268
+
269
+ ```cpp
270
+ // test_PerformanceStability_001_trigger.cpp
271
+
272
+ // 触发用例1:完全缺少终止条件
273
+ int trigger_bad_1(int n)
274
+ {
275
+ return n * trigger_bad_1(n - 1); // 应该触发:无终止条件
276
+ }
277
+
278
+ // 触发用例2:终止条件不完整
279
+ int trigger_bad_2(int n)
280
+ {
281
+ if (n == 0) return 0; // 应该触发:n<0 时无限递归
282
+ return trigger_bad_2(n - 1) + trigger_bad_2(n - 2);
283
+ }
284
+
285
+ // 触发用例3:终止条件逻辑错误
286
+ int trigger_bad_3(int* arr, int left, int right, int target)
287
+ {
288
+ if (left >= right) return -1;
289
+ int mid = (left + right) / 2;
290
+ if (arr[mid] == target) return mid;
291
+ return trigger_bad_3(arr, left, mid, target); // 应该触发:死循环
292
+ }
293
+
294
+ // 触发用例4:深度递归无保护
295
+ void trigger_bad_4(TreeNode* node)
296
+ {
297
+ if (node == nullptr) return;
298
+ Process(node);
299
+ for (auto child : node->children) {
300
+ trigger_bad_4(child); // 应该触发:无深度限制
301
+ }
302
+ }
303
+
304
+ // 触发用例5:传入相同节点导致无限递归
305
+ void trigger_bad_5(Node* node)
306
+ {
307
+ if (node == nullptr) return;
308
+ Process(node);
309
+ trigger_bad_5(node); // 应该触发:传入相同节点
310
+ }
311
+ ```
312
+
313
+ ### 安全用例(不应该报)
314
+
315
+ ```cpp
316
+ // test_PerformanceStability_001_safe.cpp
317
+ constexpr int MAX_RECURSION_DEPTH = 100;
318
+
319
+ // 安全用例1:完整的终止条件
320
+ int safe_good_1(int n)
321
+ {
322
+ if (n <= 1) return 1; // 安全:完整终止条件
323
+ return n * safe_good_1(n - 1);
324
+ }
325
+
326
+ // 安全用例2:边界条件处理
327
+ int safe_good_2(int n)
328
+ {
329
+ if (n < 0) { // 安全:处理所有边界
330
+ LOGE("Invalid input");
331
+ return -1;
332
+ }
333
+ if (n <= 1) return n;
334
+ return safe_good_2(n - 1) + safe_good_2(n - 2);
335
+ }
336
+
337
+ // 安全用例3:正确的二分查找
338
+ int safe_good_3(int* arr, int left, int right, int target)
339
+ {
340
+ if (left > right) return -1; // 安全:正确终止
341
+ int mid = left + (right - left) / 2;
342
+ if (arr[mid] == target) return mid;
343
+ if (arr[mid] > target) {
344
+ return safe_good_3(arr, left, mid - 1, target);
345
+ }
346
+ return safe_good_3(arr, mid + 1, right, target);
347
+ }
348
+
349
+ // 安全用例4:有深度限制
350
+ void safe_good_4(TreeNode* node, int depth = 0)
351
+ {
352
+ if (node == nullptr) return;
353
+ if (depth > MAX_RECURSION_DEPTH) { // 安全:深度保护
354
+ LOGE("Depth exceeded");
355
+ return;
356
+ }
357
+ Process(node);
358
+ for (auto child : node->children) {
359
+ safe_good_4(child, depth + 1);
360
+ }
361
+ }
362
+
363
+ // 安全用例5:正确的树遍历
364
+ void safe_good_5(TreeNode* node)
365
+ {
366
+ if (node == nullptr) return;
367
+ Process(node);
368
+ for (auto child : node->children) {
369
+ safe_good_5(child); // 安全:传入子节点
370
+ }
371
+ }
372
+
373
+ // NOPROTECT用例:特殊情况
374
+ // NOPROTECT: 递归深度由外部严格控制
375
+ void noprotect_case(int n)
376
+ {
377
+ if (n == 0) return;
378
+ noprotect_case(n - 1);
379
+ }
380
+ ```