Skip to content

Commit 1232120

Browse files
committed
C++: Naively copy the 'surprising lifetimes' query from Coding Standards and add required metadata.
1 parent e2602fb commit 1232120

File tree

3 files changed

+833
-0
lines changed

3 files changed

+833
-0
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
void c_api(const char*);
2+
3+
void bad_call_c_api() {
4+
// BAD: the memory returned by `c_str()` is freed when the temporary string is destroyed
5+
const char* p = std::string("hello").c_str();
6+
c_api(p);
7+
}
8+
9+
void good_call_c_api() {
10+
// GOOD: the "hello" string outlives the pointer returned by `c_str()`, so it's safe to pass it to `c_api()`
11+
std::string hello("hello");
12+
const char* p = hello.c_str();
13+
c_api(p);
14+
}
15+
16+
void bad_remove_even_numbers(std::vector<int>& v) {
17+
// BAD: the iterator is invalidated after the call to `erase`.
18+
for(std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
19+
if(*it % 2 == 0) {
20+
v.erase(it);
21+
}
22+
}
23+
}
24+
25+
void good_remove_even_numbers(std::vector<int>& v) {
26+
// GOOD: `erase` returns the iterator to the next element.
27+
for(std::vector<int>::iterator it = v.begin(); it != v.end(); ) {
28+
if(*it % 2 == 0) {
29+
it = v.erase(it);
30+
} else {
31+
++it;
32+
}
33+
}
34+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
Using an object after its lifetime has ended results in undefined behavior.
8+
When an object's lifetime has ended it relinquishes ownership of its resources and the memory it occupied may be reused for other purposes.
9+
If the object is accessed after its lifetime has ended, the program may crash or behave in unexpected ways.
10+
</p>
11+
12+
</overview>
13+
<recommendation>
14+
15+
<p>
16+
Ensure that no objct is accessed after its lifetime has ended.
17+
Use RAII ("Resource Acquisition Is Initialization") to manage the lifetime of objects, and avoid manual memory management, if possible.
18+
</p>
19+
20+
</recommendation>
21+
<example>
22+
<p>
23+
The following two functions demonstrate common lifetime violations when working with the C++ standard library.
24+
25+
The <code>bad_call_c_api</code> function contains a use of an expired lifetime.
26+
First, a temporary object of type <code>std::string</code> is constructed, and a pointer to its internal buffer is stored in a local variable.
27+
Once the <code>c_str()</code> call returns, the temporary object is destroyed, and the memory pointed to by <code>p</code> is freed.
28+
Thus, any attempt to dereference <code>p</code> inside <code>c_api</code> will result in a use-after-free vulnerability.
29+
30+
The <code>good_call_c_api</code> function contains a fixed version of the first example.
31+
The variable <code>hello</code> is declared as a local variable, and the pointer to its internal buffer is stored in <code>p</code>.
32+
The lifetime of hello outlives the call to <code>c_api</code>, so the pointer stored in <code>p</code> remains valid throughout the call to <code>c_api</code>.
33+
</p>
34+
35+
<p>
36+
The <code>bad_remove_even_numbers</code> function demonstrates a potential issue with iterator invalidation.
37+
Each C++ standard library container comes with a specification of which operations invalidates iterators pointing into the container.
38+
For example, calling <code>erase</code> on an object of type <code>std::vector&lt;T&gt;</code> invalidates all its iterators, and thus any attempt to dereference the iterator can result in a use-after-free vulnerability.
39+
40+
The <code>good_remove_even_numbers</code> function contains a fixd version of the third example.
41+
The <code>erase</code> function returns an iterator to the element following the last element removed, and this return value is used to ensure that <code>it</code> remains valid after the call to <code>erase</code>.
42+
43+
</p>
44+
<sample src="UseAfterExpiredLifetime.cpp" />
45+
46+
</example>
47+
<references>
48+
49+
<li>CERT C Coding Standard:
50+
<a href="https://wiki.sei.cmu.edu/confluence/display/c/MEM30-C.+Do+not+access+freed+memory">MEM30-C. Do not access freed memory</a>.</li>
51+
<li>
52+
OWASP:
53+
<a href="https://owasp.org/www-community/vulnerabilities/Using_freed_memory">Using freed memory</a>.
54+
</li>
55+
<li>
56+
<a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/docs/Lifetime.pdf">Lifetime safety: Preventing common dangling</a>
57+
</li>
58+
<li>
59+
<a href="https://en.cppreference.com/w/cpp/container">Containers library</a>
60+
</li>
61+
62+
</references>
63+
</qhelp>

0 commit comments

Comments
 (0)