Skip to content

Commit bf3aae6

Browse files
committed
unified: Handle implicit 'self' references
1 parent e5efdbd commit bf3aae6

5 files changed

Lines changed: 78 additions & 2 deletions

File tree

unified/ql/lib/codeql/unified/internal/StaticNameBinding.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,9 @@ module Public {
667667
LocalVariable getImplicitQualifierVariable() {
668668
ResolveImplicitReceiverAccess::access(this, result)
669669
}
670+
671+
/** Gets the simple name of this identifier, that is, the name of the member being accessed. */
672+
string getName() { result = this.getValue() }
670673
}
671674
}
672675

unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ predicate step(Node node1, Step step, Node node2) {
2828
node2.isLocalVariablePostUpdate(access, access.getLocalVariable())
2929
)
3030
or
31+
exists(UnqualifiedMemberAccess access | access.isInstanceAccess() |
32+
node1.isLocalVariableRead(access, access.getImplicitQualifierVariable()) and
33+
step.readName(access.getName()) and
34+
node2.isResultValue(access)
35+
or
36+
(node1.isIncomingValue(access) or node1.isPostUpdate(access)) and
37+
step.storeName(access.getName()) and
38+
node2.isLocalVariablePostUpdate(access, access.getImplicitQualifierVariable())
39+
)
40+
or
3141
exists(BinaryExpr expr |
3242
expr.getOperator().getValue() = "+" and
3343
node1.isResultValue([expr.getLeft(), expr.getRight()]) and

unified/ql/lib/codeql/unified/internal/dataflow/DataFlowNode.qll

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,23 @@ private predicate hasPostUpdate(Expr expr) {
1515
predicate performsVariableAccess(
1616
Expr expr, LocalVariable var, VariableRefKind kind, ControlFlowNode cfgNode
1717
) {
18-
// TODO: add UnqualifiedMemberAccess here
1918
exists(LocalVariableAccess access | var = access.getLocalVariable() and expr = access |
2019
hasResultValue(access) and kind.isRead() and cfgNode.isAfter(expr)
2120
or
2221
hasIncomingValue(access, _) and kind.isWrite() and cfgNode.asExpr() = expr // TODO: use more precise CFG node
2322
or
2423
hasPostUpdate(access) and kind.isPostUpdate() and cfgNode.asExpr() = expr // TODO: use more precise CFG node
2524
)
25+
or
26+
exists(UnqualifiedMemberAccess access |
27+
access.isInstanceAccess() and var = access.getImplicitQualifierVariable() and expr = access
28+
|
29+
kind.isRead() and cfgNode.isBefore(access)
30+
or
31+
(hasIncomingValue(access, _) or hasPostUpdate(access)) and
32+
kind.isPostUpdate() and
33+
cfgNode.asExpr() = access // TODO: use more precise CFG node
34+
)
2635
}
2736

2837
newtype TDataFlowNode =

unified/ql/lib/codeql/unified/internal/dataflow/LocalSsa.qll

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ module LocalSsaInput implements InputSig<Location, BasicBlock> {
1111

1212
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
1313
certain = true and
14-
performsVariableAccess(_, v, TWrite(), bb.getNode(i))
14+
(
15+
performsVariableAccess(_, v, TWrite(), bb.getNode(i))
16+
or
17+
// Add implicit initialization of all variables at index -1 before the entry block
18+
bb.(EntryBasicBlock).getEnclosingCallable() = v.getDeclaringCallable() and
19+
i = -1
20+
)
1521
}
1622

1723
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
class Box {
2+
var x: String = ""
3+
}
4+
5+
class C {
6+
var x: String = ""
7+
var box = Box()
8+
9+
func t1() {
10+
self.x = source("t1.1");
11+
sink(self.x); // $ hasValueFlow=t1.1
12+
}
13+
14+
func t2() {
15+
x = source("t2.1");
16+
sink(x); // $ hasValueFlow=t2.1
17+
}
18+
19+
func t3() {
20+
x = source("t3.1");
21+
sink(self.x); // $ hasValueFlow=t3.1
22+
}
23+
24+
func t4() {
25+
self.x = source("t4.1");
26+
sink(x); // $ hasValueFlow=t4.1
27+
}
28+
29+
func t5() {
30+
self.box.x = source("t5.1");
31+
sink(self.box.x); // $ hasValueFlow=t5.1
32+
}
33+
34+
func t6() {
35+
box.x = source("t6.1");
36+
sink(box.x); // $ hasValueFlow=t6.1
37+
}
38+
39+
func t7() {
40+
box.x = source("t7.1");
41+
sink(self.box.x); // $ hasValueFlow=t7.1
42+
}
43+
44+
func t8() {
45+
self.box.x = source("t8.1");
46+
sink(box.x); // $ hasValueFlow=t8.1
47+
}
48+
}

0 commit comments

Comments
 (0)