Merge branch 'master' into models5

This commit is contained in:
Geoffrey White
2020-06-22 10:05:14 +01:00
102 changed files with 7271 additions and 5829 deletions

View File

@@ -23,7 +23,7 @@ import semmle.code.cpp.ir.ValueNumbering
class NullInstruction extends ConstantValueInstruction {
NullInstruction() {
this.getValue() = "0" and
this.getResultType().getUnspecifiedType() instanceof PointerType
this.getResultIRType() instanceof IRAddressType
}
}
@@ -44,8 +44,8 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
bool =
any(ConvertInstruction convert |
checked = convert.getUnary() and
convert.getResultType() instanceof BoolType and
checked.getResultType() instanceof PointerType
convert.getResultIRType() instanceof IRBooleanType and
checked.getResultIRType() instanceof IRAddressType
)
}

View File

@@ -2,5 +2,5 @@
- qlpack: codeql-cpp
- apply: security-extended-selectors.yml
from: codeql-suite-helpers
- apply: codeql-suites/excluded-slow-queries.yml
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql-cpp

View File

@@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
exists(Node mid |
useFieldFlow(config) and
nodeCandFwd1(mid, fromArg, config) and
store(mid, _, node) and
store(mid, _, node, _) and
not outBarrier(mid, config)
)
or
// read
exists(Content f |
nodeCandFwd1Read(f, node, fromArg, config) and
nodeCandFwd1IsStored(f, config) and
exists(Content c |
nodeCandFwd1Read(c, node, fromArg, config) and
nodeCandFwd1IsStored(c, config) and
not inBarrier(node, config)
)
or
@@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
pragma[nomagic]
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) {
exists(Node mid |
nodeCandFwd1(mid, fromArg, config) and
read(mid, f, node)
read(mid, c, node)
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`.
*/
pragma[nomagic]
private predicate nodeCandFwd1IsStored(Content f, Configuration config) {
exists(Node mid, Node node |
private predicate nodeCandFwd1IsStored(Content c, Configuration config) {
exists(Node mid, Node node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
nodeCandFwd1(mid, config) and
store(mid, f, node)
store(mid, tc, node, _) and
c = tc.getContent()
)
}
@@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
)
or
// store
exists(Content f |
nodeCand1Store(f, node, toReturn, config) and
nodeCand1IsRead(f, config)
exists(Content c |
nodeCand1Store(c, node, toReturn, config) and
nodeCand1IsRead(c, config)
)
or
// read
exists(Node mid, Content f |
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
exists(Node mid, Content c |
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, toReturn, config)
)
or
@@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand1`.
*/
pragma[nomagic]
private predicate nodeCand1IsRead(Content f, Configuration config) {
private predicate nodeCand1IsRead(Content c, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, _, config)
)
}
pragma[nomagic]
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
exists(Node mid |
private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
nodeCand1(mid, toReturn, config) and
nodeCandFwd1IsStored(f, unbind(config)) and
store(node, f, mid)
nodeCandFwd1IsStored(c, unbind(config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
}
/**
* Holds if `f` is the target of both a read and a store in the flow covered
* Holds if `c` is the target of both a read and a store in the flow covered
* by `nodeCand1`.
*/
private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) {
nodeCand1IsRead(f, conf) and
nodeCand1Store(f, _, _, conf)
private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) {
nodeCand1IsRead(c, conf) and
nodeCand1Store(c, _, _, conf)
}
pragma[nomagic]
@@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c
}
pragma[nomagic]
private predicate store(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
nodeCand1(n2, unbind(config)) and
store(n1, f, n2)
private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) {
exists(TypedContent tc |
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
store(n1, tc, n2, _) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate read(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
private predicate read(Node n1, Content c, Node n2, Configuration config) {
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
read(n1, f, n2)
read(n1, c, n2)
}
pragma[noinline]
@@ -748,16 +753,16 @@ private predicate nodeCandFwd2(
)
or
// store
exists(Node mid, Content f |
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, _, config) and
store(mid, f, node, config) and
storeCand1(mid, _, node, config) and
stored = true
)
or
// read
exists(Content f |
nodeCandFwd2Read(f, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(f, stored, config)
exists(Content c |
nodeCandFwd2Read(c, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(c, stored, config)
)
or
// flow into a callable
@@ -781,25 +786,25 @@ private predicate nodeCandFwd2(
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`.
*/
pragma[noinline]
private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) {
private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCand1(node, unbind(config)) and
nodeCandFwd2(mid, _, _, stored, config) and
store(mid, f, node, config)
storeCand1(mid, c, node, config)
)
}
pragma[nomagic]
private predicate nodeCandFwd2Read(
Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config
Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config
) {
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, true, config) and
read(mid, f, node, config)
read(mid, c, node, config)
)
}
@@ -896,15 +901,15 @@ private predicate nodeCand2(
)
or
// store
exists(Content f |
nodeCand2Store(f, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(f, read, config)
exists(Content c |
nodeCand2Store(c, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(c, read, config)
)
or
// read
exists(Node mid, Content f, boolean read0 |
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and
exists(Node mid, Content c, boolean read0 |
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and
nodeCand2(mid, toReturn, returnRead, read0, config) and
read = true
)
@@ -930,51 +935,51 @@ private predicate nodeCand2(
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) {
private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd2(node, _, _, true, unbind(config)) and
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and
nodeCand2(mid, _, _, read, config)
)
}
pragma[nomagic]
private predicate nodeCand2Store(
Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Configuration config
) {
exists(Node mid |
store(node, f, mid, config) and
storeCand1(node, c, mid, config) and
nodeCand2(mid, toReturn, returnRead, true, config) and
nodeCandFwd2(node, _, _, stored, unbind(config))
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCand2`.
*/
pragma[nomagic]
private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) {
private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) {
exists(Node node |
nodeCand2Store(f, node, _, _, stored, conf) and
nodeCand2Store(c, node, _, _, stored, conf) and
nodeCand2(node, _, _, stored, conf)
)
}
/**
* Holds if `f` is the target of both a store and a read in the path graph
* Holds if `c` is the target of both a store and a read in the path graph
* covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) {
private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) {
exists(boolean apNonEmpty |
nodeCand2IsStored(f, apNonEmpty, conf) and
nodeCand2IsRead(f, apNonEmpty, conf)
nodeCand2IsStored(c, apNonEmpty, conf) and
nodeCand2IsRead(c, apNonEmpty, conf)
)
}
@@ -1058,7 +1063,7 @@ private module LocalFlowBigStep {
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof OutNodeExt or
store(_, _, node) or
store(_, _, node, _) or
read(_, _, node) or
node instanceof CastNode
)
@@ -1074,7 +1079,7 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next) or
store(node, _, next, _) or
read(node, _, next)
)
or
@@ -1154,19 +1159,21 @@ private module LocalFlowBigStep {
private import LocalFlowBigStep
pragma[nomagic]
private predicate readCand2(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2, config) and
private predicate readCand2(Node node1, Content c, Node node2, Configuration config) {
read(node1, c, node2, config) and
nodeCand2(node1, _, _, true, unbind(config)) and
nodeCand2(node2, config) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(c, unbind(config))
}
pragma[nomagic]
private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2, config) and
private predicate storeCand2(
Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
store(node1, tc, node2, contentType) and
nodeCand2(node1, config) and
nodeCand2(node2, _, _, true, unbind(config)) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(tc.getContent(), unbind(config))
}
/**
@@ -1227,17 +1234,18 @@ private predicate flowCandFwd0(
)
or
// store
exists(Node mid, Content f |
flowCandFwd(mid, fromArg, argApf, _, config) and
storeCand2(mid, f, node, config) and
exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
storeCand2(mid, tc, node, contentType, config) and
nodeCand2(node, _, _, true, unbind(config)) and
apf.headUsesContent(f)
apf.headUsesContent(tc) and
compatibleTypes(apf0.getType(), contentType)
)
or
// read
exists(Content f |
flowCandFwdRead(f, node, fromArg, argApf, config) and
flowCandFwdConsCand(f, apf, config) and
exists(TypedContent tc |
flowCandFwdRead(tc, node, fromArg, argApf, config) and
flowCandFwdConsCand(tc, apf, config) and
nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config))
)
or
@@ -1261,24 +1269,30 @@ private predicate flowCandFwd0(
}
pragma[nomagic]
private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n |
private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n, DataFlowType contentType |
flowCandFwd(mid, _, _, apf, config) and
storeCand2(mid, f, n, config) and
storeCand2(mid, tc, n, contentType, config) and
nodeCand2(n, _, _, true, unbind(config)) and
compatibleTypes(apf.getType(), f.getType())
compatibleTypes(apf.getType(), contentType)
)
}
pragma[nomagic]
private predicate flowCandFwdRead(
Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
private predicate flowCandFwdRead0(
Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf,
AccessPathFrontHead apf, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f)
)
flowCandFwd(node1, fromArg, argApf, apf, config) and
readCand2(node1, c, node2, config) and
apf.headUsesContent(tc)
}
pragma[nomagic]
private predicate flowCandFwdRead(
TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
) {
flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config)
}
pragma[nomagic]
@@ -1385,17 +1399,15 @@ private predicate flowCand0(
)
or
// store
exists(Content f, AccessPathFrontHead apf0 |
flowCandStore(node, f, toReturn, returnApf, apf0, config) and
apf0.headUsesContent(f) and
flowCandConsCand(f, apf, config)
exists(TypedContent tc |
flowCandStore(node, tc, apf, toReturn, returnApf, config) and
flowCandConsCand(tc, apf, config)
)
or
// read
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(f, apf0, config) and
apf.headUsesContent(f)
exists(TypedContent tc, AccessPathFront apf0 |
flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(tc, apf0, config)
)
or
// flow into a callable
@@ -1417,36 +1429,40 @@ private predicate flowCand0(
else returnApf = TAccessPathFrontNone()
}
pragma[nomagic]
private predicate readCandFwd(
Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config
) {
flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config)
}
pragma[nomagic]
private predicate flowCandRead(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config
) {
exists(Node mid |
readCand2(node, f, mid, config) and
readCandFwd(node, tc, apf, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
)
}
pragma[nomagic]
private predicate flowCandStore(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, Configuration config
) {
exists(Node mid |
storeCand2(node, f, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
flowCandFwd(node, _, _, apf, config) and
storeCand2(node, tc, mid, _, unbind(config)) and
flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config))
)
}
pragma[nomagic]
private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(f, apf, config) and
exists(Node n, AccessPathFrontHead apf0 |
flowCandFwd(n, _, _, apf0, config) and
apf0.headUsesContent(f) and
flowCandRead(n, f, _, _, apf, config)
)
private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(tc, apf, config) and
flowCandRead(_, tc, _, _, _, apf, config)
}
pragma[nomagic]
@@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned(
private newtype TAccessPath =
TNil(DataFlowType t) or
TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or
TConsCons(Content f1, Content f2, int len) {
flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()]
TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()]
}
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -1514,7 +1530,7 @@ private newtype TAccessPath =
abstract private class AccessPath extends TAccessPath {
abstract string toString();
abstract Content getHead();
abstract TypedContent getHead();
abstract int len();
@@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath {
/**
* Holds if this access path has `head` at the front and may be followed by `tail`.
*/
abstract predicate pop(Content head, AccessPath tail);
abstract predicate pop(TypedContent head, AccessPath tail);
}
private class AccessPathNil extends AccessPath, TNil {
@@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil {
override string toString() { result = concat(": " + ppReprType(t)) }
override Content getHead() { none() }
override TypedContent getHead() { none() }
override int len() { result = 0 }
@@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil {
override AccessPathFront getFront() { result = TFrontNil(t) }
override predicate pop(Content head, AccessPath tail) { none() }
override predicate pop(TypedContent head, AccessPath tail) { none() }
}
abstract private class AccessPathCons extends AccessPath { }
private class AccessPathConsNil extends AccessPathCons, TConsNil {
private Content f;
private TypedContent tc;
private DataFlowType t;
AccessPathConsNil() { this = TConsNil(f, t) }
AccessPathConsNil() { this = TConsNil(tc, t) }
override string toString() {
// The `concat` becomes "" if `ppReprType` has no result.
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t))
}
override Content getHead() { result = f }
override TypedContent getHead() { result = tc }
override int len() { result = 1 }
override DataFlowType getType() { result = f.getContainerType() }
override DataFlowType getType() { result = tc.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f) }
override AccessPathFront getFront() { result = TFrontHead(tc) }
override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) }
override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) }
}
private class AccessPathConsCons extends AccessPathCons, TConsCons {
private Content f1;
private Content f2;
private TypedContent tc1;
private TypedContent tc2;
private int len;
AccessPathConsCons() { this = TConsCons(f1, f2, len) }
AccessPathConsCons() { this = TConsCons(tc1, tc2, len) }
override string toString() {
if len = 2
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc1.toString() + ", " + tc2.toString() + "]"
else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]"
}
override Content getHead() { result = f1 }
override TypedContent getHead() { result = tc1 }
override int len() { result = len }
override DataFlowType getType() { result = f1.getContainerType() }
override DataFlowType getType() { result = tc1.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f1) }
override AccessPathFront getFront() { result = TFrontHead(tc1) }
override predicate pop(Content head, AccessPath tail) {
head = f1 and
override predicate pop(TypedContent head, AccessPath tail) {
head = tc1 and
(
tail = TConsCons(f2, _, len - 1)
tail = TConsCons(tc2, _, len - 1)
or
len = 2 and
tail = TConsNil(f2, _)
tail = TConsNil(tc2, _)
)
}
}
/** Gets the access path obtained by popping `f` from `ap`, if any. */
private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) }
/** Gets the access path obtained by popping `tc` from `ap`, if any. */
private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) }
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/** Gets the access path obtained by pushing `tc` onto `ap`. */
private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) }
private newtype TAccessPathOption =
TAccessPathNone() or
@@ -1678,15 +1694,12 @@ private predicate flowFwd0(
)
or
// store
exists(Content f, AccessPath ap0 |
flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and
ap = push(f, ap0)
)
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
or
// read
exists(Content f |
flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and
flowFwdConsCand(f, apf, ap, config)
exists(TypedContent tc |
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
flowFwdConsCand(tc, apf, ap, config)
)
or
// flow into a callable
@@ -1710,54 +1723,63 @@ private predicate flowFwd0(
pragma[nomagic]
private predicate flowFwdStore(
Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg,
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFront apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
flowFwdStore1(mid, f, node, apf0, apf, config)
flowFwdStore0(mid, tc, node, apf0, apf, config)
)
}
pragma[nomagic]
private predicate flowFwdStore0(
Node mid, Content f, Node node, AccessPathFront apf0, Configuration config
private predicate storeCand(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf,
Configuration config
) {
storeCand2(mid, f, node, config) and
flowCand(mid, _, _, apf0, config)
storeCand2(mid, tc, node, _, config) and
flowCand(mid, _, _, apf0, config) and
apf.headUsesContent(tc)
}
pragma[noinline]
private predicate flowFwdStore1(
Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
private predicate flowFwdStore0(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
Configuration config
) {
flowFwdStore0(mid, f, node, apf0, config) and
flowCandConsCand(f, apf0, config) and
apf.headUsesContent(f) and
storeCand(mid, tc, node, apf0, apf, config) and
flowCandConsCand(tc, apf0, config) and
flowCand(node, _, _, apf, unbind(config))
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp,
Configuration config
private predicate flowFwdRead0(
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
boolean fromArg, AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f) and
flowCand(node, _, _, _, unbind(config))
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
readCandFwd(node1, tc, apf0, node2, config)
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, TypedContent tc |
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
flowCand(node, _, _, apf, unbind(config)) and
flowCandConsCand(tc, apf, unbind(config))
)
}
pragma[nomagic]
private predicate flowFwdConsCand(
Content f, AccessPathFront apf, AccessPath ap, Configuration config
TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config
) {
exists(Node n |
flowFwd(n, _, _, apf, ap, config) and
flowFwdStore1(n, f, _, apf, _, config)
flowFwdStore0(n, tc, _, apf, _, config)
)
}
@@ -1863,9 +1885,9 @@ private predicate flow0(
)
or
// store
exists(Content f |
flowStore(f, node, toReturn, returnAp, ap, config) and
flowConsCand(f, ap, config)
exists(TypedContent tc |
flowStore(tc, node, toReturn, returnAp, ap, config) and
flowConsCand(tc, ap, config)
)
or
// read
@@ -1895,39 +1917,41 @@ private predicate flow0(
pragma[nomagic]
private predicate storeFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
storeCand2(node1, f, node2, config) and
flowFwdStore(node2, f, ap, _, _, _, config) and
ap0 = push(f, ap)
storeCand2(node1, tc, node2, _, config) and
flowFwdStore(node2, tc, ap, _, _, _, config) and
ap0 = push(tc, ap)
}
pragma[nomagic]
private predicate flowStore(
Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
Configuration config
) {
exists(Node mid, AccessPath ap0 |
storeFlowFwd(node, f, mid, ap, ap0, config) and
storeFlowFwd(node, tc, mid, ap, ap0, config) and
flow(mid, toReturn, returnAp, ap0, config)
)
}
pragma[nomagic]
private predicate readFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
readCand2(node1, f, node2, config) and
flowFwdRead(node2, f, ap, _, _, config) and
ap0 = pop(f, ap) and
flowFwdConsCand(f, _, ap0, unbind(config))
exists(AccessPathFrontHead apf |
readCandFwd(node1, tc, apf, node2, config) and
flowFwdRead(node2, apf, ap, _, _, _, config) and
ap0 = pop(tc, ap) and
flowFwdConsCand(tc, _, ap0, unbind(config))
)
}
pragma[nomagic]
private predicate flowConsCand(Content f, AccessPath ap, Configuration config) {
private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) {
exists(Node n, Node mid |
flow(mid, _, _, ap, config) and
readFlowFwd(n, f, mid, _, ap, config)
readFlowFwd(n, tc, mid, _, ap, config)
)
}
@@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and
exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
@@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
}
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2) and
private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) {
readCandFwd(node1, tc, _, node2, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) {
private predicate pathReadStep(
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
readCand(mid.getNode(), f, node, mid.getConfiguration()) and
readCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate storeCand(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2) and
private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) {
storeCand2(node1, tc, node2, _, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathStoreStep(
PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
storeCand(mid.getNode(), f, node, mid.getConfiguration()) and
storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -2538,10 +2564,10 @@ private module FlowExploration {
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(Content f, int len) { len in [1 .. 5] }
TPartialCons(TypedContent tc, int len) { len in [1 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -2550,7 +2576,7 @@ private module FlowExploration {
private class PartialAccessPath extends TPartialAccessPath {
abstract string toString();
Content getHead() { this = TPartialCons(result, _) }
TypedContent getHead() { this = TPartialCons(result, _) }
int len() {
this = TPartialNil(_) and result = 0
@@ -2561,7 +2587,7 @@ private module FlowExploration {
DataFlowType getType() {
this = TPartialNil(result)
or
exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType())
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
@@ -2579,15 +2605,15 @@ private module FlowExploration {
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
exists(TypedContent tc, int len | this = TPartialCons(tc, len) |
if len = 1
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc.toString() + "]"
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
override AccessPathFront getFront() {
exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f))
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
}
}
@@ -2763,11 +2789,12 @@ private module FlowExploration {
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(PartialAccessPath ap0, Content f |
partialPathReadStep(mid, ap0, f, node, cc, config) and
exists(PartialAccessPath ap0, TypedContent tc |
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, f, ap0, config)
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -2786,35 +2813,42 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
) {
ap1 = mid.getAp() and
store(mid.getNode(), f, node) and
ap2.getHead() = f and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), f.getType())
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
)
}
pragma[nomagic]
private predicate apConsFwd(
PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
partialPathStoreStep(mid, ap1, f, _, ap2) and
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc,
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
ap = mid.getAp() and
readStep(mid.getNode(), f, node) and
ap.getHead() = f and
config = mid.getConfiguration() and
cc = mid.getCallContext()
exists(Node midNode |
midNode = mid.getNode() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node) and
ap.getHead() = tc and
config = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
private predicate partialPathOutOfCallable0(

View File

@@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
exists(Node mid |
useFieldFlow(config) and
nodeCandFwd1(mid, fromArg, config) and
store(mid, _, node) and
store(mid, _, node, _) and
not outBarrier(mid, config)
)
or
// read
exists(Content f |
nodeCandFwd1Read(f, node, fromArg, config) and
nodeCandFwd1IsStored(f, config) and
exists(Content c |
nodeCandFwd1Read(c, node, fromArg, config) and
nodeCandFwd1IsStored(c, config) and
not inBarrier(node, config)
)
or
@@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
pragma[nomagic]
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) {
exists(Node mid |
nodeCandFwd1(mid, fromArg, config) and
read(mid, f, node)
read(mid, c, node)
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`.
*/
pragma[nomagic]
private predicate nodeCandFwd1IsStored(Content f, Configuration config) {
exists(Node mid, Node node |
private predicate nodeCandFwd1IsStored(Content c, Configuration config) {
exists(Node mid, Node node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
nodeCandFwd1(mid, config) and
store(mid, f, node)
store(mid, tc, node, _) and
c = tc.getContent()
)
}
@@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
)
or
// store
exists(Content f |
nodeCand1Store(f, node, toReturn, config) and
nodeCand1IsRead(f, config)
exists(Content c |
nodeCand1Store(c, node, toReturn, config) and
nodeCand1IsRead(c, config)
)
or
// read
exists(Node mid, Content f |
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
exists(Node mid, Content c |
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, toReturn, config)
)
or
@@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand1`.
*/
pragma[nomagic]
private predicate nodeCand1IsRead(Content f, Configuration config) {
private predicate nodeCand1IsRead(Content c, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, _, config)
)
}
pragma[nomagic]
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
exists(Node mid |
private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
nodeCand1(mid, toReturn, config) and
nodeCandFwd1IsStored(f, unbind(config)) and
store(node, f, mid)
nodeCandFwd1IsStored(c, unbind(config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
}
/**
* Holds if `f` is the target of both a read and a store in the flow covered
* Holds if `c` is the target of both a read and a store in the flow covered
* by `nodeCand1`.
*/
private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) {
nodeCand1IsRead(f, conf) and
nodeCand1Store(f, _, _, conf)
private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) {
nodeCand1IsRead(c, conf) and
nodeCand1Store(c, _, _, conf)
}
pragma[nomagic]
@@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c
}
pragma[nomagic]
private predicate store(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
nodeCand1(n2, unbind(config)) and
store(n1, f, n2)
private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) {
exists(TypedContent tc |
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
store(n1, tc, n2, _) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate read(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
private predicate read(Node n1, Content c, Node n2, Configuration config) {
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
read(n1, f, n2)
read(n1, c, n2)
}
pragma[noinline]
@@ -748,16 +753,16 @@ private predicate nodeCandFwd2(
)
or
// store
exists(Node mid, Content f |
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, _, config) and
store(mid, f, node, config) and
storeCand1(mid, _, node, config) and
stored = true
)
or
// read
exists(Content f |
nodeCandFwd2Read(f, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(f, stored, config)
exists(Content c |
nodeCandFwd2Read(c, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(c, stored, config)
)
or
// flow into a callable
@@ -781,25 +786,25 @@ private predicate nodeCandFwd2(
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`.
*/
pragma[noinline]
private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) {
private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCand1(node, unbind(config)) and
nodeCandFwd2(mid, _, _, stored, config) and
store(mid, f, node, config)
storeCand1(mid, c, node, config)
)
}
pragma[nomagic]
private predicate nodeCandFwd2Read(
Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config
Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config
) {
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, true, config) and
read(mid, f, node, config)
read(mid, c, node, config)
)
}
@@ -896,15 +901,15 @@ private predicate nodeCand2(
)
or
// store
exists(Content f |
nodeCand2Store(f, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(f, read, config)
exists(Content c |
nodeCand2Store(c, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(c, read, config)
)
or
// read
exists(Node mid, Content f, boolean read0 |
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and
exists(Node mid, Content c, boolean read0 |
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and
nodeCand2(mid, toReturn, returnRead, read0, config) and
read = true
)
@@ -930,51 +935,51 @@ private predicate nodeCand2(
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) {
private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd2(node, _, _, true, unbind(config)) and
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and
nodeCand2(mid, _, _, read, config)
)
}
pragma[nomagic]
private predicate nodeCand2Store(
Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Configuration config
) {
exists(Node mid |
store(node, f, mid, config) and
storeCand1(node, c, mid, config) and
nodeCand2(mid, toReturn, returnRead, true, config) and
nodeCandFwd2(node, _, _, stored, unbind(config))
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCand2`.
*/
pragma[nomagic]
private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) {
private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) {
exists(Node node |
nodeCand2Store(f, node, _, _, stored, conf) and
nodeCand2Store(c, node, _, _, stored, conf) and
nodeCand2(node, _, _, stored, conf)
)
}
/**
* Holds if `f` is the target of both a store and a read in the path graph
* Holds if `c` is the target of both a store and a read in the path graph
* covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) {
private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) {
exists(boolean apNonEmpty |
nodeCand2IsStored(f, apNonEmpty, conf) and
nodeCand2IsRead(f, apNonEmpty, conf)
nodeCand2IsStored(c, apNonEmpty, conf) and
nodeCand2IsRead(c, apNonEmpty, conf)
)
}
@@ -1058,7 +1063,7 @@ private module LocalFlowBigStep {
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof OutNodeExt or
store(_, _, node) or
store(_, _, node, _) or
read(_, _, node) or
node instanceof CastNode
)
@@ -1074,7 +1079,7 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next) or
store(node, _, next, _) or
read(node, _, next)
)
or
@@ -1154,19 +1159,21 @@ private module LocalFlowBigStep {
private import LocalFlowBigStep
pragma[nomagic]
private predicate readCand2(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2, config) and
private predicate readCand2(Node node1, Content c, Node node2, Configuration config) {
read(node1, c, node2, config) and
nodeCand2(node1, _, _, true, unbind(config)) and
nodeCand2(node2, config) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(c, unbind(config))
}
pragma[nomagic]
private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2, config) and
private predicate storeCand2(
Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
store(node1, tc, node2, contentType) and
nodeCand2(node1, config) and
nodeCand2(node2, _, _, true, unbind(config)) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(tc.getContent(), unbind(config))
}
/**
@@ -1227,17 +1234,18 @@ private predicate flowCandFwd0(
)
or
// store
exists(Node mid, Content f |
flowCandFwd(mid, fromArg, argApf, _, config) and
storeCand2(mid, f, node, config) and
exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
storeCand2(mid, tc, node, contentType, config) and
nodeCand2(node, _, _, true, unbind(config)) and
apf.headUsesContent(f)
apf.headUsesContent(tc) and
compatibleTypes(apf0.getType(), contentType)
)
or
// read
exists(Content f |
flowCandFwdRead(f, node, fromArg, argApf, config) and
flowCandFwdConsCand(f, apf, config) and
exists(TypedContent tc |
flowCandFwdRead(tc, node, fromArg, argApf, config) and
flowCandFwdConsCand(tc, apf, config) and
nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config))
)
or
@@ -1261,24 +1269,30 @@ private predicate flowCandFwd0(
}
pragma[nomagic]
private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n |
private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n, DataFlowType contentType |
flowCandFwd(mid, _, _, apf, config) and
storeCand2(mid, f, n, config) and
storeCand2(mid, tc, n, contentType, config) and
nodeCand2(n, _, _, true, unbind(config)) and
compatibleTypes(apf.getType(), f.getType())
compatibleTypes(apf.getType(), contentType)
)
}
pragma[nomagic]
private predicate flowCandFwdRead(
Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
private predicate flowCandFwdRead0(
Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf,
AccessPathFrontHead apf, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f)
)
flowCandFwd(node1, fromArg, argApf, apf, config) and
readCand2(node1, c, node2, config) and
apf.headUsesContent(tc)
}
pragma[nomagic]
private predicate flowCandFwdRead(
TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
) {
flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config)
}
pragma[nomagic]
@@ -1385,17 +1399,15 @@ private predicate flowCand0(
)
or
// store
exists(Content f, AccessPathFrontHead apf0 |
flowCandStore(node, f, toReturn, returnApf, apf0, config) and
apf0.headUsesContent(f) and
flowCandConsCand(f, apf, config)
exists(TypedContent tc |
flowCandStore(node, tc, apf, toReturn, returnApf, config) and
flowCandConsCand(tc, apf, config)
)
or
// read
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(f, apf0, config) and
apf.headUsesContent(f)
exists(TypedContent tc, AccessPathFront apf0 |
flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(tc, apf0, config)
)
or
// flow into a callable
@@ -1417,36 +1429,40 @@ private predicate flowCand0(
else returnApf = TAccessPathFrontNone()
}
pragma[nomagic]
private predicate readCandFwd(
Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config
) {
flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config)
}
pragma[nomagic]
private predicate flowCandRead(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config
) {
exists(Node mid |
readCand2(node, f, mid, config) and
readCandFwd(node, tc, apf, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
)
}
pragma[nomagic]
private predicate flowCandStore(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, Configuration config
) {
exists(Node mid |
storeCand2(node, f, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
flowCandFwd(node, _, _, apf, config) and
storeCand2(node, tc, mid, _, unbind(config)) and
flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config))
)
}
pragma[nomagic]
private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(f, apf, config) and
exists(Node n, AccessPathFrontHead apf0 |
flowCandFwd(n, _, _, apf0, config) and
apf0.headUsesContent(f) and
flowCandRead(n, f, _, _, apf, config)
)
private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(tc, apf, config) and
flowCandRead(_, tc, _, _, _, apf, config)
}
pragma[nomagic]
@@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned(
private newtype TAccessPath =
TNil(DataFlowType t) or
TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or
TConsCons(Content f1, Content f2, int len) {
flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()]
TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()]
}
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -1514,7 +1530,7 @@ private newtype TAccessPath =
abstract private class AccessPath extends TAccessPath {
abstract string toString();
abstract Content getHead();
abstract TypedContent getHead();
abstract int len();
@@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath {
/**
* Holds if this access path has `head` at the front and may be followed by `tail`.
*/
abstract predicate pop(Content head, AccessPath tail);
abstract predicate pop(TypedContent head, AccessPath tail);
}
private class AccessPathNil extends AccessPath, TNil {
@@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil {
override string toString() { result = concat(": " + ppReprType(t)) }
override Content getHead() { none() }
override TypedContent getHead() { none() }
override int len() { result = 0 }
@@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil {
override AccessPathFront getFront() { result = TFrontNil(t) }
override predicate pop(Content head, AccessPath tail) { none() }
override predicate pop(TypedContent head, AccessPath tail) { none() }
}
abstract private class AccessPathCons extends AccessPath { }
private class AccessPathConsNil extends AccessPathCons, TConsNil {
private Content f;
private TypedContent tc;
private DataFlowType t;
AccessPathConsNil() { this = TConsNil(f, t) }
AccessPathConsNil() { this = TConsNil(tc, t) }
override string toString() {
// The `concat` becomes "" if `ppReprType` has no result.
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t))
}
override Content getHead() { result = f }
override TypedContent getHead() { result = tc }
override int len() { result = 1 }
override DataFlowType getType() { result = f.getContainerType() }
override DataFlowType getType() { result = tc.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f) }
override AccessPathFront getFront() { result = TFrontHead(tc) }
override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) }
override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) }
}
private class AccessPathConsCons extends AccessPathCons, TConsCons {
private Content f1;
private Content f2;
private TypedContent tc1;
private TypedContent tc2;
private int len;
AccessPathConsCons() { this = TConsCons(f1, f2, len) }
AccessPathConsCons() { this = TConsCons(tc1, tc2, len) }
override string toString() {
if len = 2
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc1.toString() + ", " + tc2.toString() + "]"
else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]"
}
override Content getHead() { result = f1 }
override TypedContent getHead() { result = tc1 }
override int len() { result = len }
override DataFlowType getType() { result = f1.getContainerType() }
override DataFlowType getType() { result = tc1.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f1) }
override AccessPathFront getFront() { result = TFrontHead(tc1) }
override predicate pop(Content head, AccessPath tail) {
head = f1 and
override predicate pop(TypedContent head, AccessPath tail) {
head = tc1 and
(
tail = TConsCons(f2, _, len - 1)
tail = TConsCons(tc2, _, len - 1)
or
len = 2 and
tail = TConsNil(f2, _)
tail = TConsNil(tc2, _)
)
}
}
/** Gets the access path obtained by popping `f` from `ap`, if any. */
private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) }
/** Gets the access path obtained by popping `tc` from `ap`, if any. */
private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) }
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/** Gets the access path obtained by pushing `tc` onto `ap`. */
private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) }
private newtype TAccessPathOption =
TAccessPathNone() or
@@ -1678,15 +1694,12 @@ private predicate flowFwd0(
)
or
// store
exists(Content f, AccessPath ap0 |
flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and
ap = push(f, ap0)
)
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
or
// read
exists(Content f |
flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and
flowFwdConsCand(f, apf, ap, config)
exists(TypedContent tc |
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
flowFwdConsCand(tc, apf, ap, config)
)
or
// flow into a callable
@@ -1710,54 +1723,63 @@ private predicate flowFwd0(
pragma[nomagic]
private predicate flowFwdStore(
Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg,
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFront apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
flowFwdStore1(mid, f, node, apf0, apf, config)
flowFwdStore0(mid, tc, node, apf0, apf, config)
)
}
pragma[nomagic]
private predicate flowFwdStore0(
Node mid, Content f, Node node, AccessPathFront apf0, Configuration config
private predicate storeCand(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf,
Configuration config
) {
storeCand2(mid, f, node, config) and
flowCand(mid, _, _, apf0, config)
storeCand2(mid, tc, node, _, config) and
flowCand(mid, _, _, apf0, config) and
apf.headUsesContent(tc)
}
pragma[noinline]
private predicate flowFwdStore1(
Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
private predicate flowFwdStore0(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
Configuration config
) {
flowFwdStore0(mid, f, node, apf0, config) and
flowCandConsCand(f, apf0, config) and
apf.headUsesContent(f) and
storeCand(mid, tc, node, apf0, apf, config) and
flowCandConsCand(tc, apf0, config) and
flowCand(node, _, _, apf, unbind(config))
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp,
Configuration config
private predicate flowFwdRead0(
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
boolean fromArg, AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f) and
flowCand(node, _, _, _, unbind(config))
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
readCandFwd(node1, tc, apf0, node2, config)
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, TypedContent tc |
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
flowCand(node, _, _, apf, unbind(config)) and
flowCandConsCand(tc, apf, unbind(config))
)
}
pragma[nomagic]
private predicate flowFwdConsCand(
Content f, AccessPathFront apf, AccessPath ap, Configuration config
TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config
) {
exists(Node n |
flowFwd(n, _, _, apf, ap, config) and
flowFwdStore1(n, f, _, apf, _, config)
flowFwdStore0(n, tc, _, apf, _, config)
)
}
@@ -1863,9 +1885,9 @@ private predicate flow0(
)
or
// store
exists(Content f |
flowStore(f, node, toReturn, returnAp, ap, config) and
flowConsCand(f, ap, config)
exists(TypedContent tc |
flowStore(tc, node, toReturn, returnAp, ap, config) and
flowConsCand(tc, ap, config)
)
or
// read
@@ -1895,39 +1917,41 @@ private predicate flow0(
pragma[nomagic]
private predicate storeFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
storeCand2(node1, f, node2, config) and
flowFwdStore(node2, f, ap, _, _, _, config) and
ap0 = push(f, ap)
storeCand2(node1, tc, node2, _, config) and
flowFwdStore(node2, tc, ap, _, _, _, config) and
ap0 = push(tc, ap)
}
pragma[nomagic]
private predicate flowStore(
Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
Configuration config
) {
exists(Node mid, AccessPath ap0 |
storeFlowFwd(node, f, mid, ap, ap0, config) and
storeFlowFwd(node, tc, mid, ap, ap0, config) and
flow(mid, toReturn, returnAp, ap0, config)
)
}
pragma[nomagic]
private predicate readFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
readCand2(node1, f, node2, config) and
flowFwdRead(node2, f, ap, _, _, config) and
ap0 = pop(f, ap) and
flowFwdConsCand(f, _, ap0, unbind(config))
exists(AccessPathFrontHead apf |
readCandFwd(node1, tc, apf, node2, config) and
flowFwdRead(node2, apf, ap, _, _, _, config) and
ap0 = pop(tc, ap) and
flowFwdConsCand(tc, _, ap0, unbind(config))
)
}
pragma[nomagic]
private predicate flowConsCand(Content f, AccessPath ap, Configuration config) {
private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) {
exists(Node n, Node mid |
flow(mid, _, _, ap, config) and
readFlowFwd(n, f, mid, _, ap, config)
readFlowFwd(n, tc, mid, _, ap, config)
)
}
@@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and
exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
@@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
}
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2) and
private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) {
readCandFwd(node1, tc, _, node2, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) {
private predicate pathReadStep(
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
readCand(mid.getNode(), f, node, mid.getConfiguration()) and
readCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate storeCand(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2) and
private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) {
storeCand2(node1, tc, node2, _, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathStoreStep(
PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
storeCand(mid.getNode(), f, node, mid.getConfiguration()) and
storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -2538,10 +2564,10 @@ private module FlowExploration {
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(Content f, int len) { len in [1 .. 5] }
TPartialCons(TypedContent tc, int len) { len in [1 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -2550,7 +2576,7 @@ private module FlowExploration {
private class PartialAccessPath extends TPartialAccessPath {
abstract string toString();
Content getHead() { this = TPartialCons(result, _) }
TypedContent getHead() { this = TPartialCons(result, _) }
int len() {
this = TPartialNil(_) and result = 0
@@ -2561,7 +2587,7 @@ private module FlowExploration {
DataFlowType getType() {
this = TPartialNil(result)
or
exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType())
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
@@ -2579,15 +2605,15 @@ private module FlowExploration {
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
exists(TypedContent tc, int len | this = TPartialCons(tc, len) |
if len = 1
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc.toString() + "]"
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
override AccessPathFront getFront() {
exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f))
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
}
}
@@ -2763,11 +2789,12 @@ private module FlowExploration {
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(PartialAccessPath ap0, Content f |
partialPathReadStep(mid, ap0, f, node, cc, config) and
exists(PartialAccessPath ap0, TypedContent tc |
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, f, ap0, config)
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -2786,35 +2813,42 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
) {
ap1 = mid.getAp() and
store(mid.getNode(), f, node) and
ap2.getHead() = f and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), f.getType())
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
)
}
pragma[nomagic]
private predicate apConsFwd(
PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
partialPathStoreStep(mid, ap1, f, _, ap2) and
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc,
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
ap = mid.getAp() and
readStep(mid.getNode(), f, node) and
ap.getHead() = f and
config = mid.getConfiguration() and
cc = mid.getCallContext()
exists(Node midNode |
midNode = mid.getNode() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node) and
ap.getHead() = tc and
config = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
private predicate partialPathOutOfCallable0(

View File

@@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
exists(Node mid |
useFieldFlow(config) and
nodeCandFwd1(mid, fromArg, config) and
store(mid, _, node) and
store(mid, _, node, _) and
not outBarrier(mid, config)
)
or
// read
exists(Content f |
nodeCandFwd1Read(f, node, fromArg, config) and
nodeCandFwd1IsStored(f, config) and
exists(Content c |
nodeCandFwd1Read(c, node, fromArg, config) and
nodeCandFwd1IsStored(c, config) and
not inBarrier(node, config)
)
or
@@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
pragma[nomagic]
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) {
exists(Node mid |
nodeCandFwd1(mid, fromArg, config) and
read(mid, f, node)
read(mid, c, node)
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`.
*/
pragma[nomagic]
private predicate nodeCandFwd1IsStored(Content f, Configuration config) {
exists(Node mid, Node node |
private predicate nodeCandFwd1IsStored(Content c, Configuration config) {
exists(Node mid, Node node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
nodeCandFwd1(mid, config) and
store(mid, f, node)
store(mid, tc, node, _) and
c = tc.getContent()
)
}
@@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
)
or
// store
exists(Content f |
nodeCand1Store(f, node, toReturn, config) and
nodeCand1IsRead(f, config)
exists(Content c |
nodeCand1Store(c, node, toReturn, config) and
nodeCand1IsRead(c, config)
)
or
// read
exists(Node mid, Content f |
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
exists(Node mid, Content c |
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, toReturn, config)
)
or
@@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand1`.
*/
pragma[nomagic]
private predicate nodeCand1IsRead(Content f, Configuration config) {
private predicate nodeCand1IsRead(Content c, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, _, config)
)
}
pragma[nomagic]
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
exists(Node mid |
private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
nodeCand1(mid, toReturn, config) and
nodeCandFwd1IsStored(f, unbind(config)) and
store(node, f, mid)
nodeCandFwd1IsStored(c, unbind(config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
}
/**
* Holds if `f` is the target of both a read and a store in the flow covered
* Holds if `c` is the target of both a read and a store in the flow covered
* by `nodeCand1`.
*/
private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) {
nodeCand1IsRead(f, conf) and
nodeCand1Store(f, _, _, conf)
private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) {
nodeCand1IsRead(c, conf) and
nodeCand1Store(c, _, _, conf)
}
pragma[nomagic]
@@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c
}
pragma[nomagic]
private predicate store(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
nodeCand1(n2, unbind(config)) and
store(n1, f, n2)
private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) {
exists(TypedContent tc |
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
store(n1, tc, n2, _) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate read(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
private predicate read(Node n1, Content c, Node n2, Configuration config) {
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
read(n1, f, n2)
read(n1, c, n2)
}
pragma[noinline]
@@ -748,16 +753,16 @@ private predicate nodeCandFwd2(
)
or
// store
exists(Node mid, Content f |
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, _, config) and
store(mid, f, node, config) and
storeCand1(mid, _, node, config) and
stored = true
)
or
// read
exists(Content f |
nodeCandFwd2Read(f, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(f, stored, config)
exists(Content c |
nodeCandFwd2Read(c, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(c, stored, config)
)
or
// flow into a callable
@@ -781,25 +786,25 @@ private predicate nodeCandFwd2(
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`.
*/
pragma[noinline]
private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) {
private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCand1(node, unbind(config)) and
nodeCandFwd2(mid, _, _, stored, config) and
store(mid, f, node, config)
storeCand1(mid, c, node, config)
)
}
pragma[nomagic]
private predicate nodeCandFwd2Read(
Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config
Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config
) {
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, true, config) and
read(mid, f, node, config)
read(mid, c, node, config)
)
}
@@ -896,15 +901,15 @@ private predicate nodeCand2(
)
or
// store
exists(Content f |
nodeCand2Store(f, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(f, read, config)
exists(Content c |
nodeCand2Store(c, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(c, read, config)
)
or
// read
exists(Node mid, Content f, boolean read0 |
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and
exists(Node mid, Content c, boolean read0 |
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and
nodeCand2(mid, toReturn, returnRead, read0, config) and
read = true
)
@@ -930,51 +935,51 @@ private predicate nodeCand2(
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) {
private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd2(node, _, _, true, unbind(config)) and
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and
nodeCand2(mid, _, _, read, config)
)
}
pragma[nomagic]
private predicate nodeCand2Store(
Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Configuration config
) {
exists(Node mid |
store(node, f, mid, config) and
storeCand1(node, c, mid, config) and
nodeCand2(mid, toReturn, returnRead, true, config) and
nodeCandFwd2(node, _, _, stored, unbind(config))
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCand2`.
*/
pragma[nomagic]
private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) {
private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) {
exists(Node node |
nodeCand2Store(f, node, _, _, stored, conf) and
nodeCand2Store(c, node, _, _, stored, conf) and
nodeCand2(node, _, _, stored, conf)
)
}
/**
* Holds if `f` is the target of both a store and a read in the path graph
* Holds if `c` is the target of both a store and a read in the path graph
* covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) {
private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) {
exists(boolean apNonEmpty |
nodeCand2IsStored(f, apNonEmpty, conf) and
nodeCand2IsRead(f, apNonEmpty, conf)
nodeCand2IsStored(c, apNonEmpty, conf) and
nodeCand2IsRead(c, apNonEmpty, conf)
)
}
@@ -1058,7 +1063,7 @@ private module LocalFlowBigStep {
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof OutNodeExt or
store(_, _, node) or
store(_, _, node, _) or
read(_, _, node) or
node instanceof CastNode
)
@@ -1074,7 +1079,7 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next) or
store(node, _, next, _) or
read(node, _, next)
)
or
@@ -1154,19 +1159,21 @@ private module LocalFlowBigStep {
private import LocalFlowBigStep
pragma[nomagic]
private predicate readCand2(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2, config) and
private predicate readCand2(Node node1, Content c, Node node2, Configuration config) {
read(node1, c, node2, config) and
nodeCand2(node1, _, _, true, unbind(config)) and
nodeCand2(node2, config) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(c, unbind(config))
}
pragma[nomagic]
private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2, config) and
private predicate storeCand2(
Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
store(node1, tc, node2, contentType) and
nodeCand2(node1, config) and
nodeCand2(node2, _, _, true, unbind(config)) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(tc.getContent(), unbind(config))
}
/**
@@ -1227,17 +1234,18 @@ private predicate flowCandFwd0(
)
or
// store
exists(Node mid, Content f |
flowCandFwd(mid, fromArg, argApf, _, config) and
storeCand2(mid, f, node, config) and
exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
storeCand2(mid, tc, node, contentType, config) and
nodeCand2(node, _, _, true, unbind(config)) and
apf.headUsesContent(f)
apf.headUsesContent(tc) and
compatibleTypes(apf0.getType(), contentType)
)
or
// read
exists(Content f |
flowCandFwdRead(f, node, fromArg, argApf, config) and
flowCandFwdConsCand(f, apf, config) and
exists(TypedContent tc |
flowCandFwdRead(tc, node, fromArg, argApf, config) and
flowCandFwdConsCand(tc, apf, config) and
nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config))
)
or
@@ -1261,24 +1269,30 @@ private predicate flowCandFwd0(
}
pragma[nomagic]
private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n |
private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n, DataFlowType contentType |
flowCandFwd(mid, _, _, apf, config) and
storeCand2(mid, f, n, config) and
storeCand2(mid, tc, n, contentType, config) and
nodeCand2(n, _, _, true, unbind(config)) and
compatibleTypes(apf.getType(), f.getType())
compatibleTypes(apf.getType(), contentType)
)
}
pragma[nomagic]
private predicate flowCandFwdRead(
Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
private predicate flowCandFwdRead0(
Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf,
AccessPathFrontHead apf, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f)
)
flowCandFwd(node1, fromArg, argApf, apf, config) and
readCand2(node1, c, node2, config) and
apf.headUsesContent(tc)
}
pragma[nomagic]
private predicate flowCandFwdRead(
TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
) {
flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config)
}
pragma[nomagic]
@@ -1385,17 +1399,15 @@ private predicate flowCand0(
)
or
// store
exists(Content f, AccessPathFrontHead apf0 |
flowCandStore(node, f, toReturn, returnApf, apf0, config) and
apf0.headUsesContent(f) and
flowCandConsCand(f, apf, config)
exists(TypedContent tc |
flowCandStore(node, tc, apf, toReturn, returnApf, config) and
flowCandConsCand(tc, apf, config)
)
or
// read
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(f, apf0, config) and
apf.headUsesContent(f)
exists(TypedContent tc, AccessPathFront apf0 |
flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(tc, apf0, config)
)
or
// flow into a callable
@@ -1417,36 +1429,40 @@ private predicate flowCand0(
else returnApf = TAccessPathFrontNone()
}
pragma[nomagic]
private predicate readCandFwd(
Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config
) {
flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config)
}
pragma[nomagic]
private predicate flowCandRead(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config
) {
exists(Node mid |
readCand2(node, f, mid, config) and
readCandFwd(node, tc, apf, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
)
}
pragma[nomagic]
private predicate flowCandStore(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, Configuration config
) {
exists(Node mid |
storeCand2(node, f, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
flowCandFwd(node, _, _, apf, config) and
storeCand2(node, tc, mid, _, unbind(config)) and
flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config))
)
}
pragma[nomagic]
private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(f, apf, config) and
exists(Node n, AccessPathFrontHead apf0 |
flowCandFwd(n, _, _, apf0, config) and
apf0.headUsesContent(f) and
flowCandRead(n, f, _, _, apf, config)
)
private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(tc, apf, config) and
flowCandRead(_, tc, _, _, _, apf, config)
}
pragma[nomagic]
@@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned(
private newtype TAccessPath =
TNil(DataFlowType t) or
TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or
TConsCons(Content f1, Content f2, int len) {
flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()]
TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()]
}
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -1514,7 +1530,7 @@ private newtype TAccessPath =
abstract private class AccessPath extends TAccessPath {
abstract string toString();
abstract Content getHead();
abstract TypedContent getHead();
abstract int len();
@@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath {
/**
* Holds if this access path has `head` at the front and may be followed by `tail`.
*/
abstract predicate pop(Content head, AccessPath tail);
abstract predicate pop(TypedContent head, AccessPath tail);
}
private class AccessPathNil extends AccessPath, TNil {
@@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil {
override string toString() { result = concat(": " + ppReprType(t)) }
override Content getHead() { none() }
override TypedContent getHead() { none() }
override int len() { result = 0 }
@@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil {
override AccessPathFront getFront() { result = TFrontNil(t) }
override predicate pop(Content head, AccessPath tail) { none() }
override predicate pop(TypedContent head, AccessPath tail) { none() }
}
abstract private class AccessPathCons extends AccessPath { }
private class AccessPathConsNil extends AccessPathCons, TConsNil {
private Content f;
private TypedContent tc;
private DataFlowType t;
AccessPathConsNil() { this = TConsNil(f, t) }
AccessPathConsNil() { this = TConsNil(tc, t) }
override string toString() {
// The `concat` becomes "" if `ppReprType` has no result.
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t))
}
override Content getHead() { result = f }
override TypedContent getHead() { result = tc }
override int len() { result = 1 }
override DataFlowType getType() { result = f.getContainerType() }
override DataFlowType getType() { result = tc.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f) }
override AccessPathFront getFront() { result = TFrontHead(tc) }
override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) }
override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) }
}
private class AccessPathConsCons extends AccessPathCons, TConsCons {
private Content f1;
private Content f2;
private TypedContent tc1;
private TypedContent tc2;
private int len;
AccessPathConsCons() { this = TConsCons(f1, f2, len) }
AccessPathConsCons() { this = TConsCons(tc1, tc2, len) }
override string toString() {
if len = 2
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc1.toString() + ", " + tc2.toString() + "]"
else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]"
}
override Content getHead() { result = f1 }
override TypedContent getHead() { result = tc1 }
override int len() { result = len }
override DataFlowType getType() { result = f1.getContainerType() }
override DataFlowType getType() { result = tc1.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f1) }
override AccessPathFront getFront() { result = TFrontHead(tc1) }
override predicate pop(Content head, AccessPath tail) {
head = f1 and
override predicate pop(TypedContent head, AccessPath tail) {
head = tc1 and
(
tail = TConsCons(f2, _, len - 1)
tail = TConsCons(tc2, _, len - 1)
or
len = 2 and
tail = TConsNil(f2, _)
tail = TConsNil(tc2, _)
)
}
}
/** Gets the access path obtained by popping `f` from `ap`, if any. */
private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) }
/** Gets the access path obtained by popping `tc` from `ap`, if any. */
private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) }
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/** Gets the access path obtained by pushing `tc` onto `ap`. */
private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) }
private newtype TAccessPathOption =
TAccessPathNone() or
@@ -1678,15 +1694,12 @@ private predicate flowFwd0(
)
or
// store
exists(Content f, AccessPath ap0 |
flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and
ap = push(f, ap0)
)
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
or
// read
exists(Content f |
flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and
flowFwdConsCand(f, apf, ap, config)
exists(TypedContent tc |
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
flowFwdConsCand(tc, apf, ap, config)
)
or
// flow into a callable
@@ -1710,54 +1723,63 @@ private predicate flowFwd0(
pragma[nomagic]
private predicate flowFwdStore(
Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg,
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFront apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
flowFwdStore1(mid, f, node, apf0, apf, config)
flowFwdStore0(mid, tc, node, apf0, apf, config)
)
}
pragma[nomagic]
private predicate flowFwdStore0(
Node mid, Content f, Node node, AccessPathFront apf0, Configuration config
private predicate storeCand(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf,
Configuration config
) {
storeCand2(mid, f, node, config) and
flowCand(mid, _, _, apf0, config)
storeCand2(mid, tc, node, _, config) and
flowCand(mid, _, _, apf0, config) and
apf.headUsesContent(tc)
}
pragma[noinline]
private predicate flowFwdStore1(
Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
private predicate flowFwdStore0(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
Configuration config
) {
flowFwdStore0(mid, f, node, apf0, config) and
flowCandConsCand(f, apf0, config) and
apf.headUsesContent(f) and
storeCand(mid, tc, node, apf0, apf, config) and
flowCandConsCand(tc, apf0, config) and
flowCand(node, _, _, apf, unbind(config))
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp,
Configuration config
private predicate flowFwdRead0(
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
boolean fromArg, AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f) and
flowCand(node, _, _, _, unbind(config))
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
readCandFwd(node1, tc, apf0, node2, config)
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, TypedContent tc |
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
flowCand(node, _, _, apf, unbind(config)) and
flowCandConsCand(tc, apf, unbind(config))
)
}
pragma[nomagic]
private predicate flowFwdConsCand(
Content f, AccessPathFront apf, AccessPath ap, Configuration config
TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config
) {
exists(Node n |
flowFwd(n, _, _, apf, ap, config) and
flowFwdStore1(n, f, _, apf, _, config)
flowFwdStore0(n, tc, _, apf, _, config)
)
}
@@ -1863,9 +1885,9 @@ private predicate flow0(
)
or
// store
exists(Content f |
flowStore(f, node, toReturn, returnAp, ap, config) and
flowConsCand(f, ap, config)
exists(TypedContent tc |
flowStore(tc, node, toReturn, returnAp, ap, config) and
flowConsCand(tc, ap, config)
)
or
// read
@@ -1895,39 +1917,41 @@ private predicate flow0(
pragma[nomagic]
private predicate storeFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
storeCand2(node1, f, node2, config) and
flowFwdStore(node2, f, ap, _, _, _, config) and
ap0 = push(f, ap)
storeCand2(node1, tc, node2, _, config) and
flowFwdStore(node2, tc, ap, _, _, _, config) and
ap0 = push(tc, ap)
}
pragma[nomagic]
private predicate flowStore(
Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
Configuration config
) {
exists(Node mid, AccessPath ap0 |
storeFlowFwd(node, f, mid, ap, ap0, config) and
storeFlowFwd(node, tc, mid, ap, ap0, config) and
flow(mid, toReturn, returnAp, ap0, config)
)
}
pragma[nomagic]
private predicate readFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
readCand2(node1, f, node2, config) and
flowFwdRead(node2, f, ap, _, _, config) and
ap0 = pop(f, ap) and
flowFwdConsCand(f, _, ap0, unbind(config))
exists(AccessPathFrontHead apf |
readCandFwd(node1, tc, apf, node2, config) and
flowFwdRead(node2, apf, ap, _, _, _, config) and
ap0 = pop(tc, ap) and
flowFwdConsCand(tc, _, ap0, unbind(config))
)
}
pragma[nomagic]
private predicate flowConsCand(Content f, AccessPath ap, Configuration config) {
private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) {
exists(Node n, Node mid |
flow(mid, _, _, ap, config) and
readFlowFwd(n, f, mid, _, ap, config)
readFlowFwd(n, tc, mid, _, ap, config)
)
}
@@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and
exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
@@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
}
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2) and
private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) {
readCandFwd(node1, tc, _, node2, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) {
private predicate pathReadStep(
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
readCand(mid.getNode(), f, node, mid.getConfiguration()) and
readCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate storeCand(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2) and
private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) {
storeCand2(node1, tc, node2, _, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathStoreStep(
PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
storeCand(mid.getNode(), f, node, mid.getConfiguration()) and
storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -2538,10 +2564,10 @@ private module FlowExploration {
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(Content f, int len) { len in [1 .. 5] }
TPartialCons(TypedContent tc, int len) { len in [1 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -2550,7 +2576,7 @@ private module FlowExploration {
private class PartialAccessPath extends TPartialAccessPath {
abstract string toString();
Content getHead() { this = TPartialCons(result, _) }
TypedContent getHead() { this = TPartialCons(result, _) }
int len() {
this = TPartialNil(_) and result = 0
@@ -2561,7 +2587,7 @@ private module FlowExploration {
DataFlowType getType() {
this = TPartialNil(result)
or
exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType())
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
@@ -2579,15 +2605,15 @@ private module FlowExploration {
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
exists(TypedContent tc, int len | this = TPartialCons(tc, len) |
if len = 1
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc.toString() + "]"
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
override AccessPathFront getFront() {
exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f))
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
}
}
@@ -2763,11 +2789,12 @@ private module FlowExploration {
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(PartialAccessPath ap0, Content f |
partialPathReadStep(mid, ap0, f, node, cc, config) and
exists(PartialAccessPath ap0, TypedContent tc |
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, f, ap0, config)
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -2786,35 +2813,42 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
) {
ap1 = mid.getAp() and
store(mid.getNode(), f, node) and
ap2.getHead() = f and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), f.getType())
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
)
}
pragma[nomagic]
private predicate apConsFwd(
PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
partialPathStoreStep(mid, ap1, f, _, ap2) and
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc,
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
ap = mid.getAp() and
readStep(mid.getNode(), f, node) and
ap.getHead() = f and
config = mid.getConfiguration() and
cc = mid.getCallContext()
exists(Node midNode |
midNode = mid.getNode() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node) and
ap.getHead() = tc and
config = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
private predicate partialPathOutOfCallable0(

View File

@@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
exists(Node mid |
useFieldFlow(config) and
nodeCandFwd1(mid, fromArg, config) and
store(mid, _, node) and
store(mid, _, node, _) and
not outBarrier(mid, config)
)
or
// read
exists(Content f |
nodeCandFwd1Read(f, node, fromArg, config) and
nodeCandFwd1IsStored(f, config) and
exists(Content c |
nodeCandFwd1Read(c, node, fromArg, config) and
nodeCandFwd1IsStored(c, config) and
not inBarrier(node, config)
)
or
@@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
pragma[nomagic]
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) {
exists(Node mid |
nodeCandFwd1(mid, fromArg, config) and
read(mid, f, node)
read(mid, c, node)
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`.
*/
pragma[nomagic]
private predicate nodeCandFwd1IsStored(Content f, Configuration config) {
exists(Node mid, Node node |
private predicate nodeCandFwd1IsStored(Content c, Configuration config) {
exists(Node mid, Node node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
nodeCandFwd1(mid, config) and
store(mid, f, node)
store(mid, tc, node, _) and
c = tc.getContent()
)
}
@@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
)
or
// store
exists(Content f |
nodeCand1Store(f, node, toReturn, config) and
nodeCand1IsRead(f, config)
exists(Content c |
nodeCand1Store(c, node, toReturn, config) and
nodeCand1IsRead(c, config)
)
or
// read
exists(Node mid, Content f |
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
exists(Node mid, Content c |
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, toReturn, config)
)
or
@@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand1`.
*/
pragma[nomagic]
private predicate nodeCand1IsRead(Content f, Configuration config) {
private predicate nodeCand1IsRead(Content c, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, _, config)
)
}
pragma[nomagic]
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
exists(Node mid |
private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
nodeCand1(mid, toReturn, config) and
nodeCandFwd1IsStored(f, unbind(config)) and
store(node, f, mid)
nodeCandFwd1IsStored(c, unbind(config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
}
/**
* Holds if `f` is the target of both a read and a store in the flow covered
* Holds if `c` is the target of both a read and a store in the flow covered
* by `nodeCand1`.
*/
private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) {
nodeCand1IsRead(f, conf) and
nodeCand1Store(f, _, _, conf)
private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) {
nodeCand1IsRead(c, conf) and
nodeCand1Store(c, _, _, conf)
}
pragma[nomagic]
@@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c
}
pragma[nomagic]
private predicate store(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
nodeCand1(n2, unbind(config)) and
store(n1, f, n2)
private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) {
exists(TypedContent tc |
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
store(n1, tc, n2, _) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate read(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
private predicate read(Node n1, Content c, Node n2, Configuration config) {
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
read(n1, f, n2)
read(n1, c, n2)
}
pragma[noinline]
@@ -748,16 +753,16 @@ private predicate nodeCandFwd2(
)
or
// store
exists(Node mid, Content f |
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, _, config) and
store(mid, f, node, config) and
storeCand1(mid, _, node, config) and
stored = true
)
or
// read
exists(Content f |
nodeCandFwd2Read(f, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(f, stored, config)
exists(Content c |
nodeCandFwd2Read(c, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(c, stored, config)
)
or
// flow into a callable
@@ -781,25 +786,25 @@ private predicate nodeCandFwd2(
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`.
*/
pragma[noinline]
private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) {
private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCand1(node, unbind(config)) and
nodeCandFwd2(mid, _, _, stored, config) and
store(mid, f, node, config)
storeCand1(mid, c, node, config)
)
}
pragma[nomagic]
private predicate nodeCandFwd2Read(
Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config
Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config
) {
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, true, config) and
read(mid, f, node, config)
read(mid, c, node, config)
)
}
@@ -896,15 +901,15 @@ private predicate nodeCand2(
)
or
// store
exists(Content f |
nodeCand2Store(f, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(f, read, config)
exists(Content c |
nodeCand2Store(c, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(c, read, config)
)
or
// read
exists(Node mid, Content f, boolean read0 |
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and
exists(Node mid, Content c, boolean read0 |
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and
nodeCand2(mid, toReturn, returnRead, read0, config) and
read = true
)
@@ -930,51 +935,51 @@ private predicate nodeCand2(
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) {
private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd2(node, _, _, true, unbind(config)) and
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and
nodeCand2(mid, _, _, read, config)
)
}
pragma[nomagic]
private predicate nodeCand2Store(
Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Configuration config
) {
exists(Node mid |
store(node, f, mid, config) and
storeCand1(node, c, mid, config) and
nodeCand2(mid, toReturn, returnRead, true, config) and
nodeCandFwd2(node, _, _, stored, unbind(config))
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCand2`.
*/
pragma[nomagic]
private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) {
private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) {
exists(Node node |
nodeCand2Store(f, node, _, _, stored, conf) and
nodeCand2Store(c, node, _, _, stored, conf) and
nodeCand2(node, _, _, stored, conf)
)
}
/**
* Holds if `f` is the target of both a store and a read in the path graph
* Holds if `c` is the target of both a store and a read in the path graph
* covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) {
private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) {
exists(boolean apNonEmpty |
nodeCand2IsStored(f, apNonEmpty, conf) and
nodeCand2IsRead(f, apNonEmpty, conf)
nodeCand2IsStored(c, apNonEmpty, conf) and
nodeCand2IsRead(c, apNonEmpty, conf)
)
}
@@ -1058,7 +1063,7 @@ private module LocalFlowBigStep {
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof OutNodeExt or
store(_, _, node) or
store(_, _, node, _) or
read(_, _, node) or
node instanceof CastNode
)
@@ -1074,7 +1079,7 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next) or
store(node, _, next, _) or
read(node, _, next)
)
or
@@ -1154,19 +1159,21 @@ private module LocalFlowBigStep {
private import LocalFlowBigStep
pragma[nomagic]
private predicate readCand2(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2, config) and
private predicate readCand2(Node node1, Content c, Node node2, Configuration config) {
read(node1, c, node2, config) and
nodeCand2(node1, _, _, true, unbind(config)) and
nodeCand2(node2, config) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(c, unbind(config))
}
pragma[nomagic]
private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2, config) and
private predicate storeCand2(
Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
store(node1, tc, node2, contentType) and
nodeCand2(node1, config) and
nodeCand2(node2, _, _, true, unbind(config)) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(tc.getContent(), unbind(config))
}
/**
@@ -1227,17 +1234,18 @@ private predicate flowCandFwd0(
)
or
// store
exists(Node mid, Content f |
flowCandFwd(mid, fromArg, argApf, _, config) and
storeCand2(mid, f, node, config) and
exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
storeCand2(mid, tc, node, contentType, config) and
nodeCand2(node, _, _, true, unbind(config)) and
apf.headUsesContent(f)
apf.headUsesContent(tc) and
compatibleTypes(apf0.getType(), contentType)
)
or
// read
exists(Content f |
flowCandFwdRead(f, node, fromArg, argApf, config) and
flowCandFwdConsCand(f, apf, config) and
exists(TypedContent tc |
flowCandFwdRead(tc, node, fromArg, argApf, config) and
flowCandFwdConsCand(tc, apf, config) and
nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config))
)
or
@@ -1261,24 +1269,30 @@ private predicate flowCandFwd0(
}
pragma[nomagic]
private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n |
private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n, DataFlowType contentType |
flowCandFwd(mid, _, _, apf, config) and
storeCand2(mid, f, n, config) and
storeCand2(mid, tc, n, contentType, config) and
nodeCand2(n, _, _, true, unbind(config)) and
compatibleTypes(apf.getType(), f.getType())
compatibleTypes(apf.getType(), contentType)
)
}
pragma[nomagic]
private predicate flowCandFwdRead(
Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
private predicate flowCandFwdRead0(
Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf,
AccessPathFrontHead apf, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f)
)
flowCandFwd(node1, fromArg, argApf, apf, config) and
readCand2(node1, c, node2, config) and
apf.headUsesContent(tc)
}
pragma[nomagic]
private predicate flowCandFwdRead(
TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
) {
flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config)
}
pragma[nomagic]
@@ -1385,17 +1399,15 @@ private predicate flowCand0(
)
or
// store
exists(Content f, AccessPathFrontHead apf0 |
flowCandStore(node, f, toReturn, returnApf, apf0, config) and
apf0.headUsesContent(f) and
flowCandConsCand(f, apf, config)
exists(TypedContent tc |
flowCandStore(node, tc, apf, toReturn, returnApf, config) and
flowCandConsCand(tc, apf, config)
)
or
// read
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(f, apf0, config) and
apf.headUsesContent(f)
exists(TypedContent tc, AccessPathFront apf0 |
flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(tc, apf0, config)
)
or
// flow into a callable
@@ -1417,36 +1429,40 @@ private predicate flowCand0(
else returnApf = TAccessPathFrontNone()
}
pragma[nomagic]
private predicate readCandFwd(
Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config
) {
flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config)
}
pragma[nomagic]
private predicate flowCandRead(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config
) {
exists(Node mid |
readCand2(node, f, mid, config) and
readCandFwd(node, tc, apf, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
)
}
pragma[nomagic]
private predicate flowCandStore(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, Configuration config
) {
exists(Node mid |
storeCand2(node, f, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
flowCandFwd(node, _, _, apf, config) and
storeCand2(node, tc, mid, _, unbind(config)) and
flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config))
)
}
pragma[nomagic]
private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(f, apf, config) and
exists(Node n, AccessPathFrontHead apf0 |
flowCandFwd(n, _, _, apf0, config) and
apf0.headUsesContent(f) and
flowCandRead(n, f, _, _, apf, config)
)
private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(tc, apf, config) and
flowCandRead(_, tc, _, _, _, apf, config)
}
pragma[nomagic]
@@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned(
private newtype TAccessPath =
TNil(DataFlowType t) or
TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or
TConsCons(Content f1, Content f2, int len) {
flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()]
TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()]
}
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -1514,7 +1530,7 @@ private newtype TAccessPath =
abstract private class AccessPath extends TAccessPath {
abstract string toString();
abstract Content getHead();
abstract TypedContent getHead();
abstract int len();
@@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath {
/**
* Holds if this access path has `head` at the front and may be followed by `tail`.
*/
abstract predicate pop(Content head, AccessPath tail);
abstract predicate pop(TypedContent head, AccessPath tail);
}
private class AccessPathNil extends AccessPath, TNil {
@@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil {
override string toString() { result = concat(": " + ppReprType(t)) }
override Content getHead() { none() }
override TypedContent getHead() { none() }
override int len() { result = 0 }
@@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil {
override AccessPathFront getFront() { result = TFrontNil(t) }
override predicate pop(Content head, AccessPath tail) { none() }
override predicate pop(TypedContent head, AccessPath tail) { none() }
}
abstract private class AccessPathCons extends AccessPath { }
private class AccessPathConsNil extends AccessPathCons, TConsNil {
private Content f;
private TypedContent tc;
private DataFlowType t;
AccessPathConsNil() { this = TConsNil(f, t) }
AccessPathConsNil() { this = TConsNil(tc, t) }
override string toString() {
// The `concat` becomes "" if `ppReprType` has no result.
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t))
}
override Content getHead() { result = f }
override TypedContent getHead() { result = tc }
override int len() { result = 1 }
override DataFlowType getType() { result = f.getContainerType() }
override DataFlowType getType() { result = tc.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f) }
override AccessPathFront getFront() { result = TFrontHead(tc) }
override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) }
override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) }
}
private class AccessPathConsCons extends AccessPathCons, TConsCons {
private Content f1;
private Content f2;
private TypedContent tc1;
private TypedContent tc2;
private int len;
AccessPathConsCons() { this = TConsCons(f1, f2, len) }
AccessPathConsCons() { this = TConsCons(tc1, tc2, len) }
override string toString() {
if len = 2
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc1.toString() + ", " + tc2.toString() + "]"
else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]"
}
override Content getHead() { result = f1 }
override TypedContent getHead() { result = tc1 }
override int len() { result = len }
override DataFlowType getType() { result = f1.getContainerType() }
override DataFlowType getType() { result = tc1.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f1) }
override AccessPathFront getFront() { result = TFrontHead(tc1) }
override predicate pop(Content head, AccessPath tail) {
head = f1 and
override predicate pop(TypedContent head, AccessPath tail) {
head = tc1 and
(
tail = TConsCons(f2, _, len - 1)
tail = TConsCons(tc2, _, len - 1)
or
len = 2 and
tail = TConsNil(f2, _)
tail = TConsNil(tc2, _)
)
}
}
/** Gets the access path obtained by popping `f` from `ap`, if any. */
private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) }
/** Gets the access path obtained by popping `tc` from `ap`, if any. */
private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) }
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/** Gets the access path obtained by pushing `tc` onto `ap`. */
private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) }
private newtype TAccessPathOption =
TAccessPathNone() or
@@ -1678,15 +1694,12 @@ private predicate flowFwd0(
)
or
// store
exists(Content f, AccessPath ap0 |
flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and
ap = push(f, ap0)
)
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
or
// read
exists(Content f |
flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and
flowFwdConsCand(f, apf, ap, config)
exists(TypedContent tc |
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
flowFwdConsCand(tc, apf, ap, config)
)
or
// flow into a callable
@@ -1710,54 +1723,63 @@ private predicate flowFwd0(
pragma[nomagic]
private predicate flowFwdStore(
Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg,
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFront apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
flowFwdStore1(mid, f, node, apf0, apf, config)
flowFwdStore0(mid, tc, node, apf0, apf, config)
)
}
pragma[nomagic]
private predicate flowFwdStore0(
Node mid, Content f, Node node, AccessPathFront apf0, Configuration config
private predicate storeCand(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf,
Configuration config
) {
storeCand2(mid, f, node, config) and
flowCand(mid, _, _, apf0, config)
storeCand2(mid, tc, node, _, config) and
flowCand(mid, _, _, apf0, config) and
apf.headUsesContent(tc)
}
pragma[noinline]
private predicate flowFwdStore1(
Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
private predicate flowFwdStore0(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
Configuration config
) {
flowFwdStore0(mid, f, node, apf0, config) and
flowCandConsCand(f, apf0, config) and
apf.headUsesContent(f) and
storeCand(mid, tc, node, apf0, apf, config) and
flowCandConsCand(tc, apf0, config) and
flowCand(node, _, _, apf, unbind(config))
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp,
Configuration config
private predicate flowFwdRead0(
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
boolean fromArg, AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f) and
flowCand(node, _, _, _, unbind(config))
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
readCandFwd(node1, tc, apf0, node2, config)
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, TypedContent tc |
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
flowCand(node, _, _, apf, unbind(config)) and
flowCandConsCand(tc, apf, unbind(config))
)
}
pragma[nomagic]
private predicate flowFwdConsCand(
Content f, AccessPathFront apf, AccessPath ap, Configuration config
TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config
) {
exists(Node n |
flowFwd(n, _, _, apf, ap, config) and
flowFwdStore1(n, f, _, apf, _, config)
flowFwdStore0(n, tc, _, apf, _, config)
)
}
@@ -1863,9 +1885,9 @@ private predicate flow0(
)
or
// store
exists(Content f |
flowStore(f, node, toReturn, returnAp, ap, config) and
flowConsCand(f, ap, config)
exists(TypedContent tc |
flowStore(tc, node, toReturn, returnAp, ap, config) and
flowConsCand(tc, ap, config)
)
or
// read
@@ -1895,39 +1917,41 @@ private predicate flow0(
pragma[nomagic]
private predicate storeFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
storeCand2(node1, f, node2, config) and
flowFwdStore(node2, f, ap, _, _, _, config) and
ap0 = push(f, ap)
storeCand2(node1, tc, node2, _, config) and
flowFwdStore(node2, tc, ap, _, _, _, config) and
ap0 = push(tc, ap)
}
pragma[nomagic]
private predicate flowStore(
Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
Configuration config
) {
exists(Node mid, AccessPath ap0 |
storeFlowFwd(node, f, mid, ap, ap0, config) and
storeFlowFwd(node, tc, mid, ap, ap0, config) and
flow(mid, toReturn, returnAp, ap0, config)
)
}
pragma[nomagic]
private predicate readFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
readCand2(node1, f, node2, config) and
flowFwdRead(node2, f, ap, _, _, config) and
ap0 = pop(f, ap) and
flowFwdConsCand(f, _, ap0, unbind(config))
exists(AccessPathFrontHead apf |
readCandFwd(node1, tc, apf, node2, config) and
flowFwdRead(node2, apf, ap, _, _, _, config) and
ap0 = pop(tc, ap) and
flowFwdConsCand(tc, _, ap0, unbind(config))
)
}
pragma[nomagic]
private predicate flowConsCand(Content f, AccessPath ap, Configuration config) {
private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) {
exists(Node n, Node mid |
flow(mid, _, _, ap, config) and
readFlowFwd(n, f, mid, _, ap, config)
readFlowFwd(n, tc, mid, _, ap, config)
)
}
@@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and
exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
@@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
}
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2) and
private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) {
readCandFwd(node1, tc, _, node2, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) {
private predicate pathReadStep(
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
readCand(mid.getNode(), f, node, mid.getConfiguration()) and
readCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate storeCand(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2) and
private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) {
storeCand2(node1, tc, node2, _, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathStoreStep(
PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
storeCand(mid.getNode(), f, node, mid.getConfiguration()) and
storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -2538,10 +2564,10 @@ private module FlowExploration {
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(Content f, int len) { len in [1 .. 5] }
TPartialCons(TypedContent tc, int len) { len in [1 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -2550,7 +2576,7 @@ private module FlowExploration {
private class PartialAccessPath extends TPartialAccessPath {
abstract string toString();
Content getHead() { this = TPartialCons(result, _) }
TypedContent getHead() { this = TPartialCons(result, _) }
int len() {
this = TPartialNil(_) and result = 0
@@ -2561,7 +2587,7 @@ private module FlowExploration {
DataFlowType getType() {
this = TPartialNil(result)
or
exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType())
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
@@ -2579,15 +2605,15 @@ private module FlowExploration {
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
exists(TypedContent tc, int len | this = TPartialCons(tc, len) |
if len = 1
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc.toString() + "]"
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
override AccessPathFront getFront() {
exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f))
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
}
}
@@ -2763,11 +2789,12 @@ private module FlowExploration {
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(PartialAccessPath ap0, Content f |
partialPathReadStep(mid, ap0, f, node, cc, config) and
exists(PartialAccessPath ap0, TypedContent tc |
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, f, ap0, config)
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -2786,35 +2813,42 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
) {
ap1 = mid.getAp() and
store(mid.getNode(), f, node) and
ap2.getHead() = f and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), f.getType())
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
)
}
pragma[nomagic]
private predicate apConsFwd(
PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
partialPathStoreStep(mid, ap1, f, _, ap2) and
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc,
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
ap = mid.getAp() and
readStep(mid.getNode(), f, node) and
ap.getHead() = f and
config = mid.getConfiguration() and
cc = mid.getCallContext()
exists(Node midNode |
midNode = mid.getNode() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node) and
ap.getHead() = tc and
config = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
private predicate partialPathOutOfCallable0(

View File

@@ -198,123 +198,130 @@ private module Cached {
/**
* The final flow-through calculation:
*
* - Input access paths are abstracted with a `ContentOption` parameter
* that represents the head of the access path. `TContentNone()` means that
* the access path is unrestricted.
* - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`)
* or summarized as a single read step with before and after types recorded
* in the `ReadStepTypesOption` parameter.
* - Types are checked using the `compatibleTypes()` relation.
*/
private module Final {
/**
* Holds if `p` can flow to `node` in the same callable using only
* value-preserving steps, not taking call contexts into account.
* value-preserving steps and possibly a single read step, not taking
* call contexts into account.
*
* `contentIn` describes the content of `p` that can flow to `node`
* (if any).
* If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type.
*/
predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) {
parameterValueFlow0(p, node, contentIn) and
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and
if node instanceof CastingNode
then
// normal flow through
contentIn = TContentNone() and
read = TReadStepTypesNone() and
compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node))
or
// getter
exists(Content fIn |
contentIn.getContent() = fIn and
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node))
)
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node))
else any()
}
pragma[nomagic]
private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) {
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
p = node and
Cand::cand(p, _) and
contentIn = TContentNone()
read = TReadStepTypesNone()
or
// local flow
exists(Node mid |
parameterValueFlow(p, mid, contentIn) and
parameterValueFlow(p, mid, read) and
LocalFlowBigStep::localFlowBigStep(mid, node)
)
or
// read
exists(Node mid, Content f |
parameterValueFlow(p, mid, TContentNone()) and
readStep(mid, f, node) and
contentIn.getContent() = f and
exists(Node mid |
parameterValueFlow(p, mid, TReadStepTypesNone()) and
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType())
compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType())
)
or
// flow through: no prior read
exists(ArgumentNode arg |
parameterValueFlowArg(p, arg, TContentNone()) and
argumentValueFlowsThrough(arg, contentIn, node)
parameterValueFlowArg(p, arg, TReadStepTypesNone()) and
argumentValueFlowsThrough(arg, read, node)
)
or
// flow through: no read inside method
exists(ArgumentNode arg |
parameterValueFlowArg(p, arg, contentIn) and
argumentValueFlowsThrough(arg, TContentNone(), node)
parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, TReadStepTypesNone(), node)
)
}
pragma[nomagic]
private predicate parameterValueFlowArg(
ParameterNode p, ArgumentNode arg, ContentOption contentIn
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
) {
parameterValueFlow(p, arg, contentIn) and
parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _)
}
pragma[nomagic]
private predicate argumentValueFlowsThrough0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
) {
exists(ParameterNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, contentIn)
parameterValueFlowReturn(param, kind, read)
)
}
/**
* Holds if `arg` flows to `out` through a call using only value-preserving steps,
* not taking call contexts into account.
* Holds if `arg` flows to `out` through a call using only
* value-preserving steps and possibly a single read step, not taking
* call contexts into account.
*
* `contentIn` describes the content of `arg` that can flow to `out` (if any).
* If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type.
*/
pragma[nomagic]
predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) {
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, contentIn) and
argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind)
|
// normal flow through
contentIn = TContentNone() and
read = TReadStepTypesNone() and
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out))
or
// getter
exists(Content fIn |
contentIn.getContent() = fIn and
compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out))
)
compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out))
)
}
/**
* Holds if `arg` flows to `out` through a call using only
* value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step.
*/
predicate getterStep(ArgumentNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
}
/**
* Holds if `p` can flow to a return node of kind `kind` in the same
* callable using only value-preserving steps.
* callable using only value-preserving steps and possibly a single read
* step.
*
* `contentIn` describes the content of `p` that can flow to the return
* node (if any).
* If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type.
*/
private predicate parameterValueFlowReturn(
ParameterNode p, ReturnKind kind, ContentOption contentIn
ParameterNode p, ReturnKind kind, ReadStepTypesOption read
) {
exists(ReturnNode ret |
parameterValueFlow(p, ret, contentIn) and
parameterValueFlow(p, ret, read) and
kind = ret.getKind()
)
}
@@ -329,7 +336,27 @@ private module Cached {
*/
cached
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TContentNone())
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
}
private predicate store(
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
readStep(_, c, _) and
contentType = getErasedNodeTypeBound(node1) and
containerType = getErasedNodeTypeBound(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
readStep(n2, c, n1) and
contentType = getErasedNodeTypeBound(n1) and
containerType = getErasedNodeTypeBound(n2)
)
}
/**
@@ -340,17 +367,8 @@ private module Cached {
* been stored into, in order to handle cases like `x.f1.f2 = y`.
*/
cached
predicate store(Node node1, Content f, Node node2) {
storeStep(node1, f, node2) and readStep(_, f, _)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TContentSome(f), n1)
or
readStep(n2, f, n1)
)
predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) {
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
}
import FlowThrough
@@ -397,10 +415,13 @@ private module Cached {
TBooleanNone() or
TBooleanSome(boolean b) { b = true or b = false }
cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
cached
newtype TAccessPathFront =
TFrontNil(DataFlowType t) or
TFrontHead(Content f)
TFrontHead(TypedContent tc)
cached
newtype TAccessPathFrontOption =
@@ -415,25 +436,38 @@ class CastingNode extends Node {
CastingNode() {
this instanceof ParameterNode or
this instanceof CastNode or
this instanceof OutNodeExt
this instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
readStep(_, _, this)
}
}
newtype TContentOption =
TContentNone() or
TContentSome(Content f)
private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) {
readStep(n1, c, n2) and
container = getErasedNodeTypeBound(n1) and
content = getErasedNodeTypeBound(n2)
}
private class ContentOption extends TContentOption {
Content getContent() { this = TContentSome(result) }
predicate hasContent() { exists(this.getContent()) }
string toString() {
result = this.getContent().toString()
or
not this.hasContent() and
result = "<none>"
private newtype TReadStepTypesOption =
TReadStepTypesNone() or
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
readStepWithTypes(_, container, c, _, content)
}
private class ReadStepTypesOption extends TReadStepTypesOption {
predicate isSome() { this instanceof TReadStepTypesSome }
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
Content getContent() { this = TReadStepTypesSome(_, result, _) }
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
string toString() { if this.isSome() then result = "Some(..)" else result = "None()" }
}
/**
@@ -692,6 +726,23 @@ class BooleanOption extends TBooleanOption {
}
}
/** Content tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;
private DataFlowType t;
TypedContent() { this = MkTypedContent(c, t) }
/** Gets the content. */
Content getContent() { result = c }
/** Gets the container type. */
DataFlowType getContainerType() { result = t }
/** Gets a textual representation of this content. */
string toString() { result = c.toString() }
}
/**
* The front of an access path. This is either a head or a nil.
*/
@@ -702,25 +753,29 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract boolean toBoolNonEmpty();
predicate headUsesContent(Content f) { this = TFrontHead(f) }
predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override string toString() {
exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t))
}
private DataFlowType t;
override DataFlowType getType() { this = TFrontNil(result) }
AccessPathFrontNil() { this = TFrontNil(t) }
override string toString() { result = ppReprType(t) }
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
}
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) }
private TypedContent tc;
override DataFlowType getType() {
exists(Content head | this = TFrontHead(head) | result = head.getContainerType())
}
AccessPathFrontHead() { this = TFrontHead(tc) }
override string toString() { result = tc.toString() }
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
}

View File

@@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
exists(Node mid |
useFieldFlow(config) and
nodeCandFwd1(mid, fromArg, config) and
store(mid, _, node) and
store(mid, _, node, _) and
not outBarrier(mid, config)
)
or
// read
exists(Content f |
nodeCandFwd1Read(f, node, fromArg, config) and
nodeCandFwd1IsStored(f, config) and
exists(Content c |
nodeCandFwd1Read(c, node, fromArg, config) and
nodeCandFwd1IsStored(c, config) and
not inBarrier(node, config)
)
or
@@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
pragma[nomagic]
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) {
exists(Node mid |
nodeCandFwd1(mid, fromArg, config) and
read(mid, f, node)
read(mid, c, node)
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`.
*/
pragma[nomagic]
private predicate nodeCandFwd1IsStored(Content f, Configuration config) {
exists(Node mid, Node node |
private predicate nodeCandFwd1IsStored(Content c, Configuration config) {
exists(Node mid, Node node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
nodeCandFwd1(mid, config) and
store(mid, f, node)
store(mid, tc, node, _) and
c = tc.getContent()
)
}
@@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
)
or
// store
exists(Content f |
nodeCand1Store(f, node, toReturn, config) and
nodeCand1IsRead(f, config)
exists(Content c |
nodeCand1Store(c, node, toReturn, config) and
nodeCand1IsRead(c, config)
)
or
// read
exists(Node mid, Content f |
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
exists(Node mid, Content c |
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, toReturn, config)
)
or
@@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand1`.
*/
pragma[nomagic]
private predicate nodeCand1IsRead(Content f, Configuration config) {
private predicate nodeCand1IsRead(Content c, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, _, config)
)
}
pragma[nomagic]
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
exists(Node mid |
private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
nodeCand1(mid, toReturn, config) and
nodeCandFwd1IsStored(f, unbind(config)) and
store(node, f, mid)
nodeCandFwd1IsStored(c, unbind(config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
}
/**
* Holds if `f` is the target of both a read and a store in the flow covered
* Holds if `c` is the target of both a read and a store in the flow covered
* by `nodeCand1`.
*/
private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) {
nodeCand1IsRead(f, conf) and
nodeCand1Store(f, _, _, conf)
private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) {
nodeCand1IsRead(c, conf) and
nodeCand1Store(c, _, _, conf)
}
pragma[nomagic]
@@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c
}
pragma[nomagic]
private predicate store(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
nodeCand1(n2, unbind(config)) and
store(n1, f, n2)
private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) {
exists(TypedContent tc |
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
store(n1, tc, n2, _) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate read(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
private predicate read(Node n1, Content c, Node n2, Configuration config) {
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
read(n1, f, n2)
read(n1, c, n2)
}
pragma[noinline]
@@ -748,16 +753,16 @@ private predicate nodeCandFwd2(
)
or
// store
exists(Node mid, Content f |
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, _, config) and
store(mid, f, node, config) and
storeCand1(mid, _, node, config) and
stored = true
)
or
// read
exists(Content f |
nodeCandFwd2Read(f, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(f, stored, config)
exists(Content c |
nodeCandFwd2Read(c, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(c, stored, config)
)
or
// flow into a callable
@@ -781,25 +786,25 @@ private predicate nodeCandFwd2(
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`.
*/
pragma[noinline]
private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) {
private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCand1(node, unbind(config)) and
nodeCandFwd2(mid, _, _, stored, config) and
store(mid, f, node, config)
storeCand1(mid, c, node, config)
)
}
pragma[nomagic]
private predicate nodeCandFwd2Read(
Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config
Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config
) {
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, true, config) and
read(mid, f, node, config)
read(mid, c, node, config)
)
}
@@ -896,15 +901,15 @@ private predicate nodeCand2(
)
or
// store
exists(Content f |
nodeCand2Store(f, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(f, read, config)
exists(Content c |
nodeCand2Store(c, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(c, read, config)
)
or
// read
exists(Node mid, Content f, boolean read0 |
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and
exists(Node mid, Content c, boolean read0 |
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and
nodeCand2(mid, toReturn, returnRead, read0, config) and
read = true
)
@@ -930,51 +935,51 @@ private predicate nodeCand2(
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) {
private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd2(node, _, _, true, unbind(config)) and
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and
nodeCand2(mid, _, _, read, config)
)
}
pragma[nomagic]
private predicate nodeCand2Store(
Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Configuration config
) {
exists(Node mid |
store(node, f, mid, config) and
storeCand1(node, c, mid, config) and
nodeCand2(mid, toReturn, returnRead, true, config) and
nodeCandFwd2(node, _, _, stored, unbind(config))
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCand2`.
*/
pragma[nomagic]
private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) {
private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) {
exists(Node node |
nodeCand2Store(f, node, _, _, stored, conf) and
nodeCand2Store(c, node, _, _, stored, conf) and
nodeCand2(node, _, _, stored, conf)
)
}
/**
* Holds if `f` is the target of both a store and a read in the path graph
* Holds if `c` is the target of both a store and a read in the path graph
* covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) {
private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) {
exists(boolean apNonEmpty |
nodeCand2IsStored(f, apNonEmpty, conf) and
nodeCand2IsRead(f, apNonEmpty, conf)
nodeCand2IsStored(c, apNonEmpty, conf) and
nodeCand2IsRead(c, apNonEmpty, conf)
)
}
@@ -1058,7 +1063,7 @@ private module LocalFlowBigStep {
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof OutNodeExt or
store(_, _, node) or
store(_, _, node, _) or
read(_, _, node) or
node instanceof CastNode
)
@@ -1074,7 +1079,7 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next) or
store(node, _, next, _) or
read(node, _, next)
)
or
@@ -1154,19 +1159,21 @@ private module LocalFlowBigStep {
private import LocalFlowBigStep
pragma[nomagic]
private predicate readCand2(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2, config) and
private predicate readCand2(Node node1, Content c, Node node2, Configuration config) {
read(node1, c, node2, config) and
nodeCand2(node1, _, _, true, unbind(config)) and
nodeCand2(node2, config) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(c, unbind(config))
}
pragma[nomagic]
private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2, config) and
private predicate storeCand2(
Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
store(node1, tc, node2, contentType) and
nodeCand2(node1, config) and
nodeCand2(node2, _, _, true, unbind(config)) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(tc.getContent(), unbind(config))
}
/**
@@ -1227,17 +1234,18 @@ private predicate flowCandFwd0(
)
or
// store
exists(Node mid, Content f |
flowCandFwd(mid, fromArg, argApf, _, config) and
storeCand2(mid, f, node, config) and
exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
storeCand2(mid, tc, node, contentType, config) and
nodeCand2(node, _, _, true, unbind(config)) and
apf.headUsesContent(f)
apf.headUsesContent(tc) and
compatibleTypes(apf0.getType(), contentType)
)
or
// read
exists(Content f |
flowCandFwdRead(f, node, fromArg, argApf, config) and
flowCandFwdConsCand(f, apf, config) and
exists(TypedContent tc |
flowCandFwdRead(tc, node, fromArg, argApf, config) and
flowCandFwdConsCand(tc, apf, config) and
nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config))
)
or
@@ -1261,24 +1269,30 @@ private predicate flowCandFwd0(
}
pragma[nomagic]
private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n |
private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n, DataFlowType contentType |
flowCandFwd(mid, _, _, apf, config) and
storeCand2(mid, f, n, config) and
storeCand2(mid, tc, n, contentType, config) and
nodeCand2(n, _, _, true, unbind(config)) and
compatibleTypes(apf.getType(), f.getType())
compatibleTypes(apf.getType(), contentType)
)
}
pragma[nomagic]
private predicate flowCandFwdRead(
Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
private predicate flowCandFwdRead0(
Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf,
AccessPathFrontHead apf, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f)
)
flowCandFwd(node1, fromArg, argApf, apf, config) and
readCand2(node1, c, node2, config) and
apf.headUsesContent(tc)
}
pragma[nomagic]
private predicate flowCandFwdRead(
TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
) {
flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config)
}
pragma[nomagic]
@@ -1385,17 +1399,15 @@ private predicate flowCand0(
)
or
// store
exists(Content f, AccessPathFrontHead apf0 |
flowCandStore(node, f, toReturn, returnApf, apf0, config) and
apf0.headUsesContent(f) and
flowCandConsCand(f, apf, config)
exists(TypedContent tc |
flowCandStore(node, tc, apf, toReturn, returnApf, config) and
flowCandConsCand(tc, apf, config)
)
or
// read
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(f, apf0, config) and
apf.headUsesContent(f)
exists(TypedContent tc, AccessPathFront apf0 |
flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(tc, apf0, config)
)
or
// flow into a callable
@@ -1417,36 +1429,40 @@ private predicate flowCand0(
else returnApf = TAccessPathFrontNone()
}
pragma[nomagic]
private predicate readCandFwd(
Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config
) {
flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config)
}
pragma[nomagic]
private predicate flowCandRead(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config
) {
exists(Node mid |
readCand2(node, f, mid, config) and
readCandFwd(node, tc, apf, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
)
}
pragma[nomagic]
private predicate flowCandStore(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, Configuration config
) {
exists(Node mid |
storeCand2(node, f, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
flowCandFwd(node, _, _, apf, config) and
storeCand2(node, tc, mid, _, unbind(config)) and
flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config))
)
}
pragma[nomagic]
private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(f, apf, config) and
exists(Node n, AccessPathFrontHead apf0 |
flowCandFwd(n, _, _, apf0, config) and
apf0.headUsesContent(f) and
flowCandRead(n, f, _, _, apf, config)
)
private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(tc, apf, config) and
flowCandRead(_, tc, _, _, _, apf, config)
}
pragma[nomagic]
@@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned(
private newtype TAccessPath =
TNil(DataFlowType t) or
TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or
TConsCons(Content f1, Content f2, int len) {
flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()]
TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()]
}
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -1514,7 +1530,7 @@ private newtype TAccessPath =
abstract private class AccessPath extends TAccessPath {
abstract string toString();
abstract Content getHead();
abstract TypedContent getHead();
abstract int len();
@@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath {
/**
* Holds if this access path has `head` at the front and may be followed by `tail`.
*/
abstract predicate pop(Content head, AccessPath tail);
abstract predicate pop(TypedContent head, AccessPath tail);
}
private class AccessPathNil extends AccessPath, TNil {
@@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil {
override string toString() { result = concat(": " + ppReprType(t)) }
override Content getHead() { none() }
override TypedContent getHead() { none() }
override int len() { result = 0 }
@@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil {
override AccessPathFront getFront() { result = TFrontNil(t) }
override predicate pop(Content head, AccessPath tail) { none() }
override predicate pop(TypedContent head, AccessPath tail) { none() }
}
abstract private class AccessPathCons extends AccessPath { }
private class AccessPathConsNil extends AccessPathCons, TConsNil {
private Content f;
private TypedContent tc;
private DataFlowType t;
AccessPathConsNil() { this = TConsNil(f, t) }
AccessPathConsNil() { this = TConsNil(tc, t) }
override string toString() {
// The `concat` becomes "" if `ppReprType` has no result.
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t))
}
override Content getHead() { result = f }
override TypedContent getHead() { result = tc }
override int len() { result = 1 }
override DataFlowType getType() { result = f.getContainerType() }
override DataFlowType getType() { result = tc.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f) }
override AccessPathFront getFront() { result = TFrontHead(tc) }
override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) }
override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) }
}
private class AccessPathConsCons extends AccessPathCons, TConsCons {
private Content f1;
private Content f2;
private TypedContent tc1;
private TypedContent tc2;
private int len;
AccessPathConsCons() { this = TConsCons(f1, f2, len) }
AccessPathConsCons() { this = TConsCons(tc1, tc2, len) }
override string toString() {
if len = 2
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc1.toString() + ", " + tc2.toString() + "]"
else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]"
}
override Content getHead() { result = f1 }
override TypedContent getHead() { result = tc1 }
override int len() { result = len }
override DataFlowType getType() { result = f1.getContainerType() }
override DataFlowType getType() { result = tc1.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f1) }
override AccessPathFront getFront() { result = TFrontHead(tc1) }
override predicate pop(Content head, AccessPath tail) {
head = f1 and
override predicate pop(TypedContent head, AccessPath tail) {
head = tc1 and
(
tail = TConsCons(f2, _, len - 1)
tail = TConsCons(tc2, _, len - 1)
or
len = 2 and
tail = TConsNil(f2, _)
tail = TConsNil(tc2, _)
)
}
}
/** Gets the access path obtained by popping `f` from `ap`, if any. */
private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) }
/** Gets the access path obtained by popping `tc` from `ap`, if any. */
private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) }
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/** Gets the access path obtained by pushing `tc` onto `ap`. */
private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) }
private newtype TAccessPathOption =
TAccessPathNone() or
@@ -1678,15 +1694,12 @@ private predicate flowFwd0(
)
or
// store
exists(Content f, AccessPath ap0 |
flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and
ap = push(f, ap0)
)
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
or
// read
exists(Content f |
flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and
flowFwdConsCand(f, apf, ap, config)
exists(TypedContent tc |
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
flowFwdConsCand(tc, apf, ap, config)
)
or
// flow into a callable
@@ -1710,54 +1723,63 @@ private predicate flowFwd0(
pragma[nomagic]
private predicate flowFwdStore(
Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg,
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFront apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
flowFwdStore1(mid, f, node, apf0, apf, config)
flowFwdStore0(mid, tc, node, apf0, apf, config)
)
}
pragma[nomagic]
private predicate flowFwdStore0(
Node mid, Content f, Node node, AccessPathFront apf0, Configuration config
private predicate storeCand(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf,
Configuration config
) {
storeCand2(mid, f, node, config) and
flowCand(mid, _, _, apf0, config)
storeCand2(mid, tc, node, _, config) and
flowCand(mid, _, _, apf0, config) and
apf.headUsesContent(tc)
}
pragma[noinline]
private predicate flowFwdStore1(
Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
private predicate flowFwdStore0(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
Configuration config
) {
flowFwdStore0(mid, f, node, apf0, config) and
flowCandConsCand(f, apf0, config) and
apf.headUsesContent(f) and
storeCand(mid, tc, node, apf0, apf, config) and
flowCandConsCand(tc, apf0, config) and
flowCand(node, _, _, apf, unbind(config))
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp,
Configuration config
private predicate flowFwdRead0(
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
boolean fromArg, AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f) and
flowCand(node, _, _, _, unbind(config))
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
readCandFwd(node1, tc, apf0, node2, config)
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, TypedContent tc |
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
flowCand(node, _, _, apf, unbind(config)) and
flowCandConsCand(tc, apf, unbind(config))
)
}
pragma[nomagic]
private predicate flowFwdConsCand(
Content f, AccessPathFront apf, AccessPath ap, Configuration config
TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config
) {
exists(Node n |
flowFwd(n, _, _, apf, ap, config) and
flowFwdStore1(n, f, _, apf, _, config)
flowFwdStore0(n, tc, _, apf, _, config)
)
}
@@ -1863,9 +1885,9 @@ private predicate flow0(
)
or
// store
exists(Content f |
flowStore(f, node, toReturn, returnAp, ap, config) and
flowConsCand(f, ap, config)
exists(TypedContent tc |
flowStore(tc, node, toReturn, returnAp, ap, config) and
flowConsCand(tc, ap, config)
)
or
// read
@@ -1895,39 +1917,41 @@ private predicate flow0(
pragma[nomagic]
private predicate storeFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
storeCand2(node1, f, node2, config) and
flowFwdStore(node2, f, ap, _, _, _, config) and
ap0 = push(f, ap)
storeCand2(node1, tc, node2, _, config) and
flowFwdStore(node2, tc, ap, _, _, _, config) and
ap0 = push(tc, ap)
}
pragma[nomagic]
private predicate flowStore(
Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
Configuration config
) {
exists(Node mid, AccessPath ap0 |
storeFlowFwd(node, f, mid, ap, ap0, config) and
storeFlowFwd(node, tc, mid, ap, ap0, config) and
flow(mid, toReturn, returnAp, ap0, config)
)
}
pragma[nomagic]
private predicate readFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
readCand2(node1, f, node2, config) and
flowFwdRead(node2, f, ap, _, _, config) and
ap0 = pop(f, ap) and
flowFwdConsCand(f, _, ap0, unbind(config))
exists(AccessPathFrontHead apf |
readCandFwd(node1, tc, apf, node2, config) and
flowFwdRead(node2, apf, ap, _, _, _, config) and
ap0 = pop(tc, ap) and
flowFwdConsCand(tc, _, ap0, unbind(config))
)
}
pragma[nomagic]
private predicate flowConsCand(Content f, AccessPath ap, Configuration config) {
private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) {
exists(Node n, Node mid |
flow(mid, _, _, ap, config) and
readFlowFwd(n, f, mid, _, ap, config)
readFlowFwd(n, tc, mid, _, ap, config)
)
}
@@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and
exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
@@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
}
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2) and
private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) {
readCandFwd(node1, tc, _, node2, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) {
private predicate pathReadStep(
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
readCand(mid.getNode(), f, node, mid.getConfiguration()) and
readCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate storeCand(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2) and
private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) {
storeCand2(node1, tc, node2, _, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathStoreStep(
PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
storeCand(mid.getNode(), f, node, mid.getConfiguration()) and
storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -2538,10 +2564,10 @@ private module FlowExploration {
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(Content f, int len) { len in [1 .. 5] }
TPartialCons(TypedContent tc, int len) { len in [1 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -2550,7 +2576,7 @@ private module FlowExploration {
private class PartialAccessPath extends TPartialAccessPath {
abstract string toString();
Content getHead() { this = TPartialCons(result, _) }
TypedContent getHead() { this = TPartialCons(result, _) }
int len() {
this = TPartialNil(_) and result = 0
@@ -2561,7 +2587,7 @@ private module FlowExploration {
DataFlowType getType() {
this = TPartialNil(result)
or
exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType())
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
@@ -2579,15 +2605,15 @@ private module FlowExploration {
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
exists(TypedContent tc, int len | this = TPartialCons(tc, len) |
if len = 1
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc.toString() + "]"
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
override AccessPathFront getFront() {
exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f))
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
}
}
@@ -2763,11 +2789,12 @@ private module FlowExploration {
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(PartialAccessPath ap0, Content f |
partialPathReadStep(mid, ap0, f, node, cc, config) and
exists(PartialAccessPath ap0, TypedContent tc |
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, f, ap0, config)
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -2786,35 +2813,42 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
) {
ap1 = mid.getAp() and
store(mid.getNode(), f, node) and
ap2.getHead() = f and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), f.getType())
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
)
}
pragma[nomagic]
private predicate apConsFwd(
PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
partialPathStoreStep(mid, ap1, f, _, ap2) and
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc,
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
ap = mid.getAp() and
readStep(mid.getNode(), f, node) and
ap.getHead() = f and
config = mid.getConfiguration() and
cc = mid.getCallContext()
exists(Node midNode |
midNode = mid.getNode() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node) and
ap.getHead() = tc and
config = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
private predicate partialPathOutOfCallable0(

View File

@@ -148,12 +148,6 @@ class Content extends TContent {
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
}
/** Gets the type of the object containing this content. */
abstract Type getContainerType();
/** Gets the type of this content. */
abstract Type getType();
}
private class FieldContent extends Content, TFieldContent {
@@ -168,26 +162,14 @@ private class FieldContent extends Content, TFieldContent {
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
}
override Type getContainerType() { result = f.getDeclaringType() }
override Type getType() { result = f.getType() }
}
private class CollectionContent extends Content, TCollectionContent {
override string toString() { result = "collection" }
override Type getContainerType() { none() }
override Type getType() { none() }
}
private class ArrayContent extends Content, TArrayContent {
override string toString() { result = "array" }
override Type getContainerType() { none() }
override Type getType() { none() }
}
/**

View File

@@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
exists(Node mid |
useFieldFlow(config) and
nodeCandFwd1(mid, fromArg, config) and
store(mid, _, node) and
store(mid, _, node, _) and
not outBarrier(mid, config)
)
or
// read
exists(Content f |
nodeCandFwd1Read(f, node, fromArg, config) and
nodeCandFwd1IsStored(f, config) and
exists(Content c |
nodeCandFwd1Read(c, node, fromArg, config) and
nodeCandFwd1IsStored(c, config) and
not inBarrier(node, config)
)
or
@@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
pragma[nomagic]
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) {
exists(Node mid |
nodeCandFwd1(mid, fromArg, config) and
read(mid, f, node)
read(mid, c, node)
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`.
*/
pragma[nomagic]
private predicate nodeCandFwd1IsStored(Content f, Configuration config) {
exists(Node mid, Node node |
private predicate nodeCandFwd1IsStored(Content c, Configuration config) {
exists(Node mid, Node node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
nodeCandFwd1(mid, config) and
store(mid, f, node)
store(mid, tc, node, _) and
c = tc.getContent()
)
}
@@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
)
or
// store
exists(Content f |
nodeCand1Store(f, node, toReturn, config) and
nodeCand1IsRead(f, config)
exists(Content c |
nodeCand1Store(c, node, toReturn, config) and
nodeCand1IsRead(c, config)
)
or
// read
exists(Node mid, Content f |
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
exists(Node mid, Content c |
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, toReturn, config)
)
or
@@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand1`.
*/
pragma[nomagic]
private predicate nodeCand1IsRead(Content f, Configuration config) {
private predicate nodeCand1IsRead(Content c, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, _, config)
)
}
pragma[nomagic]
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
exists(Node mid |
private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
nodeCand1(mid, toReturn, config) and
nodeCandFwd1IsStored(f, unbind(config)) and
store(node, f, mid)
nodeCandFwd1IsStored(c, unbind(config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
}
/**
* Holds if `f` is the target of both a read and a store in the flow covered
* Holds if `c` is the target of both a read and a store in the flow covered
* by `nodeCand1`.
*/
private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) {
nodeCand1IsRead(f, conf) and
nodeCand1Store(f, _, _, conf)
private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) {
nodeCand1IsRead(c, conf) and
nodeCand1Store(c, _, _, conf)
}
pragma[nomagic]
@@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c
}
pragma[nomagic]
private predicate store(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
nodeCand1(n2, unbind(config)) and
store(n1, f, n2)
private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) {
exists(TypedContent tc |
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
store(n1, tc, n2, _) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate read(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
private predicate read(Node n1, Content c, Node n2, Configuration config) {
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
read(n1, f, n2)
read(n1, c, n2)
}
pragma[noinline]
@@ -748,16 +753,16 @@ private predicate nodeCandFwd2(
)
or
// store
exists(Node mid, Content f |
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, _, config) and
store(mid, f, node, config) and
storeCand1(mid, _, node, config) and
stored = true
)
or
// read
exists(Content f |
nodeCandFwd2Read(f, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(f, stored, config)
exists(Content c |
nodeCandFwd2Read(c, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(c, stored, config)
)
or
// flow into a callable
@@ -781,25 +786,25 @@ private predicate nodeCandFwd2(
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`.
*/
pragma[noinline]
private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) {
private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCand1(node, unbind(config)) and
nodeCandFwd2(mid, _, _, stored, config) and
store(mid, f, node, config)
storeCand1(mid, c, node, config)
)
}
pragma[nomagic]
private predicate nodeCandFwd2Read(
Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config
Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config
) {
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, true, config) and
read(mid, f, node, config)
read(mid, c, node, config)
)
}
@@ -896,15 +901,15 @@ private predicate nodeCand2(
)
or
// store
exists(Content f |
nodeCand2Store(f, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(f, read, config)
exists(Content c |
nodeCand2Store(c, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(c, read, config)
)
or
// read
exists(Node mid, Content f, boolean read0 |
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and
exists(Node mid, Content c, boolean read0 |
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and
nodeCand2(mid, toReturn, returnRead, read0, config) and
read = true
)
@@ -930,51 +935,51 @@ private predicate nodeCand2(
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) {
private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd2(node, _, _, true, unbind(config)) and
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and
nodeCand2(mid, _, _, read, config)
)
}
pragma[nomagic]
private predicate nodeCand2Store(
Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Configuration config
) {
exists(Node mid |
store(node, f, mid, config) and
storeCand1(node, c, mid, config) and
nodeCand2(mid, toReturn, returnRead, true, config) and
nodeCandFwd2(node, _, _, stored, unbind(config))
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCand2`.
*/
pragma[nomagic]
private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) {
private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) {
exists(Node node |
nodeCand2Store(f, node, _, _, stored, conf) and
nodeCand2Store(c, node, _, _, stored, conf) and
nodeCand2(node, _, _, stored, conf)
)
}
/**
* Holds if `f` is the target of both a store and a read in the path graph
* Holds if `c` is the target of both a store and a read in the path graph
* covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) {
private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) {
exists(boolean apNonEmpty |
nodeCand2IsStored(f, apNonEmpty, conf) and
nodeCand2IsRead(f, apNonEmpty, conf)
nodeCand2IsStored(c, apNonEmpty, conf) and
nodeCand2IsRead(c, apNonEmpty, conf)
)
}
@@ -1058,7 +1063,7 @@ private module LocalFlowBigStep {
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof OutNodeExt or
store(_, _, node) or
store(_, _, node, _) or
read(_, _, node) or
node instanceof CastNode
)
@@ -1074,7 +1079,7 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next) or
store(node, _, next, _) or
read(node, _, next)
)
or
@@ -1154,19 +1159,21 @@ private module LocalFlowBigStep {
private import LocalFlowBigStep
pragma[nomagic]
private predicate readCand2(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2, config) and
private predicate readCand2(Node node1, Content c, Node node2, Configuration config) {
read(node1, c, node2, config) and
nodeCand2(node1, _, _, true, unbind(config)) and
nodeCand2(node2, config) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(c, unbind(config))
}
pragma[nomagic]
private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2, config) and
private predicate storeCand2(
Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
store(node1, tc, node2, contentType) and
nodeCand2(node1, config) and
nodeCand2(node2, _, _, true, unbind(config)) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(tc.getContent(), unbind(config))
}
/**
@@ -1227,17 +1234,18 @@ private predicate flowCandFwd0(
)
or
// store
exists(Node mid, Content f |
flowCandFwd(mid, fromArg, argApf, _, config) and
storeCand2(mid, f, node, config) and
exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
storeCand2(mid, tc, node, contentType, config) and
nodeCand2(node, _, _, true, unbind(config)) and
apf.headUsesContent(f)
apf.headUsesContent(tc) and
compatibleTypes(apf0.getType(), contentType)
)
or
// read
exists(Content f |
flowCandFwdRead(f, node, fromArg, argApf, config) and
flowCandFwdConsCand(f, apf, config) and
exists(TypedContent tc |
flowCandFwdRead(tc, node, fromArg, argApf, config) and
flowCandFwdConsCand(tc, apf, config) and
nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config))
)
or
@@ -1261,24 +1269,30 @@ private predicate flowCandFwd0(
}
pragma[nomagic]
private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n |
private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n, DataFlowType contentType |
flowCandFwd(mid, _, _, apf, config) and
storeCand2(mid, f, n, config) and
storeCand2(mid, tc, n, contentType, config) and
nodeCand2(n, _, _, true, unbind(config)) and
compatibleTypes(apf.getType(), f.getType())
compatibleTypes(apf.getType(), contentType)
)
}
pragma[nomagic]
private predicate flowCandFwdRead(
Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
private predicate flowCandFwdRead0(
Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf,
AccessPathFrontHead apf, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f)
)
flowCandFwd(node1, fromArg, argApf, apf, config) and
readCand2(node1, c, node2, config) and
apf.headUsesContent(tc)
}
pragma[nomagic]
private predicate flowCandFwdRead(
TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
) {
flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config)
}
pragma[nomagic]
@@ -1385,17 +1399,15 @@ private predicate flowCand0(
)
or
// store
exists(Content f, AccessPathFrontHead apf0 |
flowCandStore(node, f, toReturn, returnApf, apf0, config) and
apf0.headUsesContent(f) and
flowCandConsCand(f, apf, config)
exists(TypedContent tc |
flowCandStore(node, tc, apf, toReturn, returnApf, config) and
flowCandConsCand(tc, apf, config)
)
or
// read
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(f, apf0, config) and
apf.headUsesContent(f)
exists(TypedContent tc, AccessPathFront apf0 |
flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(tc, apf0, config)
)
or
// flow into a callable
@@ -1417,36 +1429,40 @@ private predicate flowCand0(
else returnApf = TAccessPathFrontNone()
}
pragma[nomagic]
private predicate readCandFwd(
Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config
) {
flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config)
}
pragma[nomagic]
private predicate flowCandRead(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config
) {
exists(Node mid |
readCand2(node, f, mid, config) and
readCandFwd(node, tc, apf, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
)
}
pragma[nomagic]
private predicate flowCandStore(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, Configuration config
) {
exists(Node mid |
storeCand2(node, f, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
flowCandFwd(node, _, _, apf, config) and
storeCand2(node, tc, mid, _, unbind(config)) and
flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config))
)
}
pragma[nomagic]
private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(f, apf, config) and
exists(Node n, AccessPathFrontHead apf0 |
flowCandFwd(n, _, _, apf0, config) and
apf0.headUsesContent(f) and
flowCandRead(n, f, _, _, apf, config)
)
private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(tc, apf, config) and
flowCandRead(_, tc, _, _, _, apf, config)
}
pragma[nomagic]
@@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned(
private newtype TAccessPath =
TNil(DataFlowType t) or
TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or
TConsCons(Content f1, Content f2, int len) {
flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()]
TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()]
}
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -1514,7 +1530,7 @@ private newtype TAccessPath =
abstract private class AccessPath extends TAccessPath {
abstract string toString();
abstract Content getHead();
abstract TypedContent getHead();
abstract int len();
@@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath {
/**
* Holds if this access path has `head` at the front and may be followed by `tail`.
*/
abstract predicate pop(Content head, AccessPath tail);
abstract predicate pop(TypedContent head, AccessPath tail);
}
private class AccessPathNil extends AccessPath, TNil {
@@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil {
override string toString() { result = concat(": " + ppReprType(t)) }
override Content getHead() { none() }
override TypedContent getHead() { none() }
override int len() { result = 0 }
@@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil {
override AccessPathFront getFront() { result = TFrontNil(t) }
override predicate pop(Content head, AccessPath tail) { none() }
override predicate pop(TypedContent head, AccessPath tail) { none() }
}
abstract private class AccessPathCons extends AccessPath { }
private class AccessPathConsNil extends AccessPathCons, TConsNil {
private Content f;
private TypedContent tc;
private DataFlowType t;
AccessPathConsNil() { this = TConsNil(f, t) }
AccessPathConsNil() { this = TConsNil(tc, t) }
override string toString() {
// The `concat` becomes "" if `ppReprType` has no result.
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t))
}
override Content getHead() { result = f }
override TypedContent getHead() { result = tc }
override int len() { result = 1 }
override DataFlowType getType() { result = f.getContainerType() }
override DataFlowType getType() { result = tc.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f) }
override AccessPathFront getFront() { result = TFrontHead(tc) }
override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) }
override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) }
}
private class AccessPathConsCons extends AccessPathCons, TConsCons {
private Content f1;
private Content f2;
private TypedContent tc1;
private TypedContent tc2;
private int len;
AccessPathConsCons() { this = TConsCons(f1, f2, len) }
AccessPathConsCons() { this = TConsCons(tc1, tc2, len) }
override string toString() {
if len = 2
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc1.toString() + ", " + tc2.toString() + "]"
else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]"
}
override Content getHead() { result = f1 }
override TypedContent getHead() { result = tc1 }
override int len() { result = len }
override DataFlowType getType() { result = f1.getContainerType() }
override DataFlowType getType() { result = tc1.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f1) }
override AccessPathFront getFront() { result = TFrontHead(tc1) }
override predicate pop(Content head, AccessPath tail) {
head = f1 and
override predicate pop(TypedContent head, AccessPath tail) {
head = tc1 and
(
tail = TConsCons(f2, _, len - 1)
tail = TConsCons(tc2, _, len - 1)
or
len = 2 and
tail = TConsNil(f2, _)
tail = TConsNil(tc2, _)
)
}
}
/** Gets the access path obtained by popping `f` from `ap`, if any. */
private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) }
/** Gets the access path obtained by popping `tc` from `ap`, if any. */
private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) }
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/** Gets the access path obtained by pushing `tc` onto `ap`. */
private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) }
private newtype TAccessPathOption =
TAccessPathNone() or
@@ -1678,15 +1694,12 @@ private predicate flowFwd0(
)
or
// store
exists(Content f, AccessPath ap0 |
flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and
ap = push(f, ap0)
)
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
or
// read
exists(Content f |
flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and
flowFwdConsCand(f, apf, ap, config)
exists(TypedContent tc |
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
flowFwdConsCand(tc, apf, ap, config)
)
or
// flow into a callable
@@ -1710,54 +1723,63 @@ private predicate flowFwd0(
pragma[nomagic]
private predicate flowFwdStore(
Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg,
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFront apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
flowFwdStore1(mid, f, node, apf0, apf, config)
flowFwdStore0(mid, tc, node, apf0, apf, config)
)
}
pragma[nomagic]
private predicate flowFwdStore0(
Node mid, Content f, Node node, AccessPathFront apf0, Configuration config
private predicate storeCand(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf,
Configuration config
) {
storeCand2(mid, f, node, config) and
flowCand(mid, _, _, apf0, config)
storeCand2(mid, tc, node, _, config) and
flowCand(mid, _, _, apf0, config) and
apf.headUsesContent(tc)
}
pragma[noinline]
private predicate flowFwdStore1(
Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
private predicate flowFwdStore0(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
Configuration config
) {
flowFwdStore0(mid, f, node, apf0, config) and
flowCandConsCand(f, apf0, config) and
apf.headUsesContent(f) and
storeCand(mid, tc, node, apf0, apf, config) and
flowCandConsCand(tc, apf0, config) and
flowCand(node, _, _, apf, unbind(config))
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp,
Configuration config
private predicate flowFwdRead0(
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
boolean fromArg, AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f) and
flowCand(node, _, _, _, unbind(config))
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
readCandFwd(node1, tc, apf0, node2, config)
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, TypedContent tc |
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
flowCand(node, _, _, apf, unbind(config)) and
flowCandConsCand(tc, apf, unbind(config))
)
}
pragma[nomagic]
private predicate flowFwdConsCand(
Content f, AccessPathFront apf, AccessPath ap, Configuration config
TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config
) {
exists(Node n |
flowFwd(n, _, _, apf, ap, config) and
flowFwdStore1(n, f, _, apf, _, config)
flowFwdStore0(n, tc, _, apf, _, config)
)
}
@@ -1863,9 +1885,9 @@ private predicate flow0(
)
or
// store
exists(Content f |
flowStore(f, node, toReturn, returnAp, ap, config) and
flowConsCand(f, ap, config)
exists(TypedContent tc |
flowStore(tc, node, toReturn, returnAp, ap, config) and
flowConsCand(tc, ap, config)
)
or
// read
@@ -1895,39 +1917,41 @@ private predicate flow0(
pragma[nomagic]
private predicate storeFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
storeCand2(node1, f, node2, config) and
flowFwdStore(node2, f, ap, _, _, _, config) and
ap0 = push(f, ap)
storeCand2(node1, tc, node2, _, config) and
flowFwdStore(node2, tc, ap, _, _, _, config) and
ap0 = push(tc, ap)
}
pragma[nomagic]
private predicate flowStore(
Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
Configuration config
) {
exists(Node mid, AccessPath ap0 |
storeFlowFwd(node, f, mid, ap, ap0, config) and
storeFlowFwd(node, tc, mid, ap, ap0, config) and
flow(mid, toReturn, returnAp, ap0, config)
)
}
pragma[nomagic]
private predicate readFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
readCand2(node1, f, node2, config) and
flowFwdRead(node2, f, ap, _, _, config) and
ap0 = pop(f, ap) and
flowFwdConsCand(f, _, ap0, unbind(config))
exists(AccessPathFrontHead apf |
readCandFwd(node1, tc, apf, node2, config) and
flowFwdRead(node2, apf, ap, _, _, _, config) and
ap0 = pop(tc, ap) and
flowFwdConsCand(tc, _, ap0, unbind(config))
)
}
pragma[nomagic]
private predicate flowConsCand(Content f, AccessPath ap, Configuration config) {
private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) {
exists(Node n, Node mid |
flow(mid, _, _, ap, config) and
readFlowFwd(n, f, mid, _, ap, config)
readFlowFwd(n, tc, mid, _, ap, config)
)
}
@@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and
exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
@@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
}
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2) and
private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) {
readCandFwd(node1, tc, _, node2, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) {
private predicate pathReadStep(
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
readCand(mid.getNode(), f, node, mid.getConfiguration()) and
readCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate storeCand(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2) and
private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) {
storeCand2(node1, tc, node2, _, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathStoreStep(
PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
storeCand(mid.getNode(), f, node, mid.getConfiguration()) and
storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -2538,10 +2564,10 @@ private module FlowExploration {
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(Content f, int len) { len in [1 .. 5] }
TPartialCons(TypedContent tc, int len) { len in [1 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -2550,7 +2576,7 @@ private module FlowExploration {
private class PartialAccessPath extends TPartialAccessPath {
abstract string toString();
Content getHead() { this = TPartialCons(result, _) }
TypedContent getHead() { this = TPartialCons(result, _) }
int len() {
this = TPartialNil(_) and result = 0
@@ -2561,7 +2587,7 @@ private module FlowExploration {
DataFlowType getType() {
this = TPartialNil(result)
or
exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType())
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
@@ -2579,15 +2605,15 @@ private module FlowExploration {
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
exists(TypedContent tc, int len | this = TPartialCons(tc, len) |
if len = 1
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc.toString() + "]"
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
override AccessPathFront getFront() {
exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f))
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
}
}
@@ -2763,11 +2789,12 @@ private module FlowExploration {
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(PartialAccessPath ap0, Content f |
partialPathReadStep(mid, ap0, f, node, cc, config) and
exists(PartialAccessPath ap0, TypedContent tc |
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, f, ap0, config)
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -2786,35 +2813,42 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
) {
ap1 = mid.getAp() and
store(mid.getNode(), f, node) and
ap2.getHead() = f and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), f.getType())
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
)
}
pragma[nomagic]
private predicate apConsFwd(
PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
partialPathStoreStep(mid, ap1, f, _, ap2) and
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc,
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
ap = mid.getAp() and
readStep(mid.getNode(), f, node) and
ap.getHead() = f and
config = mid.getConfiguration() and
cc = mid.getCallContext()
exists(Node midNode |
midNode = mid.getNode() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node) and
ap.getHead() = tc and
config = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
private predicate partialPathOutOfCallable0(

View File

@@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
exists(Node mid |
useFieldFlow(config) and
nodeCandFwd1(mid, fromArg, config) and
store(mid, _, node) and
store(mid, _, node, _) and
not outBarrier(mid, config)
)
or
// read
exists(Content f |
nodeCandFwd1Read(f, node, fromArg, config) and
nodeCandFwd1IsStored(f, config) and
exists(Content c |
nodeCandFwd1Read(c, node, fromArg, config) and
nodeCandFwd1IsStored(c, config) and
not inBarrier(node, config)
)
or
@@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
pragma[nomagic]
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) {
exists(Node mid |
nodeCandFwd1(mid, fromArg, config) and
read(mid, f, node)
read(mid, c, node)
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`.
*/
pragma[nomagic]
private predicate nodeCandFwd1IsStored(Content f, Configuration config) {
exists(Node mid, Node node |
private predicate nodeCandFwd1IsStored(Content c, Configuration config) {
exists(Node mid, Node node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
nodeCandFwd1(mid, config) and
store(mid, f, node)
store(mid, tc, node, _) and
c = tc.getContent()
)
}
@@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
)
or
// store
exists(Content f |
nodeCand1Store(f, node, toReturn, config) and
nodeCand1IsRead(f, config)
exists(Content c |
nodeCand1Store(c, node, toReturn, config) and
nodeCand1IsRead(c, config)
)
or
// read
exists(Node mid, Content f |
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
exists(Node mid, Content c |
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, toReturn, config)
)
or
@@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand1`.
*/
pragma[nomagic]
private predicate nodeCand1IsRead(Content f, Configuration config) {
private predicate nodeCand1IsRead(Content c, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, _, config)
)
}
pragma[nomagic]
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
exists(Node mid |
private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
nodeCand1(mid, toReturn, config) and
nodeCandFwd1IsStored(f, unbind(config)) and
store(node, f, mid)
nodeCandFwd1IsStored(c, unbind(config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
}
/**
* Holds if `f` is the target of both a read and a store in the flow covered
* Holds if `c` is the target of both a read and a store in the flow covered
* by `nodeCand1`.
*/
private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) {
nodeCand1IsRead(f, conf) and
nodeCand1Store(f, _, _, conf)
private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) {
nodeCand1IsRead(c, conf) and
nodeCand1Store(c, _, _, conf)
}
pragma[nomagic]
@@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c
}
pragma[nomagic]
private predicate store(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
nodeCand1(n2, unbind(config)) and
store(n1, f, n2)
private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) {
exists(TypedContent tc |
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
store(n1, tc, n2, _) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate read(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
private predicate read(Node n1, Content c, Node n2, Configuration config) {
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
read(n1, f, n2)
read(n1, c, n2)
}
pragma[noinline]
@@ -748,16 +753,16 @@ private predicate nodeCandFwd2(
)
or
// store
exists(Node mid, Content f |
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, _, config) and
store(mid, f, node, config) and
storeCand1(mid, _, node, config) and
stored = true
)
or
// read
exists(Content f |
nodeCandFwd2Read(f, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(f, stored, config)
exists(Content c |
nodeCandFwd2Read(c, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(c, stored, config)
)
or
// flow into a callable
@@ -781,25 +786,25 @@ private predicate nodeCandFwd2(
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`.
*/
pragma[noinline]
private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) {
private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCand1(node, unbind(config)) and
nodeCandFwd2(mid, _, _, stored, config) and
store(mid, f, node, config)
storeCand1(mid, c, node, config)
)
}
pragma[nomagic]
private predicate nodeCandFwd2Read(
Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config
Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config
) {
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, true, config) and
read(mid, f, node, config)
read(mid, c, node, config)
)
}
@@ -896,15 +901,15 @@ private predicate nodeCand2(
)
or
// store
exists(Content f |
nodeCand2Store(f, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(f, read, config)
exists(Content c |
nodeCand2Store(c, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(c, read, config)
)
or
// read
exists(Node mid, Content f, boolean read0 |
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and
exists(Node mid, Content c, boolean read0 |
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and
nodeCand2(mid, toReturn, returnRead, read0, config) and
read = true
)
@@ -930,51 +935,51 @@ private predicate nodeCand2(
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) {
private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd2(node, _, _, true, unbind(config)) and
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and
nodeCand2(mid, _, _, read, config)
)
}
pragma[nomagic]
private predicate nodeCand2Store(
Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Configuration config
) {
exists(Node mid |
store(node, f, mid, config) and
storeCand1(node, c, mid, config) and
nodeCand2(mid, toReturn, returnRead, true, config) and
nodeCandFwd2(node, _, _, stored, unbind(config))
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCand2`.
*/
pragma[nomagic]
private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) {
private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) {
exists(Node node |
nodeCand2Store(f, node, _, _, stored, conf) and
nodeCand2Store(c, node, _, _, stored, conf) and
nodeCand2(node, _, _, stored, conf)
)
}
/**
* Holds if `f` is the target of both a store and a read in the path graph
* Holds if `c` is the target of both a store and a read in the path graph
* covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) {
private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) {
exists(boolean apNonEmpty |
nodeCand2IsStored(f, apNonEmpty, conf) and
nodeCand2IsRead(f, apNonEmpty, conf)
nodeCand2IsStored(c, apNonEmpty, conf) and
nodeCand2IsRead(c, apNonEmpty, conf)
)
}
@@ -1058,7 +1063,7 @@ private module LocalFlowBigStep {
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof OutNodeExt or
store(_, _, node) or
store(_, _, node, _) or
read(_, _, node) or
node instanceof CastNode
)
@@ -1074,7 +1079,7 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next) or
store(node, _, next, _) or
read(node, _, next)
)
or
@@ -1154,19 +1159,21 @@ private module LocalFlowBigStep {
private import LocalFlowBigStep
pragma[nomagic]
private predicate readCand2(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2, config) and
private predicate readCand2(Node node1, Content c, Node node2, Configuration config) {
read(node1, c, node2, config) and
nodeCand2(node1, _, _, true, unbind(config)) and
nodeCand2(node2, config) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(c, unbind(config))
}
pragma[nomagic]
private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2, config) and
private predicate storeCand2(
Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
store(node1, tc, node2, contentType) and
nodeCand2(node1, config) and
nodeCand2(node2, _, _, true, unbind(config)) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(tc.getContent(), unbind(config))
}
/**
@@ -1227,17 +1234,18 @@ private predicate flowCandFwd0(
)
or
// store
exists(Node mid, Content f |
flowCandFwd(mid, fromArg, argApf, _, config) and
storeCand2(mid, f, node, config) and
exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
storeCand2(mid, tc, node, contentType, config) and
nodeCand2(node, _, _, true, unbind(config)) and
apf.headUsesContent(f)
apf.headUsesContent(tc) and
compatibleTypes(apf0.getType(), contentType)
)
or
// read
exists(Content f |
flowCandFwdRead(f, node, fromArg, argApf, config) and
flowCandFwdConsCand(f, apf, config) and
exists(TypedContent tc |
flowCandFwdRead(tc, node, fromArg, argApf, config) and
flowCandFwdConsCand(tc, apf, config) and
nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config))
)
or
@@ -1261,24 +1269,30 @@ private predicate flowCandFwd0(
}
pragma[nomagic]
private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n |
private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n, DataFlowType contentType |
flowCandFwd(mid, _, _, apf, config) and
storeCand2(mid, f, n, config) and
storeCand2(mid, tc, n, contentType, config) and
nodeCand2(n, _, _, true, unbind(config)) and
compatibleTypes(apf.getType(), f.getType())
compatibleTypes(apf.getType(), contentType)
)
}
pragma[nomagic]
private predicate flowCandFwdRead(
Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
private predicate flowCandFwdRead0(
Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf,
AccessPathFrontHead apf, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f)
)
flowCandFwd(node1, fromArg, argApf, apf, config) and
readCand2(node1, c, node2, config) and
apf.headUsesContent(tc)
}
pragma[nomagic]
private predicate flowCandFwdRead(
TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
) {
flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config)
}
pragma[nomagic]
@@ -1385,17 +1399,15 @@ private predicate flowCand0(
)
or
// store
exists(Content f, AccessPathFrontHead apf0 |
flowCandStore(node, f, toReturn, returnApf, apf0, config) and
apf0.headUsesContent(f) and
flowCandConsCand(f, apf, config)
exists(TypedContent tc |
flowCandStore(node, tc, apf, toReturn, returnApf, config) and
flowCandConsCand(tc, apf, config)
)
or
// read
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(f, apf0, config) and
apf.headUsesContent(f)
exists(TypedContent tc, AccessPathFront apf0 |
flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(tc, apf0, config)
)
or
// flow into a callable
@@ -1417,36 +1429,40 @@ private predicate flowCand0(
else returnApf = TAccessPathFrontNone()
}
pragma[nomagic]
private predicate readCandFwd(
Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config
) {
flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config)
}
pragma[nomagic]
private predicate flowCandRead(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config
) {
exists(Node mid |
readCand2(node, f, mid, config) and
readCandFwd(node, tc, apf, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
)
}
pragma[nomagic]
private predicate flowCandStore(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, Configuration config
) {
exists(Node mid |
storeCand2(node, f, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
flowCandFwd(node, _, _, apf, config) and
storeCand2(node, tc, mid, _, unbind(config)) and
flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config))
)
}
pragma[nomagic]
private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(f, apf, config) and
exists(Node n, AccessPathFrontHead apf0 |
flowCandFwd(n, _, _, apf0, config) and
apf0.headUsesContent(f) and
flowCandRead(n, f, _, _, apf, config)
)
private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(tc, apf, config) and
flowCandRead(_, tc, _, _, _, apf, config)
}
pragma[nomagic]
@@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned(
private newtype TAccessPath =
TNil(DataFlowType t) or
TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or
TConsCons(Content f1, Content f2, int len) {
flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()]
TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()]
}
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -1514,7 +1530,7 @@ private newtype TAccessPath =
abstract private class AccessPath extends TAccessPath {
abstract string toString();
abstract Content getHead();
abstract TypedContent getHead();
abstract int len();
@@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath {
/**
* Holds if this access path has `head` at the front and may be followed by `tail`.
*/
abstract predicate pop(Content head, AccessPath tail);
abstract predicate pop(TypedContent head, AccessPath tail);
}
private class AccessPathNil extends AccessPath, TNil {
@@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil {
override string toString() { result = concat(": " + ppReprType(t)) }
override Content getHead() { none() }
override TypedContent getHead() { none() }
override int len() { result = 0 }
@@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil {
override AccessPathFront getFront() { result = TFrontNil(t) }
override predicate pop(Content head, AccessPath tail) { none() }
override predicate pop(TypedContent head, AccessPath tail) { none() }
}
abstract private class AccessPathCons extends AccessPath { }
private class AccessPathConsNil extends AccessPathCons, TConsNil {
private Content f;
private TypedContent tc;
private DataFlowType t;
AccessPathConsNil() { this = TConsNil(f, t) }
AccessPathConsNil() { this = TConsNil(tc, t) }
override string toString() {
// The `concat` becomes "" if `ppReprType` has no result.
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t))
}
override Content getHead() { result = f }
override TypedContent getHead() { result = tc }
override int len() { result = 1 }
override DataFlowType getType() { result = f.getContainerType() }
override DataFlowType getType() { result = tc.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f) }
override AccessPathFront getFront() { result = TFrontHead(tc) }
override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) }
override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) }
}
private class AccessPathConsCons extends AccessPathCons, TConsCons {
private Content f1;
private Content f2;
private TypedContent tc1;
private TypedContent tc2;
private int len;
AccessPathConsCons() { this = TConsCons(f1, f2, len) }
AccessPathConsCons() { this = TConsCons(tc1, tc2, len) }
override string toString() {
if len = 2
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc1.toString() + ", " + tc2.toString() + "]"
else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]"
}
override Content getHead() { result = f1 }
override TypedContent getHead() { result = tc1 }
override int len() { result = len }
override DataFlowType getType() { result = f1.getContainerType() }
override DataFlowType getType() { result = tc1.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f1) }
override AccessPathFront getFront() { result = TFrontHead(tc1) }
override predicate pop(Content head, AccessPath tail) {
head = f1 and
override predicate pop(TypedContent head, AccessPath tail) {
head = tc1 and
(
tail = TConsCons(f2, _, len - 1)
tail = TConsCons(tc2, _, len - 1)
or
len = 2 and
tail = TConsNil(f2, _)
tail = TConsNil(tc2, _)
)
}
}
/** Gets the access path obtained by popping `f` from `ap`, if any. */
private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) }
/** Gets the access path obtained by popping `tc` from `ap`, if any. */
private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) }
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/** Gets the access path obtained by pushing `tc` onto `ap`. */
private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) }
private newtype TAccessPathOption =
TAccessPathNone() or
@@ -1678,15 +1694,12 @@ private predicate flowFwd0(
)
or
// store
exists(Content f, AccessPath ap0 |
flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and
ap = push(f, ap0)
)
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
or
// read
exists(Content f |
flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and
flowFwdConsCand(f, apf, ap, config)
exists(TypedContent tc |
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
flowFwdConsCand(tc, apf, ap, config)
)
or
// flow into a callable
@@ -1710,54 +1723,63 @@ private predicate flowFwd0(
pragma[nomagic]
private predicate flowFwdStore(
Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg,
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFront apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
flowFwdStore1(mid, f, node, apf0, apf, config)
flowFwdStore0(mid, tc, node, apf0, apf, config)
)
}
pragma[nomagic]
private predicate flowFwdStore0(
Node mid, Content f, Node node, AccessPathFront apf0, Configuration config
private predicate storeCand(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf,
Configuration config
) {
storeCand2(mid, f, node, config) and
flowCand(mid, _, _, apf0, config)
storeCand2(mid, tc, node, _, config) and
flowCand(mid, _, _, apf0, config) and
apf.headUsesContent(tc)
}
pragma[noinline]
private predicate flowFwdStore1(
Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
private predicate flowFwdStore0(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
Configuration config
) {
flowFwdStore0(mid, f, node, apf0, config) and
flowCandConsCand(f, apf0, config) and
apf.headUsesContent(f) and
storeCand(mid, tc, node, apf0, apf, config) and
flowCandConsCand(tc, apf0, config) and
flowCand(node, _, _, apf, unbind(config))
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp,
Configuration config
private predicate flowFwdRead0(
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
boolean fromArg, AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f) and
flowCand(node, _, _, _, unbind(config))
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
readCandFwd(node1, tc, apf0, node2, config)
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, TypedContent tc |
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
flowCand(node, _, _, apf, unbind(config)) and
flowCandConsCand(tc, apf, unbind(config))
)
}
pragma[nomagic]
private predicate flowFwdConsCand(
Content f, AccessPathFront apf, AccessPath ap, Configuration config
TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config
) {
exists(Node n |
flowFwd(n, _, _, apf, ap, config) and
flowFwdStore1(n, f, _, apf, _, config)
flowFwdStore0(n, tc, _, apf, _, config)
)
}
@@ -1863,9 +1885,9 @@ private predicate flow0(
)
or
// store
exists(Content f |
flowStore(f, node, toReturn, returnAp, ap, config) and
flowConsCand(f, ap, config)
exists(TypedContent tc |
flowStore(tc, node, toReturn, returnAp, ap, config) and
flowConsCand(tc, ap, config)
)
or
// read
@@ -1895,39 +1917,41 @@ private predicate flow0(
pragma[nomagic]
private predicate storeFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
storeCand2(node1, f, node2, config) and
flowFwdStore(node2, f, ap, _, _, _, config) and
ap0 = push(f, ap)
storeCand2(node1, tc, node2, _, config) and
flowFwdStore(node2, tc, ap, _, _, _, config) and
ap0 = push(tc, ap)
}
pragma[nomagic]
private predicate flowStore(
Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
Configuration config
) {
exists(Node mid, AccessPath ap0 |
storeFlowFwd(node, f, mid, ap, ap0, config) and
storeFlowFwd(node, tc, mid, ap, ap0, config) and
flow(mid, toReturn, returnAp, ap0, config)
)
}
pragma[nomagic]
private predicate readFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
readCand2(node1, f, node2, config) and
flowFwdRead(node2, f, ap, _, _, config) and
ap0 = pop(f, ap) and
flowFwdConsCand(f, _, ap0, unbind(config))
exists(AccessPathFrontHead apf |
readCandFwd(node1, tc, apf, node2, config) and
flowFwdRead(node2, apf, ap, _, _, _, config) and
ap0 = pop(tc, ap) and
flowFwdConsCand(tc, _, ap0, unbind(config))
)
}
pragma[nomagic]
private predicate flowConsCand(Content f, AccessPath ap, Configuration config) {
private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) {
exists(Node n, Node mid |
flow(mid, _, _, ap, config) and
readFlowFwd(n, f, mid, _, ap, config)
readFlowFwd(n, tc, mid, _, ap, config)
)
}
@@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and
exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
@@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
}
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2) and
private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) {
readCandFwd(node1, tc, _, node2, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) {
private predicate pathReadStep(
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
readCand(mid.getNode(), f, node, mid.getConfiguration()) and
readCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate storeCand(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2) and
private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) {
storeCand2(node1, tc, node2, _, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathStoreStep(
PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
storeCand(mid.getNode(), f, node, mid.getConfiguration()) and
storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -2538,10 +2564,10 @@ private module FlowExploration {
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(Content f, int len) { len in [1 .. 5] }
TPartialCons(TypedContent tc, int len) { len in [1 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -2550,7 +2576,7 @@ private module FlowExploration {
private class PartialAccessPath extends TPartialAccessPath {
abstract string toString();
Content getHead() { this = TPartialCons(result, _) }
TypedContent getHead() { this = TPartialCons(result, _) }
int len() {
this = TPartialNil(_) and result = 0
@@ -2561,7 +2587,7 @@ private module FlowExploration {
DataFlowType getType() {
this = TPartialNil(result)
or
exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType())
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
@@ -2579,15 +2605,15 @@ private module FlowExploration {
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
exists(TypedContent tc, int len | this = TPartialCons(tc, len) |
if len = 1
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc.toString() + "]"
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
override AccessPathFront getFront() {
exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f))
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
}
}
@@ -2763,11 +2789,12 @@ private module FlowExploration {
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(PartialAccessPath ap0, Content f |
partialPathReadStep(mid, ap0, f, node, cc, config) and
exists(PartialAccessPath ap0, TypedContent tc |
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, f, ap0, config)
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -2786,35 +2813,42 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
) {
ap1 = mid.getAp() and
store(mid.getNode(), f, node) and
ap2.getHead() = f and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), f.getType())
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
)
}
pragma[nomagic]
private predicate apConsFwd(
PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
partialPathStoreStep(mid, ap1, f, _, ap2) and
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc,
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
ap = mid.getAp() and
readStep(mid.getNode(), f, node) and
ap.getHead() = f and
config = mid.getConfiguration() and
cc = mid.getCallContext()
exists(Node midNode |
midNode = mid.getNode() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node) and
ap.getHead() = tc and
config = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
private predicate partialPathOutOfCallable0(

View File

@@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
exists(Node mid |
useFieldFlow(config) and
nodeCandFwd1(mid, fromArg, config) and
store(mid, _, node) and
store(mid, _, node, _) and
not outBarrier(mid, config)
)
or
// read
exists(Content f |
nodeCandFwd1Read(f, node, fromArg, config) and
nodeCandFwd1IsStored(f, config) and
exists(Content c |
nodeCandFwd1Read(c, node, fromArg, config) and
nodeCandFwd1IsStored(c, config) and
not inBarrier(node, config)
)
or
@@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
pragma[nomagic]
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) {
exists(Node mid |
nodeCandFwd1(mid, fromArg, config) and
read(mid, f, node)
read(mid, c, node)
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`.
*/
pragma[nomagic]
private predicate nodeCandFwd1IsStored(Content f, Configuration config) {
exists(Node mid, Node node |
private predicate nodeCandFwd1IsStored(Content c, Configuration config) {
exists(Node mid, Node node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
nodeCandFwd1(mid, config) and
store(mid, f, node)
store(mid, tc, node, _) and
c = tc.getContent()
)
}
@@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
)
or
// store
exists(Content f |
nodeCand1Store(f, node, toReturn, config) and
nodeCand1IsRead(f, config)
exists(Content c |
nodeCand1Store(c, node, toReturn, config) and
nodeCand1IsRead(c, config)
)
or
// read
exists(Node mid, Content f |
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
exists(Node mid, Content c |
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, toReturn, config)
)
or
@@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand1`.
*/
pragma[nomagic]
private predicate nodeCand1IsRead(Content f, Configuration config) {
private predicate nodeCand1IsRead(Content c, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, _, config)
)
}
pragma[nomagic]
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
exists(Node mid |
private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
nodeCand1(mid, toReturn, config) and
nodeCandFwd1IsStored(f, unbind(config)) and
store(node, f, mid)
nodeCandFwd1IsStored(c, unbind(config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
}
/**
* Holds if `f` is the target of both a read and a store in the flow covered
* Holds if `c` is the target of both a read and a store in the flow covered
* by `nodeCand1`.
*/
private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) {
nodeCand1IsRead(f, conf) and
nodeCand1Store(f, _, _, conf)
private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) {
nodeCand1IsRead(c, conf) and
nodeCand1Store(c, _, _, conf)
}
pragma[nomagic]
@@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c
}
pragma[nomagic]
private predicate store(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
nodeCand1(n2, unbind(config)) and
store(n1, f, n2)
private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) {
exists(TypedContent tc |
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
store(n1, tc, n2, _) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate read(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
private predicate read(Node n1, Content c, Node n2, Configuration config) {
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
read(n1, f, n2)
read(n1, c, n2)
}
pragma[noinline]
@@ -748,16 +753,16 @@ private predicate nodeCandFwd2(
)
or
// store
exists(Node mid, Content f |
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, _, config) and
store(mid, f, node, config) and
storeCand1(mid, _, node, config) and
stored = true
)
or
// read
exists(Content f |
nodeCandFwd2Read(f, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(f, stored, config)
exists(Content c |
nodeCandFwd2Read(c, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(c, stored, config)
)
or
// flow into a callable
@@ -781,25 +786,25 @@ private predicate nodeCandFwd2(
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`.
*/
pragma[noinline]
private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) {
private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCand1(node, unbind(config)) and
nodeCandFwd2(mid, _, _, stored, config) and
store(mid, f, node, config)
storeCand1(mid, c, node, config)
)
}
pragma[nomagic]
private predicate nodeCandFwd2Read(
Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config
Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config
) {
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, true, config) and
read(mid, f, node, config)
read(mid, c, node, config)
)
}
@@ -896,15 +901,15 @@ private predicate nodeCand2(
)
or
// store
exists(Content f |
nodeCand2Store(f, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(f, read, config)
exists(Content c |
nodeCand2Store(c, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(c, read, config)
)
or
// read
exists(Node mid, Content f, boolean read0 |
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and
exists(Node mid, Content c, boolean read0 |
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and
nodeCand2(mid, toReturn, returnRead, read0, config) and
read = true
)
@@ -930,51 +935,51 @@ private predicate nodeCand2(
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) {
private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd2(node, _, _, true, unbind(config)) and
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and
nodeCand2(mid, _, _, read, config)
)
}
pragma[nomagic]
private predicate nodeCand2Store(
Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Configuration config
) {
exists(Node mid |
store(node, f, mid, config) and
storeCand1(node, c, mid, config) and
nodeCand2(mid, toReturn, returnRead, true, config) and
nodeCandFwd2(node, _, _, stored, unbind(config))
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCand2`.
*/
pragma[nomagic]
private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) {
private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) {
exists(Node node |
nodeCand2Store(f, node, _, _, stored, conf) and
nodeCand2Store(c, node, _, _, stored, conf) and
nodeCand2(node, _, _, stored, conf)
)
}
/**
* Holds if `f` is the target of both a store and a read in the path graph
* Holds if `c` is the target of both a store and a read in the path graph
* covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) {
private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) {
exists(boolean apNonEmpty |
nodeCand2IsStored(f, apNonEmpty, conf) and
nodeCand2IsRead(f, apNonEmpty, conf)
nodeCand2IsStored(c, apNonEmpty, conf) and
nodeCand2IsRead(c, apNonEmpty, conf)
)
}
@@ -1058,7 +1063,7 @@ private module LocalFlowBigStep {
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof OutNodeExt or
store(_, _, node) or
store(_, _, node, _) or
read(_, _, node) or
node instanceof CastNode
)
@@ -1074,7 +1079,7 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next) or
store(node, _, next, _) or
read(node, _, next)
)
or
@@ -1154,19 +1159,21 @@ private module LocalFlowBigStep {
private import LocalFlowBigStep
pragma[nomagic]
private predicate readCand2(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2, config) and
private predicate readCand2(Node node1, Content c, Node node2, Configuration config) {
read(node1, c, node2, config) and
nodeCand2(node1, _, _, true, unbind(config)) and
nodeCand2(node2, config) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(c, unbind(config))
}
pragma[nomagic]
private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2, config) and
private predicate storeCand2(
Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
store(node1, tc, node2, contentType) and
nodeCand2(node1, config) and
nodeCand2(node2, _, _, true, unbind(config)) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(tc.getContent(), unbind(config))
}
/**
@@ -1227,17 +1234,18 @@ private predicate flowCandFwd0(
)
or
// store
exists(Node mid, Content f |
flowCandFwd(mid, fromArg, argApf, _, config) and
storeCand2(mid, f, node, config) and
exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
storeCand2(mid, tc, node, contentType, config) and
nodeCand2(node, _, _, true, unbind(config)) and
apf.headUsesContent(f)
apf.headUsesContent(tc) and
compatibleTypes(apf0.getType(), contentType)
)
or
// read
exists(Content f |
flowCandFwdRead(f, node, fromArg, argApf, config) and
flowCandFwdConsCand(f, apf, config) and
exists(TypedContent tc |
flowCandFwdRead(tc, node, fromArg, argApf, config) and
flowCandFwdConsCand(tc, apf, config) and
nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config))
)
or
@@ -1261,24 +1269,30 @@ private predicate flowCandFwd0(
}
pragma[nomagic]
private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n |
private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n, DataFlowType contentType |
flowCandFwd(mid, _, _, apf, config) and
storeCand2(mid, f, n, config) and
storeCand2(mid, tc, n, contentType, config) and
nodeCand2(n, _, _, true, unbind(config)) and
compatibleTypes(apf.getType(), f.getType())
compatibleTypes(apf.getType(), contentType)
)
}
pragma[nomagic]
private predicate flowCandFwdRead(
Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
private predicate flowCandFwdRead0(
Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf,
AccessPathFrontHead apf, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f)
)
flowCandFwd(node1, fromArg, argApf, apf, config) and
readCand2(node1, c, node2, config) and
apf.headUsesContent(tc)
}
pragma[nomagic]
private predicate flowCandFwdRead(
TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
) {
flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config)
}
pragma[nomagic]
@@ -1385,17 +1399,15 @@ private predicate flowCand0(
)
or
// store
exists(Content f, AccessPathFrontHead apf0 |
flowCandStore(node, f, toReturn, returnApf, apf0, config) and
apf0.headUsesContent(f) and
flowCandConsCand(f, apf, config)
exists(TypedContent tc |
flowCandStore(node, tc, apf, toReturn, returnApf, config) and
flowCandConsCand(tc, apf, config)
)
or
// read
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(f, apf0, config) and
apf.headUsesContent(f)
exists(TypedContent tc, AccessPathFront apf0 |
flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(tc, apf0, config)
)
or
// flow into a callable
@@ -1417,36 +1429,40 @@ private predicate flowCand0(
else returnApf = TAccessPathFrontNone()
}
pragma[nomagic]
private predicate readCandFwd(
Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config
) {
flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config)
}
pragma[nomagic]
private predicate flowCandRead(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config
) {
exists(Node mid |
readCand2(node, f, mid, config) and
readCandFwd(node, tc, apf, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
)
}
pragma[nomagic]
private predicate flowCandStore(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, Configuration config
) {
exists(Node mid |
storeCand2(node, f, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
flowCandFwd(node, _, _, apf, config) and
storeCand2(node, tc, mid, _, unbind(config)) and
flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config))
)
}
pragma[nomagic]
private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(f, apf, config) and
exists(Node n, AccessPathFrontHead apf0 |
flowCandFwd(n, _, _, apf0, config) and
apf0.headUsesContent(f) and
flowCandRead(n, f, _, _, apf, config)
)
private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(tc, apf, config) and
flowCandRead(_, tc, _, _, _, apf, config)
}
pragma[nomagic]
@@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned(
private newtype TAccessPath =
TNil(DataFlowType t) or
TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or
TConsCons(Content f1, Content f2, int len) {
flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()]
TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()]
}
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -1514,7 +1530,7 @@ private newtype TAccessPath =
abstract private class AccessPath extends TAccessPath {
abstract string toString();
abstract Content getHead();
abstract TypedContent getHead();
abstract int len();
@@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath {
/**
* Holds if this access path has `head` at the front and may be followed by `tail`.
*/
abstract predicate pop(Content head, AccessPath tail);
abstract predicate pop(TypedContent head, AccessPath tail);
}
private class AccessPathNil extends AccessPath, TNil {
@@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil {
override string toString() { result = concat(": " + ppReprType(t)) }
override Content getHead() { none() }
override TypedContent getHead() { none() }
override int len() { result = 0 }
@@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil {
override AccessPathFront getFront() { result = TFrontNil(t) }
override predicate pop(Content head, AccessPath tail) { none() }
override predicate pop(TypedContent head, AccessPath tail) { none() }
}
abstract private class AccessPathCons extends AccessPath { }
private class AccessPathConsNil extends AccessPathCons, TConsNil {
private Content f;
private TypedContent tc;
private DataFlowType t;
AccessPathConsNil() { this = TConsNil(f, t) }
AccessPathConsNil() { this = TConsNil(tc, t) }
override string toString() {
// The `concat` becomes "" if `ppReprType` has no result.
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t))
}
override Content getHead() { result = f }
override TypedContent getHead() { result = tc }
override int len() { result = 1 }
override DataFlowType getType() { result = f.getContainerType() }
override DataFlowType getType() { result = tc.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f) }
override AccessPathFront getFront() { result = TFrontHead(tc) }
override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) }
override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) }
}
private class AccessPathConsCons extends AccessPathCons, TConsCons {
private Content f1;
private Content f2;
private TypedContent tc1;
private TypedContent tc2;
private int len;
AccessPathConsCons() { this = TConsCons(f1, f2, len) }
AccessPathConsCons() { this = TConsCons(tc1, tc2, len) }
override string toString() {
if len = 2
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc1.toString() + ", " + tc2.toString() + "]"
else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]"
}
override Content getHead() { result = f1 }
override TypedContent getHead() { result = tc1 }
override int len() { result = len }
override DataFlowType getType() { result = f1.getContainerType() }
override DataFlowType getType() { result = tc1.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f1) }
override AccessPathFront getFront() { result = TFrontHead(tc1) }
override predicate pop(Content head, AccessPath tail) {
head = f1 and
override predicate pop(TypedContent head, AccessPath tail) {
head = tc1 and
(
tail = TConsCons(f2, _, len - 1)
tail = TConsCons(tc2, _, len - 1)
or
len = 2 and
tail = TConsNil(f2, _)
tail = TConsNil(tc2, _)
)
}
}
/** Gets the access path obtained by popping `f` from `ap`, if any. */
private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) }
/** Gets the access path obtained by popping `tc` from `ap`, if any. */
private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) }
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/** Gets the access path obtained by pushing `tc` onto `ap`. */
private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) }
private newtype TAccessPathOption =
TAccessPathNone() or
@@ -1678,15 +1694,12 @@ private predicate flowFwd0(
)
or
// store
exists(Content f, AccessPath ap0 |
flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and
ap = push(f, ap0)
)
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
or
// read
exists(Content f |
flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and
flowFwdConsCand(f, apf, ap, config)
exists(TypedContent tc |
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
flowFwdConsCand(tc, apf, ap, config)
)
or
// flow into a callable
@@ -1710,54 +1723,63 @@ private predicate flowFwd0(
pragma[nomagic]
private predicate flowFwdStore(
Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg,
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFront apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
flowFwdStore1(mid, f, node, apf0, apf, config)
flowFwdStore0(mid, tc, node, apf0, apf, config)
)
}
pragma[nomagic]
private predicate flowFwdStore0(
Node mid, Content f, Node node, AccessPathFront apf0, Configuration config
private predicate storeCand(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf,
Configuration config
) {
storeCand2(mid, f, node, config) and
flowCand(mid, _, _, apf0, config)
storeCand2(mid, tc, node, _, config) and
flowCand(mid, _, _, apf0, config) and
apf.headUsesContent(tc)
}
pragma[noinline]
private predicate flowFwdStore1(
Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
private predicate flowFwdStore0(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
Configuration config
) {
flowFwdStore0(mid, f, node, apf0, config) and
flowCandConsCand(f, apf0, config) and
apf.headUsesContent(f) and
storeCand(mid, tc, node, apf0, apf, config) and
flowCandConsCand(tc, apf0, config) and
flowCand(node, _, _, apf, unbind(config))
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp,
Configuration config
private predicate flowFwdRead0(
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
boolean fromArg, AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f) and
flowCand(node, _, _, _, unbind(config))
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
readCandFwd(node1, tc, apf0, node2, config)
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, TypedContent tc |
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
flowCand(node, _, _, apf, unbind(config)) and
flowCandConsCand(tc, apf, unbind(config))
)
}
pragma[nomagic]
private predicate flowFwdConsCand(
Content f, AccessPathFront apf, AccessPath ap, Configuration config
TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config
) {
exists(Node n |
flowFwd(n, _, _, apf, ap, config) and
flowFwdStore1(n, f, _, apf, _, config)
flowFwdStore0(n, tc, _, apf, _, config)
)
}
@@ -1863,9 +1885,9 @@ private predicate flow0(
)
or
// store
exists(Content f |
flowStore(f, node, toReturn, returnAp, ap, config) and
flowConsCand(f, ap, config)
exists(TypedContent tc |
flowStore(tc, node, toReturn, returnAp, ap, config) and
flowConsCand(tc, ap, config)
)
or
// read
@@ -1895,39 +1917,41 @@ private predicate flow0(
pragma[nomagic]
private predicate storeFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
storeCand2(node1, f, node2, config) and
flowFwdStore(node2, f, ap, _, _, _, config) and
ap0 = push(f, ap)
storeCand2(node1, tc, node2, _, config) and
flowFwdStore(node2, tc, ap, _, _, _, config) and
ap0 = push(tc, ap)
}
pragma[nomagic]
private predicate flowStore(
Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
Configuration config
) {
exists(Node mid, AccessPath ap0 |
storeFlowFwd(node, f, mid, ap, ap0, config) and
storeFlowFwd(node, tc, mid, ap, ap0, config) and
flow(mid, toReturn, returnAp, ap0, config)
)
}
pragma[nomagic]
private predicate readFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
readCand2(node1, f, node2, config) and
flowFwdRead(node2, f, ap, _, _, config) and
ap0 = pop(f, ap) and
flowFwdConsCand(f, _, ap0, unbind(config))
exists(AccessPathFrontHead apf |
readCandFwd(node1, tc, apf, node2, config) and
flowFwdRead(node2, apf, ap, _, _, _, config) and
ap0 = pop(tc, ap) and
flowFwdConsCand(tc, _, ap0, unbind(config))
)
}
pragma[nomagic]
private predicate flowConsCand(Content f, AccessPath ap, Configuration config) {
private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) {
exists(Node n, Node mid |
flow(mid, _, _, ap, config) and
readFlowFwd(n, f, mid, _, ap, config)
readFlowFwd(n, tc, mid, _, ap, config)
)
}
@@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and
exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
@@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
}
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2) and
private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) {
readCandFwd(node1, tc, _, node2, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) {
private predicate pathReadStep(
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
readCand(mid.getNode(), f, node, mid.getConfiguration()) and
readCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate storeCand(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2) and
private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) {
storeCand2(node1, tc, node2, _, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathStoreStep(
PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
storeCand(mid.getNode(), f, node, mid.getConfiguration()) and
storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -2538,10 +2564,10 @@ private module FlowExploration {
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(Content f, int len) { len in [1 .. 5] }
TPartialCons(TypedContent tc, int len) { len in [1 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -2550,7 +2576,7 @@ private module FlowExploration {
private class PartialAccessPath extends TPartialAccessPath {
abstract string toString();
Content getHead() { this = TPartialCons(result, _) }
TypedContent getHead() { this = TPartialCons(result, _) }
int len() {
this = TPartialNil(_) and result = 0
@@ -2561,7 +2587,7 @@ private module FlowExploration {
DataFlowType getType() {
this = TPartialNil(result)
or
exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType())
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
@@ -2579,15 +2605,15 @@ private module FlowExploration {
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
exists(TypedContent tc, int len | this = TPartialCons(tc, len) |
if len = 1
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc.toString() + "]"
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
override AccessPathFront getFront() {
exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f))
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
}
}
@@ -2763,11 +2789,12 @@ private module FlowExploration {
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(PartialAccessPath ap0, Content f |
partialPathReadStep(mid, ap0, f, node, cc, config) and
exists(PartialAccessPath ap0, TypedContent tc |
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, f, ap0, config)
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -2786,35 +2813,42 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
) {
ap1 = mid.getAp() and
store(mid.getNode(), f, node) and
ap2.getHead() = f and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), f.getType())
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
)
}
pragma[nomagic]
private predicate apConsFwd(
PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
partialPathStoreStep(mid, ap1, f, _, ap2) and
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc,
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
ap = mid.getAp() and
readStep(mid.getNode(), f, node) and
ap.getHead() = f and
config = mid.getConfiguration() and
cc = mid.getCallContext()
exists(Node midNode |
midNode = mid.getNode() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node) and
ap.getHead() = tc and
config = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
private predicate partialPathOutOfCallable0(

View File

@@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
exists(Node mid |
useFieldFlow(config) and
nodeCandFwd1(mid, fromArg, config) and
store(mid, _, node) and
store(mid, _, node, _) and
not outBarrier(mid, config)
)
or
// read
exists(Content f |
nodeCandFwd1Read(f, node, fromArg, config) and
nodeCandFwd1IsStored(f, config) and
exists(Content c |
nodeCandFwd1Read(c, node, fromArg, config) and
nodeCandFwd1IsStored(c, config) and
not inBarrier(node, config)
)
or
@@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config)
private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) }
pragma[nomagic]
private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) {
private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) {
exists(Node mid |
nodeCandFwd1(mid, fromArg, config) and
read(mid, f, node)
read(mid, c, node)
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`.
*/
pragma[nomagic]
private predicate nodeCandFwd1IsStored(Content f, Configuration config) {
exists(Node mid, Node node |
private predicate nodeCandFwd1IsStored(Content c, Configuration config) {
exists(Node mid, Node node, TypedContent tc |
not fullBarrier(node, config) and
useFieldFlow(config) and
nodeCandFwd1(mid, config) and
store(mid, f, node)
store(mid, tc, node, _) and
c = tc.getContent()
)
}
@@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
)
or
// store
exists(Content f |
nodeCand1Store(f, node, toReturn, config) and
nodeCand1IsRead(f, config)
exists(Content c |
nodeCand1Store(c, node, toReturn, config) and
nodeCand1IsRead(c, config)
)
or
// read
exists(Node mid, Content f |
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
exists(Node mid, Content c |
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, toReturn, config)
)
or
@@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config)
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand1`.
*/
pragma[nomagic]
private predicate nodeCand1IsRead(Content f, Configuration config) {
private predicate nodeCand1IsRead(Content c, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd1(node, unbind(config)) and
read(node, f, mid) and
nodeCandFwd1IsStored(f, unbind(config)) and
read(node, c, mid) and
nodeCandFwd1IsStored(c, unbind(config)) and
nodeCand1(mid, _, config)
)
}
pragma[nomagic]
private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) {
exists(Node mid |
private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) {
exists(Node mid, TypedContent tc |
nodeCand1(mid, toReturn, config) and
nodeCandFwd1IsStored(f, unbind(config)) and
store(node, f, mid)
nodeCandFwd1IsStored(c, unbind(config)) and
store(node, tc, mid, _) and
c = tc.getContent()
)
}
/**
* Holds if `f` is the target of both a read and a store in the flow covered
* Holds if `c` is the target of both a read and a store in the flow covered
* by `nodeCand1`.
*/
private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) {
nodeCand1IsRead(f, conf) and
nodeCand1Store(f, _, _, conf)
private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) {
nodeCand1IsRead(c, conf) and
nodeCand1Store(c, _, _, conf)
}
pragma[nomagic]
@@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c
}
pragma[nomagic]
private predicate store(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
nodeCand1(n2, unbind(config)) and
store(n1, f, n2)
private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) {
exists(TypedContent tc |
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
store(n1, tc, n2, _) and
c = tc.getContent()
)
}
pragma[nomagic]
private predicate read(Node n1, Content f, Node n2, Configuration config) {
nodeCand1IsReadAndStored(f, config) and
private predicate read(Node n1, Content c, Node n2, Configuration config) {
nodeCand1IsReadAndStored(c, config) and
nodeCand1(n2, unbind(config)) and
read(n1, f, n2)
read(n1, c, n2)
}
pragma[noinline]
@@ -748,16 +753,16 @@ private predicate nodeCandFwd2(
)
or
// store
exists(Node mid, Content f |
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, _, config) and
store(mid, f, node, config) and
storeCand1(mid, _, node, config) and
stored = true
)
or
// read
exists(Content f |
nodeCandFwd2Read(f, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(f, stored, config)
exists(Content c |
nodeCandFwd2Read(c, node, fromArg, argStored, config) and
nodeCandFwd2IsStored(c, stored, config)
)
or
// flow into a callable
@@ -781,25 +786,25 @@ private predicate nodeCandFwd2(
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`.
*/
pragma[noinline]
private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) {
private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCand1(node, unbind(config)) and
nodeCandFwd2(mid, _, _, stored, config) and
store(mid, f, node, config)
storeCand1(mid, c, node, config)
)
}
pragma[nomagic]
private predicate nodeCandFwd2Read(
Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config
Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config
) {
exists(Node mid |
nodeCandFwd2(mid, fromArg, argStored, true, config) and
read(mid, f, node, config)
read(mid, c, node, config)
)
}
@@ -896,15 +901,15 @@ private predicate nodeCand2(
)
or
// store
exists(Content f |
nodeCand2Store(f, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(f, read, config)
exists(Content c |
nodeCand2Store(c, node, toReturn, returnRead, read, config) and
nodeCand2IsRead(c, read, config)
)
or
// read
exists(Node mid, Content f, boolean read0 |
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and
exists(Node mid, Content c, boolean read0 |
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and
nodeCand2(mid, toReturn, returnRead, read0, config) and
read = true
)
@@ -930,51 +935,51 @@ private predicate nodeCand2(
}
/**
* Holds if `f` is the target of a read in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a read in the flow covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) {
private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) {
exists(Node mid, Node node |
useFieldFlow(config) and
nodeCandFwd2(node, _, _, true, unbind(config)) and
read(node, f, mid, config) and
nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and
read(node, c, mid, config) and
nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and
nodeCand2(mid, _, _, read, config)
)
}
pragma[nomagic]
private predicate nodeCand2Store(
Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored,
Configuration config
) {
exists(Node mid |
store(node, f, mid, config) and
storeCand1(node, c, mid, config) and
nodeCand2(mid, toReturn, returnRead, true, config) and
nodeCandFwd2(node, _, _, stored, unbind(config))
)
}
/**
* Holds if `f` is the target of a store in the flow covered by `nodeCand2`.
* Holds if `c` is the target of a store in the flow covered by `nodeCand2`.
*/
pragma[nomagic]
private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) {
private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) {
exists(Node node |
nodeCand2Store(f, node, _, _, stored, conf) and
nodeCand2Store(c, node, _, _, stored, conf) and
nodeCand2(node, _, _, stored, conf)
)
}
/**
* Holds if `f` is the target of both a store and a read in the path graph
* Holds if `c` is the target of both a store and a read in the path graph
* covered by `nodeCand2`.
*/
pragma[noinline]
private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) {
private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) {
exists(boolean apNonEmpty |
nodeCand2IsStored(f, apNonEmpty, conf) and
nodeCand2IsRead(f, apNonEmpty, conf)
nodeCand2IsStored(c, apNonEmpty, conf) and
nodeCand2IsRead(c, apNonEmpty, conf)
)
}
@@ -1058,7 +1063,7 @@ private module LocalFlowBigStep {
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof OutNodeExt or
store(_, _, node) or
store(_, _, node, _) or
read(_, _, node) or
node instanceof CastNode
)
@@ -1074,7 +1079,7 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next) or
store(node, _, next, _) or
read(node, _, next)
)
or
@@ -1154,19 +1159,21 @@ private module LocalFlowBigStep {
private import LocalFlowBigStep
pragma[nomagic]
private predicate readCand2(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2, config) and
private predicate readCand2(Node node1, Content c, Node node2, Configuration config) {
read(node1, c, node2, config) and
nodeCand2(node1, _, _, true, unbind(config)) and
nodeCand2(node2, config) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(c, unbind(config))
}
pragma[nomagic]
private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2, config) and
private predicate storeCand2(
Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
) {
store(node1, tc, node2, contentType) and
nodeCand2(node1, config) and
nodeCand2(node2, _, _, true, unbind(config)) and
nodeCand2IsReadAndStored(f, unbind(config))
nodeCand2IsReadAndStored(tc.getContent(), unbind(config))
}
/**
@@ -1227,17 +1234,18 @@ private predicate flowCandFwd0(
)
or
// store
exists(Node mid, Content f |
flowCandFwd(mid, fromArg, argApf, _, config) and
storeCand2(mid, f, node, config) and
exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
storeCand2(mid, tc, node, contentType, config) and
nodeCand2(node, _, _, true, unbind(config)) and
apf.headUsesContent(f)
apf.headUsesContent(tc) and
compatibleTypes(apf0.getType(), contentType)
)
or
// read
exists(Content f |
flowCandFwdRead(f, node, fromArg, argApf, config) and
flowCandFwdConsCand(f, apf, config) and
exists(TypedContent tc |
flowCandFwdRead(tc, node, fromArg, argApf, config) and
flowCandFwdConsCand(tc, apf, config) and
nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config))
)
or
@@ -1261,24 +1269,30 @@ private predicate flowCandFwd0(
}
pragma[nomagic]
private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n |
private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
exists(Node mid, Node n, DataFlowType contentType |
flowCandFwd(mid, _, _, apf, config) and
storeCand2(mid, f, n, config) and
storeCand2(mid, tc, n, contentType, config) and
nodeCand2(n, _, _, true, unbind(config)) and
compatibleTypes(apf.getType(), f.getType())
compatibleTypes(apf.getType(), contentType)
)
}
pragma[nomagic]
private predicate flowCandFwdRead(
Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
private predicate flowCandFwdRead0(
Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf,
AccessPathFrontHead apf, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowCandFwd(mid, fromArg, argApf, apf0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f)
)
flowCandFwd(node1, fromArg, argApf, apf, config) and
readCand2(node1, c, node2, config) and
apf.headUsesContent(tc)
}
pragma[nomagic]
private predicate flowCandFwdRead(
TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config
) {
flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config)
}
pragma[nomagic]
@@ -1385,17 +1399,15 @@ private predicate flowCand0(
)
or
// store
exists(Content f, AccessPathFrontHead apf0 |
flowCandStore(node, f, toReturn, returnApf, apf0, config) and
apf0.headUsesContent(f) and
flowCandConsCand(f, apf, config)
exists(TypedContent tc |
flowCandStore(node, tc, apf, toReturn, returnApf, config) and
flowCandConsCand(tc, apf, config)
)
or
// read
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(f, apf0, config) and
apf.headUsesContent(f)
exists(TypedContent tc, AccessPathFront apf0 |
flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and
flowCandFwdConsCand(tc, apf0, config)
)
or
// flow into a callable
@@ -1417,36 +1429,40 @@ private predicate flowCand0(
else returnApf = TAccessPathFrontNone()
}
pragma[nomagic]
private predicate readCandFwd(
Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config
) {
flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config)
}
pragma[nomagic]
private predicate flowCandRead(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config
) {
exists(Node mid |
readCand2(node, f, mid, config) and
readCandFwd(node, tc, apf, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
)
}
pragma[nomagic]
private predicate flowCandStore(
Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0,
Configuration config
Node node, TypedContent tc, AccessPathFront apf, boolean toReturn,
AccessPathFrontOption returnApf, Configuration config
) {
exists(Node mid |
storeCand2(node, f, mid, config) and
flowCand(mid, toReturn, returnApf, apf0, config)
flowCandFwd(node, _, _, apf, config) and
storeCand2(node, tc, mid, _, unbind(config)) and
flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config))
)
}
pragma[nomagic]
private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(f, apf, config) and
exists(Node n, AccessPathFrontHead apf0 |
flowCandFwd(n, _, _, apf0, config) and
apf0.headUsesContent(f) and
flowCandRead(n, f, _, _, apf, config)
)
private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) {
flowCandFwdConsCand(tc, apf, config) and
flowCandRead(_, tc, _, _, _, apf, config)
}
pragma[nomagic]
@@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned(
private newtype TAccessPath =
TNil(DataFlowType t) or
TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or
TConsCons(Content f1, Content f2, int len) {
flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()]
TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()]
}
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -1514,7 +1530,7 @@ private newtype TAccessPath =
abstract private class AccessPath extends TAccessPath {
abstract string toString();
abstract Content getHead();
abstract TypedContent getHead();
abstract int len();
@@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath {
/**
* Holds if this access path has `head` at the front and may be followed by `tail`.
*/
abstract predicate pop(Content head, AccessPath tail);
abstract predicate pop(TypedContent head, AccessPath tail);
}
private class AccessPathNil extends AccessPath, TNil {
@@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil {
override string toString() { result = concat(": " + ppReprType(t)) }
override Content getHead() { none() }
override TypedContent getHead() { none() }
override int len() { result = 0 }
@@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil {
override AccessPathFront getFront() { result = TFrontNil(t) }
override predicate pop(Content head, AccessPath tail) { none() }
override predicate pop(TypedContent head, AccessPath tail) { none() }
}
abstract private class AccessPathCons extends AccessPath { }
private class AccessPathConsNil extends AccessPathCons, TConsNil {
private Content f;
private TypedContent tc;
private DataFlowType t;
AccessPathConsNil() { this = TConsNil(f, t) }
AccessPathConsNil() { this = TConsNil(tc, t) }
override string toString() {
// The `concat` becomes "" if `ppReprType` has no result.
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t))
}
override Content getHead() { result = f }
override TypedContent getHead() { result = tc }
override int len() { result = 1 }
override DataFlowType getType() { result = f.getContainerType() }
override DataFlowType getType() { result = tc.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f) }
override AccessPathFront getFront() { result = TFrontHead(tc) }
override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) }
override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) }
}
private class AccessPathConsCons extends AccessPathCons, TConsCons {
private Content f1;
private Content f2;
private TypedContent tc1;
private TypedContent tc2;
private int len;
AccessPathConsCons() { this = TConsCons(f1, f2, len) }
AccessPathConsCons() { this = TConsCons(tc1, tc2, len) }
override string toString() {
if len = 2
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc1.toString() + ", " + tc2.toString() + "]"
else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]"
}
override Content getHead() { result = f1 }
override TypedContent getHead() { result = tc1 }
override int len() { result = len }
override DataFlowType getType() { result = f1.getContainerType() }
override DataFlowType getType() { result = tc1.getContainerType() }
override AccessPathFront getFront() { result = TFrontHead(f1) }
override AccessPathFront getFront() { result = TFrontHead(tc1) }
override predicate pop(Content head, AccessPath tail) {
head = f1 and
override predicate pop(TypedContent head, AccessPath tail) {
head = tc1 and
(
tail = TConsCons(f2, _, len - 1)
tail = TConsCons(tc2, _, len - 1)
or
len = 2 and
tail = TConsNil(f2, _)
tail = TConsNil(tc2, _)
)
}
}
/** Gets the access path obtained by popping `f` from `ap`, if any. */
private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) }
/** Gets the access path obtained by popping `tc` from `ap`, if any. */
private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) }
/** Gets the access path obtained by pushing `f` onto `ap`. */
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
/** Gets the access path obtained by pushing `tc` onto `ap`. */
private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) }
private newtype TAccessPathOption =
TAccessPathNone() or
@@ -1678,15 +1694,12 @@ private predicate flowFwd0(
)
or
// store
exists(Content f, AccessPath ap0 |
flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and
ap = push(f, ap0)
)
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
or
// read
exists(Content f |
flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and
flowFwdConsCand(f, apf, ap, config)
exists(TypedContent tc |
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
flowFwdConsCand(tc, apf, ap, config)
)
or
// flow into a callable
@@ -1710,54 +1723,63 @@ private predicate flowFwd0(
pragma[nomagic]
private predicate flowFwdStore(
Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg,
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFront apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
flowFwdStore1(mid, f, node, apf0, apf, config)
flowFwdStore0(mid, tc, node, apf0, apf, config)
)
}
pragma[nomagic]
private predicate flowFwdStore0(
Node mid, Content f, Node node, AccessPathFront apf0, Configuration config
private predicate storeCand(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf,
Configuration config
) {
storeCand2(mid, f, node, config) and
flowCand(mid, _, _, apf0, config)
storeCand2(mid, tc, node, _, config) and
flowCand(mid, _, _, apf0, config) and
apf.headUsesContent(tc)
}
pragma[noinline]
private predicate flowFwdStore1(
Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
private predicate flowFwdStore0(
Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf,
Configuration config
) {
flowFwdStore0(mid, f, node, apf0, config) and
flowCandConsCand(f, apf0, config) and
apf.headUsesContent(f) and
storeCand(mid, tc, node, apf0, apf, config) and
flowCandConsCand(tc, apf0, config) and
flowCand(node, _, _, apf, unbind(config))
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp,
Configuration config
private predicate flowFwdRead0(
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
boolean fromArg, AccessPathOption argAp, Configuration config
) {
exists(Node mid, AccessPathFrontHead apf0 |
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
readCand2(mid, f, node, config) and
apf0.headUsesContent(f) and
flowCand(node, _, _, _, unbind(config))
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
readCandFwd(node1, tc, apf0, node2, config)
}
pragma[nomagic]
private predicate flowFwdRead(
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
AccessPathOption argAp, Configuration config
) {
exists(Node mid, TypedContent tc |
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
flowCand(node, _, _, apf, unbind(config)) and
flowCandConsCand(tc, apf, unbind(config))
)
}
pragma[nomagic]
private predicate flowFwdConsCand(
Content f, AccessPathFront apf, AccessPath ap, Configuration config
TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config
) {
exists(Node n |
flowFwd(n, _, _, apf, ap, config) and
flowFwdStore1(n, f, _, apf, _, config)
flowFwdStore0(n, tc, _, apf, _, config)
)
}
@@ -1863,9 +1885,9 @@ private predicate flow0(
)
or
// store
exists(Content f |
flowStore(f, node, toReturn, returnAp, ap, config) and
flowConsCand(f, ap, config)
exists(TypedContent tc |
flowStore(tc, node, toReturn, returnAp, ap, config) and
flowConsCand(tc, ap, config)
)
or
// read
@@ -1895,39 +1917,41 @@ private predicate flow0(
pragma[nomagic]
private predicate storeFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
storeCand2(node1, f, node2, config) and
flowFwdStore(node2, f, ap, _, _, _, config) and
ap0 = push(f, ap)
storeCand2(node1, tc, node2, _, config) and
flowFwdStore(node2, tc, ap, _, _, _, config) and
ap0 = push(tc, ap)
}
pragma[nomagic]
private predicate flowStore(
Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
Configuration config
) {
exists(Node mid, AccessPath ap0 |
storeFlowFwd(node, f, mid, ap, ap0, config) and
storeFlowFwd(node, tc, mid, ap, ap0, config) and
flow(mid, toReturn, returnAp, ap0, config)
)
}
pragma[nomagic]
private predicate readFlowFwd(
Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config
Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config
) {
readCand2(node1, f, node2, config) and
flowFwdRead(node2, f, ap, _, _, config) and
ap0 = pop(f, ap) and
flowFwdConsCand(f, _, ap0, unbind(config))
exists(AccessPathFrontHead apf |
readCandFwd(node1, tc, apf, node2, config) and
flowFwdRead(node2, apf, ap, _, _, _, config) and
ap0 = pop(tc, ap) and
flowFwdConsCand(tc, _, ap0, unbind(config))
)
}
pragma[nomagic]
private predicate flowConsCand(Content f, AccessPath ap, Configuration config) {
private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) {
exists(Node n, Node mid |
flow(mid, _, _, ap, config) and
readFlowFwd(n, f, mid, _, ap, config)
readFlowFwd(n, tc, mid, _, ap, config)
)
}
@@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
or
exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and
exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
or
pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp()
@@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
}
pragma[nomagic]
private predicate readCand(Node node1, Content f, Node node2, Configuration config) {
read(node1, f, node2) and
private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) {
readCandFwd(node1, tc, _, node2, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) {
private predicate pathReadStep(
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
readCand(mid.getNode(), f, node, mid.getConfiguration()) and
readCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
pragma[nomagic]
private predicate storeCand(Node node1, Content f, Node node2, Configuration config) {
store(node1, f, node2) and
private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) {
storeCand2(node1, tc, node2, _, config) and
flow(node2, config)
}
pragma[nomagic]
private predicate pathStoreStep(
PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc
PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc
) {
ap0 = mid.getAp() and
storeCand(mid.getNode(), f, node, mid.getConfiguration()) and
storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and
cc = mid.getCallContext()
}
@@ -2538,10 +2564,10 @@ private module FlowExploration {
private newtype TPartialAccessPath =
TPartialNil(DataFlowType t) or
TPartialCons(Content f, int len) { len in [1 .. 5] }
TPartialCons(TypedContent tc, int len) { len in [1 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* Conceptually a list of `TypedContent`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
@@ -2550,7 +2576,7 @@ private module FlowExploration {
private class PartialAccessPath extends TPartialAccessPath {
abstract string toString();
Content getHead() { this = TPartialCons(result, _) }
TypedContent getHead() { this = TPartialCons(result, _) }
int len() {
this = TPartialNil(_) and result = 0
@@ -2561,7 +2587,7 @@ private module FlowExploration {
DataFlowType getType() {
this = TPartialNil(result)
or
exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType())
exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType())
}
abstract AccessPathFront getFront();
@@ -2579,15 +2605,15 @@ private module FlowExploration {
private class PartialAccessPathCons extends PartialAccessPath, TPartialCons {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
exists(TypedContent tc, int len | this = TPartialCons(tc, len) |
if len = 1
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
then result = "[" + tc.toString() + "]"
else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]"
)
}
override AccessPathFront getFront() {
exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f))
exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc))
}
}
@@ -2763,11 +2789,12 @@ private module FlowExploration {
sc2 = mid.getSummaryCtx2() and
config = mid.getConfiguration()
or
exists(PartialAccessPath ap0, Content f |
partialPathReadStep(mid, ap0, f, node, cc, config) and
exists(PartialAccessPath ap0, TypedContent tc |
partialPathReadStep(mid, ap0, tc, node, cc, config) and
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, f, ap0, config)
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -2786,35 +2813,42 @@ private module FlowExploration {
pragma[inline]
private predicate partialPathStoreStep(
PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2
PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node,
PartialAccessPath ap2
) {
ap1 = mid.getAp() and
store(mid.getNode(), f, node) and
ap2.getHead() = f and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), f.getType())
exists(Node midNode, DataFlowType contentType |
midNode = mid.getNode() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
)
}
pragma[nomagic]
private predicate apConsFwd(
PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config
PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config
) {
exists(PartialPathNodePriv mid |
partialPathStoreStep(mid, ap1, f, _, ap2) and
partialPathStoreStep(mid, ap1, tc, _, ap2) and
config = mid.getConfiguration()
)
}
pragma[nomagic]
private predicate partialPathReadStep(
PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc,
PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc,
Configuration config
) {
ap = mid.getAp() and
readStep(mid.getNode(), f, node) and
ap.getHead() = f and
config = mid.getConfiguration() and
cc = mid.getCallContext()
exists(Node midNode |
midNode = mid.getNode() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node) and
ap.getHead() = tc and
config = mid.getConfiguration() and
cc = mid.getCallContext()
)
}
private predicate partialPathOutOfCallable0(

View File

@@ -198,123 +198,130 @@ private module Cached {
/**
* The final flow-through calculation:
*
* - Input access paths are abstracted with a `ContentOption` parameter
* that represents the head of the access path. `TContentNone()` means that
* the access path is unrestricted.
* - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`)
* or summarized as a single read step with before and after types recorded
* in the `ReadStepTypesOption` parameter.
* - Types are checked using the `compatibleTypes()` relation.
*/
private module Final {
/**
* Holds if `p` can flow to `node` in the same callable using only
* value-preserving steps, not taking call contexts into account.
* value-preserving steps and possibly a single read step, not taking
* call contexts into account.
*
* `contentIn` describes the content of `p` that can flow to `node`
* (if any).
* If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type.
*/
predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) {
parameterValueFlow0(p, node, contentIn) and
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and
if node instanceof CastingNode
then
// normal flow through
contentIn = TContentNone() and
read = TReadStepTypesNone() and
compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node))
or
// getter
exists(Content fIn |
contentIn.getContent() = fIn and
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node))
)
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node))
else any()
}
pragma[nomagic]
private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) {
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
p = node and
Cand::cand(p, _) and
contentIn = TContentNone()
read = TReadStepTypesNone()
or
// local flow
exists(Node mid |
parameterValueFlow(p, mid, contentIn) and
parameterValueFlow(p, mid, read) and
LocalFlowBigStep::localFlowBigStep(mid, node)
)
or
// read
exists(Node mid, Content f |
parameterValueFlow(p, mid, TContentNone()) and
readStep(mid, f, node) and
contentIn.getContent() = f and
exists(Node mid |
parameterValueFlow(p, mid, TReadStepTypesNone()) and
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType())
compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType())
)
or
// flow through: no prior read
exists(ArgumentNode arg |
parameterValueFlowArg(p, arg, TContentNone()) and
argumentValueFlowsThrough(arg, contentIn, node)
parameterValueFlowArg(p, arg, TReadStepTypesNone()) and
argumentValueFlowsThrough(arg, read, node)
)
or
// flow through: no read inside method
exists(ArgumentNode arg |
parameterValueFlowArg(p, arg, contentIn) and
argumentValueFlowsThrough(arg, TContentNone(), node)
parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, TReadStepTypesNone(), node)
)
}
pragma[nomagic]
private predicate parameterValueFlowArg(
ParameterNode p, ArgumentNode arg, ContentOption contentIn
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
) {
parameterValueFlow(p, arg, contentIn) and
parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _)
}
pragma[nomagic]
private predicate argumentValueFlowsThrough0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
) {
exists(ParameterNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, contentIn)
parameterValueFlowReturn(param, kind, read)
)
}
/**
* Holds if `arg` flows to `out` through a call using only value-preserving steps,
* not taking call contexts into account.
* Holds if `arg` flows to `out` through a call using only
* value-preserving steps and possibly a single read step, not taking
* call contexts into account.
*
* `contentIn` describes the content of `arg` that can flow to `out` (if any).
* If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type.
*/
pragma[nomagic]
predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) {
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, contentIn) and
argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind)
|
// normal flow through
contentIn = TContentNone() and
read = TReadStepTypesNone() and
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out))
or
// getter
exists(Content fIn |
contentIn.getContent() = fIn and
compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out))
)
compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out))
)
}
/**
* Holds if `arg` flows to `out` through a call using only
* value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step.
*/
predicate getterStep(ArgumentNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
}
/**
* Holds if `p` can flow to a return node of kind `kind` in the same
* callable using only value-preserving steps.
* callable using only value-preserving steps and possibly a single read
* step.
*
* `contentIn` describes the content of `p` that can flow to the return
* node (if any).
* If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type.
*/
private predicate parameterValueFlowReturn(
ParameterNode p, ReturnKind kind, ContentOption contentIn
ParameterNode p, ReturnKind kind, ReadStepTypesOption read
) {
exists(ReturnNode ret |
parameterValueFlow(p, ret, contentIn) and
parameterValueFlow(p, ret, read) and
kind = ret.getKind()
)
}
@@ -329,7 +336,27 @@ private module Cached {
*/
cached
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TContentNone())
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
}
private predicate store(
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
readStep(_, c, _) and
contentType = getErasedNodeTypeBound(node1) and
containerType = getErasedNodeTypeBound(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
readStep(n2, c, n1) and
contentType = getErasedNodeTypeBound(n1) and
containerType = getErasedNodeTypeBound(n2)
)
}
/**
@@ -340,17 +367,8 @@ private module Cached {
* been stored into, in order to handle cases like `x.f1.f2 = y`.
*/
cached
predicate store(Node node1, Content f, Node node2) {
storeStep(node1, f, node2) and readStep(_, f, _)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TContentSome(f), n1)
or
readStep(n2, f, n1)
)
predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) {
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
}
import FlowThrough
@@ -397,10 +415,13 @@ private module Cached {
TBooleanNone() or
TBooleanSome(boolean b) { b = true or b = false }
cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
cached
newtype TAccessPathFront =
TFrontNil(DataFlowType t) or
TFrontHead(Content f)
TFrontHead(TypedContent tc)
cached
newtype TAccessPathFrontOption =
@@ -415,25 +436,38 @@ class CastingNode extends Node {
CastingNode() {
this instanceof ParameterNode or
this instanceof CastNode or
this instanceof OutNodeExt
this instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
readStep(_, _, this)
}
}
newtype TContentOption =
TContentNone() or
TContentSome(Content f)
private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) {
readStep(n1, c, n2) and
container = getErasedNodeTypeBound(n1) and
content = getErasedNodeTypeBound(n2)
}
private class ContentOption extends TContentOption {
Content getContent() { this = TContentSome(result) }
predicate hasContent() { exists(this.getContent()) }
string toString() {
result = this.getContent().toString()
or
not this.hasContent() and
result = "<none>"
private newtype TReadStepTypesOption =
TReadStepTypesNone() or
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
readStepWithTypes(_, container, c, _, content)
}
private class ReadStepTypesOption extends TReadStepTypesOption {
predicate isSome() { this instanceof TReadStepTypesSome }
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
Content getContent() { this = TReadStepTypesSome(_, result, _) }
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
string toString() { if this.isSome() then result = "Some(..)" else result = "None()" }
}
/**
@@ -692,6 +726,23 @@ class BooleanOption extends TBooleanOption {
}
}
/** Content tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;
private DataFlowType t;
TypedContent() { this = MkTypedContent(c, t) }
/** Gets the content. */
Content getContent() { result = c }
/** Gets the container type. */
DataFlowType getContainerType() { result = t }
/** Gets a textual representation of this content. */
string toString() { result = c.toString() }
}
/**
* The front of an access path. This is either a head or a nil.
*/
@@ -702,25 +753,29 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract boolean toBoolNonEmpty();
predicate headUsesContent(Content f) { this = TFrontHead(f) }
predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override string toString() {
exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t))
}
private DataFlowType t;
override DataFlowType getType() { this = TFrontNil(result) }
AccessPathFrontNil() { this = TFrontNil(t) }
override string toString() { result = ppReprType(t) }
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
}
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) }
private TypedContent tc;
override DataFlowType getType() {
exists(Content head | this = TFrontHead(head) | result = head.getContainerType())
}
AccessPathFrontHead() { this = TFrontHead(tc) }
override string toString() { result = tc.toString() }
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
}

View File

@@ -128,8 +128,13 @@ private class SideEffectOutNode extends OutNode {
* `kind`.
*/
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
result.getCall() = call and
result.getReturnKind() = kind
// There should be only one `OutNode` for a given `(call, kind)` pair. Showing the optimizer that
// this is true helps it make better decisions downstream, especially in virtual dispatch.
result =
unique(OutNode outNode |
outNode.getCall() = call and
outNode.getReturnKind() = kind
)
}
/**
@@ -155,12 +160,6 @@ class Content extends TContent {
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
}
/** Gets the type of the object containing this content. */
abstract Type getContainerType();
/** Gets the type of this content. */
abstract Type getType();
}
private class FieldContent extends Content, TFieldContent {
@@ -175,26 +174,14 @@ private class FieldContent extends Content, TFieldContent {
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
}
override Type getContainerType() { result = f.getDeclaringType() }
override Type getType() { result = f.getType() }
}
private class CollectionContent extends Content, TCollectionContent {
override string toString() { result = "collection" }
override Type getContainerType() { none() }
override Type getType() { none() }
}
private class ArrayContent extends Content, TArrayContent {
override string toString() { result = "array" }
override Type getContainerType() { none() }
override Type getType() { none() }
}
/**

View File

@@ -111,6 +111,8 @@ private class IRSizedType extends IRType {
this = TIRFunctionAddressType(byteSize) or
this = TIROpaqueType(_, byteSize)
}
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
// overridden only in the leaf classes.
}
/**
@@ -128,7 +130,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType {
}
/**
* A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
* A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
* `IRFloatingPointType`.
*/
class IRNumericType extends IRSizedType {
@@ -137,13 +139,27 @@ class IRNumericType extends IRSizedType {
this = TIRUnsignedIntegerType(byteSize) or
this = TIRFloatingPointType(byteSize, _, _)
}
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
// overridden only in the leaf classes.
}
/**
* An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`.
*/
class IRIntegerType extends IRNumericType {
IRIntegerType() {
this = TIRSignedIntegerType(byteSize) or
this = TIRUnsignedIntegerType(byteSize)
}
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
// overridden only in the leaf classes.
}
/**
* A signed two's-complement integer. Also used to represent enums whose underlying type is a signed
* integer, as well as character types whose representation is signed.
*/
class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType {
final override string toString() { result = "int" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {
@@ -158,7 +174,7 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
* An unsigned two's-complement integer. Also used to represent enums whose underlying type is an
* unsigned integer, as well as character types whose representation is unsigned.
*/
class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType {
final override string toString() { result = "uint" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {

View File

@@ -1,29 +1,12 @@
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase
import Instruction
private newtype TIRFunction =
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
/**
* Represents the IR for a function.
* The IR for a function.
*/
class IRFunction extends TIRFunction {
Language::Function func;
IRFunction() { this = MkIRFunction(func) }
final string toString() { result = "IR: " + func.toString() }
/**
* Gets the function whose IR is represented.
*/
final Language::Function getFunction() { result = func }
/**
* Gets the location of the function.
*/
final Language::Location getLocation() { result = func.getLocation() }
class IRFunction extends IRFunctionBase {
/**
* Gets the entry point for this function.
*/

View File

@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
/**
* Represents a single operation in the IR.
*/
class Instruction extends Construction::TInstruction {
class Instruction extends Construction::TStageInstruction {
Instruction() {
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
Construction::hasInstruction(this)
}
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
/**
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
* conversion.
*/
final Language::Expr getConvertedResultExpression() {
result = Construction::getInstructionConvertedResultExpression(this)
result = Raw::getInstructionConvertedResultExpression(this)
}
/**
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
*/
final Language::Expr getUnconvertedResultExpression() {
result = Construction::getInstructionUnconvertedResultExpression(this)
result = Raw::getInstructionUnconvertedResultExpression(this)
}
final Language::LanguageType getResultLanguageType() {
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
cached
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/**
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing
* the integer value loaded from variable `x`.
*/
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
/**
* Gets the size of the result produced by this instruction, in bytes. If the
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of
* `getResultSize()` will always be the size of a pointer.
*/
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
final int getResultSize() { result = getResultLanguageType().getByteSize() }
/**
* Gets the opcode that specifies the operation performed by this instruction.
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
class VariableInstruction extends Instruction {
IRVariable var;
VariableInstruction() { var = Construction::getInstructionVariable(this) }
VariableInstruction() { var = Raw::getInstructionVariable(this) }
override string getImmediateString() { result = var.toString() }
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
class FieldInstruction extends Instruction {
Language::Field field;
FieldInstruction() { field = Construction::getInstructionField(this) }
FieldInstruction() { field = Raw::getInstructionField(this) }
final override string getImmediateString() { result = field.toString() }
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
class FunctionInstruction extends Instruction {
Language::Function funcSymbol;
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
final override string getImmediateString() { result = funcSymbol.toString() }
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
class ConstantValueInstruction extends Instruction {
string value;
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
final override string getImmediateString() { result = value }
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
}
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
IntegerConstantInstruction() {
exists(IRType resultType |
resultType = getResultIRType() and
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
)
}
}
class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
}
class StringConstantInstruction extends VariableInstruction {
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
PointerArithmeticInstruction() {
getOpcode() instanceof PointerArithmeticOpcode and
elementSize = Construction::getInstructionElementSize(this)
elementSize = Raw::getInstructionElementSize(this)
}
final override string getImmediateString() { result = elementSize.toString() }
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class derivedClass;
InheritanceConversionInstruction() {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
Raw::getInstructionInheritance(this, baseClass, derivedClass)
}
final override string getImmediateString() {
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and
exceptionType = Construction::getInstructionExceptionType(this)
exceptionType = Raw::getInstructionExceptionType(this)
}
final override string getImmediateString() { result = exceptionType.toString() }
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
BuiltInOperationInstruction() {
getOpcode() instanceof BuiltInOperationOpcode and
operation = Construction::getInstructionBuiltInOperation(this)
operation = Raw::getInstructionBuiltInOperation(this)
}
final Language::BuiltInOperation getBuiltInOperation() { result = operation }

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import SSAConstruction as Construction
import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw

View File

@@ -1,5 +1,11 @@
import SSAConstructionInternal
private import SSAConstructionImports
private import SSAConstructionImports as Imports
private import Imports::Opcode
private import Imports::OperandTag
private import Imports::Overlap
private import Imports::TInstruction
private import Imports::RawIR as RawIR
private import SSAInstructions
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
@@ -10,54 +16,47 @@ import Cached
cached
private module Cached {
cached
predicate hasPhiInstructionCached(
OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
) {
exists(OldBlock oldBlock |
definitionHasPhiNode(defLocation, oldBlock) and
blockStartInstr = oldBlock.getFirstInstruction()
)
}
cached
predicate hasChiInstructionCached(OldInstruction primaryInstruction) {
hasChiNode(_, primaryInstruction)
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and instr instanceof OldInstruction
or
instr instanceof TPhiInstruction
or
instr instanceof TChiInstruction
or
instr instanceof TUnreachedInstruction
}
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached
predicate functionHasIR(Language::Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
}
cached
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
// This is just a type cast. Both classes derive from the same newtype.
result = var
}
cached
newtype TInstruction =
WrappedInstruction(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction
} or
Phi(OldBlock block, Alias::MemoryLocation defLocation) {
definitionHasPhiNode(defLocation, block)
} or
Chi(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction and
hasChiNode(_, oldInstruction)
} or
Unreached(Language::Function function) {
exists(OldInstruction oldInstruction |
function = oldInstruction.getEnclosingFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
cached
predicate hasTempVariable(
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
exists(OldIR::IRTempVariable var |
var.getEnclosingFunction() = func and
var.getAST() = ast and
var.getTag() = tag and
var.getLanguageType() = type
)
}
cached
predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
@@ -73,7 +72,7 @@ private module Cached {
or
// Chi instructions track virtual variables, and therefore a chi instruction is
// conflated if it's associated with the aliased virtual variable.
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable
)
@@ -81,7 +80,7 @@ private module Cached {
// Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
instruction = getPhi(_, location) and
not exists(location.getAllocation())
)
}
@@ -128,7 +127,7 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
)
or
instruction = Chi(getOldInstruction(result)) and
instruction = getChi(getOldInstruction(result)) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
or
@@ -172,13 +171,15 @@ private module Cached {
pragma[noopt]
cached
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
Instruction getPhiOperandDefinition(
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
) {
exists(
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
instr = Phi(phiBlock, useLocation) and
instr = getPhi(phiBlock, useLocation) and
newPredecessorBlock = getNewBlock(predBlock) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
overlap = Alias::getOverlap(actualDefLocation, useLocation)
@@ -191,7 +192,7 @@ private module Cached {
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
chiInstr = Chi(oldInstr) and
chiInstr = getChi(oldInstr) and
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
@@ -203,21 +204,11 @@ private module Cached {
cached
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldBlock oldBlock |
instr = Phi(oldBlock, _) and
instr = getPhi(oldBlock, _) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
}
cached
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression()
}
cached
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression()
}
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
@@ -228,20 +219,20 @@ private module Cached {
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = Chi(getOldInstruction(instruction)) and
result = getChi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
else (
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = Unreached(instruction.getEnclosingFunction())
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or
exists(OldInstruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
@@ -260,137 +251,73 @@ private module Cached {
// `oldInstruction`, in which case the back edge should come out of the
// chi node instead.
if hasChiNode(_, oldInstruction)
then instruction = Chi(oldInstruction)
then instruction = getChi(oldInstruction)
else instruction = getNewInstruction(oldInstruction)
)
}
cached
Language::AST getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result = oldInstruction.getAST()
Language::AST getInstructionAST(Instruction instr) {
result = getOldInstruction(instr).getAST()
or
exists(RawIR::Instruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getAST()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result = block.getFirstInstruction().getAST()
exists(RawIR::Instruction primaryInstr |
instr = chiInstruction(primaryInstr) and
result = primaryInstr.getAST()
)
or
instruction = Unreached(result)
exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
)
}
cached
Language::LanguageType getInstructionResultType(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getResultLanguageType()
Language::LanguageType getInstructionResultType(Instruction instr) {
result = instr.(RawIR::Instruction).getResultLanguageType()
or
exists(Alias::MemoryLocation defLocation |
instr = phiInstruction(_, defLocation) and
result = defLocation.getType()
)
or
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
instruction = Chi(oldInstruction) and
hasChiNode(vvar, oldInstruction) and
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and
hasChiNode(vvar, primaryInstr) and
result = vvar.getType()
)
or
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
result = location.getType()
instr = unreachedInstruction(_) and result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instr) {
result = getOldInstruction(instr).getOpcode()
or
instr = phiInstruction(_, _) and result instanceof Opcode::Phi
or
instr = chiInstruction(_) and result instanceof Opcode::Chi
or
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
}
cached
IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) {
result = getOldInstruction(instr).getEnclosingIRFunction()
or
exists(OldInstruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getEnclosingIRFunction()
)
or
instruction = Unreached(_) and
result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getOpcode()
exists(OldInstruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
)
or
instruction instanceof Chi and
result instanceof Opcode::Chi
or
instruction instanceof Phi and
result instanceof Opcode::Phi
or
instruction instanceof Unreached and
result instanceof Opcode::Unreached
}
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result.getFunction() = oldInstruction.getEnclosingFunction()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result.getFunction() = block.getEnclosingFunction()
)
or
instruction = Unreached(result.getFunction())
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
result =
getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable())
}
cached
Language::Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached
int getInstructionIndex(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex()
}
cached
Language::Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
}
cached
string getInstructionConstantValue(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result =
getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation()
}
cached
Language::LanguageType getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
}
cached
int getInstructionElementSize(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
}
cached
predicate getInstructionInheritance(
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
) {
exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and
derivedClass = oldInstr.getDerivedClass()
)
instr = unreachedInstruction(result)
}
cached
@@ -401,7 +328,7 @@ private module Cached {
)
or
exists(OldIR::Instruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction)
)
}
@@ -409,6 +336,14 @@ private module Cached {
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
}
/**
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
@@ -588,7 +523,7 @@ module DefUse {
|
// An odd offset corresponds to the `Chi` instruction.
defOffset = oldOffset * 2 + 1 and
result = Chi(oldInstr) and
result = getChi(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
@@ -607,7 +542,7 @@ module DefUse {
or
defOffset = -1 and
hasDefinition(_, defLocation, defBlock, defOffset) and
result = Phi(defBlock, defLocation) and
result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation
}
@@ -891,7 +826,7 @@ private module CachedForDebugging {
)
or
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
instr = Phi(phiBlock, location) and
instr = getPhi(phiBlock, location) and
result =
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
if location instanceof Alias::VirtualVariable
@@ -901,7 +836,7 @@ private module CachedForDebugging {
else specificity = "s"
)
or
instr = Unreached(_) and
instr = unreachedInstruction(_) and
result = "Unreached"
}
@@ -961,3 +896,19 @@ module SSAConsistency {
)
}
}
/**
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
* of the IR. The raw stage of the IR does not expose these predicates.
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
* that all of SSA construction will be evaluated in the same stage.
*/
module SSA {
class MemoryLocation = Alias::MemoryLocation;
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2;
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
}

View File

@@ -1,3 +1,5 @@
import semmle.code.cpp.ir.implementation.Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.implementation.Opcode as Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
import semmle.code.cpp.ir.internal.Overlap as Overlap
import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction
import semmle.code.cpp.ir.implementation.raw.IR as RawIR

View File

@@ -2,5 +2,6 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import AliasedSSA as Alias

View File

@@ -0,0 +1,27 @@
/**
* Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`.
*/
private import IRFunctionBaseInternal
private newtype TIRFunction =
MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) }
/**
* The IR for a function. This base class contains only the predicates that are the same between all
* phases of the IR. Each instantiation of `IRFunction` extends this class.
*/
class IRFunctionBase extends TIRFunction {
Language::Function func;
IRFunctionBase() { this = MkIRFunction(func) }
/** Gets a textual representation of this element. */
final string toString() { result = "IR: " + func.toString() }
/** Gets the function whose IR is represented. */
final Language::Function getFunction() { result = func }
/** Gets the location of the function. */
final Language::Location getLocation() { result = func.getLocation() }
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction

View File

@@ -1,5 +1,5 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as Construction
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Construction
private import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag_
module Imports {

View File

@@ -0,0 +1,97 @@
private import TInstructionInternal
private import IRFunctionBase
private import TInstructionImports as Imports
private import Imports::IRType
private import Imports::Opcode
/**
* An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual
* branches of this type for instructions created directly from the AST (`TRawInstruction`) and for
* instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`,
* `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of
* all of the branches that can appear in that particular stage. The public `Instruction` class for
* each phase extends the `TStageInstruction` type for that stage.
*/
cached
newtype TInstruction =
TRawInstruction(
IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2
) {
IRConstruction::Raw::hasInstruction(tag1, tag2)
} or
TUnaliasedSSAPhiInstruction(
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
) {
UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or
TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or
TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc)
} or
TAliasedSSAPhiInstruction(
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
) {
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or
TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) {
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
} or
TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
}
/**
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
* unaliased SSA stage.
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
* a class alias.
*/
module UnaliasedSSAInstructions {
class TPhiInstruction = TUnaliasedSSAPhiInstruction;
TPhiInstruction phiInstruction(
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
) {
result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
}
class TChiInstruction = TUnaliasedSSAChiInstruction;
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
result = TUnaliasedSSAChiInstruction(primaryInstruction)
}
class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction;
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TUnaliasedSSAUnreachedInstruction(irFunc)
}
}
/**
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
* aliased SSA stage.
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
* a class alias.
*/
module AliasedSSAInstructions {
class TPhiInstruction = TAliasedSSAPhiInstruction;
TPhiInstruction phiInstruction(
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
) {
result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
}
class TChiInstruction = TAliasedSSAChiInstruction;
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
result = TAliasedSSAChiInstruction(primaryInstruction)
}
class TUnreachedInstruction = TAliasedSSAUnreachedInstruction;
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TAliasedSSAUnreachedInstruction(irFunc)
}
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.Opcode as Opcode

View File

@@ -0,0 +1,4 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA

View File

@@ -1,29 +1,12 @@
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase
import Instruction
private newtype TIRFunction =
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
/**
* Represents the IR for a function.
* The IR for a function.
*/
class IRFunction extends TIRFunction {
Language::Function func;
IRFunction() { this = MkIRFunction(func) }
final string toString() { result = "IR: " + func.toString() }
/**
* Gets the function whose IR is represented.
*/
final Language::Function getFunction() { result = func }
/**
* Gets the location of the function.
*/
final Language::Location getLocation() { result = func.getLocation() }
class IRFunction extends IRFunctionBase {
/**
* Gets the entry point for this function.
*/

View File

@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
/**
* Represents a single operation in the IR.
*/
class Instruction extends Construction::TInstruction {
class Instruction extends Construction::TStageInstruction {
Instruction() {
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
Construction::hasInstruction(this)
}
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
/**
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
* conversion.
*/
final Language::Expr getConvertedResultExpression() {
result = Construction::getInstructionConvertedResultExpression(this)
result = Raw::getInstructionConvertedResultExpression(this)
}
/**
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
*/
final Language::Expr getUnconvertedResultExpression() {
result = Construction::getInstructionUnconvertedResultExpression(this)
result = Raw::getInstructionUnconvertedResultExpression(this)
}
final Language::LanguageType getResultLanguageType() {
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
cached
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/**
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing
* the integer value loaded from variable `x`.
*/
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
/**
* Gets the size of the result produced by this instruction, in bytes. If the
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of
* `getResultSize()` will always be the size of a pointer.
*/
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
final int getResultSize() { result = getResultLanguageType().getByteSize() }
/**
* Gets the opcode that specifies the operation performed by this instruction.
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
class VariableInstruction extends Instruction {
IRVariable var;
VariableInstruction() { var = Construction::getInstructionVariable(this) }
VariableInstruction() { var = Raw::getInstructionVariable(this) }
override string getImmediateString() { result = var.toString() }
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
class FieldInstruction extends Instruction {
Language::Field field;
FieldInstruction() { field = Construction::getInstructionField(this) }
FieldInstruction() { field = Raw::getInstructionField(this) }
final override string getImmediateString() { result = field.toString() }
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
class FunctionInstruction extends Instruction {
Language::Function funcSymbol;
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
final override string getImmediateString() { result = funcSymbol.toString() }
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
class ConstantValueInstruction extends Instruction {
string value;
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
final override string getImmediateString() { result = value }
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
}
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
IntegerConstantInstruction() {
exists(IRType resultType |
resultType = getResultIRType() and
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
)
}
}
class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
}
class StringConstantInstruction extends VariableInstruction {
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
PointerArithmeticInstruction() {
getOpcode() instanceof PointerArithmeticOpcode and
elementSize = Construction::getInstructionElementSize(this)
elementSize = Raw::getInstructionElementSize(this)
}
final override string getImmediateString() { result = elementSize.toString() }
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class derivedClass;
InheritanceConversionInstruction() {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
Raw::getInstructionInheritance(this, baseClass, derivedClass)
}
final override string getImmediateString() {
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and
exceptionType = Construction::getInstructionExceptionType(this)
exceptionType = Raw::getInstructionExceptionType(this)
}
final override string getImmediateString() { result = exceptionType.toString() }
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
BuiltInOperationInstruction() {
getOpcode() instanceof BuiltInOperationOpcode and
operation = Construction::getInstructionBuiltInOperation(this)
operation = Raw::getInstructionBuiltInOperation(this)
}
final Language::BuiltInOperation getBuiltInOperation() { result = operation }

View File

@@ -1,6 +1,9 @@
private import cpp
import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.implementation.internal.IRFunctionBase
private import semmle.code.cpp.ir.implementation.internal.TInstruction
private import semmle.code.cpp.ir.implementation.internal.TIRVariable
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.Overlap
private import semmle.code.cpp.ir.internal.TempVariableTag
@@ -12,34 +15,36 @@ private import TranslatedStmt
private import TranslatedFunction
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
instruction = MkInstruction(result, _)
instruction = TRawInstruction(result, _)
}
InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) }
import Cached
InstructionTag getInstructionTag(Instruction instruction) {
instruction = TRawInstruction(_, result)
}
/**
* Provides the portion of the parameterized IR interface that is used to construct the initial
* "raw" stage of the IR. The other stages of the IR do not expose these predicates.
*/
cached
private module Cached {
module Raw {
class InstructionTag1 = TranslatedElement;
class InstructionTag2 = InstructionTag;
cached
predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) }
cached
newtype TInstruction =
MkInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _)
}
predicate hasInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _)
}
cached
predicate hasUserVariable(Function func, Variable var, CppType type) {
getTranslatedFunction(func).hasUserVariable(var, type)
}
cached
predicate hasThisVariable(Function func, CppType type) {
type = getTypeForGLValue(getTranslatedFunction(func).getThisType())
}
cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
exists(TranslatedElement element |
@@ -64,232 +69,7 @@ private module Cached {
}
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
cached
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
}
cached
Expr getInstructionConvertedResultExpression(Instruction instruction) {
exists(TranslatedExpr translatedExpr |
translatedExpr = getTranslatedExpr(result) and
instruction = translatedExpr.getResult() and
// Only associate `instruction` with this expression if the translated
// expression actually produced the instruction; not if it merely
// forwarded the result of another translated expression.
instruction = translatedExpr.getInstruction(_)
)
}
cached
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionRegisterOperand(getInstructionTag(instruction), tag)
}
cached
Instruction getMemoryOperandDefinition(
Instruction instruction, MemoryOperandTag tag, Overlap overlap
) {
none()
}
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = getRegisterOperandDefinition(instr, _)
or
result = getMemoryOperandDefinition(instr, _, _)
}
/**
* Gets a non-phi instruction that defines an operand of `instr` but only if
* both `instr` and the result have neighbor on the other side of the edge
* between them. This is a necessary condition for being in a cycle, and it
* removes about two thirds of the tuples that would otherwise be in this
* predicate.
*/
private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) {
result = getNonPhiOperandDef(instr) and
exists(getNonPhiOperandDef(result)) and
instr = getNonPhiOperandDef(_)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
cached
predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDefOfIntermediate+(instr) = instr
}
cached
CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as
// the result type of the load.
tag instanceof LoadOperandTag and
result = instruction.(LoadInstruction).getResultLanguageType()
or
not instruction instanceof LoadInstruction and
result =
getInstructionTranslatedElement(instruction)
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
}
cached
Instruction getPhiOperandDefinition(
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
) {
none()
}
cached
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionSuccessor(getInstructionTag(instruction), kind)
}
/**
* Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`-->
* `targetInstruction` is a back edge under the condition that
* `requiredAncestor` is an ancestor of `sourceElement`.
*/
private predicate backEdgeCandidate(
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor,
Instruction targetInstruction, EdgeKind kind
) {
// While loop:
// Any edge from within the body of the loop to the condition of the loop
// is a back edge. This includes edges from `continue` and the fall-through
// edge(s) after the last instruction(s) in the body.
exists(TranslatedWhileStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getBody()
)
or
// Do-while loop:
// The back edge should be the edge(s) from the condition to the
// body. This ensures that it's the back edge that will be pruned in a `do
// { ... } while (0)` statement. Note that all `continue` statements in a
// do-while loop produce forward edges.
exists(TranslatedDoStmt s |
targetInstruction = s.getBody().getFirstInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getCondition()
)
or
// For loop:
// Any edge from within the body or update of the loop to the condition of
// the loop is a back edge. When there is no loop update expression, this
// includes edges from `continue` and the fall-through edge(s) after the
// last instruction(s) in the body. A for loop may not have a condition, in
// which case `getFirstConditionInstruction` returns the body instead.
exists(TranslatedForStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
(
requiredAncestor = s.getUpdate()
or
not exists(s.getUpdate()) and
requiredAncestor = s.getBody()
)
)
or
// Range-based for loop:
// Any edge from within the update of the loop to the condition of
// the loop is a back edge.
exists(TranslatedRangeBasedForStmt s |
targetInstruction = s.getCondition().getFirstInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getUpdate()
)
}
private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) {
backEdgeCandidate(jumpSource, _, _, _, _) and
ancestor = jumpSource
or
// For performance, we don't want a fastTC here
jumpSourceHasAncestor(jumpSource, ancestor.getAChild())
}
cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor
|
backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and
jumpSourceHasAncestor(sourceElement, requiredAncestor) and
instruction = sourceElement.getInstruction(sourceTag)
)
or
// Goto statement:
// As a conservative approximation, any edge out of `goto` is a back edge
// unless it goes strictly forward in the program text. A `goto` whose
// source and target are both inside a macro will be seen as having the
// same location for source and target, so we conservatively assume that
// such a `goto` creates a back edge.
exists(TranslatedElement s, GotoStmt goto |
not isStrictlyForwardGoto(goto) and
goto = s.getAST() and
exists(InstructionTag tag |
result = s.getInstructionSuccessor(tag, kind) and
instruction = s.getInstruction(tag)
)
)
}
/** Holds if `goto` jumps strictly forward in the program text. */
private predicate isStrictlyForwardGoto(GotoStmt goto) {
goto.getLocation().isBefore(goto.getTarget().getLocation())
}
cached
Locatable getInstructionAST(Instruction instruction) {
result = getInstructionTranslatedElement(instruction).getAST()
}
cached
CppType getInstructionResultType(Instruction instruction) {
getInstructionTranslatedElement(instruction)
.hasInstruction(_, getInstructionTag(instruction), result)
}
cached
Opcode getInstructionOpcode(Instruction instruction) {
getInstructionTranslatedElement(instruction)
.hasInstruction(result, getInstructionTag(instruction), _)
}
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
result.getFunction() = getInstructionTranslatedElement(instruction).getFunction()
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
TIRVariable getInstructionVariable(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction) and
@@ -302,10 +82,9 @@ private module Cached {
cached
Field getInstructionField(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionField(tag)
)
result =
getInstructionTranslatedElement(instruction)
.getInstructionField(getInstructionTag(instruction))
}
cached
@@ -324,10 +103,9 @@ private module Cached {
cached
int getInstructionIndex(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionIndex(tag)
)
result =
getInstructionTranslatedElement(instruction)
.getInstructionIndex(getInstructionTag(instruction))
}
cached
@@ -350,20 +128,11 @@ private module Cached {
.getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass)
}
pragma[noinline]
private predicate instructionOrigin(
Instruction instruction, TranslatedElement element, InstructionTag tag
) {
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction)
}
cached
int getInstructionElementSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionElementSize(tag)
)
result =
getInstructionTranslatedElement(instruction)
.getInstructionElementSize(getInstructionTag(instruction))
}
cached
@@ -372,22 +141,225 @@ private module Cached {
}
cached
int getInstructionResultSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionResultSize(tag)
Expr getInstructionConvertedResultExpression(Instruction instruction) {
exists(TranslatedExpr translatedExpr |
translatedExpr = getTranslatedExpr(result) and
instruction = translatedExpr.getResult() and
// Only associate `instruction` with this expression if the translated
// expression actually produced the instruction; not if it merely
// forwarded the result of another translated expression.
instruction = translatedExpr.getInstruction(_)
)
}
cached
Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getPrimaryInstructionForSideEffect(tag)
)
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
}
}
class TStageInstruction = TRawInstruction;
predicate hasInstruction(TRawInstruction instr) { any() }
predicate hasModeledMemoryResult(Instruction instruction) { none() }
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
}
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionRegisterOperand(getInstructionTag(instruction), tag)
}
Instruction getMemoryOperandDefinition(
Instruction instruction, MemoryOperandTag tag, Overlap overlap
) {
none()
}
/** Gets a non-phi instruction that defines an operand of `instr`. */
private Instruction getNonPhiOperandDef(Instruction instr) {
result = getRegisterOperandDefinition(instr, _)
or
result = getMemoryOperandDefinition(instr, _, _)
}
/**
* Gets a non-phi instruction that defines an operand of `instr` but only if
* both `instr` and the result have neighbor on the other side of the edge
* between them. This is a necessary condition for being in a cycle, and it
* removes about two thirds of the tuples that would otherwise be in this
* predicate.
*/
private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) {
result = getNonPhiOperandDef(instr) and
exists(getNonPhiOperandDef(result)) and
instr = getNonPhiOperandDef(_)
}
/**
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
* through a phi instruction and therefore should be impossible.
*
* If such cycles are present, either due to a programming error in the IR
* generation or due to a malformed database, it can cause infinite loops in
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
* better to remove these operands than to leave cycles in the operand graph.
*/
pragma[noopt]
predicate isInCycle(Instruction instr) {
instr instanceof Instruction and
getNonPhiOperandDefOfIntermediate+(instr) = instr
}
CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as
// the result type of the load.
tag instanceof LoadOperandTag and
result = instruction.(LoadInstruction).getResultLanguageType()
or
not instruction instanceof LoadInstruction and
result =
getInstructionTranslatedElement(instruction)
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
}
Instruction getPhiOperandDefinition(
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
) {
none()
}
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionSuccessor(getInstructionTag(instruction), kind)
}
/**
* Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`-->
* `targetInstruction` is a back edge under the condition that
* `requiredAncestor` is an ancestor of `sourceElement`.
*/
private predicate backEdgeCandidate(
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor,
Instruction targetInstruction, EdgeKind kind
) {
// While loop:
// Any edge from within the body of the loop to the condition of the loop
// is a back edge. This includes edges from `continue` and the fall-through
// edge(s) after the last instruction(s) in the body.
exists(TranslatedWhileStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getBody()
)
or
// Do-while loop:
// The back edge should be the edge(s) from the condition to the
// body. This ensures that it's the back edge that will be pruned in a `do
// { ... } while (0)` statement. Note that all `continue` statements in a
// do-while loop produce forward edges.
exists(TranslatedDoStmt s |
targetInstruction = s.getBody().getFirstInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getCondition()
)
or
// For loop:
// Any edge from within the body or update of the loop to the condition of
// the loop is a back edge. When there is no loop update expression, this
// includes edges from `continue` and the fall-through edge(s) after the
// last instruction(s) in the body. A for loop may not have a condition, in
// which case `getFirstConditionInstruction` returns the body instead.
exists(TranslatedForStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
(
requiredAncestor = s.getUpdate()
or
not exists(s.getUpdate()) and
requiredAncestor = s.getBody()
)
)
or
// Range-based for loop:
// Any edge from within the update of the loop to the condition of
// the loop is a back edge.
exists(TranslatedRangeBasedForStmt s |
targetInstruction = s.getCondition().getFirstInstruction() and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getUpdate()
)
}
private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) {
backEdgeCandidate(jumpSource, _, _, _, _) and
ancestor = jumpSource
or
// For performance, we don't want a fastTC here
jumpSourceHasAncestor(jumpSource, ancestor.getAChild())
}
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor
|
backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and
jumpSourceHasAncestor(sourceElement, requiredAncestor) and
instruction = sourceElement.getInstruction(sourceTag)
)
or
// Goto statement:
// As a conservative approximation, any edge out of `goto` is a back edge
// unless it goes strictly forward in the program text. A `goto` whose
// source and target are both inside a macro will be seen as having the
// same location for source and target, so we conservatively assume that
// such a `goto` creates a back edge.
exists(TranslatedElement s, GotoStmt goto |
not isStrictlyForwardGoto(goto) and
goto = s.getAST() and
exists(InstructionTag tag |
result = s.getInstructionSuccessor(tag, kind) and
instruction = s.getInstruction(tag)
)
)
}
/** Holds if `goto` jumps strictly forward in the program text. */
private predicate isStrictlyForwardGoto(GotoStmt goto) {
goto.getLocation().isBefore(goto.getTarget().getLocation())
}
Locatable getInstructionAST(TStageInstruction instr) {
result = getInstructionTranslatedElement(instr).getAST()
}
CppType getInstructionResultType(TStageInstruction instr) {
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
}
Opcode getInstructionOpcode(TStageInstruction instr) {
getInstructionTranslatedElement(instr).hasInstruction(result, getInstructionTag(instr), _)
}
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
result.getFunction() = getInstructionTranslatedElement(instr).getFunction()
}
Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getPrimaryInstructionForSideEffect(getInstructionTag(instruction))
}
import CachedForDebugging
cached

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import IRConstruction as Construction
import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration
import IRConstruction::Raw as Raw

View File

@@ -705,12 +705,8 @@ abstract class TranslatedElement extends TTranslatedElement {
int getInstructionElementSize(InstructionTag tag) { none() }
/**
* If the instruction specified by `tag` has a result of type `UnknownType`,
* gets the size of the result in bytes. If the result does not have a knonwn
* constant size, this predicate does not hold.
* Holds if the generated IR refers to an opaque type with size `byteSize`.
*/
int getInstructionResultSize(InstructionTag tag) { none() }
predicate needsUnknownOpaqueType(int byteSize) { none() }
/**

View File

@@ -415,17 +415,6 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
)
}
override int getInstructionResultSize(InstructionTag tag) {
exists(int elementCount |
zeroInitRange(_, elementCount) and
(
tag = ZeroPadStringConstantTag() or
tag = ZeroPadStringStoreTag()
) and
result = elementCount * getElementType().getSize()
)
}
private Type getElementType() {
result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType()
}
@@ -772,15 +761,6 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
result = getZeroValue(getElementType())
}
override int getInstructionResultSize(InstructionTag tag) {
elementCount > 1 and
(
tag = getElementDefaultValueTag() or
tag = getElementDefaultValueStoreTag()
) and
result = elementCount * getElementType().getSize()
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
result = TranslatedElementInitialization.super.getInstructionRegisterOperand(tag, operandTag)
or

View File

@@ -1,29 +1,12 @@
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase
import Instruction
private newtype TIRFunction =
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
/**
* Represents the IR for a function.
* The IR for a function.
*/
class IRFunction extends TIRFunction {
Language::Function func;
IRFunction() { this = MkIRFunction(func) }
final string toString() { result = "IR: " + func.toString() }
/**
* Gets the function whose IR is represented.
*/
final Language::Function getFunction() { result = func }
/**
* Gets the location of the function.
*/
final Language::Location getLocation() { result = func.getLocation() }
class IRFunction extends IRFunctionBase {
/**
* Gets the entry point for this function.
*/

View File

@@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil
/**
* Represents a single operation in the IR.
*/
class Instruction extends Construction::TInstruction {
class Instruction extends Construction::TStageInstruction {
Instruction() {
// The base `TStageInstruction` type is a superset of the actual instructions appearing in this
// stage. This call lets the stage filter out the ones that are not reused from raw IR.
Construction::hasInstruction(this)
}
final string toString() { result = getOpcode().toString() + ": " + getAST().toString() }
/**
@@ -194,14 +200,14 @@ class Instruction extends Construction::TInstruction {
* conversion.
*/
final Language::Expr getConvertedResultExpression() {
result = Construction::getInstructionConvertedResultExpression(this)
result = Raw::getInstructionConvertedResultExpression(this)
}
/**
* Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any.
*/
final Language::Expr getUnconvertedResultExpression() {
result = Construction::getInstructionUnconvertedResultExpression(this)
result = Raw::getInstructionUnconvertedResultExpression(this)
}
final Language::LanguageType getResultLanguageType() {
@@ -212,6 +218,7 @@ class Instruction extends Construction::TInstruction {
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
cached
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/**
@@ -250,7 +257,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing
* the integer value loaded from variable `x`.
*/
final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
final predicate isGLValue() { getResultLanguageType().hasType(_, true) }
/**
* Gets the size of the result produced by this instruction, in bytes. If the
@@ -259,7 +266,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of
* `getResultSize()` will always be the size of a pointer.
*/
final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
final int getResultSize() { result = getResultLanguageType().getByteSize() }
/**
* Gets the opcode that specifies the operation performed by this instruction.
@@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction {
class VariableInstruction extends Instruction {
IRVariable var;
VariableInstruction() { var = Construction::getInstructionVariable(this) }
VariableInstruction() { var = Raw::getInstructionVariable(this) }
override string getImmediateString() { result = var.toString() }
@@ -410,7 +417,7 @@ class VariableInstruction extends Instruction {
class FieldInstruction extends Instruction {
Language::Field field;
FieldInstruction() { field = Construction::getInstructionField(this) }
FieldInstruction() { field = Raw::getInstructionField(this) }
final override string getImmediateString() { result = field.toString() }
@@ -420,7 +427,7 @@ class FieldInstruction extends Instruction {
class FunctionInstruction extends Instruction {
Language::Function funcSymbol;
FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) }
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
final override string getImmediateString() { result = funcSymbol.toString() }
@@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction {
class ConstantValueInstruction extends Instruction {
string value;
ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) }
ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) }
final override string getImmediateString() { result = value }
@@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction {
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
IndexedInstruction() { index = Raw::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
@@ -603,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction {
}
class IntegerConstantInstruction extends ConstantInstruction {
IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType }
IntegerConstantInstruction() {
exists(IRType resultType |
resultType = getResultIRType() and
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
)
}
}
class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType }
}
class StringConstantInstruction extends VariableInstruction {
@@ -704,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
PointerArithmeticInstruction() {
getOpcode() instanceof PointerArithmeticOpcode and
elementSize = Construction::getInstructionElementSize(this)
elementSize = Raw::getInstructionElementSize(this)
}
final override string getImmediateString() { result = elementSize.toString() }
@@ -753,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Language::Class derivedClass;
InheritanceConversionInstruction() {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
Raw::getInstructionInheritance(this, baseClass, derivedClass)
}
final override string getImmediateString() {
@@ -1216,7 +1228,7 @@ class CatchByTypeInstruction extends CatchInstruction {
CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and
exceptionType = Construction::getInstructionExceptionType(this)
exceptionType = Raw::getInstructionExceptionType(this)
}
final override string getImmediateString() { result = exceptionType.toString() }
@@ -1362,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction {
BuiltInOperationInstruction() {
getOpcode() instanceof BuiltInOperationOpcode and
operation = Construction::getInstructionBuiltInOperation(this)
operation = Raw::getInstructionBuiltInOperation(this)
}
final Language::BuiltInOperation getBuiltInOperation() { result = operation }

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import SSAConstruction as Construction
import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw

View File

@@ -1,5 +1,11 @@
import SSAConstructionInternal
private import SSAConstructionImports
private import SSAConstructionImports as Imports
private import Imports::Opcode
private import Imports::OperandTag
private import Imports::Overlap
private import Imports::TInstruction
private import Imports::RawIR as RawIR
private import SSAInstructions
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
@@ -10,54 +16,47 @@ import Cached
cached
private module Cached {
cached
predicate hasPhiInstructionCached(
OldInstruction blockStartInstr, Alias::MemoryLocation defLocation
) {
exists(OldBlock oldBlock |
definitionHasPhiNode(defLocation, oldBlock) and
blockStartInstr = oldBlock.getFirstInstruction()
)
}
cached
predicate hasChiInstructionCached(OldInstruction primaryInstruction) {
hasChiNode(_, primaryInstruction)
}
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
class TStageInstruction =
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and instr instanceof OldInstruction
or
instr instanceof TPhiInstruction
or
instr instanceof TChiInstruction
or
instr instanceof TUnreachedInstruction
}
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached
predicate functionHasIR(Language::Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
}
cached
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
// This is just a type cast. Both classes derive from the same newtype.
result = var
}
cached
newtype TInstruction =
WrappedInstruction(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction
} or
Phi(OldBlock block, Alias::MemoryLocation defLocation) {
definitionHasPhiNode(defLocation, block)
} or
Chi(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction and
hasChiNode(_, oldInstruction)
} or
Unreached(Language::Function function) {
exists(OldInstruction oldInstruction |
function = oldInstruction.getEnclosingFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
cached
predicate hasTempVariable(
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
exists(OldIR::IRTempVariable var |
var.getEnclosingFunction() = func and
var.getAST() = ast and
var.getTag() = tag and
var.getLanguageType() = type
)
}
cached
predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
@@ -73,7 +72,7 @@ private module Cached {
or
// Chi instructions track virtual variables, and therefore a chi instruction is
// conflated if it's associated with the aliased virtual variable.
exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) |
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
Alias::AliasedVirtualVariable
)
@@ -81,7 +80,7 @@ private module Cached {
// Phi instructions track locations, and therefore a phi instruction is
// conflated if it's associated with a conflated location.
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
instruction = getPhi(_, location) and
not exists(location.getAllocation())
)
}
@@ -128,7 +127,7 @@ private module Cached {
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
)
or
instruction = Chi(getOldInstruction(result)) and
instruction = getChi(getOldInstruction(result)) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
or
@@ -172,13 +171,15 @@ private module Cached {
pragma[noopt]
cached
Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) {
Instruction getPhiOperandDefinition(
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
) {
exists(
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
instr = Phi(phiBlock, useLocation) and
instr = getPhi(phiBlock, useLocation) and
newPredecessorBlock = getNewBlock(predBlock) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
overlap = Alias::getOverlap(actualDefLocation, useLocation)
@@ -191,7 +192,7 @@ private module Cached {
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
chiInstr = Chi(oldInstr) and
chiInstr = getChi(oldInstr) and
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
@@ -203,21 +204,11 @@ private module Cached {
cached
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldBlock oldBlock |
instr = Phi(oldBlock, _) and
instr = getPhi(oldBlock, _) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
}
cached
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression()
}
cached
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression()
}
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
@@ -228,20 +219,20 @@ private module Cached {
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = Chi(getOldInstruction(instruction)) and
result = getChi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
else (
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = Unreached(instruction.getEnclosingFunction())
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or
exists(OldInstruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
@@ -260,137 +251,73 @@ private module Cached {
// `oldInstruction`, in which case the back edge should come out of the
// chi node instead.
if hasChiNode(_, oldInstruction)
then instruction = Chi(oldInstruction)
then instruction = getChi(oldInstruction)
else instruction = getNewInstruction(oldInstruction)
)
}
cached
Language::AST getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result = oldInstruction.getAST()
Language::AST getInstructionAST(Instruction instr) {
result = getOldInstruction(instr).getAST()
or
exists(RawIR::Instruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getAST()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result = block.getFirstInstruction().getAST()
exists(RawIR::Instruction primaryInstr |
instr = chiInstruction(primaryInstr) and
result = primaryInstr.getAST()
)
or
instruction = Unreached(result)
exists(IRFunctionBase irFunc |
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
)
}
cached
Language::LanguageType getInstructionResultType(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getResultLanguageType()
Language::LanguageType getInstructionResultType(Instruction instr) {
result = instr.(RawIR::Instruction).getResultLanguageType()
or
exists(Alias::MemoryLocation defLocation |
instr = phiInstruction(_, defLocation) and
result = defLocation.getType()
)
or
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
instruction = Chi(oldInstruction) and
hasChiNode(vvar, oldInstruction) and
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
instr = chiInstruction(primaryInstr) and
hasChiNode(vvar, primaryInstr) and
result = vvar.getType()
)
or
exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and
result = location.getType()
instr = unreachedInstruction(_) and result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instr) {
result = getOldInstruction(instr).getOpcode()
or
instr = phiInstruction(_, _) and result instanceof Opcode::Phi
or
instr = chiInstruction(_) and result instanceof Opcode::Chi
or
instr = unreachedInstruction(_) and result instanceof Opcode::Unreached
}
cached
IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) {
result = getOldInstruction(instr).getEnclosingIRFunction()
or
exists(OldInstruction blockStartInstr |
instr = phiInstruction(blockStartInstr, _) and
result = blockStartInstr.getEnclosingIRFunction()
)
or
instruction = Unreached(_) and
result = Language::getVoidType()
}
cached
Opcode getInstructionOpcode(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getOpcode()
exists(OldInstruction primaryInstr |
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
)
or
instruction instanceof Chi and
result instanceof Opcode::Chi
or
instruction instanceof Phi and
result instanceof Opcode::Phi
or
instruction instanceof Unreached and
result instanceof Opcode::Unreached
}
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
instruction = Chi(oldInstruction)
|
result.getFunction() = oldInstruction.getEnclosingFunction()
)
or
exists(OldBlock block |
instruction = Phi(block, _) and
result.getFunction() = block.getEnclosingFunction()
)
or
instruction = Unreached(result.getFunction())
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
result =
getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable())
}
cached
Language::Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached
int getInstructionIndex(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex()
}
cached
Language::Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
}
cached
string getInstructionConstantValue(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result =
getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation()
}
cached
Language::LanguageType getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
}
cached
int getInstructionElementSize(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
}
cached
predicate getInstructionInheritance(
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
) {
exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and
derivedClass = oldInstr.getDerivedClass()
)
instr = unreachedInstruction(result)
}
cached
@@ -401,7 +328,7 @@ private module Cached {
)
or
exists(OldIR::Instruction oldInstruction |
instruction = Chi(oldInstruction) and
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction)
)
}
@@ -409,6 +336,14 @@ private module Cached {
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
}
/**
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
* of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the
@@ -588,7 +523,7 @@ module DefUse {
|
// An odd offset corresponds to the `Chi` instruction.
defOffset = oldOffset * 2 + 1 and
result = Chi(oldInstr) and
result = getChi(oldInstr) and
(
defLocation = Alias::getResultMemoryLocation(oldInstr) or
defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable()
@@ -607,7 +542,7 @@ module DefUse {
or
defOffset = -1 and
hasDefinition(_, defLocation, defBlock, defOffset) and
result = Phi(defBlock, defLocation) and
result = getPhi(defBlock, defLocation) and
actualDefLocation = defLocation
}
@@ -891,7 +826,7 @@ private module CachedForDebugging {
)
or
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
instr = Phi(phiBlock, location) and
instr = getPhi(phiBlock, location) and
result =
"Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
if location instanceof Alias::VirtualVariable
@@ -901,7 +836,7 @@ private module CachedForDebugging {
else specificity = "s"
)
or
instr = Unreached(_) and
instr = unreachedInstruction(_) and
result = "Unreached"
}
@@ -961,3 +896,19 @@ module SSAConsistency {
)
}
}
/**
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
* of the IR. The raw stage of the IR does not expose these predicates.
* These predicates are all just aliases for predicates defined in the `Cached` module. This ensures
* that all of SSA construction will be evaluated in the same stage.
*/
module SSA {
class MemoryLocation = Alias::MemoryLocation;
predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2;
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
}

View File

@@ -1,3 +1,5 @@
import semmle.code.cpp.ir.implementation.Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.implementation.Opcode as Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
import semmle.code.cpp.ir.internal.Overlap as Overlap
import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction
import semmle.code.cpp.ir.implementation.raw.IR as RawIR

View File

@@ -2,5 +2,7 @@ import semmle.code.cpp.ir.implementation.raw.IR as OldIR
import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import SimpleSSA as Alias

View File

@@ -1,7 +1,7 @@
private import cpp
private import semmle.code.cpp.Print
private import semmle.code.cpp.ir.implementation.IRType
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw
private int getPointerSize() { result = max(any(NullPointerType t).getSize()) }
@@ -143,7 +143,7 @@ private predicate isOpaqueType(Type type) {
predicate hasOpaqueType(Type tag, int byteSize) {
isOpaqueType(tag) and byteSize = getTypeSize(tag)
or
tag instanceof UnknownType and IRConstruction::needsUnknownOpaqueType(byteSize)
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
}
/**
@@ -191,7 +191,7 @@ private newtype TCppType =
TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or
TFunctionGLValueType() or
TGLValueAddressType(Type type) or
TUnknownOpaqueType(int byteSize) { IRConstruction::needsUnknownOpaqueType(byteSize) } or
TUnknownOpaqueType(int byteSize) { Raw::needsUnknownOpaqueType(byteSize) } or
TUnknownType()
/**

View File

@@ -0,0 +1,159 @@
#include "shared.h"
typedef unsigned long size_t;
namespace std
{
template<class charT> struct char_traits;
typedef size_t streamsize;
template <class T> class allocator {
public:
allocator() throw();
};
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
class basic_string {
public:
explicit basic_string(const Allocator& a = Allocator());
basic_string(const charT* s, const Allocator& a = Allocator());
const charT* c_str() const;
};
typedef basic_string<char> string;
template <class charT, class traits = char_traits<charT> >
class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
basic_istream<charT,traits>& operator>>(int& n);
};
template <class charT, class traits = char_traits<charT> >
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
typedef charT char_type;
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
basic_ostream<charT, traits>& operator<<(int n);
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT, traits, Allocator>& str);
template<class charT, class traits = char_traits<charT>>
class basic_iostream : public basic_istream<charT, traits>, public basic_ostream<charT, traits> {
public:
};
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
class basic_stringstream : public basic_iostream<charT, traits> {
public:
explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/);
basic_string<charT, traits, Allocator> str() const;
};
using stringstream = basic_stringstream<char>;
}
char *source() { return getenv("USERDATA"); }
void sink(const std::string &s) {};
void sink(const std::stringstream &s) {};
void test_string()
{
char *a = source();
std::string b("123");
std::string c(source());
sink(a); // tainted
sink(b);
sink(c); // tainted [NOT DETECTED]
sink(b.c_str());
sink(c.c_str()); // tainted [NOT DETECTED]
}
void test_stringstream()
{
std::stringstream ss1, ss2, ss3, ss4, ss5;
std::string t(source());
ss1 << "1234";
ss2 << source();
ss3 << "123" << source();
ss4 << source() << "456";
ss5 << t;
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss3); // tainted [NOT DETECTED]
sink(ss4); // tainted [NOT DETECTED]
sink(ss5); // tainted [NOT DETECTED]
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
sink(ss3.str()); // tainted [NOT DETECTED]
sink(ss4.str()); // tainted [NOT DETECTED]
sink(ss5.str()); // tainted [NOT DETECTED]
}
void test_stringstream_int(int source)
{
std::stringstream ss1, ss2;
ss1 << 1234;
ss2 << source;
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
}
using namespace std;
char *user_input() {
return source();
}
void sink(const char *filename, const char *mode);
void test_strings2()
{
string path1 = user_input();
sink(path1.c_str(), "r"); // tainted [NOT DETECTED]
string path2;
path2 = user_input();
sink(path2.c_str(), "r"); // tainted
string path3(user_input());
sink(path3.c_str(), "r"); // tainted [NOT DETECTED]
}
void test_string3()
{
const char *cs = source();
// convert char * -> std::string
std::string ss(cs);
sink(cs); // tainted
sink(ss); // tainted [NOT DETECTED]
}
void test_string4()
{
const char *cs = source();
// convert char * -> std::string
std::string ss(cs);
// convert back std::string -> char *
cs = ss.c_str();
sink(cs); // tainted [NOT DETECTED]
sink(ss); // tainted [NOT DETECTED]
}

View File

@@ -153,6 +153,50 @@
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:15:13:20 | call to getenv |
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:16:15:16:21 | global2 |
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:15:23:20 | call to getenv |
| stl.cpp:62:25:62:30 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:21:29:21:29 | s |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | p#1 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:21 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:23 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | a |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:21 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:14 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:16 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:23 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:25 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:14 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:118:10:118:15 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:26 | call to user_input |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:28 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:19 | call to user_input |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:24 | call to user_input |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:26 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:14:138:15 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:24 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:26 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:18 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:143:7:143:8 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:14:149:15 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:24 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:26 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:18 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string |
| test_diff.cpp:92:10:92:13 | argv | shared.h:5:23:5:31 | sinkparam |
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:13 | argv |
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | (const char *)... |

View File

@@ -31,6 +31,20 @@
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:150:13:150:14 | & ... | IR only |
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only |
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:7:62:12 | source | AST only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:117:7:117:16 | user_input | AST only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | IR only |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:157:7:157:8 | cs | AST only |
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only |
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:36:24:36:24 | p | AST only |
| test_diff.cpp:111:10:111:13 | argv | shared.h:5:23:5:31 | sinkparam | AST only |

View File

@@ -312,31 +312,42 @@
| stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT |
| stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | |
| stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT |
| stl.cpp:138:18:138:24 | hello | stl.cpp:138:18:138:25 | call to basic_string | TAINT |
| stl.cpp:138:18:138:25 | call to basic_string | stl.cpp:143:8:143:9 | s1 | |
| stl.cpp:139:19:139:26 | call to basic_string | stl.cpp:144:8:144:9 | s2 | |
| stl.cpp:139:20:139:26 | hello | stl.cpp:139:19:139:26 | call to basic_string | TAINT |
| stl.cpp:141:8:141:14 | call to basic_string | stl.cpp:141:3:141:14 | ... = ... | |
| stl.cpp:141:8:141:14 | call to basic_string | stl.cpp:145:8:145:9 | s3 | |
| stl.cpp:141:8:141:14 | hello | stl.cpp:141:8:141:14 | call to basic_string | TAINT |
| stl.cpp:149:18:149:23 | call to source | stl.cpp:149:18:149:26 | call to basic_string | TAINT |
| stl.cpp:149:18:149:26 | call to basic_string | stl.cpp:154:8:154:9 | s1 | |
| stl.cpp:150:19:150:27 | call to basic_string | stl.cpp:155:8:155:9 | s2 | |
| stl.cpp:150:20:150:25 | call to source | stl.cpp:150:19:150:27 | call to basic_string | TAINT |
| stl.cpp:152:8:152:13 | call to source | stl.cpp:152:8:152:15 | call to basic_string | TAINT |
| stl.cpp:152:8:152:15 | call to basic_string | stl.cpp:152:3:152:15 | ... = ... | |
| stl.cpp:152:8:152:15 | call to basic_string | stl.cpp:156:8:156:9 | s3 | |
| stl.cpp:160:15:160:16 | call to basic_string | stl.cpp:161:20:161:21 | s1 | |
| stl.cpp:160:15:160:16 | call to basic_string | stl.cpp:163:8:163:9 | s1 | |
| stl.cpp:160:15:160:16 | call to basic_string | stl.cpp:165:8:165:9 | s1 | |
| stl.cpp:161:20:161:21 | s1 | stl.cpp:166:8:166:9 | s2 | |
| stl.cpp:163:8:163:9 | s1 | stl.cpp:163:3:163:9 | ... = ... | |
| stl.cpp:163:8:163:9 | s1 | stl.cpp:167:8:167:9 | s3 | |
| stl.cpp:171:19:171:40 | call to basic_string | stl.cpp:175:8:175:9 | s1 | |
| stl.cpp:171:32:171:37 | call to source | stl.cpp:171:19:171:40 | call to basic_string | TAINT |
| stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:173:3:173:28 | ... = ... | |
| stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:176:8:176:9 | s2 | |
| stl.cpp:173:20:173:25 | call to source | stl.cpp:173:8:173:28 | call to basic_string | TAINT |
| stl.cpp:137:19:137:24 | call to source | stl.cpp:140:17:140:18 | cs | |
| stl.cpp:137:19:137:24 | call to source | stl.cpp:142:7:142:8 | cs | |
| stl.cpp:140:17:140:18 | cs | stl.cpp:140:17:140:19 | call to basic_string | TAINT |
| stl.cpp:140:17:140:19 | call to basic_string | stl.cpp:143:7:143:8 | ss | |
| stl.cpp:148:19:148:24 | call to source | stl.cpp:151:17:151:18 | cs | |
| stl.cpp:151:17:151:18 | cs | stl.cpp:151:17:151:19 | call to basic_string | TAINT |
| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:154:7:154:8 | ss | |
| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:157:7:157:8 | ss | |
| stl.cpp:154:7:154:8 | ss | stl.cpp:154:10:154:14 | call to c_str | TAINT |
| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:154:2:154:16 | ... = ... | |
| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:156:7:156:8 | cs | |
| stl.cpp:163:18:163:24 | hello | stl.cpp:163:18:163:25 | call to basic_string | TAINT |
| stl.cpp:163:18:163:25 | call to basic_string | stl.cpp:168:8:168:9 | s1 | |
| stl.cpp:164:19:164:26 | call to basic_string | stl.cpp:169:8:169:9 | s2 | |
| stl.cpp:164:20:164:26 | hello | stl.cpp:164:19:164:26 | call to basic_string | TAINT |
| stl.cpp:166:8:166:14 | call to basic_string | stl.cpp:166:3:166:14 | ... = ... | |
| stl.cpp:166:8:166:14 | call to basic_string | stl.cpp:170:8:170:9 | s3 | |
| stl.cpp:166:8:166:14 | hello | stl.cpp:166:8:166:14 | call to basic_string | TAINT |
| stl.cpp:174:18:174:23 | call to source | stl.cpp:174:18:174:26 | call to basic_string | TAINT |
| stl.cpp:174:18:174:26 | call to basic_string | stl.cpp:179:8:179:9 | s1 | |
| stl.cpp:175:19:175:27 | call to basic_string | stl.cpp:180:8:180:9 | s2 | |
| stl.cpp:175:20:175:25 | call to source | stl.cpp:175:19:175:27 | call to basic_string | TAINT |
| stl.cpp:177:8:177:13 | call to source | stl.cpp:177:8:177:15 | call to basic_string | TAINT |
| stl.cpp:177:8:177:15 | call to basic_string | stl.cpp:177:3:177:15 | ... = ... | |
| stl.cpp:177:8:177:15 | call to basic_string | stl.cpp:181:8:181:9 | s3 | |
| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:186:20:186:21 | s1 | |
| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:188:8:188:9 | s1 | |
| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:190:8:190:9 | s1 | |
| stl.cpp:186:20:186:21 | s1 | stl.cpp:191:8:191:9 | s2 | |
| stl.cpp:188:8:188:9 | s1 | stl.cpp:188:3:188:9 | ... = ... | |
| stl.cpp:188:8:188:9 | s1 | stl.cpp:192:8:192:9 | s3 | |
| stl.cpp:196:19:196:40 | call to basic_string | stl.cpp:200:8:200:9 | s1 | |
| stl.cpp:196:32:196:37 | call to source | stl.cpp:196:19:196:40 | call to basic_string | TAINT |
| stl.cpp:198:8:198:28 | call to basic_string | stl.cpp:198:3:198:28 | ... = ... | |
| stl.cpp:198:8:198:28 | call to basic_string | stl.cpp:201:8:201:9 | s2 | |
| stl.cpp:198:20:198:25 | call to source | stl.cpp:198:8:198:28 | call to basic_string | TAINT |
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |

View File

@@ -132,6 +132,31 @@ void test_strings2()
sink(path3.c_str(), "r"); // tainted
}
void test_string3()
{
const char *cs = source();
// convert char * -> std::string
std::string ss(cs);
sink(cs); // tainted
sink(ss); // tainted
}
void test_string4()
{
const char *cs = source();
// convert char * -> std::string
std::string ss(cs);
// convert back std::string -> char *
cs = ss.c_str();
sink(cs); // tainted
sink(ss); // tainted
}
void test_string_constructors_assignments()
{
{
@@ -176,3 +201,4 @@ void test_string_constructors_assignments()
sink(s2); // tainted
}
}

View File

@@ -30,11 +30,15 @@
| stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
| stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
| stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
| stl.cpp:154:8:154:9 | s1 | stl.cpp:149:18:149:23 | call to source |
| stl.cpp:155:8:155:9 | s2 | stl.cpp:150:20:150:25 | call to source |
| stl.cpp:156:8:156:9 | s3 | stl.cpp:152:8:152:13 | call to source |
| stl.cpp:175:8:175:9 | s1 | stl.cpp:171:32:171:37 | call to source |
| stl.cpp:176:8:176:9 | s2 | stl.cpp:173:20:173:25 | call to source |
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source |
| stl.cpp:143:7:143:8 | ss | stl.cpp:137:19:137:24 | call to source |
| stl.cpp:156:7:156:8 | cs | stl.cpp:148:19:148:24 | call to source |
| stl.cpp:157:7:157:8 | ss | stl.cpp:148:19:148:24 | call to source |
| stl.cpp:179:8:179:9 | s1 | stl.cpp:174:18:174:23 | call to source |
| stl.cpp:180:8:180:9 | s2 | stl.cpp:175:20:175:25 | call to source |
| stl.cpp:181:8:181:9 | s3 | stl.cpp:177:8:177:13 | call to source |
| stl.cpp:200:8:200:9 | s1 | stl.cpp:196:32:196:37 | call to source |
| stl.cpp:201:8:201:9 | s2 | stl.cpp:198:20:198:25 | call to source |
| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source |
| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source |
| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source |

View File

@@ -27,11 +27,15 @@
| stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only |
| stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only |
| stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only |
| stl.cpp:154:8:154:9 | stl.cpp:149:18:149:23 | AST only |
| stl.cpp:155:8:155:9 | stl.cpp:150:20:150:25 | AST only |
| stl.cpp:156:8:156:9 | stl.cpp:152:8:152:13 | AST only |
| stl.cpp:175:8:175:9 | stl.cpp:171:32:171:37 | AST only |
| stl.cpp:176:8:176:9 | stl.cpp:173:20:173:25 | AST only |
| stl.cpp:142:7:142:8 | stl.cpp:137:19:137:26 | IR only |
| stl.cpp:143:7:143:8 | stl.cpp:137:19:137:24 | AST only |
| stl.cpp:156:7:156:8 | stl.cpp:148:19:148:24 | AST only |
| stl.cpp:157:7:157:8 | stl.cpp:148:19:148:24 | AST only |
| stl.cpp:179:8:179:9 | stl.cpp:174:18:174:23 | AST only |
| stl.cpp:180:8:180:9 | stl.cpp:175:20:175:25 | AST only |
| stl.cpp:181:8:181:9 | stl.cpp:177:8:177:13 | AST only |
| stl.cpp:200:8:200:9 | stl.cpp:196:32:196:37 | AST only |
| stl.cpp:201:8:201:9 | stl.cpp:198:20:198:25 | AST only |
| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only |
| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only |
| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only |

View File

@@ -3,6 +3,8 @@
| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source |
| stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source |
| stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source |
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source |
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:26 | (const char *)... |
| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | call to source |
| structlikeclass.cpp:61:8:61:9 | s2 | structlikeclass.cpp:58:24:58:29 | call to source |
| structlikeclass.cpp:62:8:62:20 | ... = ... | structlikeclass.cpp:62:13:62:18 | call to source |