@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,445 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_ResourceManagement_005"
|
|
3
|
+
name: "文件描述符泄漏"
|
|
4
|
+
category: "资源管理"
|
|
5
|
+
severity: "HIGH"
|
|
6
|
+
language: ["cpp", "c", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# 文件描述符泄漏
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
文件描述符fd资源需要确保申请和释放一一对应。遗漏释放会造成fd泄露,重复释放会造成double free。文件描述符是操作系统的重要资源,每个进程可打开的文件描述符数量有限,泄漏会导致进程无法打开新文件。
|
|
15
|
+
|
|
16
|
+
## 检测示例
|
|
17
|
+
|
|
18
|
+
### ❌ 问题代码
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
// 场景1:异常分支fd泄漏
|
|
22
|
+
int read_config(const char* path) {
|
|
23
|
+
int fd = open(path, O_RDONLY); // 打开文件描述符
|
|
24
|
+
if (fd < 0) {
|
|
25
|
+
return -1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
char buf[1024];
|
|
29
|
+
ssize_t n = read(fd, buf, sizeof(buf));
|
|
30
|
+
if (n < 0) {
|
|
31
|
+
return -1; // 错误:fd泄漏
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 处理数据...
|
|
35
|
+
close(fd);
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 场景2:多分支fd泄漏
|
|
40
|
+
int process_file(const char* path, int mode) {
|
|
41
|
+
int fd = open(path, mode);
|
|
42
|
+
if (fd < 0) {
|
|
43
|
+
return -1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (mode == O_RDONLY) {
|
|
47
|
+
char buf[100];
|
|
48
|
+
if (read(fd, buf, sizeof(buf)) < 0) {
|
|
49
|
+
return -1; // 错误:fd泄漏
|
|
50
|
+
}
|
|
51
|
+
} else if (mode == O_WRONLY) {
|
|
52
|
+
char data[] = "hello";
|
|
53
|
+
if (write(fd, data, sizeof(data)) < 0) {
|
|
54
|
+
return -1; // 错误:fd泄漏
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
return -1; // 错误:fd泄漏
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
close(fd);
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 场景3:socket fd泄漏
|
|
65
|
+
int connect_server(const char* host, int port) {
|
|
66
|
+
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
67
|
+
if (sock < 0) {
|
|
68
|
+
return -1;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
struct sockaddr_in addr;
|
|
72
|
+
addr.sin_family = AF_INET;
|
|
73
|
+
addr.sin_port = htons(port);
|
|
74
|
+
inet_pton(AF_INET, host, &addr.sin_addr);
|
|
75
|
+
|
|
76
|
+
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
|
77
|
+
return -1; // 错误:sock泄漏
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return sock; // 调用者需要关闭
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 场景4:double close
|
|
84
|
+
void process_data(int fd) {
|
|
85
|
+
char buf[100];
|
|
86
|
+
read(fd, buf, sizeof(buf));
|
|
87
|
+
close(fd);
|
|
88
|
+
// ... 一些代码
|
|
89
|
+
close(fd); // 错误:double close!
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 场景5:pipe fd泄漏
|
|
93
|
+
int create_pipe(int* read_fd, int* write_fd) {
|
|
94
|
+
int fds[2];
|
|
95
|
+
if (pipe(fds) < 0) {
|
|
96
|
+
return -1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
*read_fd = fds[0];
|
|
100
|
+
*write_fd = fds[1];
|
|
101
|
+
|
|
102
|
+
if (*read_fd < 0) {
|
|
103
|
+
return -1; // 错误:fds[0]和fds[1]都泄漏
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### ✅ 修复方案
|
|
111
|
+
|
|
112
|
+
```cpp
|
|
113
|
+
// 修复场景1:使用RAII封装
|
|
114
|
+
class FdGuard {
|
|
115
|
+
public:
|
|
116
|
+
explicit FdGuard(int fd) : fd_(fd) {}
|
|
117
|
+
~FdGuard() { if (fd_ >= 0) close(fd_); }
|
|
118
|
+
int get() const { return fd_; }
|
|
119
|
+
int release() { int tmp = fd_; fd_ = -1; return tmp; }
|
|
120
|
+
private:
|
|
121
|
+
int fd_;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
int read_config(const char* path) {
|
|
125
|
+
int fd = open(path, O_RDONLY);
|
|
126
|
+
if (fd < 0) {
|
|
127
|
+
return -1;
|
|
128
|
+
}
|
|
129
|
+
FdGuard guard(fd); // RAII管理
|
|
130
|
+
|
|
131
|
+
char buf[1024];
|
|
132
|
+
ssize_t n = read(guard.get(), buf, sizeof(buf));
|
|
133
|
+
if (n < 0) {
|
|
134
|
+
return -1; // FdGuard自动关闭
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 修复场景2:统一清理
|
|
141
|
+
int process_file(const char* path, int mode) {
|
|
142
|
+
int fd = open(path, mode);
|
|
143
|
+
if (fd < 0) {
|
|
144
|
+
return -1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
int ret = -1;
|
|
148
|
+
|
|
149
|
+
if (mode == O_RDONLY) {
|
|
150
|
+
char buf[100];
|
|
151
|
+
if (read(fd, buf, sizeof(buf)) >= 0) {
|
|
152
|
+
ret = 0;
|
|
153
|
+
}
|
|
154
|
+
} else if (mode == O_WRONLY) {
|
|
155
|
+
char data[] = "hello";
|
|
156
|
+
if (write(fd, data, sizeof(data)) >= 0) {
|
|
157
|
+
ret = 0;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
close(fd); // 统一清理
|
|
162
|
+
return ret;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 修复场景3:使用unique_fd
|
|
166
|
+
using unique_fd = std::unique_ptr<int, decltype(&close_fd)>;
|
|
167
|
+
|
|
168
|
+
int safe_connect(const char* host, int port) {
|
|
169
|
+
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
170
|
+
if (sock < 0) {
|
|
171
|
+
return -1;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
unique_fd fd_ptr(sock, close_fd);
|
|
175
|
+
|
|
176
|
+
struct sockaddr_in addr;
|
|
177
|
+
addr.sin_family = AF_INET;
|
|
178
|
+
addr.sin_port = htons(port);
|
|
179
|
+
inet_pton(AF_INET, host, &addr.sin_addr);
|
|
180
|
+
|
|
181
|
+
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
|
182
|
+
return -1; // unique_fd自动关闭
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return fd_ptr.release(); // 转移所有权
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 修复场景4:避免double close
|
|
189
|
+
void process_data(int fd) {
|
|
190
|
+
char buf[100];
|
|
191
|
+
read(fd, buf, sizeof(buf));
|
|
192
|
+
close(fd);
|
|
193
|
+
fd = -1; // 设为无效值,防止误用
|
|
194
|
+
// ... 一些代码
|
|
195
|
+
// 不再调用close(fd)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 修复场景5:pipe正确处理
|
|
199
|
+
int create_pipe(int* read_fd, int* write_fd) {
|
|
200
|
+
int fds[2];
|
|
201
|
+
if (pipe(fds) < 0) {
|
|
202
|
+
return -1;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
*read_fd = fds[0];
|
|
206
|
+
*write_fd = fds[1];
|
|
207
|
+
|
|
208
|
+
// 检查有效性
|
|
209
|
+
if (*read_fd < 0 || *write_fd < 0) {
|
|
210
|
+
close(fds[0]);
|
|
211
|
+
close(fds[1]);
|
|
212
|
+
return -1;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 修复场景6:goto统一清理(C风格)
|
|
219
|
+
int read_file_goto(const char* path, char* buf, size_t size) {
|
|
220
|
+
int fd = -1;
|
|
221
|
+
ssize_t n = -1;
|
|
222
|
+
|
|
223
|
+
fd = open(path, O_RDONLY);
|
|
224
|
+
if (fd < 0) {
|
|
225
|
+
goto error;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
n = read(fd, buf, size);
|
|
229
|
+
if (n < 0) {
|
|
230
|
+
goto error;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
close(fd);
|
|
234
|
+
return 0;
|
|
235
|
+
|
|
236
|
+
error:
|
|
237
|
+
if (fd >= 0) {
|
|
238
|
+
close(fd);
|
|
239
|
+
}
|
|
240
|
+
return -1;
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## 检测范围
|
|
245
|
+
|
|
246
|
+
检查以下模式:
|
|
247
|
+
|
|
248
|
+
- `open/openat/socket/accept/creat` 打开的fd
|
|
249
|
+
- `pipe/pipe2` 创建的管道fd
|
|
250
|
+
- `epoll_create/epoll_create1` 创建的epoll fd
|
|
251
|
+
- `inotify_init/signalfd/timerfd_create/eventfd` 等特殊fd
|
|
252
|
+
- 异常分支未关闭fd
|
|
253
|
+
- 重复关闭同一个fd
|
|
254
|
+
|
|
255
|
+
### OpenHarmony特有fd类型
|
|
256
|
+
|
|
257
|
+
OpenHarmony系统中有以下特殊的文件描述符类型:
|
|
258
|
+
|
|
259
|
+
- **Ashmem fd**:匿名共享内存文件描述符
|
|
260
|
+
- 创建:`AshmemCreate()` 或通过Parcel传递
|
|
261
|
+
- 释放:需要调用专门的释放函数,不是简单的close
|
|
262
|
+
- 示例:`int ashmemFd = AshmemCreate("name", size);`
|
|
263
|
+
|
|
264
|
+
- **Parcel fd**:IPC数据传输中的文件描述符
|
|
265
|
+
- 通过Parcel传递的fd,所有权可能转移
|
|
266
|
+
- 接收方需要明确是否负责关闭
|
|
267
|
+
- 示例:`int fd = parcel.ReadFileDescriptor();`
|
|
268
|
+
|
|
269
|
+
- **socketpair fd**:用于IPC通信的socket对
|
|
270
|
+
- 创建:`socketpair()`,返回两个fd
|
|
271
|
+
- 注意两个fd都需要正确管理
|
|
272
|
+
- 示例:`int fds[2]; socketpair(AF_UNIX, SOCK_STREAM, 0, fds);`
|
|
273
|
+
|
|
274
|
+
- **SyncFence fd**:图形系统同步栅栏
|
|
275
|
+
- 通常通过sptr<SyncFence>管理,fd封装在对象内
|
|
276
|
+
- 不应直接操作内部的fd
|
|
277
|
+
- 示例:`sptr<SyncFence> fence = new SyncFence(fd);`
|
|
278
|
+
|
|
279
|
+
### 实际代码示例(从graphic_graphic_2d)
|
|
280
|
+
|
|
281
|
+
```cpp
|
|
282
|
+
// 示例1:使用RAII管理dlopen handle
|
|
283
|
+
void LoadAndUseLibrary() {
|
|
284
|
+
void* handle = dlopen("libname.so", RTLD_NOW);
|
|
285
|
+
if (!handle) {
|
|
286
|
+
ROSEN_LOGE("dlopen failed");
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// 使用库函数
|
|
291
|
+
auto func = dlsym(handle, "function_name");
|
|
292
|
+
if (!func) {
|
|
293
|
+
dlclose(handle); // 异常分支正确关闭
|
|
294
|
+
ROSEN_LOGE("dlsym failed");
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// 正常使用
|
|
299
|
+
dlclose(handle); // 正常关闭
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 示例2:socketpair的正确管理
|
|
303
|
+
bool CreateCommunicationChannel(int& readFd, int& writeFd) {
|
|
304
|
+
int fds[2];
|
|
305
|
+
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
|
|
306
|
+
ROSEN_LOGE("socketpair failed");
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
readFd = fds[0];
|
|
311
|
+
writeFd = fds[1];
|
|
312
|
+
|
|
313
|
+
// 如果后续操作失败,需要关闭两个fd
|
|
314
|
+
if (!SetupChannel(fds[0], fds[1])) {
|
|
315
|
+
close(fds[0]);
|
|
316
|
+
close(fds[1]);
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return true; // 调用者负责关闭readFd和writeFd
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// 示例3:Ashmem fd管理
|
|
324
|
+
void UseAshmem() {
|
|
325
|
+
int ashmemFd = AshmemCreate("shared_memory", 4096);
|
|
326
|
+
if (ashmemFd < 0) {
|
|
327
|
+
ROSEN_LOGE("AshmemCreate failed");
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
void* addr = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);
|
|
332
|
+
if (addr == MAP_FAILED) {
|
|
333
|
+
close(ashmemFd); // mmap失败,关闭fd
|
|
334
|
+
ROSEN_LOGE("mmap failed");
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// 使用共享内存
|
|
339
|
+
munmap(addr, 4096);
|
|
340
|
+
close(ashmemFd); // 使用完成,关闭fd
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## 检测要点
|
|
345
|
+
|
|
346
|
+
1. 识别fd申请操作(open, socket, pipe等)
|
|
347
|
+
2. 追踪fd变量到函数结束
|
|
348
|
+
3. 检查异常返回分支是否关闭fd
|
|
349
|
+
4. 检查是否存在double close
|
|
350
|
+
5. 排除使用RAII封装的情况
|
|
351
|
+
|
|
352
|
+
## 风险流分析(RiskFlow)
|
|
353
|
+
|
|
354
|
+
- **RISK_SOURCE**:打开的文件描述符fd
|
|
355
|
+
- **RISK_TYPE**:资源泄漏/双重释放
|
|
356
|
+
- **RISK_PATH**:open -> 异常返回 -> 未close -> fd泄漏 或 close -> close -> double free
|
|
357
|
+
- **IMPACT_POINT**:系统资源耗尽、进程崩溃
|
|
358
|
+
|
|
359
|
+
## 影响分析(ImpactAnalysis)
|
|
360
|
+
|
|
361
|
+
- **Trigger**:异常分支返回时未关闭fd,或同一fd被关闭两次
|
|
362
|
+
- **Propagation**:文件描述符泄漏累积,或无效内存访问
|
|
363
|
+
- **Consequence**:进程无法打开新文件、系统资源耗尽、程序崩溃
|
|
364
|
+
- **Mitigation**:使用RAII封装(FdGuard/unique_fd)或确保所有分支都调用close
|
|
365
|
+
|
|
366
|
+
## 误报排除
|
|
367
|
+
|
|
368
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
369
|
+
|------|----------|----------|
|
|
370
|
+
| 使用RAII封装 | FdGuard/unique_fd/AutoCloseFd | 不报 |
|
|
371
|
+
| 有close释放 | 异常分支前有close调用 | 不报 |
|
|
372
|
+
| fd作为返回值 | return fd变量 | 不报 |
|
|
373
|
+
| NOPROTECT标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
374
|
+
| 第三方库 | 位于 third_party 目录 | 白名单排除 |
|
|
375
|
+
## 测试用例
|
|
376
|
+
|
|
377
|
+
### 触发用例(应该报)
|
|
378
|
+
|
|
379
|
+
```cpp
|
|
380
|
+
// test_ResourceManagement_005_trigger.cpp
|
|
381
|
+
int trigger_bad_1(const char* path) {
|
|
382
|
+
int fd = open(path, O_RDONLY); // 应该报:fd泄漏
|
|
383
|
+
if (fd < 0) return -1;
|
|
384
|
+
char buf[100];
|
|
385
|
+
if (read(fd, buf, sizeof(buf)) < 0) {
|
|
386
|
+
return -1; // fd泄漏
|
|
387
|
+
}
|
|
388
|
+
close(fd);
|
|
389
|
+
return 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
int trigger_bad_2(const char* host, int port) {
|
|
393
|
+
int sock = socket(AF_INET, SOCK_STREAM, 0); // 应该报:sock泄漏
|
|
394
|
+
if (sock < 0) return -1;
|
|
395
|
+
struct sockaddr_in addr;
|
|
396
|
+
// ...
|
|
397
|
+
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
|
398
|
+
return -1; // sock泄漏
|
|
399
|
+
}
|
|
400
|
+
return sock;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
void trigger_bad_3(int fd) {
|
|
404
|
+
close(fd);
|
|
405
|
+
close(fd); // 应该报:double close
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### 安全用例(不应该报)
|
|
410
|
+
|
|
411
|
+
```cpp
|
|
412
|
+
// test_ResourceManagement_005_safe.cpp
|
|
413
|
+
int safe_good_1(const char* path) {
|
|
414
|
+
int fd = open(path, O_RDONLY);
|
|
415
|
+
if (fd < 0) return -1;
|
|
416
|
+
FdGuard guard(fd); // 安全:RAII管理
|
|
417
|
+
char buf[100];
|
|
418
|
+
if (read(guard.get(), buf, sizeof(buf)) < 0) {
|
|
419
|
+
return -1;
|
|
420
|
+
}
|
|
421
|
+
return 0;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
int safe_good_2(const char* path) {
|
|
425
|
+
int fd = open(path, O_RDONLY);
|
|
426
|
+
if (fd < 0) return -1;
|
|
427
|
+
char buf[100];
|
|
428
|
+
if (read(fd, buf, sizeof(buf)) < 0) {
|
|
429
|
+
close(fd); // 安全:手动关闭
|
|
430
|
+
return -1;
|
|
431
|
+
}
|
|
432
|
+
close(fd);
|
|
433
|
+
return 0;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// NOPROTECT: 测试代码
|
|
437
|
+
int noprotect_case(const char* path) {
|
|
438
|
+
int fd = open(path, O_RDONLY);
|
|
439
|
+
if (read(fd, nullptr, 0) < 0) {
|
|
440
|
+
return -1;
|
|
441
|
+
}
|
|
442
|
+
close(fd);
|
|
443
|
+
return 0;
|
|
444
|
+
}
|
|
445
|
+
```
|