88import cpp
99private import semmle.code.cpp.ir.IR
1010private import semmle.code.cpp.controlflow.IRGuards
11+ private import semmle.code.cpp.ir.ValueNumbering
1112
1213private newtype TSign = TNeg ( ) or TZero ( ) or TPos ( )
1314private class Sign extends TSign {
@@ -130,21 +131,29 @@ private Sign certainInstructionSign(Instruction inst) {
130131/** Holds if the sign of `e` is too complicated to determine. */
131132private predicate unknownSign ( Instruction i ) {
132133 (
133- i instanceof UnmodeledDefinitionInstruction or
134- i instanceof UninitializedInstruction or
135- i instanceof InitializeParameterInstruction or
136- i instanceof BuiltInInstruction or
134+ i instanceof UnmodeledDefinitionInstruction
135+ or
136+ i instanceof UninitializedInstruction
137+ or
138+ i instanceof InitializeParameterInstruction
139+ or
140+ i instanceof BuiltInInstruction
141+ or
137142 i instanceof CallInstruction
143+ or
144+ i instanceof ConvertInstruction and
145+ i .getResultType ( ) .( IntegralType ) .isSigned ( )
138146 )
139147}
140148
141149/**
142- * Holds if `lowerbound` is a lower bound for `compared ` at `pos`. This is restricted
150+ * Holds if `lowerbound` is a lower bound for `bounded ` at `pos`. This is restricted
143151 * to only include bounds for which we might determine a sign.
144152 */
145- private predicate lowerBound ( Instruction lowerbound , Instruction compared , Instruction pos , boolean isStrict ) {
146- exists ( int adjustment , IRGuardCondition comp |
147- pos .getAnOperand ( ) = compared and
153+ private predicate lowerBound ( IRGuardCondition comp , Instruction lowerbound , Instruction bounded , Instruction pos , boolean isStrict ) {
154+ exists ( int adjustment , Instruction compared |
155+ valueNumber ( bounded ) = valueNumber ( compared ) and
156+ bounded = pos .getAnOperand ( ) and
148157 /*
149158 * Java library uses guardControlsSsaRead here. I think that the phi node logic doesn't need to
150159 * be duplicated but the implication predicates may need to be ported
@@ -156,18 +165,19 @@ private predicate lowerBound(Instruction lowerbound, Instruction compared, Instr
156165 isStrict = false and
157166 adjustment = 1
158167 ) and
159- comp .ensuresLt ( lowerbound , compared , 0 , pos .getBlock ( ) , true )
168+ comp .ensuresLt ( lowerbound , compared , adjustment , pos .getBlock ( ) , true )
160169 )
161170}
162171
163172
164173/**
165- * Holds if `upperbound` is an upper bound for `compared ` at `pos`. This is restricted
174+ * Holds if `upperbound` is an upper bound for `bounded ` at `pos`. This is restricted
166175 * to only include bounds for which we might determine a sign.
167176 */
168- private predicate upperBound ( Instruction upperbound , Instruction compared , Instruction pos , boolean isStrict ) {
169- exists ( int adjustment , IRGuardCondition comp |
170- pos .getAnOperand ( ) = compared and
177+ private predicate upperBound ( IRGuardCondition comp , Instruction upperbound , Instruction bounded , Instruction pos , boolean isStrict ) {
178+ exists ( int adjustment , Instruction compared |
179+ valueNumber ( bounded ) = valueNumber ( compared ) and
180+ bounded = pos .getAnOperand ( ) and
171181 /*
172182 * Java library uses guardControlsSsaRead here. I think that the phi node logic doesn't need to
173183 * be duplicated but the implication predicates may need to be ported
@@ -179,20 +189,21 @@ private predicate upperBound(Instruction upperbound, Instruction compared, Instr
179189 isStrict = false and
180190 adjustment = 1
181191 ) and
182- comp .ensuresLt ( compared , upperbound , 0 , pos .getBlock ( ) , true )
192+ comp .ensuresLt ( compared , upperbound , adjustment , pos .getBlock ( ) , true )
183193 )
184194}
185195
186196/**
187- * Holds if `eqbound` is an equality/inequality for `v ` at `pos`. This is
197+ * Holds if `eqbound` is an equality/inequality for `bounded ` at `pos`. This is
188198 * restricted to only include bounds for which we might determine a sign. The
189199 * boolean `isEq` gives the polarity:
190- * - `isEq = true` : `v = eqbound`
191- * - `isEq = false` : `v != eqbound`
200+ * - `isEq = true` : `bounded = eqbound`
201+ * - `isEq = false` : `bounded != eqbound`
192202 */
193- private predicate eqBound ( Instruction eqbound , Instruction compared , Instruction pos , boolean isEq ) {
194- exists ( IRGuardCondition guard |
195- pos .getAnOperand ( ) = compared and
203+ private predicate eqBound ( IRGuardCondition guard , Instruction eqbound , Instruction bounded , Instruction pos , boolean isEq ) {
204+ exists ( Instruction compared |
205+ valueNumber ( bounded ) = valueNumber ( compared ) and
206+ bounded = pos .getAnOperand ( ) and
196207 guard .ensuresEq ( compared , eqbound , 0 , pos .getBlock ( ) , isEq )
197208 )
198209}
@@ -203,48 +214,48 @@ private predicate eqBound(Instruction eqbound, Instruction compared, Instruction
203214 * Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
204215 * order for `v` to be positive.
205216 */
206- private predicate posBound ( Instruction bound , Instruction v , Instruction pos ) {
207- upperBound ( bound , v , pos , _) or
208- eqBound ( bound , v , pos , true )
217+ private predicate posBound ( IRGuardCondition comp , Instruction bound , Instruction v , Instruction pos ) {
218+ upperBound ( comp , bound , v , pos , _) or
219+ eqBound ( comp , bound , v , pos , true )
209220}
210221
211222/**
212223 * Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
213224 * order for `v` to be negative.
214225 */
215- private predicate negBound ( Instruction bound , Instruction v , Instruction pos ) {
216- lowerBound ( bound , v , pos , _) or
217- eqBound ( bound , v , pos , true )
226+ private predicate negBound ( IRGuardCondition comp , Instruction bound , Instruction v , Instruction pos ) {
227+ lowerBound ( comp , bound , v , pos , _) or
228+ eqBound ( comp , bound , v , pos , true )
218229}
219230
220231/**
221232 * Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
222233 * can be zero.
223234 */
224- private predicate zeroBound ( Instruction bound , Instruction v , Instruction pos ) {
225- lowerBound ( bound , v , pos , _) or
226- upperBound ( bound , v , pos , _) or
227- eqBound ( bound , v , pos , _)
235+ private predicate zeroBound ( IRGuardCondition comp , Instruction bound , Instruction v , Instruction pos ) {
236+ lowerBound ( comp , bound , v , pos , _) or
237+ upperBound ( comp , bound , v , pos , _) or
238+ eqBound ( comp , bound , v , pos , _)
228239}
229240
230241/** Holds if `bound` allows `v` to be positive at `pos`. */
231- private predicate posBoundOk ( Instruction bound , Instruction v , Instruction pos ) {
232- posBound ( bound , v , pos ) and TPos ( ) = instructionSign ( bound )
242+ private predicate posBoundOk ( IRGuardCondition comp , Instruction bound , Instruction v , Instruction pos ) {
243+ posBound ( comp , bound , v , pos ) and TPos ( ) = operandSign ( comp , bound )
233244}
234245
235246/** Holds if `bound` allows `v` to be negative at `pos`. */
236- private predicate negBoundOk ( Instruction bound , Instruction v , Instruction pos ) {
237- negBound ( bound , v , pos ) and TNeg ( ) = instructionSign ( bound )
247+ private predicate negBoundOk ( IRGuardCondition comp , Instruction bound , Instruction v , Instruction pos ) {
248+ negBound ( comp , bound , v , pos ) and TNeg ( ) = operandSign ( comp , bound )
238249}
239250
240251/** Holds if `bound` allows `v` to be zero at `pos`. */
241- private predicate zeroBoundOk ( Instruction bound , Instruction v , Instruction pos ) {
242- lowerBound ( bound , v , pos , _) and TNeg ( ) = instructionSign ( bound ) or
243- lowerBound ( bound , v , pos , false ) and TZero ( ) = instructionSign ( bound ) or
244- upperBound ( bound , v , pos , _) and TPos ( ) = instructionSign ( bound ) or
245- upperBound ( bound , v , pos , false ) and TZero ( ) = instructionSign ( bound ) or
246- eqBound ( bound , v , pos , true ) and TZero ( ) = instructionSign ( bound ) or
247- eqBound ( bound , v , pos , false ) and TZero ( ) != instructionSign ( bound )
252+ private predicate zeroBoundOk ( IRGuardCondition comp , Instruction bound , Instruction v , Instruction pos ) {
253+ lowerBound ( comp , bound , v , pos , _) and TNeg ( ) = operandSign ( comp , bound ) or
254+ lowerBound ( comp , bound , v , pos , false ) and TZero ( ) = operandSign ( comp , bound ) or
255+ upperBound ( comp , bound , v , pos , _) and TPos ( ) = operandSign ( comp , bound ) or
256+ upperBound ( comp , bound , v , pos , false ) and TZero ( ) = operandSign ( comp , bound ) or
257+ eqBound ( comp , bound , v , pos , true ) and TZero ( ) = operandSign ( comp , bound ) or
258+ eqBound ( comp , bound , v , pos , false ) and TZero ( ) != operandSign ( comp , bound )
248259}
249260
250261private Sign binaryOpLhsSign ( Instruction i ) {
@@ -254,28 +265,50 @@ private Sign binaryOpLhsSign(Instruction i) {
254265private Sign binaryOpRhsSign ( Instruction i ) {
255266 result = operandSign ( i , i .( BinaryInstruction ) .getRightOperand ( ) )
256267}
268+
257269pragma [ noinline]
258270private predicate binaryOpSigns ( Instruction i , Sign lhs , Sign rhs ) {
259271 lhs = binaryOpLhsSign ( i ) and
260272 rhs = binaryOpRhsSign ( i )
261273}
262274
275+ private Sign unguardedOperandSign ( Instruction pos , Instruction operand ) {
276+ result = instructionSign ( operand ) and
277+ not hasGuard ( operand , pos , result )
278+ }
279+
280+ private Sign guardedOperandSign ( Instruction pos , Instruction operand ) {
281+ result = instructionSign ( operand ) and
282+ hasGuard ( operand , pos , result )
283+ }
284+
285+ private Sign guardedOperandSignOk ( Instruction pos , Instruction operand ) {
286+ result = TPos ( ) and forex ( IRGuardCondition guard , Instruction bound | posBound ( guard , bound , operand , pos ) | posBoundOk ( guard , bound , operand , pos ) ) or
287+ result = TNeg ( ) and forex ( IRGuardCondition guard , Instruction bound | negBound ( guard , bound , operand , pos ) | negBoundOk ( guard , bound , operand , pos ) ) or
288+ result = TZero ( ) and forex ( IRGuardCondition guard , Instruction bound | zeroBound ( guard , bound , operand , pos ) | zeroBoundOk ( guard , bound , operand , pos ) )
289+ }
290+
263291/**
264292 * Holds if there is a bound that might restrict whether `v` has the sign `s`
265293 * at `pos`.
266294 */
267295private predicate hasGuard ( Instruction v , Instruction pos , Sign s ) {
268- s = TPos ( ) and posBound ( _, v , pos ) or
269- s = TNeg ( ) and negBound ( _, v , pos ) or
270- s = TZero ( ) and zeroBound ( _, v , pos )
296+ s = TPos ( ) and posBound ( _, _, v , pos )
297+ or
298+ s = TNeg ( ) and negBound ( _, _, v , pos )
299+ or
300+ s = TZero ( ) and zeroBound ( _, _, v , pos )
271301}
272302
303+ /**
304+ * Gets a sign that `operand` may have at `pos`, taking guards into account.
305+ */
273306cached
274307private Sign operandSign ( Instruction pos , Instruction operand ) {
275- hasGuard ( operand , pos , result )
308+ result = unguardedOperandSign ( pos , operand )
276309 or
277- not hasGuard ( operand , pos , _ ) and
278- result = instructionSign ( operand )
310+ result = guardedOperandSign ( pos , operand ) and
311+ result = guardedOperandSignOk ( pos , operand )
279312}
280313
281314cached
@@ -289,15 +322,12 @@ private Sign instructionSign(Instruction i) {
289322 exists ( Instruction prior |
290323 prior = i .( CopyInstruction ) .getSourceValue ( )
291324 |
292- hasGuard ( prior , i , result )
293- or
294- not exists ( Sign s | hasGuard ( prior , i , s ) ) and
295- result = instructionSign ( prior )
325+ result = operandSign ( i , prior )
296326 )
297327 or
298- result = instructionSign ( i .( BitComplementInstruction ) .getOperand ( ) ) .bitnot ( )
328+ result = operandSign ( i , i .( BitComplementInstruction ) .getOperand ( ) ) .bitnot ( )
299329 or
300- result = instructionSign ( i . ( AddInstruction ) )
330+ result = operandSign ( i , i . ( NegateInstruction ) . getOperand ( ) ) . neg ( )
301331 or
302332 exists ( Sign s1 , Sign s2 |
303333 binaryOpSigns ( i , s1 , s2 )
@@ -340,22 +370,47 @@ predicate positive(Instruction i) {
340370 not instructionSign ( i ) = TNeg ( )
341371}
342372
373+ predicate positive ( Instruction i , Instruction pos ) {
374+ operandSign ( pos , i ) = TPos ( ) and
375+ not operandSign ( pos , i ) = TNeg ( )
376+ }
377+
343378/** Holds if `e` can be negative and cannot be positive. */
344379predicate negative ( Instruction i ) {
345380 instructionSign ( i ) = TNeg ( ) and
346381 not instructionSign ( i ) = TPos ( )
347382}
348383
384+ /** Holds if `e` can be negative and cannot be positive. */
385+ predicate negative ( Instruction i , Instruction pos ) {
386+ operandSign ( pos , i ) = TNeg ( ) and
387+ not operandSign ( pos , i ) = TPos ( )
388+ }
389+
349390/** Holds if `e` is strictly positive. */
350391predicate strictlyPositive ( Instruction i ) {
351392 instructionSign ( i ) = TPos ( ) and
352393 not instructionSign ( i ) = TNeg ( ) and
353394 not instructionSign ( i ) = TZero ( )
354395}
355396
397+ /** Holds if `e` is strictly positive. */
398+ predicate strictlyPositive ( Instruction i , Instruction pos ) {
399+ operandSign ( pos , i ) = TPos ( ) and
400+ not operandSign ( pos , i ) = TNeg ( ) and
401+ not operandSign ( pos , i ) = TZero ( )
402+ }
356403/** Holds if `e` is strictly negative. */
357404predicate strictlyNegative ( Instruction i ) {
358405 instructionSign ( i ) = TNeg ( ) and
359406 not instructionSign ( i ) = TPos ( ) and
360407 not instructionSign ( i ) = TZero ( )
361408}
409+
410+
411+ /** Holds if `e` can be negative and cannot be positive. */
412+ predicate strictlyNegative ( Instruction i , Instruction pos ) {
413+ operandSign ( pos , i ) = TNeg ( ) and
414+ not operandSign ( pos , i ) = TPos ( ) and
415+ not operandSign ( pos , i ) = TZero ( )
416+ }
0 commit comments