Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d1ae939

Browse files
author
Robert Marsh
committed
C++: use guards and operands in sign analysis
1 parent 08e9eea commit d1ae939

11 files changed

Lines changed: 671 additions & 468 deletions

File tree

cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll

Lines changed: 108 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import cpp
99
private import semmle.code.cpp.ir.IR
1010
private import semmle.code.cpp.controlflow.IRGuards
11+
private import semmle.code.cpp.ir.ValueNumbering
1112

1213
private newtype TSign = TNeg() or TZero() or TPos()
1314
private 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. */
131132
private 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

250261
private Sign binaryOpLhsSign(Instruction i) {
@@ -254,28 +265,50 @@ private Sign binaryOpLhsSign(Instruction i) {
254265
private Sign binaryOpRhsSign(Instruction i) {
255266
result = operandSign(i, i.(BinaryInstruction).getRightOperand())
256267
}
268+
257269
pragma[noinline]
258270
private 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
*/
267295
private 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+
*/
273306
cached
274307
private 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

281314
cached
@@ -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. */
344379
predicate 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. */
350391
predicate 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. */
357404
predicate 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

Comments
 (0)