Skip to content

Commit 3195f93

Browse files
authored
Rules- std-vector-invalidation - c/cpp (#32)
1 parent 6e4fca9 commit 3195f93

6 files changed

+360
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
id: std-vector-invalidation-c
2+
language: c
3+
severity: warning
4+
message: >-
5+
Modifying an `std::vector` while iterating over it could cause the
6+
container to reallocate, triggering memory corruption.
7+
note: >-
8+
[CWE-416: Use After Free.
9+
[REFERENCES]
10+
- https://wiki.sei.cmu.edu/confluence/display/c/MEM30-C.+Do+not+access+freed+memory
11+
- https://wiki.sei.cmu.edu/confluence/display/cplusplus/EXP54-CPP.+Do+not+access+an+object+outside+of+its+lifetime
12+
rule:
13+
kind: call_expression
14+
all:
15+
- pattern: $CONTAINER.$R($$$)
16+
inside:
17+
stopBy: end
18+
kind: for_statement
19+
any:
20+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.begin(); $IT!= $CONTAINER.end(); ++$IT){$$$}
21+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.begin(); $IT!= $CONTAINER.end(); $IT++){$$$}
22+
- pattern:
23+
for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.rbegin(); $IT!= $CONTAINER.rend(); ++$IT)
24+
{$$$}
25+
- pattern:
26+
for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.rbegin(); $IT!= $CONTAINER.rend(); $IT++)
27+
{$$$}
28+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.begin(),$IT_END = $CONTAINER.end(); $IT !=$IT_END; ++$IT){$$$}
29+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.begin(),
30+
$IT_END = $CONTAINER.end(); $IT != $IT_END; $IT++){$$$}
31+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.rbegin(),
32+
$IT_END = $CONTAINER.rend(); $IT != $IT_END; ++$IT){$$$}
33+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.rbegin(),
34+
$IT_END = $CONTAINER.rend(); $IT != $IT_END; $IT++){$$$}
35+
- inside:
36+
not:
37+
kind: assignment_expression
38+
all:
39+
- has:
40+
stopBy: neighbor
41+
kind: identifier
42+
pattern: $IT
43+
- has:
44+
stopBy: neighbor
45+
regex: "^=$"
46+
- has:
47+
stopBy: neighbor
48+
kind: call_expression
49+
pattern: $CONTAINER.$R($IT)
50+
51+
constraints:
52+
R:
53+
regex: "^erase|assign|clear|insert|resize|push_back|reserve|shrink_to_fit|resize|pop_back$"
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
id: std-vector-invalidation-cpp
2+
language: cpp
3+
severity: warning
4+
message: >-
5+
Modifying an `std::vector` while iterating over it could cause the
6+
container to reallocate, triggering memory corruption.
7+
note: >-
8+
[CWE-416: Use After Free.
9+
[REFERENCES]
10+
- https://wiki.sei.cmu.edu/confluence/display/c/MEM30-C.+Do+not+access+freed+memory
11+
- https://wiki.sei.cmu.edu/confluence/display/cplusplus/EXP54-CPP.+Do+not+access+an+object+outside+of+its+lifetime
12+
rule:
13+
kind: call_expression
14+
all:
15+
- pattern: $CONTAINER.$R($$$)
16+
inside:
17+
stopBy: end
18+
kind: for_statement
19+
any:
20+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.begin(); $IT!= $CONTAINER.end(); ++$IT){$$$}
21+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.begin(); $IT!= $CONTAINER.end(); $IT++){$$$}
22+
- pattern:
23+
for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.rbegin(); $IT!= $CONTAINER.rend(); ++$IT)
24+
{$$$}
25+
- pattern:
26+
for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.rbegin(); $IT!= $CONTAINER.rend(); $IT++)
27+
{$$$}
28+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.begin(),$IT_END = $CONTAINER.end(); $IT !=$IT_END; ++$IT){$$$}
29+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.begin(),
30+
$IT_END = $CONTAINER.end(); $IT != $IT_END; $IT++){$$$}
31+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.rbegin(),
32+
$IT_END = $CONTAINER.rend(); $IT != $IT_END; ++$IT){$$$}
33+
- pattern: for(std::vector<$TY>::$IT_TYPE $IT = $CONTAINER.rbegin(),
34+
$IT_END = $CONTAINER.rend(); $IT != $IT_END; $IT++){$$$}
35+
- inside:
36+
not:
37+
kind: assignment_expression
38+
all:
39+
- has:
40+
stopBy: neighbor
41+
kind: identifier
42+
pattern: $IT
43+
- has:
44+
stopBy: neighbor
45+
regex: "^=$"
46+
- has:
47+
stopBy: neighbor
48+
kind: call_expression
49+
pattern: $CONTAINER.$R($IT)
50+
51+
constraints:
52+
R:
53+
regex: "^erase|assign|clear|insert|resize|push_back|reserve|shrink_to_fit|resize|pop_back$"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
id: std-vector-invalidation-c
2+
snapshots:
3+
? "void loop_variant_5(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_6(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_7(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.rbegin(); it != vec.rend(); ++it) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_8(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.rbegin(); it != vec.rend(); it++) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_9(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.begin(), end = vec.end(); it != end; ++it) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_10(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.begin(), end = vec.end(); it != end; it++) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_11(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.rbegin(), end = vec.rend(); it != end; ++it) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_12(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.rbegin(), end = vec.rend(); it != end; it++) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n} \nvoid f(std::vector<int> &vec, std::vector<int> &other_vec) {\nfor(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {\nif (foo()) {\n // ruleid: std-vector-invalidation\n vec.push_back(0);\n\n // Modifying a different container is OK\n // ok: std-vector-invalidation\n other_vec.push_back(0);\n}\n}\n}\n"
4+
: labels:
5+
- source: vec.erase(it)
6+
style: primary
7+
start: 183
8+
end: 196
9+
- source: |-
10+
for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
11+
if (should_erase(*it)) {
12+
// ruleid: std-vector-invalidation
13+
vec.erase(it);
14+
}
15+
}
16+
style: secondary
17+
start: 45
18+
end: 201
19+
- source: vec.erase(it);
20+
style: secondary
21+
start: 183
22+
end: 197
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
id: std-vector-invalidation-cpp
2+
snapshots:
3+
? "void loop_variant_5(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_6(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_7(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.rbegin(); it != vec.rend(); ++it) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_8(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.rbegin(); it != vec.rend(); it++) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_9(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.begin(), end = vec.end(); it != end; ++it) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_10(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.begin(), end = vec.end(); it != end; it++) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_11(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.rbegin(), end = vec.rend(); it != end; ++it) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n}\nvoid loop_variant_12(std::vector<int> &vec) {\nfor(std::vector<int>::iterator it = vec.rbegin(), end = vec.rend(); it != end; it++) {\nif (should_erase(*it)) {\n // ruleid: std-vector-invalidation\n vec.erase(it);\n}\n}\n} \nvoid f(std::vector<int> &vec, std::vector<int> &other_vec) {\nfor(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {\nif (foo()) {\n // ruleid: std-vector-invalidation\n vec.push_back(0);\n\n // Modifying a different container is OK\n // ok: std-vector-invalidation\n other_vec.push_back(0);\n}\n}\n}\n"
4+
: labels:
5+
- source: vec.erase(it)
6+
style: primary
7+
start: 183
8+
end: 196
9+
- source: |-
10+
for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
11+
if (should_erase(*it)) {
12+
// ruleid: std-vector-invalidation
13+
vec.erase(it);
14+
}
15+
}
16+
style: secondary
17+
start: 45
18+
end: 201
19+
- source: vec.erase(it);
20+
style: secondary
21+
start: 183
22+
end: 197
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
id: std-vector-invalidation-c
2+
valid:
3+
- |
4+
void f(std::vector<int> &vec) {
5+
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
6+
if (should_erase(*it)) {
7+
// This is the correct way to iterate while erasing
8+
// ok: std-vector-invalidation
9+
it = vec.erase(it);
10+
} else {
11+
++it;
12+
}
13+
}
14+
}
15+
bool isInList(const TCHAR *token2Find, std::vector<int> &params, bool eraseArg = true)
16+
{
17+
for (std::vector<int>::iterator = params.begin(); it != params.end(); ++it)
18+
{
19+
if (lstrcmp(token2Find, it->c_str()) == 0)
20+
{
21+
// ok: std-vector-invalidation
22+
if (eraseArg) params.erase(it);
23+
return true;
24+
}
25+
}
26+
return false;
27+
}
28+
invalid:
29+
- |
30+
void loop_variant_5(std::vector<int> &vec) {
31+
for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
32+
if (should_erase(*it)) {
33+
// ruleid: std-vector-invalidation
34+
vec.erase(it);
35+
}
36+
}
37+
}
38+
void loop_variant_6(std::vector<int> &vec) {
39+
for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
40+
if (should_erase(*it)) {
41+
// ruleid: std-vector-invalidation
42+
vec.erase(it);
43+
}
44+
}
45+
}
46+
void loop_variant_7(std::vector<int> &vec) {
47+
for(std::vector<int>::iterator it = vec.rbegin(); it != vec.rend(); ++it) {
48+
if (should_erase(*it)) {
49+
// ruleid: std-vector-invalidation
50+
vec.erase(it);
51+
}
52+
}
53+
}
54+
void loop_variant_8(std::vector<int> &vec) {
55+
for(std::vector<int>::iterator it = vec.rbegin(); it != vec.rend(); it++) {
56+
if (should_erase(*it)) {
57+
// ruleid: std-vector-invalidation
58+
vec.erase(it);
59+
}
60+
}
61+
}
62+
void loop_variant_9(std::vector<int> &vec) {
63+
for(std::vector<int>::iterator it = vec.begin(), end = vec.end(); it != end; ++it) {
64+
if (should_erase(*it)) {
65+
// ruleid: std-vector-invalidation
66+
vec.erase(it);
67+
}
68+
}
69+
}
70+
void loop_variant_10(std::vector<int> &vec) {
71+
for(std::vector<int>::iterator it = vec.begin(), end = vec.end(); it != end; it++) {
72+
if (should_erase(*it)) {
73+
// ruleid: std-vector-invalidation
74+
vec.erase(it);
75+
}
76+
}
77+
}
78+
void loop_variant_11(std::vector<int> &vec) {
79+
for(std::vector<int>::iterator it = vec.rbegin(), end = vec.rend(); it != end; ++it) {
80+
if (should_erase(*it)) {
81+
// ruleid: std-vector-invalidation
82+
vec.erase(it);
83+
}
84+
}
85+
}
86+
void loop_variant_12(std::vector<int> &vec) {
87+
for(std::vector<int>::iterator it = vec.rbegin(), end = vec.rend(); it != end; it++) {
88+
if (should_erase(*it)) {
89+
// ruleid: std-vector-invalidation
90+
vec.erase(it);
91+
}
92+
}
93+
}
94+
void f(std::vector<int> &vec, std::vector<int> &other_vec) {
95+
for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
96+
if (foo()) {
97+
// ruleid: std-vector-invalidation
98+
vec.push_back(0);
99+
100+
// Modifying a different container is OK
101+
// ok: std-vector-invalidation
102+
other_vec.push_back(0);
103+
}
104+
}
105+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
id: std-vector-invalidation-cpp
2+
valid:
3+
- |
4+
void f(std::vector<int> &vec) {
5+
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
6+
if (should_erase(*it)) {
7+
// This is the correct way to iterate while erasing
8+
// ok: std-vector-invalidation
9+
it = vec.erase(it);
10+
} else {
11+
++it;
12+
}
13+
}
14+
}
15+
bool isInList(const TCHAR *token2Find, std::vector<int> &params, bool eraseArg = true)
16+
{
17+
for (std::vector<int>::iterator = params.begin(); it != params.end(); ++it)
18+
{
19+
if (lstrcmp(token2Find, it->c_str()) == 0)
20+
{
21+
// ok: std-vector-invalidation
22+
if (eraseArg) params.erase(it);
23+
return true;
24+
}
25+
}
26+
return false;
27+
}
28+
invalid:
29+
- |
30+
void loop_variant_5(std::vector<int> &vec) {
31+
for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
32+
if (should_erase(*it)) {
33+
// ruleid: std-vector-invalidation
34+
vec.erase(it);
35+
}
36+
}
37+
}
38+
void loop_variant_6(std::vector<int> &vec) {
39+
for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
40+
if (should_erase(*it)) {
41+
// ruleid: std-vector-invalidation
42+
vec.erase(it);
43+
}
44+
}
45+
}
46+
void loop_variant_7(std::vector<int> &vec) {
47+
for(std::vector<int>::iterator it = vec.rbegin(); it != vec.rend(); ++it) {
48+
if (should_erase(*it)) {
49+
// ruleid: std-vector-invalidation
50+
vec.erase(it);
51+
}
52+
}
53+
}
54+
void loop_variant_8(std::vector<int> &vec) {
55+
for(std::vector<int>::iterator it = vec.rbegin(); it != vec.rend(); it++) {
56+
if (should_erase(*it)) {
57+
// ruleid: std-vector-invalidation
58+
vec.erase(it);
59+
}
60+
}
61+
}
62+
void loop_variant_9(std::vector<int> &vec) {
63+
for(std::vector<int>::iterator it = vec.begin(), end = vec.end(); it != end; ++it) {
64+
if (should_erase(*it)) {
65+
// ruleid: std-vector-invalidation
66+
vec.erase(it);
67+
}
68+
}
69+
}
70+
void loop_variant_10(std::vector<int> &vec) {
71+
for(std::vector<int>::iterator it = vec.begin(), end = vec.end(); it != end; it++) {
72+
if (should_erase(*it)) {
73+
// ruleid: std-vector-invalidation
74+
vec.erase(it);
75+
}
76+
}
77+
}
78+
void loop_variant_11(std::vector<int> &vec) {
79+
for(std::vector<int>::iterator it = vec.rbegin(), end = vec.rend(); it != end; ++it) {
80+
if (should_erase(*it)) {
81+
// ruleid: std-vector-invalidation
82+
vec.erase(it);
83+
}
84+
}
85+
}
86+
void loop_variant_12(std::vector<int> &vec) {
87+
for(std::vector<int>::iterator it = vec.rbegin(), end = vec.rend(); it != end; it++) {
88+
if (should_erase(*it)) {
89+
// ruleid: std-vector-invalidation
90+
vec.erase(it);
91+
}
92+
}
93+
}
94+
void f(std::vector<int> &vec, std::vector<int> &other_vec) {
95+
for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
96+
if (foo()) {
97+
// ruleid: std-vector-invalidation
98+
vec.push_back(0);
99+
100+
// Modifying a different container is OK
101+
// ok: std-vector-invalidation
102+
other_vec.push_back(0);
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)