22 * @name Iterator to expired container
33 * @description Using an iterator owned by a container whose lifetime has expired may lead to unexpected behavior.
44 * @kind problem
5- * @precision high
5+ * @precision medium
66 * @id cpp/iterator-to-expired-container
77 * @problem.severity warning
8+ * @security-severity 8.8
89 * @tags reliability
910 * security
1011 * external/cwe/cwe-416
@@ -69,6 +70,31 @@ predicate destroyedToBeginSink(DataFlow::Node sink, FunctionCall fc) {
6970 )
7071}
7172
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+
7298/**
7399 * A configuration to track flow from a temporary variable to the qualifier of
74100 * a destructor call, and subsequently to a qualifier of a call to `begin` or
@@ -78,12 +104,15 @@ module Config implements DataFlow::StateConfigSig {
78104 newtype FlowState =
79105 additional TempToDestructor ( ) or
80106 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
85108 }
86109
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+
87116 predicate isSource ( DataFlow:: Node source , FlowState state ) {
88117 source .asInstruction ( ) .( VariableAddressInstruction ) .getIRVariable ( ) instanceof IRTempVariable and
89118 state = TempToDestructor ( )
@@ -92,16 +121,16 @@ module Config implements DataFlow::StateConfigSig {
92121 predicate isAdditionalFlowStep (
93122 DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
94123 ) {
95- tempToDestructorSink ( node1 , _) and
96124 state1 = TempToDestructor ( ) and
97125 state2 = DestroyedToBegin ( node2 ) and
98- node2 = getADestroyedNode ( node1 )
126+ qualifierToDestroyed ( node1 , node2 )
99127 }
100128
101129 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+ )
105134 }
106135
107136 DataFlow:: FlowFeature getAFeature ( ) {
0 commit comments