@@ -104,6 +104,9 @@ private module SizeBarrier {
104104 hasSize ( _, source , _)
105105 }
106106
107+ /**
108+ * Holds if `left < right + k` holds if `g` evaluates to `testIsTrue`.
109+ */
107110 additional predicate isSink (
108111 DataFlow:: Node left , DataFlow:: Node right , IRGuardCondition g , int k , boolean testIsTrue
109112 ) {
@@ -124,11 +127,11 @@ private module SizeBarrier {
124127 )
125128 }
126129
127- private predicate operandGuardChecks (
128- IRGuardCondition g , Operand left , Operand right , int state , boolean edge
129- ) {
130+ /**
131+ * Holds if `small < large + state` holds if `g` evaluates to `edge`.
132+ */
133+ private predicate operandGuardChecks ( IRGuardCondition g , Operand left , int state , boolean edge ) {
130134 exists ( DataFlow:: Node nLeft , DataFlow:: Node nRight , int k |
131- nRight .asOperand ( ) = right and
132135 nLeft .asOperand ( ) = left and
133136 SizeBarrierConfig:: isSink ( nLeft , nRight , g , k , edge ) and
134137 state = getAFlowStateForNode ( nRight ) and
@@ -137,32 +140,71 @@ private module SizeBarrier {
137140 }
138141
139142 /**
140- * Gets an instruction that is guarded by a guard condition which ensures that
141- * the value of the instruction is upper-bounded by size of some allocation.
143+ * Gets an instruction `instr` that is guarded by a check such as `instr <= left + delta` where
144+ * `left <= _ + k` and `left` is the "small side" of of a relational comparison that checks
145+ * whether `left <= size` where `size` is the size of an allocation.
142146 */
143- Instruction getABarrierInstruction ( int state ) {
147+ Instruction getABarrierInstruction0 ( int delta , int k ) {
144148 exists ( IRGuardCondition g , ValueNumber value , Operand use , boolean edge |
145149 use = value .getAUse ( ) and
146- operandGuardChecks ( pragma [ only_bind_into ] ( g ) , pragma [ only_bind_into ] ( use ) , _,
147- pragma [ only_bind_into ] ( state ) , pragma [ only_bind_into ] ( edge ) ) and
148- result = value .getAnInstruction ( ) and
150+ // We know:
151+ // 1. result <= value + delta (by `bounded`)
152+ // 2. value < size + k + 1 (by `operandGuardChecks`).
153+ // Condition 2 implies: value <= size + k, so if we know
154+ // that `state >= k + delta` then we have:
155+ // result <= value + delta (by 1.)
156+ // <= size + k + delta (by 2.)
157+ // <= size + state (by the assumption).
158+ // Callers of `getABarrierInstruction0` should ensure that `state >= k + delta`
159+ // is satisfied.
160+ operandGuardChecks ( pragma [ only_bind_into ] ( g ) , pragma [ only_bind_into ] ( use ) ,
161+ pragma [ only_bind_into ] ( k + 1 ) , pragma [ only_bind_into ] ( edge ) ) and
162+ bounded ( result , value .getAnInstruction ( ) , delta ) and
149163 g .controls ( result .getBlock ( ) , edge )
150164 )
151165 }
152166
153167 /**
154- * Gets a `DataFlow::Node` that is guarded by a guard condition which ensures that
155- * the value of the node is upper-bounded by size of some allocation.
168+ * Gets an instruction that is guarded by a guard condition which ensures that
169+ * the value of the instruction is upper-bounded by size of some allocation.
156170 */
157- DataFlow:: Node getABarrierNode ( int state ) {
158- result .asOperand ( ) = getABarrierInstruction ( state ) .getAUse ( )
171+ bindingset [ state]
172+ pragma [ inline_late]
173+ Instruction getABarrierInstruction ( int state ) {
174+ exists ( int delta , int k |
175+ // See the implementation comments in `getABarrierInstruction0` for why
176+ // this conjunct is necessary.
177+ state >= k + delta and
178+ result = getABarrierInstruction0 ( delta , k )
179+ )
180+ }
181+
182+ private module ValidForStateConfig implements DataFlow:: ConfigSig {
183+ predicate isSource ( DataFlow:: Node source ) { hasSize ( _, source , _) }
184+
185+ predicate isSink ( DataFlow:: Node sink ) { isSink ( sink , _, _) }
186+
187+ additional predicate isSink ( DataFlow:: Node sink , int delta , int k ) {
188+ sink .asOperand ( ) = SizeBarrier:: getABarrierInstruction0 ( delta , k ) .getAUse ( )
189+ }
159190 }
160191
192+ private module ValidForStateFlow = DataFlow:: Global< ValidForStateConfig > ;
193+
161194 /**
162- * Gets the block of a node that is guarded (see `getABarrierInstruction` or
163- * `getABarrierNode` for the definition of what it means to be guarded) .
195+ * Gets a `DataFlow::Node` that is guarded by a guard condition which ensures that
196+ * the value of the node is upper-bounded by size of some allocation .
164197 */
165- IRBlock getABarrierBlock ( int state ) { result .getAnInstruction ( ) = getABarrierInstruction ( state ) }
198+ DataFlow:: Node getABarrierNode ( int state ) {
199+ exists ( DataFlow:: Node source , int delta , int k |
200+ ValidForStateFlow:: flow ( source , result ) and
201+ hasSize ( _, source , state ) and
202+ ValidForStateConfig:: isSink ( result , delta , k ) and
203+ // See the implementation comments in `getABarrierInstruction0` for why
204+ // this conjunct is necessary.
205+ state >= k + delta
206+ )
207+ }
166208}
167209
168210private module InterestingPointerAddInstruction {
0 commit comments