C++: respond to further PR comments

This commit is contained in:
Robert Marsh
2018-12-12 16:50:26 -08:00
parent ae4ffd9166
commit 89148a9ec7
9 changed files with 146 additions and 104 deletions

View File

@@ -295,7 +295,7 @@ class IRGuardCondition extends Instruction {
* return x;
* ```
*/
predicate controlsEdgeDirectly(ConditionalBranchInstruction branch, IRBlock succ, boolean testIsTrue) {
predicate hasBranchEdge(ConditionalBranchInstruction branch, IRBlock succ, boolean testIsTrue) {
branch.getCondition() = this and
(
testIsTrue = true and

View File

@@ -751,6 +751,9 @@ class BinaryInstruction extends Instruction {
result = getAnOperand().(RightOperand).getDefinitionInstruction()
}
/**
* Holds if this instruction's operands are `op1` and `op2`, in either order.
*/
final predicate hasOperands(Operand op1, Operand op2) {
op1 = getAnOperand().(LeftOperand) and op2 = getAnOperand().(RightOperand)
or

View File

@@ -83,6 +83,10 @@ class ValueNumber extends TValueNumber {
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
}
final Operand getAUse() {
this = valueNumber(result.getDefinitionInstruction())
}
}
/**
@@ -220,6 +224,13 @@ ValueNumber valueNumber(Instruction instr) {
)
}
/**
* Gets the value number assigned to `instr`, if any. Returns at most one result.
*/
ValueNumber valueNumberOfOperand(Operand op) {
result = valueNumber(op.getDefinitionInstruction())
}
/**
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
* value number.

View File

@@ -6,10 +6,6 @@ private newtype TBound =
TBoundInstruction(Instruction i) {
i.getResultType() instanceof IntegralType or
i.getResultType() instanceof PointerType
} or
TBoundOperand(Operand o) {
o.getDefinitionInstruction().getResultType() instanceof IntegralType or
o.getDefinitionInstruction().getResultType() instanceof PointerType
}
/**
@@ -53,23 +49,3 @@ class InstructionBound extends Bound, TBoundInstruction {
getInstruction().getLocation().hasLocationInfo(path, sl, sc, el, ec)
}
}
/**
* A bound corresponding to the value of an `Operand`.
*/
class OperandBound extends Bound, TBoundOperand {
Operand getOperand() {
this = TBoundOperand(result)
}
override Instruction getInstruction(int delta) {
this = TBoundOperand(result.getAUse()) and
delta = 0
}
override string toString() { result = getOperand().toString() }
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
getOperand().getLocation().hasLocationInfo(path, sl, sc, el, ec)
}
}

View File

@@ -124,14 +124,10 @@ import RangeAnalysisPublic
* - `isEq = true` : `i == bound + delta`
* - `isEq = false` : `i != bound + delta`
*/
private IRGuardCondition eqFlowCond(Operand op, Operand bound, int delta,
private IRGuardCondition eqFlowCond(ValueNumber vn, Operand bound, int delta,
boolean isEq, boolean testIsTrue)
{
exists(Operand compared |
result.ensuresEq(compared, bound, delta, op.getInstruction().getBlock(), isEq) and
result.controls(bound.getInstruction().getBlock(), testIsTrue) and
valueNumber(compared.getDefinitionInstruction()) = valueNumber (op.getDefinitionInstruction())
)
result.comparesEq(vn.getAUse(), bound, delta, isEq, testIsTrue)
}
/**
@@ -147,8 +143,9 @@ private predicate boundFlowStepSsa(
reason = TNoReason() and
delta = 0
or*/
exists(IRGuardCondition guard |
guard = boundFlowCond(op2, op1, delta, upper, _) and
exists(IRGuardCondition guard, boolean testIsTrue |
guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and
guard.controls(op2.getInstruction().getBlock(), testIsTrue) and
reason = TCondReason(guard)
)
}
@@ -160,37 +157,19 @@ private predicate boundFlowStepSsa(
* - `upper = true` : `op <= bound + delta`
* - `upper = false` : `op >= bound + delta`
*/
private IRGuardCondition boundFlowCond(NonPhiOperand op, NonPhiOperand bound, int delta, boolean upper,
private IRGuardCondition boundFlowCond(ValueNumber vn, NonPhiOperand bound, int delta, boolean upper,
boolean testIsTrue)
{
exists(Operand compared |
result.comparesLt(compared, bound, delta, upper, testIsTrue) and
result.controls(op.getInstruction().getBlock(), testIsTrue) and
valueNumber(compared.getDefinitionInstruction()) = valueNumber(op.getDefinitionInstruction())
)
// TODO: strengthening through modulus library
}
/**
* Gets a condition that tests whether `op` is bounded by `bound + delta`.
*
* - `upper = true` : `op <= bound + delta`
* - `upper = false` : `op >= bound + delta`
*/
private IRGuardCondition boundFlowCondPhi(PhiOperand op, NonPhiOperand bound, int delta, boolean upper,
boolean testIsTrue)
{
exists(Operand compared |
result.comparesLt(compared, bound, delta, upper, testIsTrue) and
result.controlsEdgeDirectly(op.getPredecessorBlock().getLastInstruction(), op.getInstruction().getBlock(), testIsTrue) and
valueNumber(compared.getDefinitionInstruction()) = valueNumber (op.getDefinitionInstruction())
exists(int d |
result.comparesLt(vn.getAUse(), bound, d, upper, testIsTrue) and
// strengthen from x < y to x <= y-1
if upper = true
then delta = d-1
else delta = d
)
or
exists(Operand compared |
result.comparesLt(compared, bound, delta, upper, testIsTrue) and
result.controls(op.getPredecessorBlock(), testIsTrue) and
valueNumber(compared.getDefinitionInstruction()) = valueNumber (op.getDefinitionInstruction())
)
result = eqFlowCond(vn, bound, delta, true, testIsTrue) and
(upper = true or upper = false)
// TODO: strengthening through modulus library
}
@@ -239,6 +218,9 @@ private predicate safeCast(IntegralType fromtyp, IntegralType totyp) {
private class SafeCastInstruction extends ConvertInstruction {
SafeCastInstruction() {
safeCast(getResultType(), getOperand().getResultType())
or
getResultType() instanceof PointerType and
getOperand().getResultType() instanceof PointerType
}
}
@@ -402,8 +384,13 @@ private predicate boundFlowStepPhi(
reason = TNoReason() and
delta = 0
or
exists(IRGuardCondition guard |
guard = boundFlowCondPhi(op2, op1, delta, upper, _) and
exists(IRGuardCondition guard, boolean testIsTrue |
guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and
(
guard.hasBranchEdge(op2.getPredecessorBlock().getLastInstruction(), op2.getInstruction().getBlock(), testIsTrue)
or
guard.controls(op2.getPredecessorBlock(), testIsTrue)
) and
reason = TCondReason(guard)
)
}
@@ -476,8 +463,6 @@ private predicate boundedPhiInp(
) {
phi.getAnOperand() = op and
exists(int d, boolean fromBackEdge0 |
boundedInstruction(op.getDefinitionInstruction(), b, d, upper, fromBackEdge0, origdelta, reason)
or
boundedPhiOperand(op, b, d, upper, fromBackEdge0, origdelta, reason)
or
b.(InstructionBound).getInstruction() = op.getDefinitionInstruction() and
@@ -564,6 +549,7 @@ private predicate boundedInstruction(
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
)
or
not i instanceof PhiInstruction and
i = b.getInstruction(delta) and
(upper = true or upper = false) and
fromBackEdge = false and

View File

@@ -44,4 +44,21 @@ predicate valueFlowStep(Instruction i, Operand op, int delta) {
|
delta = -getValue(getConstantValue(x.getDefinitionInstruction()))
)
or
exists(Operand x |
i.(PointerAddInstruction).getAnOperand() = op and
i.(PointerAddInstruction).getAnOperand() = x and
op != x
|
delta = i.(PointerAddInstruction).getElementSize() *
getValue(getConstantValue(x.getDefinitionInstruction()))
)
or
exists(Operand x |
i.(PointerSubInstruction).getAnOperand().(LeftOperand) = op and
i.(PointerSubInstruction).getAnOperand().(RightOperand) = x
|
delta = i.(PointerSubInstruction).getElementSize() *
-getValue(getConstantValue(x.getDefinitionInstruction()))
)
}

View File

@@ -1,26 +1,39 @@
| test.cpp:8:9:8:9 | Load: y | test.cpp:6:15:6:15 | InitializeParameter: x | 1 | false | CompareLT: ... < ... |
| test.cpp:10:10:10:10 | Load: x | test.cpp:6:15:6:15 | InitializeParameter: x | 0 | false | NoReason |
| test.cpp:10:10:10:10 | Load: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | CompareLT: ... < ... |
| test.cpp:10:10:10:10 | Load: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | NoReason |
| test.cpp:16:9:16:9 | Load: y | test.cpp:14:15:14:15 | InitializeParameter: x | 1 | false | CompareLT: ... < ... |
| test.cpp:18:9:18:9 | Load: x | test.cpp:14:22:14:22 | InitializeParameter: y | 0 | false | CompareLT: ... < ... |
| test.cpp:20:10:20:10 | Load: x | test.cpp:14:15:14:15 | InitializeParameter: x | -2 | false | NoReason |
| test.cpp:20:10:20:10 | Load: x | test.cpp:14:22:14:22 | InitializeParameter: y | -2 | false | CompareLT: ... < ... |
| test.cpp:26:14:26:14 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason |
| test.cpp:26:21:26:23 | Load: ... ++ | file://:0:0:0:0 | 0 | 0 | false | NoReason |
| test.cpp:26:21:26:23 | Load: ... ++ | test.cpp:24:15:24:15 | InitializeParameter: x | 0 | true | CompareLT: ... < ... |
| test.cpp:27:7:27:7 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason |
| test.cpp:27:7:27:7 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | 0 | true | CompareLT: ... < ... |
| test.cpp:29:14:29:14 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | 0 | true | NoReason |
| test.cpp:29:21:29:23 | Load: ... -- | file://:0:0:0:0 | 0 | 1 | false | CompareGT: ... > ... |
| test.cpp:29:21:29:23 | Load: ... -- | test.cpp:24:15:24:15 | InitializeParameter: x | 0 | true | NoReason |
| test.cpp:30:7:30:7 | Load: i | file://:0:0:0:0 | 0 | 1 | false | CompareGT: ... > ... |
| test.cpp:30:7:30:7 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | 0 | true | NoReason |
| test.cpp:37:6:37:10 | Load: begin | test.cpp:35:28:35:30 | InitializeParameter: end | 0 | true | CompareLT: ... < ... |
| test.cpp:37:16:37:20 | Load: begin | test.cpp:35:28:35:30 | InitializeParameter: end | 0 | true | CompareLT: ... < ... |
| test.cpp:38:5:38:11 | Load: ... ++ | test.cpp:35:28:35:30 | InitializeParameter: end | 0 | true | CompareLT: ... < ... |
| test.cpp:44:13:44:13 | Load: y | test.cpp:42:29:42:29 | InitializeParameter: z | 0 | true | CompareLT: ... < ... |
| test.cpp:45:12:45:12 | Load: x | test.cpp:42:22:42:22 | InitializeParameter: y | 0 | true | CompareLT: ... < ... |
| test.cpp:45:12:45:12 | Load: x | test.cpp:42:29:42:29 | InitializeParameter: z | 0 | true | CompareLT: ... < ... |
| test.cpp:49:9:49:9 | Load: y | test.cpp:42:15:42:15 | InitializeParameter: x | 1 | false | CompareLT: ... < ... |
| test.cpp:50:12:50:12 | Load: x | test.cpp:42:22:42:22 | InitializeParameter: y | 0 | true | CompareLT: ... < ... |
| test.cpp:10:10:10:10 | Store: x | test.cpp:6:15:6:15 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:7:7:7:11 | test.cpp:7:7:7:11 |
| test.cpp:10:10:10:10 | Store: x | test.cpp:6:22:6:22 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:20:10:20:10 | Store: x | test.cpp:14:15:14:15 | InitializeParameter: x | -2 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:20:10:20:10 | Store: x | test.cpp:14:22:14:22 | InitializeParameter: y | -2 | false | CompareLT: ... < ... | test.cpp:15:7:15:11 | test.cpp:15:7:15:11 |
| test.cpp:27:10:27:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:27:10:27:10 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:26:14:26:18 | test.cpp:26:14:26:18 |
| test.cpp:27:10:27:10 | Load: i | test.cpp:26:18:26:18 | Load: x | -1 | true | CompareLT: ... < ... | test.cpp:26:14:26:18 | test.cpp:26:14:26:18 |
| test.cpp:30:10:30:10 | Load: i | file://:0:0:0:0 | 0 | 1 | false | CompareGT: ... > ... | test.cpp:29:14:29:18 | test.cpp:29:14:29:18 |
| test.cpp:30:10:30:10 | Load: i | test.cpp:29:18:29:18 | Constant: 0 | 1 | false | CompareGT: ... > ... | test.cpp:29:14:29:18 | test.cpp:29:14:29:18 |
| test.cpp:33:10:33:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:33:10:33:10 | Load: i | test.cpp:24:15:24:15 | InitializeParameter: x | 1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 |
| test.cpp:33:10:33:10 | Load: i | test.cpp:26:14:26:14 | Load: i | 1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 |
| test.cpp:33:10:33:10 | Load: i | test.cpp:32:18:32:18 | Load: x | 1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 |
| test.cpp:33:10:33:10 | Load: i | test.cpp:32:18:32:22 | Add: ... + ... | -1 | true | CompareLT: ... < ... | test.cpp:32:14:32:22 | test.cpp:32:14:32:22 |
| test.cpp:40:10:40:14 | Load: begin | test.cpp:38:28:38:30 | InitializeParameter: end | -1 | true | CompareLT: ... < ... | test.cpp:39:10:39:20 | test.cpp:39:10:39:20 |
| test.cpp:40:10:40:14 | Load: begin | test.cpp:39:18:39:20 | Load: end | -1 | true | CompareLT: ... < ... | test.cpp:39:10:39:20 | test.cpp:39:10:39:20 |
| test.cpp:49:12:49:12 | Load: x | test.cpp:46:22:46:22 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 |
| test.cpp:49:12:49:12 | Load: x | test.cpp:46:29:46:29 | InitializeParameter: z | -2 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 |
| test.cpp:49:12:49:12 | Load: x | test.cpp:47:11:47:11 | Load: z | -2 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 |
| test.cpp:49:12:49:12 | Load: x | test.cpp:48:13:48:13 | Load: y | -1 | true | CompareLT: ... < ... | test.cpp:48:9:48:13 | test.cpp:48:9:48:13 |
| test.cpp:54:12:54:12 | Load: x | test.cpp:46:22:46:22 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:52:7:52:11 | test.cpp:52:7:52:11 |
| test.cpp:54:12:54:12 | Load: x | test.cpp:52:11:52:11 | Load: y | -1 | true | CompareLT: ... < ... | test.cpp:52:7:52:11 | test.cpp:52:7:52:11 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:60:17:60:17 | InitializeParameter: p | 3 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:61:39:61:51 | Convert: (char *)... | -1 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:61:48:61:48 | Load: p | 3 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 |
| test.cpp:62:10:62:13 | Load: iter | test.cpp:61:48:61:50 | PointerAdd: ... + ... | -1 | true | CompareLT: ... < ... | test.cpp:61:32:61:51 | test.cpp:61:32:61:51 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:60:17:60:17 | InitializeParameter: p | 3 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:61:32:61:35 | Load: iter | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:65:15:65:27 | Convert: (char *)... | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:65:15:65:27 | Store: (char *)... | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:65:24:65:24 | Load: p | 3 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:65:24:65:26 | PointerAdd: ... + ... | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:67:10:67:13 | Load: iter | test.cpp:66:39:66:41 | Load: end | -1 | true | CompareLT: ... < ... | test.cpp:66:32:66:41 | test.cpp:66:32:66:41 |
| test.cpp:77:12:77:12 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
| test.cpp:77:12:77:12 | Load: i | test.cpp:72:15:72:15 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 |
| test.cpp:77:12:77:12 | Load: i | test.cpp:72:22:72:22 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 |
| test.cpp:77:12:77:12 | Load: i | test.cpp:75:7:75:7 | Load: x | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 |
| test.cpp:77:12:77:12 | Load: i | test.cpp:76:24:76:24 | Load: y | -1 | true | CompareLT: ... < ... | test.cpp:76:20:76:24 | test.cpp:76:20:76:24 |

View File

@@ -3,14 +3,23 @@ import semmle.code.cpp.ir.IR
import semmle.code.cpp.controlflow.IRGuards
import semmle.code.cpp.ir.ValueNumbering
query predicate instructionBounds(Instruction i, Bound b, int delta, boolean upper, Reason reason)
query predicate instructionBounds(Instruction i, Bound b, int delta, boolean upper, Reason reason,
Location reasonLoc)
{
i instanceof LoadInstruction and
boundedInstruction(i, b, delta, upper, reason) and
(
b.(InstructionBound).getInstruction() instanceof InitializeParameterInstruction or
b.(InstructionBound).getInstruction() instanceof CallInstruction or
b instanceof ZeroBound
i.getAUse() instanceof ArgumentOperand
or
i.getAUse() instanceof ReturnValueOperand
) and
not valueNumber(b.(InstructionBound).getInstruction()) = valueNumber(i)
(
upper = true and
delta = min(int d | boundedInstruction(i, b, d, upper, reason))
or
upper = false and
delta = max(int d | boundedInstruction(i, b, d, upper, reason))
) and
not valueNumber(b.getInstruction()) = valueNumber(i)
and if reason instanceof CondReason
then reasonLoc = reason.(CondReason).getCond().getLocation()
else reasonLoc instanceof UnknownDefaultLocation
}

View File

@@ -21,24 +21,28 @@ int test2(int x, int y) {
}
// for loops
int test3(int x, int *p) {
int test3(int x) {
int i;
for(i = 0; i < x; i++) {
p[i];
sink(i);
}
for(i = x; i > 0; i--) {
p[i];
sink(i);
}
for(i = 0; i < x + 2; i++) {
sink(i);
}
}
// pointer bounds
int test4(int *begin, int *end) {
while (begin < end) {
*begin = (*begin) + 1;
sink(begin);
begin++;
}
}
// bound propagation through conditionals
int test5(int x, int y, int z) {
if (y < z) {
if (x < y) {
@@ -51,3 +55,26 @@ int test5(int x, int y, int z) {
}
}
}
// pointer arithmetic and sizes
void test6(int *p) {
for (char *iter = (char *)p; iter < (char *)(p+1); iter++) {
sink(iter);
}
char *end = (char *)(p+1);
for (char *iter = (char *)p; iter < end; iter++) {
sink(iter);
}
}
// inference from equality
int test8(int x, int y) {
int *p = new int[x];
if (x == y) {
for(int i = 0; i < y; ++i) {
sink(i);
}
}
}