Skip to content

Commit aeccebc

Browse files
committed
return-c-str-cpp
1 parent 93e4125 commit aeccebc

File tree

3 files changed

+302
-0
lines changed

3 files changed

+302
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
id: return-c-str-cpp
2+
language: cpp
3+
severity: warning
4+
message: >-
5+
"`$FUNC` returns a pointer to the memory owned by `$STR`. This pointer
6+
is invalid after `$STR` goes out of scope, which can trigger a use after
7+
free."
8+
note: >-
9+
[CWE-416] Use After Free
10+
[REFERENCES]
11+
- https://wiki.sei.cmu.edu/confluence/display/c/DCL30-C.+Declare+objects+with+appropriate+storage+durations
12+
- https://wiki.sei.cmu.edu/confluence/display/cplusplus/EXP54-CPP.+Do+not+access+an+object+outside+of+its+lifetime
13+
14+
utils:
15+
util_for_declaration_inside_function:
16+
kind: return_statement
17+
pattern: return $STR.$METHOD();
18+
follows:
19+
kind: declaration
20+
stopBy: end
21+
any:
22+
- pattern: string $STR;
23+
- pattern: wstring $STR;
24+
- pattern: basic_string $STR;
25+
- pattern: std::string $STR;
26+
- pattern: std::wstring $STR;
27+
- pattern: std::basic_string<$TYPE> $STR;
28+
29+
util_for_assignment_inside_function:
30+
kind: return_statement
31+
pattern: return $STR.$METHOD();
32+
follows:
33+
kind: declaration
34+
stopBy: end
35+
any:
36+
- pattern: string $STR = string($STRING);
37+
- pattern: wstring $STR = wstring($STRING);
38+
- pattern: basic_string<$TYPE> $STR = basic_string<$TYPE>($STRING);
39+
- pattern: std::string $STR = std::string($STRING);
40+
- pattern: std::wstring $STR = std::wstring($STRING);
41+
- pattern: std::basic_string<$TYPE> $STR = std::basic_string<$TYPE>($STRING);
42+
43+
util_for_func_params:
44+
kind: return_statement
45+
pattern: return $STR.$METHOD();
46+
inside:
47+
stopBy: end
48+
kind: function_definition
49+
has:
50+
stopBy: end
51+
kind: parameter_list
52+
has:
53+
stopBy: end
54+
kind: parameter_declaration
55+
has:
56+
stopBy: end
57+
kind: identifier
58+
field: declarator
59+
pattern: $STR
60+
any:
61+
- has:
62+
any:
63+
- kind: type_identifier
64+
pattern: $IDENTIFIFER
65+
- kind: qualified_identifier
66+
any:
67+
- all:
68+
- has:
69+
kind: namespace_identifier
70+
pattern: $NAMESPACE_IDEN
71+
- has:
72+
kind: template_type
73+
all:
74+
- has:
75+
kind: type_identifier
76+
field: name
77+
pattern: $BASIC_STR
78+
precedes:
79+
kind: template_argument_list
80+
- pattern: $IDENTIFIFER
81+
- kind: template_type
82+
has:
83+
kind: type_identifier
84+
field: name
85+
pattern: $BASIC_STR
86+
precedes:
87+
kind: template_argument_list
88+
89+
rule:
90+
any:
91+
- matches: util_for_declaration_inside_function
92+
- matches: util_for_assignment_inside_function
93+
- matches: util_for_func_params
94+
- pattern: return basic_string<$TYPE>($$$).$METHOD();
95+
- pattern: return std::basic_string<$TYPE>($$$).$METHOD();
96+
- pattern: return string($$$).$METHOD();
97+
- pattern: return std::string($$$).$METHOD();
98+
- pattern: return wstring($$$).$METHOD();
99+
- pattern: return std::wstring($$$).$METHOD();
100+
101+
constraints:
102+
METHOD:
103+
regex: ^(c_str|data)$
104+
IDENTIFIFER:
105+
regex: ^(string|wstring|std::string|std::wstring)$
106+
BASIC_STR:
107+
regex: ^(basic_string)$
108+
NAMESPACE_IDEN:
109+
regex: ^(std)$
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
id: return-c-str-cpp
2+
snapshots:
3+
? |
4+
char *f() {
5+
std::string s = std::string("foo");
6+
return s.c_str();
7+
}
8+
: labels:
9+
- source: return s.c_str();
10+
style: primary
11+
start: 52
12+
end: 69
13+
- source: std::string s = std::string("foo");
14+
style: secondary
15+
start: 14
16+
end: 49
17+
? |
18+
char *f() {
19+
std::string s;
20+
return s.c_str();
21+
}
22+
: labels:
23+
- source: return s.c_str();
24+
style: primary
25+
start: 31
26+
end: 48
27+
- source: std::string s;
28+
style: secondary
29+
start: 14
30+
end: 28
31+
? |
32+
char *f(std::string s) {
33+
return s.c_str();
34+
}
35+
: labels:
36+
- source: return s.c_str();
37+
style: primary
38+
start: 27
39+
end: 44
40+
- source: std::string
41+
style: secondary
42+
start: 8
43+
end: 19
44+
- source: s
45+
style: secondary
46+
start: 20
47+
end: 21
48+
- source: std::string s
49+
style: secondary
50+
start: 8
51+
end: 21
52+
- source: (std::string s)
53+
style: secondary
54+
start: 7
55+
end: 22
56+
- source: |-
57+
char *f(std::string s) {
58+
return s.c_str();
59+
}
60+
style: secondary
61+
start: 0
62+
end: 46
63+
? |
64+
char *return_basic_string_directly() {
65+
return std::basic_string<char>("foo").c_str();
66+
}
67+
: labels:
68+
- source: return std::basic_string<char>("foo").c_str();
69+
style: primary
70+
start: 41
71+
end: 87
72+
? |
73+
char *return_data_directly() {
74+
return std::string("foo").data();
75+
}
76+
: labels:
77+
- source: return std::string("foo").data();
78+
style: primary
79+
start: 33
80+
end: 66
81+
? |
82+
char *return_directly() {
83+
return string("foo").c_str();
84+
}
85+
: labels:
86+
- source: return string("foo").c_str();
87+
style: primary
88+
start: 28
89+
end: 57
90+
? |
91+
char *return_namespace_directly() {
92+
return std::string("foo").c_str();
93+
}
94+
: labels:
95+
- source: return std::string("foo").c_str();
96+
style: primary
97+
start: 38
98+
end: 72
99+
? |
100+
class Foo {
101+
char *f() {
102+
std::string s = std::string("foo");
103+
return s.c_str();
104+
}
105+
};
106+
: labels:
107+
- source: return s.c_str();
108+
style: primary
109+
start: 70
110+
end: 87
111+
- source: std::string s = std::string("foo");
112+
style: secondary
113+
start: 30
114+
end: 65
115+
? |
116+
class Foo {
117+
char *f() {
118+
std::string s;
119+
return s.c_str();
120+
}
121+
};
122+
: labels:
123+
- source: return s.c_str();
124+
style: primary
125+
start: 49
126+
end: 66
127+
- source: std::string s;
128+
style: secondary
129+
start: 30
130+
end: 44

tests/cpp/return-c-str-cpp-test.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
id: return-c-str-cpp
2+
valid:
3+
- |
4+
std::string return_directly() {
5+
// ok: return-c-str
6+
return std::string("foo");
7+
}
8+
- |
9+
char *f() {
10+
static std::string s;
11+
// ok: return-c-str
12+
return s.c_str();
13+
}
14+
- |
15+
char *f() {
16+
std::string s1;
17+
return s.c_str();
18+
}
19+
invalid:
20+
- |
21+
char *f() {
22+
std::string s;
23+
return s.c_str();
24+
}
25+
- |
26+
char *f() {
27+
std::string s = std::string("foo");
28+
return s.c_str();
29+
}
30+
- |
31+
char *f(std::string s) {
32+
return s.c_str();
33+
}
34+
- |
35+
class Foo {
36+
char *f() {
37+
std::string s = std::string("foo");
38+
return s.c_str();
39+
}
40+
};
41+
- |
42+
class Foo {
43+
char *f() {
44+
std::string s;
45+
return s.c_str();
46+
}
47+
};
48+
- |
49+
char *return_namespace_directly() {
50+
return std::string("foo").c_str();
51+
}
52+
- |
53+
char *return_directly() {
54+
return string("foo").c_str();
55+
}
56+
- |
57+
char *return_basic_string_directly() {
58+
return std::basic_string<char>("foo").c_str();
59+
}
60+
- |
61+
char *return_data_directly() {
62+
return std::string("foo").data();
63+
}

0 commit comments

Comments
 (0)