Skip to content

Commit dc4604f

Browse files
authored
Merge pull request github#16367 from MathiasVP/better-documentation-for-iterator-to-expired-container
C++: Improve documentation for `cpp/iterator-to-expired-container`
2 parents 541effb + 40b6e16 commit dc4604f

File tree

4 files changed

+23
-17
lines changed

4 files changed

+23
-17
lines changed

cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ This is because the temporary container is not bound to a rvalue reference.
3030
</p>
3131
<sample src="IteratorToExpiredContainerExtendedLifetime.cpp" />
3232

33+
<p>
34+
To fix <code>lifetime_of_temp_not_extended</code>, consider rewriting the code so that the lifetime of the temporary object is extended.
35+
In <code>fixed_lifetime_of_temp_not_extended</code>, the lifetime of the temporary object has been extended by storing it in an rvalue reference.
36+
</p>
37+
<sample src="IteratorToExpiredContainerExtendedLifetime-fixed.cpp" />
38+
3339
</example>
3440
<references>
3541

cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,9 @@ DataFlow::Node getADestroyedNode(DataFlow::Node n) {
6262
)
6363
}
6464

65-
predicate destroyedToBeginSink(DataFlow::Node sink, FunctionCall fc) {
65+
predicate destroyedToBeginSink(DataFlow::Node sink) {
6666
exists(CallInstruction call |
6767
call = sink.asOperand().(ThisArgumentOperand).getCall() and
68-
fc = call.getUnconvertedResultExpression() and
6968
call.getStaticCallTarget() instanceof BeginOrEndFunction
7069
)
7170
}
@@ -90,7 +89,7 @@ private predicate qualifierToDestroyed(DataFlow::Node node1, DataFlow::Node node
9089
module Config0 implements DataFlow::ConfigSig {
9190
predicate isSource(DataFlow::Node source) { qualifierToDestroyed(_, source) }
9291

93-
predicate isSink(DataFlow::Node sink) { destroyedToBeginSink(sink, _) }
92+
predicate isSink(DataFlow::Node sink) { destroyedToBeginSink(sink) }
9493
}
9594

9695
module Flow0 = DataFlow::Global<Config0>;
@@ -150,9 +149,9 @@ module Config implements DataFlow::StateConfigSig {
150149

151150
module Flow = DataFlow::GlobalWithState<Config>;
152151

153-
from Flow::PathNode source, Flow::PathNode sink, FunctionCall beginOrEnd, DataFlow::Node mid
152+
from Flow::PathNode source, Flow::PathNode sink, DataFlow::Node mid
154153
where
155154
Flow::flowPath(source, sink) and
156-
destroyedToBeginSink(sink.getNode(), beginOrEnd) and
155+
destroyedToBeginSink(sink.getNode()) and
157156
sink.getState() = Config::DestroyedToBegin(mid)
158-
select mid, "This object is destroyed before $@ is called.", beginOrEnd, beginOrEnd.toString()
157+
select mid, "This object is destroyed at the end of the full-expression."
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
void fixed_lifetime_of_temp_not_extended() {
2+
auto&& v = get_vector();
3+
for(auto x : log_and_return_argument(v)) {
4+
use(x); // GOOD: The lifetime of the container returned by `get_vector()` has been extended to the lifetime of `v`.
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to begin | call to begin |
2-
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to end | call to end |
3-
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to begin | call to begin |
4-
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to end | call to end |
5-
| test.cpp:689:46:689:58 | pointer to ~vector output argument | This object is destroyed before $@ is called. | test.cpp:689:60:689:62 | call to end | call to end |
6-
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:19:703:23 | call to begin | call to begin |
7-
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:36:703:38 | call to end | call to end |
8-
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to begin | call to begin |
9-
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to end | call to end |
10-
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to begin | call to begin |
11-
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to end | call to end |
1+
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed at the end of the full-expression. |
2+
| test.cpp:683:31:683:32 | call to at | This object is destroyed at the end of the full-expression. |
3+
| test.cpp:689:46:689:58 | pointer to ~vector output argument | This object is destroyed at the end of the full-expression. |
4+
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed at the end of the full-expression. |
5+
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed at the end of the full-expression. |
6+
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed at the end of the full-expression. |

0 commit comments

Comments
 (0)