@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,425 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_ResourceManagement_002"
3
+ name: "dlopen需配对dlclose"
4
+ category: "资源管理"
5
+ severity: "HIGH"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # dlopen需配对dlclose
11
+
12
+ ## 问题描述
13
+
14
+ 使用dlopen动态加载共享库函数后,需要使用dlclose进行关闭,否则存在资源泄露。未关闭的动态库会占用系统资源,多次加载但不关闭会导致资源累积,影响系统稳定性。
15
+
16
+ ## 检测示例
17
+
18
+ ### ❌ 问题代码
19
+
20
+ ```cpp
21
+ // 场景1:dlopen后未dlclose
22
+ void LoadAndCallFunction()
23
+ {
24
+ void* handle = dlopen("libplugin.so", RTLD_NOW);
25
+ if (handle == nullptr) {
26
+ LOGE("dlopen failed: %s", dlerror());
27
+ return;
28
+ }
29
+
30
+ void* func = dlsym(handle, "plugin_func");
31
+ if (func == nullptr) {
32
+ LOGE("dlsym failed: %s", dlerror());
33
+ return; // 错误:handle未关闭
34
+ }
35
+
36
+ ((void(*)())func)();
37
+ // 错误:函数执行后handle未关闭
38
+ }
39
+
40
+ // 场景2:异常分支未关闭
41
+ typedef int (*PluginFunc)(int);
42
+
43
+ int CallPlugin(const char* libPath, int param)
44
+ {
45
+ void* handle = dlopen(libPath, RTLD_NOW);
46
+ if (!handle) {
47
+ return -1; // 正确:dlopen失败无需关闭
48
+ }
49
+
50
+ PluginFunc func = (PluginFunc)dlsym(handle, "process");
51
+ if (!func) {
52
+ LOGE("dlsym failed");
53
+ return -1; // 错误:handle未关闭
54
+ }
55
+
56
+ int result = func(param);
57
+ if (result < 0) {
58
+ LOGE("Plugin execution failed");
59
+ return -1; // 错误:handle未关闭
60
+ }
61
+
62
+ return result; // 错误:handle未关闭
63
+ }
64
+
65
+ // 场景3:多次dlopen未配对关闭
66
+ class PluginManager {
67
+ private:
68
+ std::vector<void*> handles_;
69
+
70
+ public:
71
+ bool LoadPlugins(const std::vector<std::string>& paths) {
72
+ for (const auto& path : paths) {
73
+ void* handle = dlopen(path.c_str(), RTLD_NOW);
74
+ if (handle) {
75
+ handles_.push_back(handle);
76
+ }
77
+ // 错误:即使失败,已加载的handles未在析构时关闭
78
+ }
79
+ return !handles_.empty();
80
+ }
81
+
82
+ // 错误:缺少析构函数关闭handles
83
+ };
84
+
85
+ // 场景4:全局变量持有handle未关闭
86
+ void* g_pluginHandle = nullptr;
87
+
88
+ bool InitPlugin()
89
+ {
90
+ g_pluginHandle = dlopen("libservice.so", RTLD_NOW);
91
+ if (!g_pluginHandle) {
92
+ return false;
93
+ }
94
+ return true;
95
+ // 错误:全局handle从未关闭
96
+ }
97
+
98
+ // 场景5:循环中dlopen未关闭
99
+ void ProcessMultiplePlugins(const std::vector<std::string>& paths)
100
+ {
101
+ for (const auto& path : paths) {
102
+ void* handle = dlopen(path.c_str(), RTLD_NOW);
103
+ if (handle) {
104
+ void* func = dlsym(handle, "execute");
105
+ if (func) {
106
+ ((void(*)())func)();
107
+ }
108
+ // 错误:每次循环handle未关闭
109
+ }
110
+ }
111
+ }
112
+
113
+ // 场景6:条件分支未关闭
114
+ void LoadPluginWithOptions(const char* path, bool useLazy)
115
+ {
116
+ int flags = useLazy ? RTLD_LAZY : RTLD_NOW;
117
+ void* handle = dlopen(path, flags);
118
+ if (!handle) {
119
+ return;
120
+ }
121
+
122
+ if (useLazy) {
123
+ // 懒加载场景
124
+ void* func = dlsym(handle, "lazy_init");
125
+ if (!func) {
126
+ return; // 错误:handle未关闭
127
+ }
128
+ ((void(*)())func)();
129
+ } else {
130
+ // 立即加载场景
131
+ void* func = dlsym(handle, "init");
132
+ ((void(*)())func)();
133
+ // 错误:handle未关闭
134
+ }
135
+ }
136
+ ```
137
+
138
+ ### ✅ 修复方案
139
+
140
+ ```cpp
141
+ // 修复场景1:正确配对dlclose
142
+ void LoadAndCallFunction()
143
+ {
144
+ void* handle = dlopen("libplugin.so", RTLD_NOW);
145
+ if (handle == nullptr) {
146
+ LOGE("dlopen failed: %s", dlerror());
147
+ return;
148
+ }
149
+
150
+ void* func = dlsym(handle, "plugin_func");
151
+ if (func == nullptr) {
152
+ LOGE("dlsym failed: %s", dlerror());
153
+ dlclose(handle); // 正确:dlsym失败时关闭
154
+ return;
155
+ }
156
+
157
+ ((void(*)())func)();
158
+ dlclose(handle); // 正确:函数执行后关闭
159
+ }
160
+
161
+ // 修复场景2:所有分支正确关闭
162
+ typedef int (*PluginFunc)(int);
163
+
164
+ int CallPlugin(const char* libPath, int param)
165
+ {
166
+ void* handle = dlopen(libPath, RTLD_NOW);
167
+ if (!handle) {
168
+ return -1;
169
+ }
170
+
171
+ PluginFunc func = (PluginFunc)dlsym(handle, "process");
172
+ if (!func) {
173
+ LOGE("dlsym failed");
174
+ dlclose(handle); // 正确:dlsym失败时关闭
175
+ return -1;
176
+ }
177
+
178
+ int result = func(param);
179
+ dlclose(handle); // 正确:执行完成后关闭
180
+
181
+ if (result < 0) {
182
+ LOGE("Plugin execution failed");
183
+ return -1;
184
+ }
185
+
186
+ return result;
187
+ }
188
+
189
+ // 修复场景3:RAII封装管理
190
+ class DlHandle {
191
+ private:
192
+ void* handle_;
193
+
194
+ public:
195
+ explicit DlHandle(const char* path, int flags = RTLD_NOW)
196
+ : handle_(dlopen(path, flags)) {}
197
+
198
+ ~DlHandle() {
199
+ if (handle_) {
200
+ dlclose(handle_);
201
+ }
202
+ }
203
+
204
+ bool IsValid() const { return handle_ != nullptr; }
205
+ void* Get() const { return handle_; }
206
+ void* Sym(const char* name) const { return dlsym(handle_, name); }
207
+
208
+ DlHandle(const DlHandle&) = delete;
209
+ DlHandle& operator=(const DlHandle&) = delete;
210
+ };
211
+
212
+ void UsePluginRAII()
213
+ {
214
+ DlHandle handle("libplugin.so");
215
+ if (!handle.IsValid()) {
216
+ LOGE("dlopen failed");
217
+ return; // 自动关闭
218
+ }
219
+
220
+ auto func = handle.Sym("plugin_func");
221
+ if (func) {
222
+ ((void(*)())func)();
223
+ }
224
+ // 自动关闭
225
+ }
226
+
227
+ // 修复场景4:PluginManager正确析构
228
+ class PluginManager {
229
+ private:
230
+ std::vector<void*> handles_;
231
+
232
+ public:
233
+ ~PluginManager() {
234
+ for (void* handle : handles_) {
235
+ if (handle) {
236
+ dlclose(handle);
237
+ }
238
+ }
239
+ }
240
+
241
+ bool LoadPlugins(const std::vector<std::string>& paths) {
242
+ for (const auto& path : paths) {
243
+ void* handle = dlopen(path.c_str(), RTLD_NOW);
244
+ if (handle) {
245
+ handles_.push_back(handle);
246
+ }
247
+ }
248
+ return !handles_.empty();
249
+ }
250
+ };
251
+
252
+ // 修复场景5:全局变量使用RAII或提供清理函数
253
+ class GlobalPluginHandle {
254
+ private:
255
+ void* handle_;
256
+
257
+ public:
258
+ GlobalPluginHandle() : handle_(nullptr) {}
259
+
260
+ ~GlobalPluginHandle() {
261
+ Close();
262
+ }
263
+
264
+ bool Open(const char* path) {
265
+ Close(); // 先关闭之前的
266
+ handle_ = dlopen(path, RTLD_NOW);
267
+ return handle_ != nullptr;
268
+ }
269
+
270
+ void Close() {
271
+ if (handle_) {
272
+ dlclose(handle_);
273
+ handle_ = nullptr;
274
+ }
275
+ }
276
+
277
+ void* Get() { return handle_; }
278
+ };
279
+
280
+ GlobalPluginHandle g_pluginHandle;
281
+
282
+ bool InitPlugin()
283
+ {
284
+ return g_pluginHandle.Open("libservice.so");
285
+ }
286
+
287
+ // 修复场景6:循环中每次关闭
288
+ void ProcessMultiplePlugins(const std::vector<std::string>& paths)
289
+ {
290
+ for (const auto& path : paths) {
291
+ void* handle = dlopen(path.c_str(), RTLD_NOW);
292
+ if (handle) {
293
+ void* func = dlsym(handle, "execute");
294
+ if (func) {
295
+ ((void(*)())func)();
296
+ }
297
+ dlclose(handle); // 正确:每次循环都关闭
298
+ }
299
+ }
300
+ }
301
+
302
+ // 修复场景7:使用goto统一清理
303
+ void LoadPluginWithOptionsGoto(const char* path, bool useLazy)
304
+ {
305
+ void* handle = nullptr;
306
+
307
+ int flags = useLazy ? RTLD_LAZY : RTLD_NOW;
308
+ handle = dlopen(path, flags);
309
+ if (!handle) {
310
+ goto cleanup;
311
+ }
312
+
313
+ if (useLazy) {
314
+ void* func = dlsym(handle, "lazy_init");
315
+ if (!func) {
316
+ goto cleanup;
317
+ }
318
+ ((void(*)())func)();
319
+ } else {
320
+ void* func = dlsym(handle, "init");
321
+ ((void(*)())func)();
322
+ }
323
+
324
+ cleanup:
325
+ if (handle) {
326
+ dlclose(handle);
327
+ }
328
+ }
329
+ ```
330
+
331
+ ## 检测范围
332
+
333
+ 检查以下API调用:
334
+
335
+ - `dlopen()` 动态库加载
336
+ - `dlclose()` 动态库关闭
337
+ - `dlsym()` 符号查找
338
+
339
+ ## 检测要点
340
+
341
+ 1. 检测`dlopen`调用并记录handle变量
342
+ 2. 追踪handle变量的生命周期
343
+ 3. 检查函数结束时是否有对应的`dlclose`
344
+ 4. 检查所有异常返回分支是否有`dlclose`
345
+ 5. 排除使用RAII封装类的情况
346
+
347
+ ## 风险流分析(RiskFlow)
348
+
349
+ - **RISK_SOURCE**:dlopen打开的动态库handle
350
+ - **RISK_TYPE**:动态库资源泄露
351
+ - **RISK_PATH**:dlopen -> 未dlclose -> handle泄露 -> 系统资源占用
352
+ - **IMPACT_POINT**:系统资源耗尽、内存增长
353
+
354
+ ## 影响分析(ImpactAnalysis)
355
+
356
+ - **Trigger**:使用dlopen加载动态库但未配对dlclose
357
+ - **Propagation**:多次加载累积,系统资源持续占用
358
+ - **Consequence**:内存增长、文件描述符泄漏、系统不稳定
359
+ - **Mitigation**:确保dlopen/dlclose配对使用,或使用RAII封装
360
+
361
+ ## 误报排除
362
+
363
+ | 场景 | 识别特征 | 处理方式 |
364
+ |------|----------|----------|
365
+ | 有dlclose配对 | 存在dlclose调用 | 不报 |
366
+ | RAII封装 | DlHandle/ScopeDl类 | 不报 |
367
+ | 全局管理类 | 有析构函数管理 | 不报 |
368
+ | NOPROTECT标记 | 有 // NOPROTECT 注释 | 不报 |
369
+ | 第三方库 | 位于 third_party 目录 | 白名单排除 |
370
+ ## 测试用例
371
+
372
+ ### 触发用例(应该报)
373
+
374
+ ```cpp
375
+ // test_ResourceManagement_002_trigger.cpp
376
+ void trigger_bad_1()
377
+ {
378
+ void* handle = dlopen("lib.so", RTLD_NOW); // 应该报:无dlclose
379
+ if (!handle) return;
380
+
381
+ auto func = dlsym(handle, "func");
382
+ if (func) ((void(*)())func)();
383
+ }
384
+
385
+ int trigger_bad_2(const char* path)
386
+ {
387
+ void* h = dlopen(path, RTLD_LAZY);
388
+ if (!h) return -1;
389
+
390
+ if (!dlsym(h, "entry")) {
391
+ return -1; // 应该报:异常返回未dlclose
392
+ }
393
+ return 0; // 应该报:正常返回也未dlclose
394
+ }
395
+ ```
396
+
397
+ ### 安全用例(不应该报)
398
+
399
+ ```cpp
400
+ // test_ResourceManagement_002_safe.cpp
401
+ void safe_good_1()
402
+ {
403
+ void* handle = dlopen("lib.so", RTLD_NOW);
404
+ if (!handle) return;
405
+
406
+ auto func = dlsym(handle, "func");
407
+ if (func) ((void(*)())func)();
408
+
409
+ dlclose(handle); // 安全:有dlclose
410
+ }
411
+
412
+ void safe_good_2()
413
+ {
414
+ DlHandle handle("lib.so"); // 安全:RAII封装
415
+ if (!handle.IsValid()) return;
416
+
417
+ auto func = handle.Sym("func");
418
+ if (func) ((void(*)())func)();
419
+ // 自动关闭
420
+ }
421
+
422
+ // NOPROTECT: 特殊场景
423
+ // NOPROTECT: 长期持有的插件handle
424
+ void* g_handle = dlopen("lib.so", RTLD_NOW);
425
+ ```