@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,472 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_BoundaryCondition_010"
|
|
3
|
+
name: "容器find返回迭代器需校验有效性"
|
|
4
|
+
category: "边界条件"
|
|
5
|
+
severity: "HIGH"
|
|
6
|
+
language: ["cpp", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# 容器find返回迭代器需校验有效性
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
容器find返回的迭代器在使用前需要先校验有效性,直接使用可能为end()的迭代器会导致未定义行为、程序崩溃或内存访问错误。
|
|
15
|
+
|
|
16
|
+
## 检测示例
|
|
17
|
+
|
|
18
|
+
### ❌ 问题代码
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
// 错误示例1:map find后直接使用
|
|
22
|
+
std::map<int, std::string> dataMap;
|
|
23
|
+
|
|
24
|
+
std::string GetValue(int key)
|
|
25
|
+
{
|
|
26
|
+
auto it = dataMap.find(key);
|
|
27
|
+
return it->second; // 危险:it可能是end()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 错误示例2:unordered_map直接访问
|
|
31
|
+
std::unordered_map<std::string, int> cache;
|
|
32
|
+
|
|
33
|
+
int GetCachedValue(const std::string& key)
|
|
34
|
+
{
|
|
35
|
+
auto it = cache.find(key);
|
|
36
|
+
return it->second; // 危险:未检查有效性
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 错误示例3:set find后直接访问
|
|
40
|
+
std::set<int> validIds;
|
|
41
|
+
|
|
42
|
+
bool IsValid(int id)
|
|
43
|
+
{
|
|
44
|
+
auto it = validIds.find(id);
|
|
45
|
+
return *it == id; // 危险:it可能是end()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 错误示例4:vector find后访问
|
|
49
|
+
std::vector<int> numbers;
|
|
50
|
+
|
|
51
|
+
int GetFirstMatch(int value)
|
|
52
|
+
{
|
|
53
|
+
auto it = std::find(numbers.begin(), numbers.end(), value);
|
|
54
|
+
return *it; // 危险:it可能是end()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 错误示例5:多重容器find
|
|
58
|
+
std::multimap<int, std::string> multiMap;
|
|
59
|
+
|
|
60
|
+
std::string GetFirstValue(int key)
|
|
61
|
+
{
|
|
62
|
+
auto it = multiMap.find(key);
|
|
63
|
+
return it->second; // 危险:未检查有效性
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 错误示例6:find后修改
|
|
67
|
+
std::map<int, Data> dataStore;
|
|
68
|
+
|
|
69
|
+
void UpdateData(int key, const Data& newData)
|
|
70
|
+
{
|
|
71
|
+
auto it = dataStore.find(key);
|
|
72
|
+
it->second = newData; // 危险:未检查有效性
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 错误示例7:find_if后使用
|
|
76
|
+
std::vector<Item> items;
|
|
77
|
+
|
|
78
|
+
Item* FindItemById(int id)
|
|
79
|
+
{
|
|
80
|
+
auto it = std::find_if(items.begin(), items.end(),
|
|
81
|
+
[id](const Item& item) { return item.id == id; });
|
|
82
|
+
return &(*it); // 危险:it可能是end()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 错误示例8:find后访问成员
|
|
86
|
+
std::map<std::string, Config> configs;
|
|
87
|
+
|
|
88
|
+
int GetConfigValue(const std::string& name)
|
|
89
|
+
{
|
|
90
|
+
auto it = configs.find(name);
|
|
91
|
+
return it->second.value; // 危险:未检查有效性
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 错误示例9:find后删除
|
|
95
|
+
std::map<int, std::string> names;
|
|
96
|
+
|
|
97
|
+
void RemoveName(int id)
|
|
98
|
+
{
|
|
99
|
+
auto it = names.find(id);
|
|
100
|
+
names.erase(it); // 危险:erase(end())未定义
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 错误示例10:链式find调用
|
|
104
|
+
std::map<int, std::map<std::string, int>> nested;
|
|
105
|
+
|
|
106
|
+
int GetNestedValue(int outerKey, const std::string& innerKey)
|
|
107
|
+
{
|
|
108
|
+
auto outer = nested.find(outerKey);
|
|
109
|
+
auto inner = outer->second.find(innerKey); // 危险:outer可能是end()
|
|
110
|
+
return inner->second; // 危险:inner可能是end()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 错误示例11:find后distance
|
|
114
|
+
std::vector<int> vec;
|
|
115
|
+
|
|
116
|
+
size_t GetIndex(int value)
|
|
117
|
+
{
|
|
118
|
+
auto it = std::find(vec.begin(), vec.end(), value);
|
|
119
|
+
return std::distance(vec.begin(), it); // 危险:it可能是end(),返回无效索引
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### ✅ 修复方案
|
|
124
|
+
|
|
125
|
+
```cpp
|
|
126
|
+
// 正确示例1:map find后检查有效性
|
|
127
|
+
std::map<int, std::string> dataMap;
|
|
128
|
+
|
|
129
|
+
std::string GetValue(int key)
|
|
130
|
+
{
|
|
131
|
+
auto it = dataMap.find(key);
|
|
132
|
+
if (it == dataMap.end()) { // 正确:检查有效性
|
|
133
|
+
return ""; // 或返回默认值
|
|
134
|
+
}
|
|
135
|
+
return it->second; // 安全:已验证有效
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 正确示例2:使用count()检查(更简洁)
|
|
139
|
+
std::map<int, std::string> dataMap;
|
|
140
|
+
|
|
141
|
+
std::string GetValue(int key)
|
|
142
|
+
{
|
|
143
|
+
if (dataMap.count(key) > 0) { // 正确:使用count检查
|
|
144
|
+
return dataMap[key]; // 安全:已确认存在
|
|
145
|
+
}
|
|
146
|
+
return "";
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 正确示例3:使用contains()检查(C++20,推荐)
|
|
150
|
+
std::map<int, std::string> dataMap;
|
|
151
|
+
|
|
152
|
+
std::string GetValue(int key)
|
|
153
|
+
{
|
|
154
|
+
if (dataMap.contains(key)) { // 正确:C++20 contains方法,语义更清晰
|
|
155
|
+
return dataMap[key]; // 安全:已确认存在
|
|
156
|
+
}
|
|
157
|
+
return "";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 正确示例4:unordered_map find检查
|
|
161
|
+
std::unordered_map<std::string, int> cache;
|
|
162
|
+
|
|
163
|
+
int GetCachedValue(const std::string& key, int defaultValue = 0)
|
|
164
|
+
{
|
|
165
|
+
auto it = cache.find(key);
|
|
166
|
+
if (it != cache.end()) { // 正确:检查有效性
|
|
167
|
+
return it->second;
|
|
168
|
+
}
|
|
169
|
+
return defaultValue; // 返回默认值
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 正确示例5:使用contains()替代find()(推荐)
|
|
173
|
+
std::unordered_map<std::string, int> cache;
|
|
174
|
+
|
|
175
|
+
bool HasCachedValue(const std::string& key)
|
|
176
|
+
{
|
|
177
|
+
return cache.contains(key); // 正确:C++20 contains,更简洁
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
int GetCachedValueSafe(const std::string& key)
|
|
181
|
+
{
|
|
182
|
+
if (cache.contains(key)) { // 正确:先检查存在性
|
|
183
|
+
return cache[key]; // 安全访问
|
|
184
|
+
}
|
|
185
|
+
return 0; // 默认值
|
|
186
|
+
}
|
|
187
|
+
return it->second;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 正确示例2:unordered_map安全访问
|
|
191
|
+
std::unordered_map<std::string, int> cache;
|
|
192
|
+
|
|
193
|
+
int GetCachedValue(const std::string& key)
|
|
194
|
+
{
|
|
195
|
+
auto it = cache.find(key);
|
|
196
|
+
if (it != cache.end()) { // 正确:先检查
|
|
197
|
+
return it->second;
|
|
198
|
+
}
|
|
199
|
+
LOGE("Cache miss for key: %s", key.c_str());
|
|
200
|
+
return -1;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 正确示例3:set find安全使用
|
|
204
|
+
std::set<int> validIds;
|
|
205
|
+
|
|
206
|
+
bool IsValid(int id)
|
|
207
|
+
{
|
|
208
|
+
return validIds.find(id) != validIds.end(); // 正确:直接返回检查结果
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 正确示例4:vector find安全访问
|
|
212
|
+
std::vector<int> numbers;
|
|
213
|
+
|
|
214
|
+
int GetFirstMatch(int value, int defaultValue = -1)
|
|
215
|
+
{
|
|
216
|
+
auto it = std::find(numbers.begin(), numbers.end(), value);
|
|
217
|
+
if (it == numbers.end()) { // 正确:先检查
|
|
218
|
+
return defaultValue;
|
|
219
|
+
}
|
|
220
|
+
return *it;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// 正确示例5:多重容器find安全使用
|
|
224
|
+
std::multimap<int, std::string> multiMap;
|
|
225
|
+
|
|
226
|
+
std::string GetFirstValue(int key)
|
|
227
|
+
{
|
|
228
|
+
auto it = multiMap.find(key);
|
|
229
|
+
if (it == multiMap.end()) { // 正确:先检查
|
|
230
|
+
return "";
|
|
231
|
+
}
|
|
232
|
+
return it->second;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// 正确示例6:find后安全修改
|
|
236
|
+
std::map<int, Data> dataStore;
|
|
237
|
+
|
|
238
|
+
bool UpdateData(int key, const Data& newData)
|
|
239
|
+
{
|
|
240
|
+
auto it = dataStore.find(key);
|
|
241
|
+
if (it == dataStore.end()) { // 正确:先检查
|
|
242
|
+
LOGE("Key not found: %d", key);
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
it->second = newData;
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 正确示例7:find_if安全使用
|
|
250
|
+
std::vector<Item> items;
|
|
251
|
+
|
|
252
|
+
Item* FindItemById(int id)
|
|
253
|
+
{
|
|
254
|
+
auto it = std::find_if(items.begin(), items.end(),
|
|
255
|
+
[id](const Item& item) { return item.id == id; });
|
|
256
|
+
if (it == items.end()) { // 正确:先检查
|
|
257
|
+
return nullptr;
|
|
258
|
+
}
|
|
259
|
+
return &(*it);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// 正确示例8:find后安全访问成员
|
|
263
|
+
std::map<std::string, Config> configs;
|
|
264
|
+
|
|
265
|
+
int GetConfigValue(const std::string& name, int defaultValue = 0)
|
|
266
|
+
{
|
|
267
|
+
auto it = configs.find(name);
|
|
268
|
+
if (it == configs.end()) { // 正确:先检查
|
|
269
|
+
return defaultValue;
|
|
270
|
+
}
|
|
271
|
+
return it->second.value;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// 正确示例9:find后安全删除
|
|
275
|
+
std::map<int, std::string> names;
|
|
276
|
+
|
|
277
|
+
bool RemoveName(int id)
|
|
278
|
+
{
|
|
279
|
+
auto it = names.find(id);
|
|
280
|
+
if (it == names.end()) { // 正确:先检查
|
|
281
|
+
LOGE("Name not found for id: %d", id);
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
names.erase(it);
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 正确示例10:链式find安全调用
|
|
289
|
+
std::map<int, std::map<std::string, int>> nested;
|
|
290
|
+
|
|
291
|
+
int GetNestedValue(int outerKey, const std::string& innerKey)
|
|
292
|
+
{
|
|
293
|
+
auto outer = nested.find(outerKey);
|
|
294
|
+
if (outer == nested.end()) { // 正确:先检查外层
|
|
295
|
+
LOGE("Outer key not found: %d", outerKey);
|
|
296
|
+
return -1;
|
|
297
|
+
}
|
|
298
|
+
auto inner = outer->second.find(innerKey);
|
|
299
|
+
if (inner == outer->second.end()) { // 正确:再检查内层
|
|
300
|
+
LOGE("Inner key not found: %s", innerKey.c_str());
|
|
301
|
+
return -1;
|
|
302
|
+
}
|
|
303
|
+
return inner->second;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// 正确示例11:find后安全distance
|
|
307
|
+
std::vector<int> vec;
|
|
308
|
+
|
|
309
|
+
bool GetIndex(int value, size_t& index)
|
|
310
|
+
{
|
|
311
|
+
auto it = std::find(vec.begin(), vec.end(), value);
|
|
312
|
+
if (it == vec.end()) { // 正确:先检查
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
index = std::distance(vec.begin(), it);
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// 正确示例12:使用辅助函数
|
|
320
|
+
template<typename Container, typename Key>
|
|
321
|
+
typename Container::mapped_type SafeFind(
|
|
322
|
+
Container& container,
|
|
323
|
+
const Key& key,
|
|
324
|
+
typename Container::mapped_type defaultValue = {}
|
|
325
|
+
) {
|
|
326
|
+
auto it = container.find(key);
|
|
327
|
+
if (it == container.end()) {
|
|
328
|
+
return defaultValue;
|
|
329
|
+
}
|
|
330
|
+
return it->second;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// 使用
|
|
334
|
+
std::map<int, std::string> map;
|
|
335
|
+
std::string value = SafeFind(map, key, "");
|
|
336
|
+
|
|
337
|
+
// 正确示例13:使用contains检查(C++20)
|
|
338
|
+
std::map<int, std::string> dataMap;
|
|
339
|
+
|
|
340
|
+
bool HasKey(int key)
|
|
341
|
+
{
|
|
342
|
+
return dataMap.contains(key); // C++20: 直接检查是否存在
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
std::string GetValue(int key)
|
|
346
|
+
{
|
|
347
|
+
if (dataMap.contains(key)) { // 正确:先检查
|
|
348
|
+
return dataMap[key];
|
|
349
|
+
}
|
|
350
|
+
return "";
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## 检测范围
|
|
355
|
+
|
|
356
|
+
检查以下模式:
|
|
357
|
+
|
|
358
|
+
1. `container.find(key)` 后直接使用 `->`
|
|
359
|
+
2. `std::find(begin, end, value)` 后直接使用 `*`
|
|
360
|
+
3. `std::find_if(...)` 后直接访问
|
|
361
|
+
4. find返回值用于erase但未检查
|
|
362
|
+
5. 链式find调用未逐层检查
|
|
363
|
+
|
|
364
|
+
## 检测要点
|
|
365
|
+
|
|
366
|
+
1. 识别`find`, `find_if`函数调用
|
|
367
|
+
2. 检查返回的迭代器是否与`end()`比较
|
|
368
|
+
3. 检查在`if (it != end())`条件内使用
|
|
369
|
+
4. 识别`->second`, `->first`, `*it`等访问操作
|
|
370
|
+
5. 排除NOPROTECT标记的代码
|
|
371
|
+
|
|
372
|
+
## 风险流分析(RiskFlow)
|
|
373
|
+
|
|
374
|
+
- **RISK_SOURCE**: find返回可能为end()的迭代器
|
|
375
|
+
- **RISK_TYPE**: 使用无效迭代器
|
|
376
|
+
- **RISK_PATH**: find -> 未检查 -> 直接访问 -> 未定义行为
|
|
377
|
+
- **IMPACT_POINT**: 程序崩溃、内存访问错误
|
|
378
|
+
|
|
379
|
+
## 影响分析(ImpactAnalysis)
|
|
380
|
+
|
|
381
|
+
- **Trigger**: find后未校验迭代器有效性
|
|
382
|
+
- **Propagation**: end()迭代器访问导致崩溃
|
|
383
|
+
- **Consequence**: 程序崩溃、数据损坏、未定义行为
|
|
384
|
+
- **Mitigation**: 使用前与end()比较,或使用contains/count
|
|
385
|
+
|
|
386
|
+
## 误报排除
|
|
387
|
+
|
|
388
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
389
|
+
|------|----------|----------|
|
|
390
|
+
| NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
391
|
+
| 已有end检查 | 存在 != end() 或 == end() 判断 | 不报 |
|
|
392
|
+
| 在条件内使用 | 在 if 条件返回true后使用 | 不报 |
|
|
393
|
+
| 使用contains | 使用C++20 contains() | 不报 |
|
|
394
|
+
| 第三方库 | 位于 third_party 目录 | 白名单排除 |
|
|
395
|
+
## 测试用例
|
|
396
|
+
|
|
397
|
+
### 触发用例(应该报)
|
|
398
|
+
|
|
399
|
+
```cpp
|
|
400
|
+
// test_BoundaryCondition_010_trigger.cpp
|
|
401
|
+
std::map<int, std::string> map;
|
|
402
|
+
|
|
403
|
+
std::string trigger_bad_1(int key)
|
|
404
|
+
{
|
|
405
|
+
auto it = map.find(key);
|
|
406
|
+
return it->second; // 应该报:未检查end()
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
std::vector<int> vec;
|
|
410
|
+
|
|
411
|
+
int trigger_bad_2(int value)
|
|
412
|
+
{
|
|
413
|
+
auto it = std::find(vec.begin(), vec.end(), value);
|
|
414
|
+
return *it; // 应该报:未检查end()
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
std::set<int> set;
|
|
418
|
+
|
|
419
|
+
bool trigger_bad_3(int id)
|
|
420
|
+
{
|
|
421
|
+
auto it = set.find(id);
|
|
422
|
+
return *it == id; // 应该报:未检查end()
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
std::map<int, Data> dataMap;
|
|
426
|
+
|
|
427
|
+
void trigger_bad_4(int key)
|
|
428
|
+
{
|
|
429
|
+
auto it = dataMap.find(key);
|
|
430
|
+
it->second.value = 0; // 应该报:未检查end()
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### 安全用例(不应该报)
|
|
435
|
+
|
|
436
|
+
```cpp
|
|
437
|
+
// test_BoundaryCondition_010_safe.cpp
|
|
438
|
+
std::map<int, std::string> map;
|
|
439
|
+
|
|
440
|
+
std::string safe_good_1(int key)
|
|
441
|
+
{
|
|
442
|
+
auto it = map.find(key);
|
|
443
|
+
if (it == map.end()) { // 安全:有检查
|
|
444
|
+
return "";
|
|
445
|
+
}
|
|
446
|
+
return it->second;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
std::string safe_good_2(int key)
|
|
450
|
+
{
|
|
451
|
+
auto it = map.find(key);
|
|
452
|
+
if (it != map.end()) { // 安全:有检查
|
|
453
|
+
return it->second;
|
|
454
|
+
}
|
|
455
|
+
return "";
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
int safe_good_3(int key)
|
|
459
|
+
{
|
|
460
|
+
if (map.count(key) > 0) { // 安全:使用count检查
|
|
461
|
+
return map[key].length();
|
|
462
|
+
}
|
|
463
|
+
return 0;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// NOPROTECT: 特殊处理场景
|
|
467
|
+
std::string noprotect_case(int key)
|
|
468
|
+
{
|
|
469
|
+
auto it = map.find(key);
|
|
470
|
+
return it->second;
|
|
471
|
+
}
|
|
472
|
+
```
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_BoundaryCondition_011"
|
|
3
|
+
name: "加减乘除运算应避免类型溢出或回绕"
|
|
4
|
+
category: "边界条件"
|
|
5
|
+
severity: "HIGH"
|
|
6
|
+
language: ["cpp", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# 加减乘除运算应避免类型溢出或回绕
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
整数运算时未检查溢出,可能导致数值回绕、逻辑错误或安全问题。尤其在内存分配大小计算、数组索引计算等关键场景,溢出可能导致内存分配不足或越界访问。
|
|
15
|
+
|
|
16
|
+
## 检测示例
|
|
17
|
+
|
|
18
|
+
### ❌ 问题代码
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
// 错误示例1:乘法溢出导致内存分配不足
|
|
22
|
+
void AllocateBuffer(int count, int itemSize)
|
|
23
|
+
{
|
|
24
|
+
int totalSize = count * itemSize; // 危险:可能溢出
|
|
25
|
+
char* buffer = new char[totalSize];
|
|
26
|
+
// ...
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 错误示例2:加法溢出
|
|
30
|
+
void ProcessData(int offset, int length)
|
|
31
|
+
{
|
|
32
|
+
int end = offset + length; // 危险:可能溢出
|
|
33
|
+
for (int i = offset; i < end; i++) {
|
|
34
|
+
ProcessItem(i);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 错误示例3:减法回绕(无符号)
|
|
39
|
+
void CopyData(uint32_t start, uint32_t end)
|
|
40
|
+
{
|
|
41
|
+
uint32_t size = end - start; // 危险:若end < start,回绕到超大值
|
|
42
|
+
char* buffer = new char[size];
|
|
43
|
+
// ...
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 错误示例4:计算缓冲区大小
|
|
47
|
+
int CalculateBufferSize(int width, int height, int bpp)
|
|
48
|
+
{
|
|
49
|
+
return width * height * bpp; // 危险:多次乘法可能溢出
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### ✅ 修复方案
|
|
54
|
+
|
|
55
|
+
```cpp
|
|
56
|
+
// 正确示例1:乘法溢出检查
|
|
57
|
+
void AllocateBuffer(int count, int itemSize)
|
|
58
|
+
{
|
|
59
|
+
// 检查乘法溢出
|
|
60
|
+
if (itemSize > 0 && count > INT_MAX / itemSize) {
|
|
61
|
+
LOGE("Multiplication overflow: %d * %d", count, itemSize);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
int totalSize = count * itemSize;
|
|
65
|
+
if (totalSize <= 0) {
|
|
66
|
+
LOGE("Invalid size: %d", totalSize);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
char* buffer = new char[totalSize];
|
|
70
|
+
// ...
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 正确示例2:使用安全整数运算库
|
|
74
|
+
void AllocateBufferSafe(int count, int itemSize)
|
|
75
|
+
{
|
|
76
|
+
int totalSize;
|
|
77
|
+
if (!base::CheckMul(count, itemSize).AssignIfValid(&totalSize)) {
|
|
78
|
+
LOGE("Multiplication overflow");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
char* buffer = new char[totalSize];
|
|
82
|
+
// ...
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 正确示例3:使用saturated_cast
|
|
86
|
+
void ProcessData(int offset, int length)
|
|
87
|
+
{
|
|
88
|
+
int64_t end = base::saturated_cast<int64_t>(offset) +
|
|
89
|
+
base::saturated_cast<int64_t>(length);
|
|
90
|
+
if (end > INT_MAX || end < offset) {
|
|
91
|
+
LOGE("Addition overflow");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
for (int i = offset; i < static_cast<int>(end); i++) {
|
|
95
|
+
ProcessItem(i);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 正确示例4:使用64位中间值
|
|
100
|
+
int64_t CalculateBufferSize(int width, int height, int bpp)
|
|
101
|
+
{
|
|
102
|
+
int64_t size = static_cast<int64_t>(width) *
|
|
103
|
+
static_cast<int64_t>(height) *
|
|
104
|
+
static_cast<int64_t>(bpp);
|
|
105
|
+
if (size > INT_MAX || size <= 0) {
|
|
106
|
+
LOGE("Buffer size overflow or invalid");
|
|
107
|
+
return -1;
|
|
108
|
+
}
|
|
109
|
+
return static_cast<int>(size);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 检测范围
|
|
114
|
+
|
|
115
|
+
检查以下运算模式:
|
|
116
|
+
|
|
117
|
+
- `a * b`、`a * b * c` 等乘法运算
|
|
118
|
+
- `a + b`、`a + b + c` 等加法运算
|
|
119
|
+
- `a - b` 减法运算(特别是无符号类型)
|
|
120
|
+
- 内存分配大小计算:`malloc(a * b)`、`new char[a * b]`
|
|
121
|
+
- 数组索引计算:`array[a + b]`、`array[a * b]`
|
|
122
|
+
|
|
123
|
+
## 检测要点
|
|
124
|
+
|
|
125
|
+
1. 识别算术运算表达式(+、-、*)
|
|
126
|
+
2. 检查是否在内存分配上下文中使用
|
|
127
|
+
3. 检查是否在数组索引上下文中使用
|
|
128
|
+
4. 检查是否存在溢出保护机制
|
|
129
|
+
5. 排除NOPROTECT标记的代码
|
|
130
|
+
|
|
131
|
+
## 风险流分析(RiskFlow)
|
|
132
|
+
|
|
133
|
+
- **RISK_SOURCE**: 整数运算表达式
|
|
134
|
+
- **RISK_TYPE**: 整数溢出/回绕
|
|
135
|
+
- **RISK_PATH**: 运算结果溢出 -> 数值回绕 -> 内存分配错误/数组越界
|
|
136
|
+
- **IMPACT_POINT**: 内存损坏、安全漏洞、程序崩溃
|
|
137
|
+
|
|
138
|
+
## 影响分析(ImpactAnalysis)
|
|
139
|
+
|
|
140
|
+
- **Trigger**: 运算结果超出类型表示范围
|
|
141
|
+
- **Propagation**: 结果回绕为负值或意外大值
|
|
142
|
+
- **Consequence**: 内存分配不足、缓冲区溢出、数据损坏
|
|
143
|
+
- **Mitigation**: 使用安全整数运算库或添加溢出检查
|
|
144
|
+
|
|
145
|
+
## 误报排除
|
|
146
|
+
|
|
147
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
148
|
+
|------|----------|----------|
|
|
149
|
+
| NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
150
|
+
| 已有溢出检查 | 存在 INT_MAX、溢出函数调用 | 不报 |
|
|
151
|
+
| 第三方库 | 位于 third_party 目录 | 白名单排除 |
|
|
152
|
+
| 测试代码 | 位于 test 目录 | 自动跳过 |
|
|
153
|
+
| 常量运算 | 编译期可计算的表达式 | 不报 |
|
|
154
|
+
## 测试用例
|
|
155
|
+
|
|
156
|
+
### 触发用例(应该报)
|
|
157
|
+
|
|
158
|
+
```cpp
|
|
159
|
+
// test_BoundaryCondition_011_trigger.cpp
|
|
160
|
+
void trigger_bad_1(int count, int itemSize)
|
|
161
|
+
{
|
|
162
|
+
int total = count * itemSize; // 应该报:乘法溢出风险
|
|
163
|
+
char* buffer = new char[total];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
void trigger_bad_2(int a, int b, int c)
|
|
167
|
+
{
|
|
168
|
+
int size = a * b * c; // 应该报:多次乘法溢出风险
|
|
169
|
+
ProcessBuffer(size);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
void trigger_bad_3(uint32_t start, uint32_t end)
|
|
173
|
+
{
|
|
174
|
+
uint32_t size = end - start; // 应该报:无符号减法回绕风险
|
|
175
|
+
char* buffer = new char[size];
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 安全用例(不应该报)
|
|
180
|
+
|
|
181
|
+
```cpp
|
|
182
|
+
// test_BoundaryCondition_011_safe.cpp
|
|
183
|
+
void safe_good_1(int count, int itemSize)
|
|
184
|
+
{
|
|
185
|
+
if (itemSize > 0 && count <= INT_MAX / itemSize) { // 安全:有溢出检查
|
|
186
|
+
int total = count * itemSize;
|
|
187
|
+
char* buffer = new char[total];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
void safe_good_2(int count, int itemSize)
|
|
192
|
+
{
|
|
193
|
+
int total = base::saturated_cast<int>(
|
|
194
|
+
static_cast<int64_t>(count) * itemSize); // 安全:使用saturated
|
|
195
|
+
char* buffer = new char[total];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// NOPROTECT: 常量运算不会溢出
|
|
199
|
+
void noprotect_case()
|
|
200
|
+
{
|
|
201
|
+
const int SIZE = 10 * 20; // 编译期常量,不报
|
|
202
|
+
char buffer[SIZE];
|
|
203
|
+
}
|
|
204
|
+
```
|