@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,400 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_MemoryStability_004"
3
+ name: "多返回路径资源泄漏"
4
+ category: "内存稳定性"
5
+ severity: "HIGH"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # 多返回路径资源泄漏
11
+
12
+ ## 问题描述
13
+
14
+ 代码使用裸指针 new / malloc 或需显式关闭的资源(句柄、文件描述符、互斥锁)时,在函数存在多条返回路径(早返回、失败分支、异常传播)时未在所有路径上释放,造成内存泄漏、句柄泄漏、锁未释放或 use-after-free / double-free。长时间运行可致 OOM、资源耗尽、死锁,甚至被用作触发崩溃或提权的前提条件。
15
+
16
+ ## 检测示例
17
+
18
+ ### ❌ 问题代码
19
+
20
+ ```cpp
21
+ // 场景1:多条return路径导致内存泄漏
22
+ int ProcessRequest(Request* req)
23
+ {
24
+ char* buffer = (char*)malloc(1024);
25
+ if (req == nullptr) {
26
+ return -1; // 错误:buffer未释放
27
+ }
28
+
29
+ if (req->type == TYPE_INVALID) {
30
+ return -2; // 错误:buffer未释放
31
+ }
32
+
33
+ if (req->size > MAX_SIZE) {
34
+ return -3; // 错误:buffer未释放
35
+ }
36
+
37
+ ProcessBuffer(buffer);
38
+ free(buffer);
39
+ return 0;
40
+ }
41
+
42
+ // 场景2:文件句柄多路径泄漏
43
+ int ReadConfig(const char* path, Config* config)
44
+ {
45
+ FILE* file = fopen(path, "r");
46
+ if (file == nullptr) {
47
+ return -1; // 正确:打开失败,无需关闭
48
+ }
49
+
50
+ if (!ValidateConfig(config)) {
51
+ return -2; // 错误:file未关闭
52
+ }
53
+
54
+ if (!ParseFile(file, config)) {
55
+ return -3; // 错误:file未关闭
56
+ }
57
+
58
+ fclose(file);
59
+ return 0;
60
+ }
61
+
62
+ // 场景3:互斥锁多路径未释放
63
+ void ProcessSharedData(pthread_mutex_t* mutex, Data* data)
64
+ {
65
+ pthread_mutex_lock(mutex);
66
+
67
+ if (data == nullptr) {
68
+ return; // 错误:锁未释放,其他线程无法获取
69
+ }
70
+
71
+ if (!ValidateData(data)) {
72
+ return; // 错误:锁未释放
73
+ }
74
+
75
+ UpdateData(data);
76
+ pthread_mutex_unlock(mutex);
77
+ }
78
+
79
+ // 场景4:动态库句柄泄漏
80
+ void* LoadFunction(const char* libPath, const char* funcName)
81
+ {
82
+ void* handle = dlopen(libPath, RTLD_NOW);
83
+ if (handle == nullptr) {
84
+ return nullptr; // 正确:打开失败,无需关闭
85
+ }
86
+
87
+ if (!ValidatePath(funcName)) {
88
+ return nullptr; // 错误:handle未关闭
89
+ }
90
+
91
+ void* func = dlsym(handle, funcName);
92
+ if (func == nullptr) {
93
+ return nullptr; // 错误:handle未关闭
94
+ }
95
+
96
+ return func;
97
+ }
98
+
99
+ // 场景5:嵌套条件多路径泄漏
100
+ int HandleCommand(Command* cmd)
101
+ {
102
+ int* temp = new int[256];
103
+
104
+ if (cmd == nullptr) {
105
+ return -1; // 错误:temp未释放
106
+ }
107
+
108
+ if (cmd->type == CMD_EXIT) {
109
+ return -2; // 错误:temp未释放
110
+ }
111
+
112
+ if (cmd->type == CMD_RESET) {
113
+ if (!ResetSystem()) {
114
+ return -3; // 错误:temp未释放
115
+ }
116
+ }
117
+
118
+ ProcessCommand(cmd, temp);
119
+ delete[] temp;
120
+ return 0;
121
+ }
122
+ ```
123
+
124
+ ### ✅ 修复方案
125
+
126
+ ```cpp
127
+ // 修复场景1:使用智能指针自动管理内存
128
+ int ProcessRequest(Request* req)
129
+ {
130
+ std::unique_ptr<char[]> buffer = std::make_unique<char[]>(1024);
131
+ if (req == nullptr) {
132
+ return -1; // 安全:智能指针自动释放
133
+ }
134
+
135
+ if (req->type == TYPE_INVALID) {
136
+ return -2; // 安全:智能指针自动释放
137
+ }
138
+
139
+ if (req->size > MAX_SIZE) {
140
+ return -3; // 安全:智能指针自动释放
141
+ }
142
+
143
+ ProcessBuffer(buffer.get());
144
+ return 0; // 安全:智能指针自动释放
145
+ }
146
+
147
+ // 修复场景2:使用RAII管理文件句柄
148
+ int ReadConfig(const char* path, Config* config)
149
+ {
150
+ std::ifstream file(path);
151
+ if (!file.is_open()) {
152
+ return -1; // 安全:ifstream自动关闭
153
+ }
154
+
155
+ if (!ValidateConfig(config)) {
156
+ return -2; // 安全:ifstream自动关闭
157
+ }
158
+
159
+ if (!ParseFile(file, config)) {
160
+ return -3; // 安全:ifstream自动关闭
161
+ }
162
+
163
+ return 0; // 安全:ifstream自动关闭
164
+ }
165
+
166
+ // 修复场景3:使用锁守卫自动释放
167
+ void ProcessSharedData(pthread_mutex_t* mutex, Data* data)
168
+ {
169
+ std::lock_guard<std::mutex> lock(*mutex); // RAII锁管理
170
+
171
+ if (data == nullptr) {
172
+ return; // 安全:lock_guard自动释放锁
173
+ }
174
+
175
+ if (!ValidateData(data)) {
176
+ return; // 安全:lock_guard自动释放锁
177
+ }
178
+
179
+ UpdateData(data);
180
+ }
181
+
182
+ // 修复场景4:使用统一清理点
183
+ void* LoadFunction(const char* libPath, const char* funcName)
184
+ {
185
+ void* handle = dlopen(libPath, RTLD_NOW);
186
+ if (handle == nullptr) {
187
+ return nullptr;
188
+ }
189
+
190
+ void* func = nullptr;
191
+
192
+ if (ValidatePath(funcName)) {
193
+ func = dlsym(handle, funcName);
194
+ }
195
+
196
+ if (func == nullptr) {
197
+ dlclose(handle); // 正确:统一清理点
198
+ return nullptr;
199
+ }
200
+
201
+ return func;
202
+ }
203
+
204
+ // 修复场景5:使用do-while(0)统一出口
205
+ int HandleCommand(Command* cmd)
206
+ {
207
+ int* temp = new int[256];
208
+ int result = 0;
209
+
210
+ do {
211
+ if (cmd == nullptr) {
212
+ result = -1;
213
+ break; // 正确:跳转到统一释放点
214
+ }
215
+
216
+ if (cmd->type == CMD_EXIT) {
217
+ result = -2;
218
+ break; // 正确:跳转到统一释放点
219
+ }
220
+
221
+ if (cmd->type == CMD_RESET) {
222
+ if (!ResetSystem()) {
223
+ result = -3;
224
+ break; // 正确:跳转到统一释放点
225
+ }
226
+ }
227
+
228
+ ProcessCommand(cmd, temp);
229
+ } while (0);
230
+
231
+ delete[] temp;
232
+ return result;
233
+ }
234
+
235
+ // 修复场景6:使用lambda封装资源清理
236
+ void ProcessFile(const char* path)
237
+ {
238
+ auto cleanup = [](FILE* f) { if (f) fclose(f); };
239
+ FILE* file = fopen(path, "r");
240
+ std::unique_ptr<FILE, decltype(cleanup)> fileGuard(file, cleanup);
241
+
242
+ if (!file) {
243
+ return; // 安全:fileGuard调用cleanup
244
+ }
245
+
246
+ ProcessData(file);
247
+ }
248
+ ```
249
+
250
+ ## 检测范围
251
+
252
+ 检查以下模式:
253
+
254
+ 1. **malloc/calloc/realloc** 在多条return路径未释放
255
+ 2. **new** 在多条return路径未释放(非智能指针)
256
+ 3. **文件句柄**(fopen、open)在多条return路径未关闭
257
+ 4. **动态库句柄**(dlopen)在多条return路径未关闭
258
+ 5. **互斥锁**(pthread_mutex_lock)在多条return路径未释放
259
+ 6. **数据库连接**在多条return路径未关闭
260
+ 7. **socket描述符**在多条return路径未关闭
261
+
262
+ ## 检测要点
263
+
264
+ 1. 识别资源分配函数调用(malloc、new、fopen、dlopen、pthread_mutex_lock等)
265
+ 2. 构建函数控制流图,识别所有退出点(return、break、continue)
266
+ 3. 在分配点和每个退出点之间检查是否存在释放操作
267
+ 4. 排除智能指针、RAII类、容器存储等自动管理场景
268
+ 5. 排除NOPROTECT标记场景
269
+
270
+ ## 风险流分析(RiskFlow)
271
+
272
+ - **RISK_SOURCE**:手动管理的资源(内存、句柄、锁)
273
+ - **RISK_TYPE**:资源泄漏
274
+ - **RISK_PATH**:资源分配 → 异常分支提前退出 → 跳过释放 → 资源累积泄漏 → OOM/资源耗尽/死锁
275
+ - **IMPACT_POINT**:系统资源耗尽,服务不可用,系统崩溃
276
+
277
+ ## 影响分析(ImpactAnalysis)
278
+
279
+ - **Trigger**:异常条件触发分支退出,跳过资源释放代码
280
+ - **Propagation**:分配的资源成为孤儿资源,无法被释放,累积占用系统资源
281
+ - **Consequence**:内存泄漏导致OOM,句柄泄漏导致资源耗尽,锁未释放导致死锁
282
+ - **Mitigation**:使用RAII智能指针、锁守卫、文件流等自动管理资源
283
+
284
+ ## 误报排除
285
+
286
+ | 场景 | 识别特征 | 处理方式 |
287
+ |------|----------|----------|
288
+ | 使用智能指针 | unique_ptr/shared_ptr/make_unique | 不报 |
289
+ | 使用RAII类 | ifstream/ofstream/lock_guard | 不报 |
290
+ | 存入容器 | vector/push_back/insert | 不报 |
291
+ | 赋值给成员变量 | this->/m_xxx | 不报 |
292
+ | NOPROTECT标记 | // NOPROTECT 注释 | 不报 |
293
+ | 全局/静态变量 | static/global | 不报 |
294
+ | 测试代码 | 文件名包含 _test.cpp | 白名单排除 |
295
+ ## 测试用例
296
+
297
+ ### 触发用例(应该报)
298
+
299
+ ```cpp
300
+ // test_MemoryStability_004_trigger.cpp
301
+ #include <cstdlib>
302
+ #include <cstdio>
303
+ #include <dlfcn.h>
304
+ #include <pthread.h>
305
+
306
+ void trigger_bad_1(Request* req)
307
+ {
308
+ char* buffer = (char*)malloc(1024);
309
+ if (req == nullptr) {
310
+ return; // 应该报:malloc后提前return未释放
311
+ }
312
+ free(buffer);
313
+ }
314
+
315
+ void trigger_bad_2(const char* path, Config* config)
316
+ {
317
+ FILE* file = fopen(path, "r");
318
+ if (!ValidateConfig(config)) {
319
+ return; // 应该报:fopen后提前return未关闭
320
+ }
321
+ fclose(file);
322
+ }
323
+
324
+ void trigger_bad_3(pthread_mutex_t* mutex)
325
+ {
326
+ pthread_mutex_lock(mutex);
327
+ if (condition) {
328
+ return; // 应该报:锁未释放
329
+ }
330
+ pthread_mutex_unlock(mutex);
331
+ }
332
+
333
+ void* trigger_bad_4(const char* libPath)
334
+ {
335
+ void* handle = dlopen(libPath, RTLD_NOW);
336
+ if (!condition) {
337
+ return nullptr; // 应该报:dlopen后未关闭
338
+ }
339
+ dlclose(handle);
340
+ return nullptr;
341
+ }
342
+ ```
343
+
344
+ ### 安全用例(不应该报)
345
+
346
+ ```cpp
347
+ // test_MemoryStability_004_safe.cpp
348
+ #include <cstdlib>
349
+ #include <memory>
350
+ #include <fstream>
351
+ #include <mutex>
352
+
353
+ void safe_good_1(Request* req)
354
+ {
355
+ std::unique_ptr<char[]> buffer = std::make_unique<char[]>(1024);
356
+ if (req == nullptr) {
357
+ return; // 安全:智能指针自动释放
358
+ }
359
+ }
360
+
361
+ void safe_good_2(const char* path)
362
+ {
363
+ std::ifstream file(path);
364
+ if (!file.is_open()) {
365
+ return; // 安全:ifstream自动关闭
366
+ }
367
+ }
368
+
369
+ void safe_good_3(pthread_mutex_t* mutex)
370
+ {
371
+ std::lock_guard<std::mutex> lock(*mutex);
372
+ if (condition) {
373
+ return; // 安全:lock_guard自动释放
374
+ }
375
+ }
376
+
377
+ void safe_good_4(int* temp)
378
+ {
379
+ int result = 0;
380
+
381
+ do {
382
+ if (condition) {
383
+ result = -1;
384
+ break; // 安全:跳转到统一释放点
385
+ }
386
+ } while (0);
387
+
388
+ delete[] temp;
389
+ }
390
+
391
+ // NOPROTECT: 特殊场景
392
+ void noprotect_case()
393
+ {
394
+ char* buffer = (char*)malloc(1024);
395
+ if (condition) {
396
+ return; // NOPROTECT标记,不报
397
+ }
398
+ free(buffer);
399
+ }
400
+ ```