@@ -104,6 +104,9 @@ private module SizeBarrier {
104
104
hasSize ( _, source , _)
105
105
}
106
106
107
+ /**
108
+ * Holds if `left < right + k` holds if `g` evaluates to `testIsTrue`.
109
+ */
107
110
additional predicate isSink (
108
111
DataFlow:: Node left , DataFlow:: Node right , IRGuardCondition g , int k , boolean testIsTrue
109
112
) {
@@ -124,11 +127,11 @@ private module SizeBarrier {
124
127
)
125
128
}
126
129
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 ) {
130
134
exists ( DataFlow:: Node nLeft , DataFlow:: Node nRight , int k |
131
- nRight .asOperand ( ) = right and
132
135
nLeft .asOperand ( ) = left and
133
136
SizeBarrierConfig:: isSink ( nLeft , nRight , g , k , edge ) and
134
137
state = getAFlowStateForNode ( nRight ) and
@@ -137,32 +140,71 @@ private module SizeBarrier {
137
140
}
138
141
139
142
/**
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.
142
146
*/
143
- Instruction getABarrierInstruction ( int state ) {
147
+ Instruction getABarrierInstruction0 ( int delta , int k ) {
144
148
exists ( IRGuardCondition g , ValueNumber value , Operand use , boolean edge |
145
149
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
149
163
g .controls ( result .getBlock ( ) , edge )
150
164
)
151
165
}
152
166
153
167
/**
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.
156
170
*/
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
+ }
159
190
}
160
191
192
+ private module ValidForStateFlow = DataFlow:: Global< ValidForStateConfig > ;
193
+
161
194
/**
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 .
164
197
*/
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
+ }
166
208
}
167
209
168
210
private module InterestingPointerAddInstruction {
0 commit comments