C++: respond to further PR comments

This commit is contained in:
Robert Marsh 2018-12-12 16:50:26 -08:00
Родитель ae4ffd9166
Коммит 89148a9ec7
9 изменённых файлов: 146 добавлений и 104 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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.

Просмотреть файл

@ -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
}
/**
@ -52,24 +48,4 @@ class InstructionBound extends Bound, TBoundInstruction {
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
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)
}
}
}

Просмотреть файл

@ -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)
)
}
@ -472,12 +459,10 @@ private int weakenDelta(boolean upper, int delta) {
private predicate boundedPhiInp(
PhiInstruction phi, PhiOperand op, Bound b, int delta, boolean upper, boolean fromBackEdge,
int origdelta, Reason reason
int origdelta, Reason reason
) {
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

Просмотреть файл

@ -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()))
)
}

Просмотреть файл

@ -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 |

Просмотреть файл

@ -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
}

Просмотреть файл

@ -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);
}
}
}