2
2
* @name Iterator to expired container
3
3
* @description Using an iterator owned by a container whose lifetime has expired may lead to unexpected behavior.
4
4
* @kind problem
5
- * @precision high
5
+ * @precision medium
6
6
* @id cpp/iterator-to-expired-container
7
7
* @problem.severity warning
8
+ * @security-severity 8.8
8
9
* @tags reliability
9
10
* security
10
11
* external/cwe/cwe-416
@@ -69,6 +70,31 @@ predicate destroyedToBeginSink(DataFlow::Node sink, FunctionCall fc) {
69
70
)
70
71
}
71
72
73
+ /**
74
+ * Holds if `node1` is the node corresponding to a qualifier of a destructor
75
+ * call and `node2` is a node that is destroyed as a result of `node1` being
76
+ * destroyed.
77
+ */
78
+ private predicate qualifierToDestroyed ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
79
+ tempToDestructorSink ( node1 , _) and
80
+ node2 = getADestroyedNode ( node1 )
81
+ }
82
+
83
+ /**
84
+ * A configuration to track flow from a destroyed node to a qualifier of
85
+ * a `begin` or `end` function call.
86
+ *
87
+ * This configuration exists to prevent a cartesian product between all sinks and
88
+ * all states in `Config::isSink`.
89
+ */
90
+ module Config0 implements DataFlow:: ConfigSig {
91
+ predicate isSource ( DataFlow:: Node source ) { qualifierToDestroyed ( _, source ) }
92
+
93
+ predicate isSink ( DataFlow:: Node sink ) { destroyedToBeginSink ( sink , _) }
94
+ }
95
+
96
+ module Flow0 = DataFlow:: Global< Config0 > ;
97
+
72
98
/**
73
99
* A configuration to track flow from a temporary variable to the qualifier of
74
100
* a destructor call, and subsequently to a qualifier of a call to `begin` or
@@ -78,12 +104,15 @@ module Config implements DataFlow::StateConfigSig {
78
104
newtype FlowState =
79
105
additional TempToDestructor ( ) or
80
106
additional DestroyedToBegin ( DataFlow:: Node n ) {
81
- exists ( DataFlow:: Node thisOperand |
82
- tempToDestructorSink ( thisOperand , _) and
83
- n = getADestroyedNode ( thisOperand )
84
- )
107
+ any ( Flow0:: PathNode pn | pn .isSource ( ) ) .getNode ( ) = n
85
108
}
86
109
110
+ /**
111
+ * Holds if `sink` is a qualifier to a call to `begin`, and `mid` is an
112
+ * object that is destroyed.
113
+ */
114
+ private predicate relevant ( DataFlow:: Node mid , DataFlow:: Node sink ) { Flow0:: flow ( mid , sink ) }
115
+
87
116
predicate isSource ( DataFlow:: Node source , FlowState state ) {
88
117
source .asInstruction ( ) .( VariableAddressInstruction ) .getIRVariable ( ) instanceof IRTempVariable and
89
118
state = TempToDestructor ( )
@@ -92,16 +121,16 @@ module Config implements DataFlow::StateConfigSig {
92
121
predicate isAdditionalFlowStep (
93
122
DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
94
123
) {
95
- tempToDestructorSink ( node1 , _) and
96
124
state1 = TempToDestructor ( ) and
97
125
state2 = DestroyedToBegin ( node2 ) and
98
- node2 = getADestroyedNode ( node1 )
126
+ qualifierToDestroyed ( node1 , node2 )
99
127
}
100
128
101
129
predicate isSink ( DataFlow:: Node sink , FlowState state ) {
102
- // Note: This is a non-trivial cartesian product!
103
- // Hopefully, both of these sets are quite small in practice
104
- destroyedToBeginSink ( sink , _) and state instanceof DestroyedToBegin
130
+ exists ( DataFlow:: Node mid |
131
+ relevant ( mid , sink ) and
132
+ state = DestroyedToBegin ( mid )
133
+ )
105
134
}
106
135
107
136
DataFlow:: FlowFeature getAFeature ( ) {
0 commit comments