@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.
- package/README.md +169 -0
- package/SKILL.md +518 -0
- package/bin/install.js +165 -0
- package/config/rules.yaml +445 -0
- package/config/whitelist.yaml +52 -0
- package/package.json +40 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_001.md +275 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_002.md +273 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_003.md +305 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_004.md +350 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_005.md +301 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_006.md +320 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_007.md +432 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_008.md +394 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_009.md +425 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_010.md +472 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_011.md +204 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_012.md +210 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_013.md +226 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_014.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_015.md +256 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_016.md +269 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_017.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_018.md +336 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_001.md +414 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_002.md +335 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_003.md +284 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_004.md +313 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_005.md +364 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_001.md +142 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_002.md +222 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_003.md +383 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_001.md +258 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_002.md +131 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_003.md +220 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_004.md +224 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_005.md +250 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_006.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_007.md +169 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_008.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_009.md +144 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_010.md +152 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_011.md +221 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_012.md +318 -0
- package/references/InitializationOrder/StabilityCodeReview_InitializationOrder_001.md +411 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_001.md +255 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_002.md +177 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_001.md +332 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_002.md +261 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_003.md +428 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_004.md +400 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_005.md +364 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_006.md +359 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_007.md +279 -0
- package/references/PROBLEM_TEMPLATE.md +65 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_001.md +380 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_002.md +437 -0
- package/references/REPORT_TEMPLATE.csv +5 -0
- package/references/REPORT_TEMPLATE.md +132 -0
- package/references/RULE_DEVELOPMENT_GUIDE.md +711 -0
- package/references/RULE_INDEX.md +101 -0
- package/references/RULE_TEMPLATE.md +192 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_001.md +334 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_002.md +425 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_003.md +420 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_004.md +409 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_005.md +445 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_006.md +384 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_007.md +395 -0
- 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
|
+
```
|