@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,261 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_MemoryStability_002"
3
+ name: "指针解引用前判空"
4
+ category: "内存稳定性"
5
+ severity: "CRITICAL"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # 指针解引用前判空
11
+
12
+ ## 问题描述
13
+
14
+ 对指针进行解引用操作(*ptr、ptr->、ptr[index])前未进行空指针检查,可能导致空指针解引用崩溃(SIGSEGV)。这是OpenHarmony系统中最常见的稳定性问题之一,会导致服务崩溃、用户数据丢失。
15
+
16
+ ## 检测示例
17
+
18
+ ### ❌ 问题代码
19
+
20
+ ```cpp
21
+ // 场景1:函数参数指针未判空直接解引用
22
+ void ProcessData(Data* data)
23
+ {
24
+ data->Process(); // 错误:未判空直接使用成员
25
+ data->value = 100;
26
+ }
27
+
28
+ // 场景2:返回值指针未判空
29
+ void HandleResult()
30
+ {
31
+ Result* result = GetResult();
32
+ result->Print(); // 错误:GetResult可能返回nullptr
33
+ }
34
+
35
+ // 场景3:数组指针未判空访问元素
36
+ void ProcessArray(int* arr, int size)
37
+ {
38
+ for (int i = 0; i < size; i++) {
39
+ arr[i] = i * 2; // 错误:arr可能为nullptr
40
+ }
41
+ }
42
+
43
+ // 场景4:链式指针解引用
44
+ void ChainAccess(Node* node)
45
+ {
46
+ node->next->value = 100; // 错误:node或node->next可能为nullptr
47
+ }
48
+
49
+ // 场景5:智能指针get()后未判空
50
+ void SmartPtrGet()
51
+ {
52
+ std::unique_ptr<Data> ptr = GetData();
53
+ Data* raw = ptr.get();
54
+ raw->Process(); // 错误:ptr可能为空,raw为nullptr
55
+ }
56
+
57
+ // 场景6:条件分支遗漏判空
58
+ void ConditionalAccess(Data* data, bool flag)
59
+ {
60
+ if (flag) {
61
+ data->Process(); // 错误:即使flag=true,data可能仍为nullptr
62
+ }
63
+ }
64
+ ```
65
+
66
+ ### ✅ 修复方案
67
+
68
+ ```cpp
69
+ // 修复场景1:函数参数判空
70
+ void ProcessData(Data* data)
71
+ {
72
+ if (data == nullptr) { // 正确:入口判空
73
+ LOGE("data is nullptr");
74
+ return;
75
+ }
76
+ data->Process();
77
+ data->value = 100;
78
+ }
79
+
80
+ // 修复场景2:返回值判空
81
+ void HandleResult()
82
+ {
83
+ Result* result = GetResult();
84
+ if (result == nullptr) { // 正确:判空后使用
85
+ LOGE("GetResult failed");
86
+ return;
87
+ }
88
+ result->Print();
89
+ }
90
+
91
+ // 修复场景3:数组指针判空
92
+ void ProcessArray(int* arr, int size)
93
+ {
94
+ if (arr == nullptr || size <= 0) { // 正确:判空+边界检查
95
+ LOGE("Invalid array parameters");
96
+ return;
97
+ }
98
+ for (int i = 0; i < size; i++) {
99
+ arr[i] = i * 2;
100
+ }
101
+ }
102
+
103
+ // 修复场景4:链式指针逐级判空
104
+ void ChainAccess(Node* node)
105
+ {
106
+ if (node == nullptr) { // 正确:第一级判空
107
+ return;
108
+ }
109
+ if (node->next == nullptr) { // 正确:第二级判空
110
+ return;
111
+ }
112
+ node->next->value = 100;
113
+ }
114
+
115
+ // 修复场景5:智能指针直接使用
116
+ void SmartPtrGet()
117
+ {
118
+ std::unique_ptr<Data> ptr = GetData();
119
+ if (!ptr) { // 正确:智能指针判空
120
+ LOGE("GetData returned empty");
121
+ return;
122
+ }
123
+ ptr->Process(); // 直接使用智能指针,无需get()
124
+ }
125
+
126
+ // 修复场景6:条件分支中判空
127
+ void ConditionalAccess(Data* data, bool flag)
128
+ {
129
+ if (data == nullptr) { // 正确:先判空
130
+ return;
131
+ }
132
+ if (flag) {
133
+ data->Process(); // 安全:已判空
134
+ }
135
+ }
136
+
137
+ // 修复场景7:使用assert断言(调试阶段)
138
+ void DebugAssert(Data* data)
139
+ {
140
+ assert(data != nullptr && "data must not be nullptr");
141
+ data->Process(); // 注意:assert在生产环境可能被禁用
142
+ }
143
+
144
+ // 修复场景8:使用引用代替指针
145
+ void UseReference(Data& data)
146
+ {
147
+ data.Process(); // 安全:引用不能为空
148
+ }
149
+ ```
150
+
151
+ ## 检测范围
152
+
153
+ 检查以下模式:
154
+
155
+ - 指针参数在函数入口未判空直接解引用
156
+ - 返回值指针未判空直接解引用
157
+ - 数组指针未判空直接访问元素
158
+ - 链式指针解引用(ptr->member->subMember)
159
+ - 智能指针get()返回的裸指针未判空
160
+ - 条件分支中遗漏的判空
161
+
162
+ ## 检测要点
163
+
164
+ 1. 识别指针变量(通过类型声明或推断)
165
+ 2. 检测解引用操作(->、*、[index])
166
+ 3. 向上搜索是否有判空语句(if ptr == nullptr 等)
167
+ 4. 检查是否在判空保护范围内
168
+ 5. 排除NOPROTECT标记和引用类型
169
+
170
+ ## 风险流分析(RiskFlow)
171
+
172
+ - **RISK_SOURCE**:可能为nullptr的指针变量
173
+ - **RISK_TYPE**:空指针解引用(SIGSEGV)
174
+ - **RISK_PATH**:指针为nullptr -> 未判空解引用 -> 内存访问违规 -> 程序崩溃
175
+ - **IMPACT_POINT**:进程崩溃、服务中断、系统不稳定
176
+
177
+ ## 影响分析(ImpactAnalysis)
178
+
179
+ - **Trigger**:指针值为nullptr时执行解引用操作
180
+ - **Propagation**:访问非法内存地址(0x0或附近)
181
+ - **Consequence**:SIGSEGV信号导致进程终止,服务崩溃
182
+ - **Mitigation**:解引用前强制判空,或使用引用/智能指针
183
+
184
+ ## 误报排除
185
+
186
+ | 场景 | 识别特征 | 处理方式 |
187
+ |------|----------|----------|
188
+ | 已判空 | 之前有 if (ptr == nullptr) return | 不报 |
189
+ | 引用类型 | 参数类型为 Type& 或 Type& | 不报 |
190
+ | 智能指针直接用 | unique_ptr/shared_ptr->method() | 不报 |
191
+ | 确信非空指针 | assert(ptr) 或 constexpr | 上下文分析 |
192
+ | NOPROTECT标记 | // NOPROTECT 注释 | 不报 |
193
+ | this指针 | this->member | 不报(this不能为空) |
194
+ | 成员函数内 | 在类成员函数内访问成员 | 上下文分析 |
195
+ ## 测试用例
196
+
197
+ ### 触发用例(应该报)
198
+
199
+ ```cpp
200
+ // test_MemoryStability_002_trigger.cpp
201
+ void trigger_bad_1(Data* data)
202
+ {
203
+ data->Process(); // 应该报:参数指针未判空
204
+ }
205
+
206
+ void trigger_bad_2()
207
+ {
208
+ Node* node = GetNode();
209
+ node->value = 100; // 应该报:返回值未判空
210
+ }
211
+
212
+ void trigger_bad_3(int* arr)
213
+ {
214
+ arr[0] = 1; // 应该报:数组指针未判空
215
+ }
216
+
217
+ void trigger_bad_4(Node* node)
218
+ {
219
+ node->next->value = 100; // 应该报:链式解引用未逐级判空
220
+ }
221
+ ```
222
+
223
+ ### 安全用例(不应该报)
224
+
225
+ ```cpp
226
+ // test_MemoryStability_002_safe.cpp
227
+ void safe_good_1(Data* data)
228
+ {
229
+ if (data == nullptr) { // 安全:入口判空
230
+ return;
231
+ }
232
+ data->Process();
233
+ }
234
+
235
+ void safe_good_2()
236
+ {
237
+ Node* node = GetNode();
238
+ if (node != nullptr) { // 安全:判空后使用
239
+ node->value = 100;
240
+ }
241
+ }
242
+
243
+ void safe_good_3(Data& data)
244
+ {
245
+ data.Process(); // 安全:使用引用,不能为空
246
+ }
247
+
248
+ void safe_good_4()
249
+ {
250
+ auto ptr = std::make_unique<Data>();
251
+ if (ptr) { // 安全:智能指针判空
252
+ ptr->Process();
253
+ }
254
+ }
255
+
256
+ // NOPROTECT: 特殊场景
257
+ void noprotect_case(Data* data)
258
+ {
259
+ data->Process(); // NOPROTECT标记,不报
260
+ }
261
+ ```
@@ -0,0 +1,428 @@
1
+ ---
2
+ rule_id: "StabilityCodeReview_MemoryStability_003"
3
+ name: "异常分支内存未及时释放"
4
+ category: "内存稳定性"
5
+ severity: "HIGH"
6
+ language: ["cpp", "c++"]
7
+ author: "OH-Department7 Stability Team"
8
+ ---
9
+
10
+ # 异常分支内存未及时释放
11
+
12
+ ## 问题描述
13
+
14
+ 在代码的异常分支(如提前return、break、continue等)退出前,已分配的内存(malloc/new)未及时释放,导致内存泄漏。这类问题在复杂的控制流中容易被忽略,是内存泄漏的常见原因之一。
15
+
16
+ ## 检测示例
17
+
18
+ ### ❌ 问题代码
19
+
20
+ ```cpp
21
+ // 场景1:条件分支提前return未释放
22
+ void ProcessData(int size)
23
+ {
24
+ char* buffer = (char*)malloc(size);
25
+ if (buffer == nullptr) {
26
+ return; // 错误:分配失败,无内存可释放,此处正确
27
+ }
28
+
29
+ if (size > MAX_SIZE) {
30
+ return; // 错误:提前return未释放buffer
31
+ }
32
+
33
+ // 处理数据
34
+ free(buffer);
35
+ }
36
+
37
+ // 场景2:错误处理分支未释放
38
+ int LoadConfig(const char* path)
39
+ {
40
+ Config* config = new Config();
41
+
42
+ if (!FileExists(path)) {
43
+ return -1; // 错误:config未释放
44
+ }
45
+
46
+ if (!ParseConfig(config, path)) {
47
+ return -2; // 错误:config未释放
48
+ }
49
+
50
+ delete config;
51
+ return 0;
52
+ }
53
+
54
+ // 场景3:循环中break未释放
55
+ void ProcessItems(int count)
56
+ {
57
+ int* items = (int*)malloc(count * sizeof(int));
58
+
59
+ for (int i = 0; i < count; i++) {
60
+ if (items[i] < 0) {
61
+ break; // 错误:break前未释放items
62
+ }
63
+ ProcessItem(items[i]);
64
+ }
65
+
66
+ free(items);
67
+ }
68
+
69
+ // 场景4:嵌套条件多个退出点
70
+ int HandleRequest(Request* req)
71
+ {
72
+ char* temp = (char*)malloc(1024);
73
+
74
+ if (req == nullptr) {
75
+ return -1; // 错误:temp未释放
76
+ }
77
+
78
+ if (req->type == TYPE_INVALID) {
79
+ return -2; // 错误:temp未释放
80
+ }
81
+
82
+ if (req->size > MAX_SIZE) {
83
+ return -3; // 错误:temp未释放
84
+ }
85
+
86
+ // 处理请求
87
+ free(temp);
88
+ return 0;
89
+ }
90
+
91
+ // 场景5:switch case中提前return
92
+ int ProcessCommand(int cmd)
93
+ {
94
+ char* buffer = (char*)malloc(256);
95
+
96
+ switch (cmd) {
97
+ case CMD_EXIT:
98
+ return -1; // 错误:buffer未释放
99
+ case CMD_RESET:
100
+ return -2; // 错误:buffer未释放
101
+ case CMD_PROCESS:
102
+ // 处理
103
+ break;
104
+ }
105
+
106
+ free(buffer);
107
+ return 0;
108
+ }
109
+
110
+ // 场景6:异常检查后多处返回
111
+ bool ValidateData(Data* data)
112
+ {
113
+ char* temp = new char[512];
114
+
115
+ if (data == nullptr) {
116
+ return false; // 错误:temp未释放
117
+ }
118
+
119
+ if (data->size <= 0) {
120
+ return false; // 错误:temp未释放
121
+ }
122
+
123
+ if (data->type == TYPE_UNKNOWN) {
124
+ return false; // 错误:temp未释放
125
+ }
126
+
127
+ delete[] temp;
128
+ return true;
129
+ }
130
+ ```
131
+
132
+ ### ✅ 修复方案
133
+
134
+ ```cpp
135
+ // 修复场景1:提前return前释放内存
136
+ void ProcessData(int size)
137
+ {
138
+ char* buffer = (char*)malloc(size);
139
+ if (buffer == nullptr) {
140
+ return;
141
+ }
142
+
143
+ if (size > MAX_SIZE) {
144
+ free(buffer); // 正确:return前释放
145
+ return;
146
+ }
147
+
148
+ // 处理数据
149
+ free(buffer);
150
+ }
151
+
152
+ // 修复场景2:使用智能指针(RAII)
153
+ int LoadConfig(const char* path)
154
+ {
155
+ std::unique_ptr<Config> config = std::make_unique<Config>();
156
+
157
+ if (!FileExists(path)) {
158
+ return -1; // 安全:智能指针自动释放
159
+ }
160
+
161
+ if (!ParseConfig(config.get(), path)) {
162
+ return -2; // 安全:智能指针自动释放
163
+ }
164
+
165
+ return 0; // 安全:智能指针自动释放
166
+ }
167
+
168
+ // 修复场景3:使用goto集中释放(C风格)
169
+ void ProcessItems(int count)
170
+ {
171
+ int* items = (int*)malloc(count * sizeof(int));
172
+ if (items == nullptr) {
173
+ return;
174
+ }
175
+
176
+ for (int i = 0; i < count; i++) {
177
+ if (items[i] < 0) {
178
+ goto cleanup; // 跳转到释放点
179
+ }
180
+ ProcessItem(items[i]);
181
+ }
182
+
183
+ cleanup:
184
+ free(items);
185
+ }
186
+
187
+ // 修复场景4:使用do-while(0)模式
188
+ int HandleRequest(Request* req)
189
+ {
190
+ char* temp = (char*)malloc(1024);
191
+ int result = 0;
192
+
193
+ do {
194
+ if (req == nullptr) {
195
+ result = -1;
196
+ break;
197
+ }
198
+
199
+ if (req->type == TYPE_INVALID) {
200
+ result = -2;
201
+ break;
202
+ }
203
+
204
+ if (req->size > MAX_SIZE) {
205
+ result = -3;
206
+ break;
207
+ }
208
+
209
+ // 处理请求
210
+ } while (0);
211
+
212
+ free(temp);
213
+ return result;
214
+ }
215
+
216
+ // 修复场景5:switch中使用统一出口
217
+ int ProcessCommand(int cmd)
218
+ {
219
+ char* buffer = (char*)malloc(256);
220
+ int result = 0;
221
+
222
+ switch (cmd) {
223
+ case CMD_EXIT:
224
+ result = -1;
225
+ break; // 正确:跳转到统一释放点
226
+ case CMD_RESET:
227
+ result = -2;
228
+ break; // 正确:跳转到统一释放点
229
+ case CMD_PROCESS:
230
+ // 处理
231
+ break;
232
+ }
233
+
234
+ free(buffer);
235
+ return result;
236
+ }
237
+
238
+ // 修复场景6:使用std::vector代替手动管理
239
+ bool ValidateData(Data* data)
240
+ {
241
+ std::vector<char> temp(512); // RAII自动管理
242
+
243
+ if (data == nullptr) {
244
+ return false; // 安全:vector自动释放
245
+ }
246
+
247
+ if (data->size <= 0) {
248
+ return false; // 安全:vector自动释放
249
+ }
250
+
251
+ if (data->type == TYPE_UNKNOWN) {
252
+ return false; // 安全:vector自动释放
253
+ }
254
+
255
+ return true;
256
+ }
257
+
258
+ // 修复场景7:使用lambda封装资源
259
+ void ProcessFile(const char* path)
260
+ {
261
+ auto cleanup = [](char* p) { if (p) free(p); };
262
+ char* buffer = (char*)malloc(1024);
263
+ std::unique_ptr<char, decltype(cleanup)> ptr(buffer, cleanup);
264
+
265
+ if (!FileExists(path)) {
266
+ return; // 安全:unique_ptr调用cleanup
267
+ }
268
+
269
+ // 处理文件
270
+ }
271
+ ```
272
+
273
+ ## 检测范围
274
+
275
+ 检查以下模式:
276
+
277
+ 1. **malloc/calloc/realloc** 分配后在分支退出未释放
278
+ 2. **new** 分配后在分支退出未释放(非智能指针)
279
+ 3. **条件分支提前return** 前内存未释放
280
+ 4. **循环中break/continue** 前内存未释放
281
+ 5. **switch case中return** 前内存未释放
282
+
283
+ ## 检测要点
284
+
285
+ 1. 识别内存分配函数调用(malloc、calloc、realloc、new)
286
+ 2. 跟踪分配变量名,检查是否存储到容器或成员变量
287
+ 3. 检测分支退出语句(return、break、continue)
288
+ 4. 在分配点和退出点之间检查是否存在释放操作
289
+ 5. 排除智能指针(unique_ptr、shared_ptr)使用场景
290
+ 6. 排除NOPROTECT标记场景
291
+
292
+ ## 风险流分析(RiskFlow)
293
+
294
+ - **RISK_SOURCE**:malloc/new分配的内存块
295
+ - **RISK_TYPE**:内存泄漏
296
+ - **RISK_PATH**:内存分配 → 异常分支退出 → 跳过释放 → 孤儿内存块 → 内存泄漏累积
297
+ - **IMPACT_POINT**:系统内存资源耗尽,服务不可用,OOM崩溃
298
+
299
+ ## 影响分析(ImpactAnalysis)
300
+
301
+ - **Trigger**:异常条件触发分支退出,跳过内存释放代码
302
+ - **Propagation**:分配的内存块成为孤儿内存,无法被任何指针引用
303
+ - **Consequence**:内存泄漏累积导致可用内存减少,最终OOM崩溃
304
+ - **Mitigation**:使用RAII智能指针,或确保每个退出点都有释放代码
305
+
306
+ ## 误报排除
307
+
308
+ | 场景 | 识别特征 | 处理方式 |
309
+ |------|----------|----------|
310
+ | 使用智能指针 | unique_ptr/shared_ptr/make_unique | 不报 |
311
+ | 存入容器 | vector/push_back/insert | 不报 |
312
+ | 赋值给成员变量 | this->/m_xxx | 不报 |
313
+ | NOPROTECT标记 | // NOPROTECT 注释 | 不报 |
314
+ | 全局/静态变量 | static/global | 不报 |
315
+ | 测试代码 | 文件名包含 _test.cpp | 白名单排除 |
316
+ ## 测试用例
317
+
318
+ ### 触发用例(应该报)
319
+
320
+ ```cpp
321
+ // test_MemoryStability_003_trigger.cpp
322
+ #include <cstdlib>
323
+
324
+ void trigger_bad_1(int size)
325
+ {
326
+ char* buffer = (char*)malloc(1024);
327
+ if (size > 100) {
328
+ return; // 应该报:malloc后提前return未释放
329
+ }
330
+ free(buffer);
331
+ }
332
+
333
+ void trigger_bad_2()
334
+ {
335
+ int* data = new int[100];
336
+ if (data == nullptr) {
337
+ return;
338
+ }
339
+ if (condition) {
340
+ return; // 应该报:new后提前return未释放
341
+ }
342
+ delete[] data;
343
+ }
344
+
345
+ void trigger_bad_3(int count)
346
+ {
347
+ int* items = (int*)malloc(count * sizeof(int));
348
+ for (int i = 0; i < count; i++) {
349
+ if (items[i] < 0) {
350
+ break; // 应该报:break前未释放
351
+ }
352
+ }
353
+ free(items);
354
+ }
355
+
356
+ int trigger_bad_4(int cmd)
357
+ {
358
+ char* buffer = (char*)malloc(256);
359
+ switch (cmd) {
360
+ case 1:
361
+ return -1; // 应该报:switch case return未释放
362
+ case 2:
363
+ return -2; // 应该报:switch case return未释放
364
+ }
365
+ free(buffer);
366
+ return 0;
367
+ }
368
+ ```
369
+
370
+ ### 安全用例(不应该报)
371
+
372
+ ```cpp
373
+ // test_MemoryStability_003_safe.cpp
374
+ #include <cstdlib>
375
+ #include <memory>
376
+ #include <vector>
377
+
378
+ void safe_good_1(int size)
379
+ {
380
+ char* buffer = (char*)malloc(1024);
381
+ if (size > 100) {
382
+ free(buffer); // 安全:return前释放
383
+ return;
384
+ }
385
+ free(buffer);
386
+ }
387
+
388
+ void safe_good_2()
389
+ {
390
+ std::unique_ptr<int[]> data = std::make_unique<int[]>(100);
391
+ if (condition) {
392
+ return; // 安全:智能指针自动释放
393
+ }
394
+ }
395
+
396
+ void safe_good_3()
397
+ {
398
+ std::vector<int> items(100);
399
+ if (condition) {
400
+ return; // 安全:vector自动释放
401
+ }
402
+ }
403
+
404
+ void safe_good_4(int count)
405
+ {
406
+ int* items = (int*)malloc(count * sizeof(int));
407
+ int result = 0;
408
+
409
+ do {
410
+ if (count <= 0) {
411
+ result = -1;
412
+ break; // 安全:跳转到统一释放点
413
+ }
414
+ } while (0);
415
+
416
+ free(items);
417
+ }
418
+
419
+ // NOPROTECT: 特殊场景,内存由调用者管理
420
+ void noprotect_case()
421
+ {
422
+ char* buffer = (char*)malloc(256);
423
+ if (condition) {
424
+ return; // NOPROTECT: 不报
425
+ }
426
+ free(buffer);
427
+ }
428
+ ```