mirror of
https://github.com/github/codeql.git
synced 2026-07-07 12:35:33 +02:00
Compare commits
159 Commits
codeql-cli
...
criemen/ex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
996990f58a | ||
|
|
bdfd651e71 | ||
|
|
bef05f885c | ||
|
|
f6541811d2 | ||
|
|
f30dad7705 | ||
|
|
7ec1fa2ebe | ||
|
|
2d7d45a8ac | ||
|
|
3c3d71d4a0 | ||
|
|
81ed3e7176 | ||
|
|
1dc712f54d | ||
|
|
7befdc9c5c | ||
|
|
c63fd4a254 | ||
|
|
5cecea42e4 | ||
|
|
b7206c1218 | ||
|
|
138a7ae67f | ||
|
|
c7146ac10c | ||
|
|
648197db35 | ||
|
|
0d88d18781 | ||
|
|
bb9911e06f | ||
|
|
b28bddd22c | ||
|
|
b7f13a7e1f | ||
|
|
5a47ddbf77 | ||
|
|
b9ef6c7e55 | ||
|
|
6a47fcaf1f | ||
|
|
23d7633cd5 | ||
|
|
4e60fd5fc7 | ||
|
|
c02a743835 | ||
|
|
ccf1a44a2b | ||
|
|
ec0066d5a4 | ||
|
|
f59a5b6574 | ||
|
|
0dd463dd2b | ||
|
|
c20cf23c98 | ||
|
|
67df890f68 | ||
|
|
76a41146a8 | ||
|
|
c06e37f3d9 | ||
|
|
9386a900eb | ||
|
|
3560853f36 | ||
|
|
d57bd34575 | ||
|
|
d22620f72f | ||
|
|
c259d0204a | ||
|
|
b9afccc015 | ||
|
|
29b9231f49 | ||
|
|
e8bdc8ba17 | ||
|
|
608d24f75e | ||
|
|
0a5410c2d3 | ||
|
|
474d983f8d | ||
|
|
fca561351d | ||
|
|
ac43ad6da2 | ||
|
|
e048a729db | ||
|
|
ca5c2b2acf | ||
|
|
9c4a50503c | ||
|
|
065075056b | ||
|
|
ad102e2746 | ||
|
|
b4963c7538 | ||
|
|
e4fd749a46 | ||
|
|
82f61ca015 | ||
|
|
1ba26237a7 | ||
|
|
1ad204d89e | ||
|
|
df04c5044c | ||
|
|
10f6cab77e | ||
|
|
7310590f90 | ||
|
|
ffd2a388a9 | ||
|
|
dccdc3be5a | ||
|
|
e9ff6e8755 | ||
|
|
a3289fabe1 | ||
|
|
537450606e | ||
|
|
ff74fe1e03 | ||
|
|
75a3f34e86 | ||
|
|
29bcd7ca6f | ||
|
|
50a9b18c92 | ||
|
|
303e02fb8a | ||
|
|
f8d46677b9 | ||
|
|
98d018ce26 | ||
|
|
21c168e229 | ||
|
|
0923d1fdc1 | ||
|
|
c92b7828cb | ||
|
|
a47efc4348 | ||
|
|
a80a367de4 | ||
|
|
d6368c3d1b | ||
|
|
49807c080b | ||
|
|
436b18a11f | ||
|
|
6bbed9d624 | ||
|
|
7156dee270 | ||
|
|
7977d9c253 | ||
|
|
b38a23daee | ||
|
|
b267d26ff8 | ||
|
|
d6ae19c87d | ||
|
|
0ba334bb22 | ||
|
|
28dce6e95a | ||
|
|
83252e5ba2 | ||
|
|
cecb6c7bdd | ||
|
|
b509627113 | ||
|
|
3d6ab81ab8 | ||
|
|
c6399dbdf4 | ||
|
|
f94d8c341d | ||
|
|
510f5abb9a | ||
|
|
5dddc48e60 | ||
|
|
c8a5397085 | ||
|
|
cf9ab83dee | ||
|
|
c3e122f5fc | ||
|
|
09aaa8f78e | ||
|
|
486b283c20 | ||
|
|
f5a1a12435 | ||
|
|
b28e956dd2 | ||
|
|
adcb90aa8c | ||
|
|
23b9028d2c | ||
|
|
04e04b3031 | ||
|
|
97faeb026f | ||
|
|
119de6c60c | ||
|
|
9d66761eeb | ||
|
|
0d174f2daf | ||
|
|
2132ee52d5 | ||
|
|
abf3bbbe8d | ||
|
|
e7611ab641 | ||
|
|
ce8d14e6ef | ||
|
|
1bd5eb5120 | ||
|
|
73d6177477 | ||
|
|
2b0f6a2723 | ||
|
|
33c727e6b9 | ||
|
|
47377c7197 | ||
|
|
b8ce5a63c5 | ||
|
|
cd40de7464 | ||
|
|
ab2bc38789 | ||
|
|
d405284d36 | ||
|
|
605bd19306 | ||
|
|
e1ae531b62 | ||
|
|
5644514606 | ||
|
|
5e155d25b1 | ||
|
|
930d576cfb | ||
|
|
38875ca0c7 | ||
|
|
c3f942f899 | ||
|
|
6e9d9fcbbd | ||
|
|
d3163d8a76 | ||
|
|
e2d3fa7093 | ||
|
|
f5ae5a581b | ||
|
|
d2efe0b84d | ||
|
|
be1cad864b | ||
|
|
6f63c03558 | ||
|
|
7e09a1cbfd | ||
|
|
7020e4132b | ||
|
|
d388dd547e | ||
|
|
f3ce3933d1 | ||
|
|
dac71ded9d | ||
|
|
133632119d | ||
|
|
4d9c86a252 | ||
|
|
9cb4899c5c | ||
|
|
09b0c300d9 | ||
|
|
04190ea308 | ||
|
|
5f5c0b11c7 | ||
|
|
4f4dec50f2 | ||
|
|
6f0a622252 | ||
|
|
7dc6518350 | ||
|
|
18c0d13efd | ||
|
|
5ec5557203 | ||
|
|
95e88c18b9 | ||
|
|
51b543c67c | ||
|
|
bced467a88 | ||
|
|
ce4b192caa | ||
|
|
6aabbf0b9a |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -48,3 +48,6 @@
|
||||
*.gif -text
|
||||
*.dll -text
|
||||
*.pdb -text
|
||||
|
||||
java/ql/test/stubs/**/*.java linguist-generated=true
|
||||
java/ql/test/experimental/stubs/**/*.java linguist-generated=true
|
||||
@@ -462,4 +462,4 @@
|
||||
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
|
||||
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll"
|
||||
]
|
||||
}
|
||||
}
|
||||
4
cpp/ql/examples/qlpack.lock.yml
Normal file
4
cpp/ql/examples/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
@@ -1,3 +1,4 @@
|
||||
name: codeql-cpp-examples
|
||||
version: 0.0.0
|
||||
libraryPathDependencies: codeql/cpp-all
|
||||
name: codeql/cpp-examples
|
||||
version: 0.0.2
|
||||
dependencies:
|
||||
codeql/cpp-all: "*"
|
||||
|
||||
@@ -3,3 +3,5 @@ version: 0.0.2
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/cpp-upgrades: 0.0.2
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -9,7 +9,7 @@ import semmle.code.cpp.Enum
|
||||
private import semmle.code.cpp.dataflow.EscapesTree
|
||||
|
||||
/**
|
||||
* A C/C++ access expression. This refers to a function, variable, or enum constant.
|
||||
* A C/C++ access expression. This refers to a function (excluding function references in function call expressions), variable, or enum constant.
|
||||
*/
|
||||
class Access extends Expr, NameQualifiableElement, @access {
|
||||
// As `@access` is a union type containing `@routineexpr` (which describes function accesses
|
||||
@@ -350,6 +350,15 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess {
|
||||
* int (*myFunctionPointer)(int) = &myFunctionTarget;
|
||||
* }
|
||||
* ```
|
||||
* This excludes function accesses in function call expressions.
|
||||
* For example the access `myFunctionTarget` in `myFunction` in the following code:
|
||||
* ```
|
||||
* int myFunctionTarget(int);
|
||||
*
|
||||
* void myFunction() {
|
||||
* myFunctionTarget(1);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class FunctionAccess extends Access, @routineexpr {
|
||||
FunctionAccess() { not iscall(underlyingElement(this), _) }
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -41,7 +41,8 @@ private predicate stmtDominates(Stmt dominator, Stmt dominated) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `use` is guarded to be less than something.
|
||||
* Holds if the value of `use` is guarded to be less than something, and `e`
|
||||
* is in code controlled by that guard (where the guard condition held).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate guardedLesser(Operation e, Expr use) {
|
||||
@@ -67,7 +68,8 @@ predicate guardedLesser(Operation e, Expr use) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `use` is guarded to be greater than something.
|
||||
* Holds if the value of `use` is guarded to be greater than something, and `e`
|
||||
* is in code controlled by that guard (where the guard condition held).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate guardedGreater(Operation e, Expr use) {
|
||||
@@ -120,6 +122,10 @@ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) {
|
||||
// overflow possible if large or small
|
||||
e instanceof MulExpr and
|
||||
not (guardedLesser(e, varUse(v)) and guardedGreater(e, varUse(v)))
|
||||
or
|
||||
// overflow possible if large or small
|
||||
e instanceof AssignMulExpr and
|
||||
not (guardedLesser(e, varUse(v)) and guardedGreater(e, varUse(v)))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -147,5 +153,9 @@ predicate missingGuardAgainstUnderflow(Operation e, VariableAccess use) {
|
||||
// underflow possible if large or small
|
||||
e instanceof MulExpr and
|
||||
not (guardedLesser(e, varUse(v)) and guardedGreater(e, varUse(v)))
|
||||
or
|
||||
// underflow possible if large or small
|
||||
e instanceof AssignMulExpr and
|
||||
not (guardedLesser(e, varUse(v)) and guardedGreater(e, varUse(v)))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
- apply: code-scanning-selectors.yml
|
||||
from: codeql/suite-helpers
|
||||
- apply: codeql-suites/exclude-slow-queries.yml
|
||||
from: codeql-cpp
|
||||
from: codeql/cpp-queries
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
- apply: lgtm-selectors.yml
|
||||
from: codeql/suite-helpers
|
||||
- apply: codeql-suites/exclude-slow-queries.yml
|
||||
from: codeql-cpp
|
||||
from: codeql/cpp-queries
|
||||
# These are only for IDE use.
|
||||
- exclude:
|
||||
tags contain:
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
- apply: security-and-quality-selectors.yml
|
||||
from: codeql/suite-helpers
|
||||
- apply: codeql-suites/exclude-slow-queries.yml
|
||||
from: codeql-cpp
|
||||
from: codeql/cpp-queries
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
- apply: security-extended-selectors.yml
|
||||
from: codeql/suite-helpers
|
||||
- apply: codeql-suites/exclude-slow-queries.yml
|
||||
from: codeql-cpp
|
||||
from: codeql/cpp-queries
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.0.2
|
||||
dependencies:
|
||||
codeql/cpp-all: ^0.0.2
|
||||
codeql/suite-helpers: ^0.0.2
|
||||
codeql/cpp-all: "*"
|
||||
codeql/suite-helpers: "*"
|
||||
suites: codeql-suites
|
||||
extractor: cpp
|
||||
defaultSuiteFile: codeql-suites/cpp-code-scanning.qls
|
||||
|
||||
@@ -8,6 +8,7 @@ nodes
|
||||
| test.cpp:23:33:23:37 | size1 | semmle.label | size1 |
|
||||
| test.cpp:30:27:30:31 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:31:27:31:31 | ... * ... | semmle.label | ... * ... |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:13:33:13:37 | ... * ... | test.cpp:13:33:13:37 | ... * ... | test.cpp:13:33:13:37 | ... * ... | Potentially overflowing value from $@ is used in the size of this allocation. | test.cpp:13:33:13:37 | ... * ... | multiplication |
|
||||
| test.cpp:15:31:15:35 | ... * ... | test.cpp:15:31:15:35 | ... * ... | test.cpp:15:31:15:35 | ... * ... | Potentially overflowing value from $@ is used in the size of this allocation. | test.cpp:15:31:15:35 | ... * ... | multiplication |
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
edges
|
||||
| test.cpp:45:18:45:23 | buffer | test.cpp:47:10:47:15 | buffer |
|
||||
| test.cpp:77:16:77:22 | medical | test.cpp:78:24:78:27 | temp |
|
||||
| test.cpp:81:17:81:20 | call to func | test.cpp:82:24:82:28 | buff5 |
|
||||
| test.cpp:81:22:81:28 | medical | test.cpp:45:18:45:23 | buffer |
|
||||
| test.cpp:81:22:81:28 | medical | test.cpp:81:17:81:20 | call to func |
|
||||
nodes
|
||||
| test.cpp:45:18:45:23 | buffer | semmle.label | buffer |
|
||||
| test.cpp:47:10:47:15 | buffer | semmle.label | buffer |
|
||||
| test.cpp:57:9:57:18 | theZipcode | semmle.label | theZipcode |
|
||||
| test.cpp:74:24:74:30 | medical | semmle.label | medical |
|
||||
| test.cpp:77:16:77:22 | medical | semmle.label | medical |
|
||||
@@ -12,6 +16,8 @@ nodes
|
||||
| test.cpp:82:24:82:28 | buff5 | semmle.label | buff5 |
|
||||
| test.cpp:96:37:96:46 | theZipcode | semmle.label | theZipcode |
|
||||
| test.cpp:99:42:99:51 | theZipcode | semmle.label | theZipcode |
|
||||
subpaths
|
||||
| test.cpp:81:22:81:28 | medical | test.cpp:45:18:45:23 | buffer | test.cpp:47:10:47:15 | buffer | test.cpp:81:17:81:20 | call to func |
|
||||
#select
|
||||
| test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:57:9:57:18 | theZipcode | this source. |
|
||||
| test.cpp:74:24:74:30 | medical | test.cpp:74:24:74:30 | medical | test.cpp:74:24:74:30 | medical | This write into the external location 'medical' may contain unencrypted data from $@ | test.cpp:74:24:74:30 | medical | this source. |
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
edges
|
||||
| A.cpp:23:10:23:10 | c | A.cpp:25:7:25:17 | Chi [c] |
|
||||
| A.cpp:27:17:27:17 | c | A.cpp:27:22:27:32 | Chi [c] |
|
||||
| A.cpp:28:8:28:10 | *#this [c] | A.cpp:28:29:28:29 | Store |
|
||||
| A.cpp:55:5:55:5 | set output argument [c] | A.cpp:56:10:56:10 | b indirection [c] |
|
||||
| A.cpp:55:8:55:10 | new | A.cpp:27:17:27:17 | c |
|
||||
| A.cpp:55:8:55:10 | new | A.cpp:55:5:55:5 | set output argument [c] |
|
||||
| A.cpp:55:12:55:19 | (C *)... | A.cpp:55:8:55:10 | new |
|
||||
| A.cpp:55:12:55:19 | new | A.cpp:55:8:55:10 | new |
|
||||
| A.cpp:56:10:56:10 | b indirection [c] | A.cpp:28:8:28:10 | *#this [c] |
|
||||
| A.cpp:56:10:56:10 | b indirection [c] | A.cpp:56:13:56:15 | call to get |
|
||||
| A.cpp:57:10:57:25 | new indirection [c] | A.cpp:28:8:28:10 | *#this [c] |
|
||||
| A.cpp:57:10:57:25 | new indirection [c] | A.cpp:57:28:57:30 | call to get |
|
||||
| A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:10:57:25 | new indirection [c] |
|
||||
| A.cpp:57:11:57:24 | new | A.cpp:23:10:23:10 | c |
|
||||
| A.cpp:57:11:57:24 | new | A.cpp:57:11:57:24 | B output argument [c] |
|
||||
| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | new |
|
||||
| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Chi [a] |
|
||||
@@ -14,10 +21,12 @@ edges
|
||||
| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a |
|
||||
| A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] |
|
||||
| A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] |
|
||||
| A.cpp:126:8:126:10 | new | A.cpp:27:17:27:17 | c |
|
||||
| A.cpp:126:8:126:10 | new | A.cpp:126:5:126:5 | set output argument [c] |
|
||||
| A.cpp:126:12:126:18 | new | A.cpp:126:8:126:10 | new |
|
||||
| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c |
|
||||
| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] |
|
||||
| A.cpp:140:13:140:13 | b | A.cpp:143:7:143:31 | Chi [b] |
|
||||
| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] |
|
||||
| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Chi [c] |
|
||||
| A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] |
|
||||
@@ -25,6 +34,7 @@ edges
|
||||
| A.cpp:150:12:150:18 | new | A.cpp:151:12:151:24 | b |
|
||||
| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b |
|
||||
| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] |
|
||||
| A.cpp:151:12:151:24 | b | A.cpp:140:13:140:13 | b |
|
||||
| A.cpp:151:12:151:24 | b | A.cpp:151:12:151:24 | D output argument [b] |
|
||||
| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c |
|
||||
| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] |
|
||||
@@ -86,21 +96,49 @@ edges
|
||||
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... |
|
||||
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array |
|
||||
| arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:37:24:37:27 | data |
|
||||
| by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:16 | Chi [a] |
|
||||
| by_reference.cpp:15:26:15:30 | value | by_reference.cpp:16:5:16:19 | Chi [a] |
|
||||
| by_reference.cpp:19:28:19:32 | value | by_reference.cpp:20:11:20:21 | value |
|
||||
| by_reference.cpp:20:5:20:8 | setDirectly output argument [a] | by_reference.cpp:20:5:20:8 | Chi [a] |
|
||||
| by_reference.cpp:20:11:20:21 | value | by_reference.cpp:15:26:15:30 | value |
|
||||
| by_reference.cpp:20:11:20:21 | value | by_reference.cpp:20:5:20:8 | setDirectly output argument [a] |
|
||||
| by_reference.cpp:23:34:23:38 | value | by_reference.cpp:24:5:24:17 | value |
|
||||
| by_reference.cpp:24:5:24:17 | value | by_reference.cpp:11:48:11:52 | value |
|
||||
| by_reference.cpp:24:5:24:17 | value | by_reference.cpp:24:19:24:22 | nonMemberSetA output argument [a] |
|
||||
| by_reference.cpp:24:19:24:22 | nonMemberSetA output argument [a] | by_reference.cpp:24:19:24:22 | Chi [a] |
|
||||
| by_reference.cpp:31:46:31:46 | *s [a] | by_reference.cpp:32:15:32:15 | Store |
|
||||
| by_reference.cpp:35:9:35:19 | *#this [a] | by_reference.cpp:36:18:36:18 | Store |
|
||||
| by_reference.cpp:39:9:39:21 | *#this [a] | by_reference.cpp:40:12:40:15 | this indirection [a] |
|
||||
| by_reference.cpp:40:12:40:15 | this indirection [a] | by_reference.cpp:35:9:35:19 | *#this [a] |
|
||||
| by_reference.cpp:40:12:40:15 | this indirection [a] | by_reference.cpp:40:18:40:28 | call to getDirectly |
|
||||
| by_reference.cpp:40:18:40:28 | call to getDirectly | by_reference.cpp:40:18:40:28 | Store |
|
||||
| by_reference.cpp:43:9:43:27 | *#this [a] | by_reference.cpp:44:26:44:29 | this indirection [a] |
|
||||
| by_reference.cpp:44:12:44:24 | call to nonMemberGetA | by_reference.cpp:44:12:44:24 | Store |
|
||||
| by_reference.cpp:44:26:44:29 | this indirection [a] | by_reference.cpp:31:46:31:46 | *s [a] |
|
||||
| by_reference.cpp:44:26:44:29 | this indirection [a] | by_reference.cpp:44:12:44:24 | call to nonMemberGetA |
|
||||
| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | by_reference.cpp:51:8:51:8 | s indirection [a] |
|
||||
| by_reference.cpp:50:5:50:15 | call to user_input | by_reference.cpp:15:26:15:30 | value |
|
||||
| by_reference.cpp:50:5:50:15 | call to user_input | by_reference.cpp:50:3:50:3 | setDirectly output argument [a] |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:5:50:15 | call to user_input |
|
||||
| by_reference.cpp:51:8:51:8 | s indirection [a] | by_reference.cpp:35:9:35:19 | *#this [a] |
|
||||
| by_reference.cpp:51:8:51:8 | s indirection [a] | by_reference.cpp:51:10:51:20 | call to getDirectly |
|
||||
| by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | by_reference.cpp:57:8:57:8 | s indirection [a] |
|
||||
| by_reference.cpp:56:5:56:17 | call to user_input | by_reference.cpp:19:28:19:32 | value |
|
||||
| by_reference.cpp:56:5:56:17 | call to user_input | by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] |
|
||||
| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:5:56:17 | call to user_input |
|
||||
| by_reference.cpp:57:8:57:8 | s indirection [a] | by_reference.cpp:39:9:39:21 | *#this [a] |
|
||||
| by_reference.cpp:57:8:57:8 | s indirection [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly |
|
||||
| by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | by_reference.cpp:63:8:63:8 | s indirection [a] |
|
||||
| by_reference.cpp:62:5:62:23 | call to user_input | by_reference.cpp:23:34:23:38 | value |
|
||||
| by_reference.cpp:62:5:62:23 | call to user_input | by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] |
|
||||
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:5:62:23 | call to user_input |
|
||||
| by_reference.cpp:63:8:63:8 | s indirection [a] | by_reference.cpp:43:9:43:27 | *#this [a] |
|
||||
| by_reference.cpp:63:8:63:8 | s indirection [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
|
||||
| by_reference.cpp:68:3:68:15 | call to user_input | by_reference.cpp:11:48:11:52 | value |
|
||||
| by_reference.cpp:68:3:68:15 | call to user_input | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] |
|
||||
| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | by_reference.cpp:69:22:69:23 | & ... indirection [a] |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:3:68:15 | call to user_input |
|
||||
| by_reference.cpp:69:22:69:23 | & ... indirection [a] | by_reference.cpp:31:46:31:46 | *s [a] |
|
||||
| by_reference.cpp:69:22:69:23 | & ... indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
|
||||
| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] |
|
||||
@@ -134,48 +172,73 @@ edges
|
||||
| by_reference.cpp:128:15:128:23 | Chi | by_reference.cpp:128:15:128:23 | Chi [a] |
|
||||
| by_reference.cpp:128:15:128:23 | Chi [a] | by_reference.cpp:136:16:136:16 | a |
|
||||
| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [[]] | by_reference.cpp:128:15:128:23 | Chi |
|
||||
| complex.cpp:9:7:9:7 | *#this [a_] | complex.cpp:9:20:9:21 | Store |
|
||||
| complex.cpp:10:7:10:7 | *#this [b_] | complex.cpp:10:20:10:21 | Store |
|
||||
| complex.cpp:11:17:11:17 | a | complex.cpp:11:22:11:27 | Chi [a_] |
|
||||
| complex.cpp:12:8:12:11 | *#this [a_] | complex.cpp:12:22:12:27 | Chi [a_] |
|
||||
| complex.cpp:12:17:12:17 | b | complex.cpp:12:22:12:27 | Chi [b_] |
|
||||
| complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:42:16:42:16 | f indirection [a_] |
|
||||
| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | f indirection [b_] |
|
||||
| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:43:16:43:16 | f indirection [b_] |
|
||||
| complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:43:16:43:16 | f indirection [b_] |
|
||||
| complex.cpp:42:16:42:16 | f indirection [a_] | complex.cpp:9:7:9:7 | *#this [a_] |
|
||||
| complex.cpp:42:16:42:16 | f indirection [a_] | complex.cpp:42:18:42:18 | call to a |
|
||||
| complex.cpp:42:16:42:16 | f indirection [b_] | complex.cpp:9:7:9:7 | *#this [b_] |
|
||||
| complex.cpp:42:16:42:16 | f indirection [b_] | complex.cpp:42:16:42:16 | a output argument [b_] |
|
||||
| complex.cpp:43:16:43:16 | f indirection [b_] | complex.cpp:10:7:10:7 | *#this [b_] |
|
||||
| complex.cpp:43:16:43:16 | f indirection [b_] | complex.cpp:43:18:43:18 | call to b |
|
||||
| complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:59:7:59:8 | b1 indirection [a_] |
|
||||
| complex.cpp:53:14:53:17 | call to user_input | complex.cpp:11:17:11:17 | a |
|
||||
| complex.cpp:53:14:53:17 | call to user_input | complex.cpp:53:12:53:12 | setA output argument [a_] |
|
||||
| complex.cpp:53:19:53:28 | call to user_input | complex.cpp:53:14:53:17 | call to user_input |
|
||||
| complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:62:7:62:8 | b2 indirection [b_] |
|
||||
| complex.cpp:54:14:54:17 | call to user_input | complex.cpp:12:17:12:17 | b |
|
||||
| complex.cpp:54:14:54:17 | call to user_input | complex.cpp:54:12:54:12 | setB output argument [b_] |
|
||||
| complex.cpp:54:19:54:28 | call to user_input | complex.cpp:54:14:54:17 | call to user_input |
|
||||
| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:56:12:56:12 | f indirection [a_] |
|
||||
| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:65:7:65:8 | b3 indirection [a_] |
|
||||
| complex.cpp:55:14:55:17 | call to user_input | complex.cpp:11:17:11:17 | a |
|
||||
| complex.cpp:55:14:55:17 | call to user_input | complex.cpp:55:12:55:12 | setA output argument [a_] |
|
||||
| complex.cpp:55:19:55:28 | call to user_input | complex.cpp:55:14:55:17 | call to user_input |
|
||||
| complex.cpp:56:12:56:12 | f indirection [a_] | complex.cpp:12:8:12:11 | *#this [a_] |
|
||||
| complex.cpp:56:12:56:12 | f indirection [a_] | complex.cpp:56:12:56:12 | setB output argument [a_] |
|
||||
| complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:65:7:65:8 | b3 indirection [a_] |
|
||||
| complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:65:7:65:8 | b3 indirection [b_] |
|
||||
| complex.cpp:56:14:56:17 | call to user_input | complex.cpp:12:17:12:17 | b |
|
||||
| complex.cpp:56:14:56:17 | call to user_input | complex.cpp:56:12:56:12 | setB output argument [b_] |
|
||||
| complex.cpp:56:19:56:28 | call to user_input | complex.cpp:56:14:56:17 | call to user_input |
|
||||
| complex.cpp:59:7:59:8 | b1 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] |
|
||||
| complex.cpp:62:7:62:8 | b2 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] |
|
||||
| complex.cpp:65:7:65:8 | b3 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] |
|
||||
| complex.cpp:65:7:65:8 | b3 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] |
|
||||
| constructors.cpp:18:9:18:9 | *#this [a_] | constructors.cpp:18:22:18:23 | Store |
|
||||
| constructors.cpp:19:9:19:9 | *#this [b_] | constructors.cpp:19:22:19:23 | Store |
|
||||
| constructors.cpp:23:13:23:13 | a | constructors.cpp:23:28:23:28 | Chi [a_] |
|
||||
| constructors.cpp:23:20:23:20 | b | constructors.cpp:23:35:23:35 | Chi [b_] |
|
||||
| constructors.cpp:23:28:23:28 | Chi [a_] | constructors.cpp:23:35:23:35 | Chi [a_] |
|
||||
| constructors.cpp:26:15:26:15 | *f [a_] | constructors.cpp:28:10:28:10 | f indirection [a_] |
|
||||
| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:28:10:28:10 | f indirection [b_] |
|
||||
| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:29:10:29:10 | f indirection [b_] |
|
||||
| constructors.cpp:28:10:28:10 | a output argument [b_] | constructors.cpp:29:10:29:10 | f indirection [b_] |
|
||||
| constructors.cpp:28:10:28:10 | f indirection [a_] | constructors.cpp:18:9:18:9 | *#this [a_] |
|
||||
| constructors.cpp:28:10:28:10 | f indirection [a_] | constructors.cpp:28:12:28:12 | call to a |
|
||||
| constructors.cpp:28:10:28:10 | f indirection [b_] | constructors.cpp:18:9:18:9 | *#this [b_] |
|
||||
| constructors.cpp:28:10:28:10 | f indirection [b_] | constructors.cpp:28:10:28:10 | a output argument [b_] |
|
||||
| constructors.cpp:29:10:29:10 | f indirection [b_] | constructors.cpp:19:9:19:9 | *#this [b_] |
|
||||
| constructors.cpp:29:10:29:10 | f indirection [b_] | constructors.cpp:29:12:29:12 | call to b |
|
||||
| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | call to user_input |
|
||||
| constructors.cpp:34:11:34:26 | Foo output argument [a_] | constructors.cpp:40:9:40:9 | f indirection [a_] |
|
||||
| constructors.cpp:34:11:34:26 | call to user_input | constructors.cpp:23:13:23:13 | a |
|
||||
| constructors.cpp:34:11:34:26 | call to user_input | constructors.cpp:34:11:34:26 | Foo output argument [a_] |
|
||||
| constructors.cpp:35:11:35:26 | Foo output argument [b_] | constructors.cpp:43:9:43:9 | g indirection [b_] |
|
||||
| constructors.cpp:35:11:35:26 | call to user_input | constructors.cpp:23:20:23:20 | b |
|
||||
| constructors.cpp:35:11:35:26 | call to user_input | constructors.cpp:35:11:35:26 | Foo output argument [b_] |
|
||||
| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | call to user_input |
|
||||
| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | call to user_input |
|
||||
| constructors.cpp:36:11:36:37 | Foo output argument [a_] | constructors.cpp:46:9:46:9 | h indirection [a_] |
|
||||
| constructors.cpp:36:11:36:37 | Foo output argument [b_] | constructors.cpp:46:9:46:9 | h indirection [b_] |
|
||||
| constructors.cpp:36:11:36:37 | call to user_input | constructors.cpp:23:13:23:13 | a |
|
||||
| constructors.cpp:36:11:36:37 | call to user_input | constructors.cpp:23:20:23:20 | b |
|
||||
| constructors.cpp:36:11:36:37 | call to user_input | constructors.cpp:36:11:36:37 | Foo output argument [a_] |
|
||||
| constructors.cpp:36:11:36:37 | call to user_input | constructors.cpp:36:11:36:37 | Foo output argument [b_] |
|
||||
| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | call to user_input |
|
||||
@@ -183,26 +246,39 @@ edges
|
||||
| constructors.cpp:43:9:43:9 | g indirection [b_] | constructors.cpp:26:15:26:15 | *f [b_] |
|
||||
| constructors.cpp:46:9:46:9 | h indirection [a_] | constructors.cpp:26:15:26:15 | *f [a_] |
|
||||
| constructors.cpp:46:9:46:9 | h indirection [b_] | constructors.cpp:26:15:26:15 | *f [b_] |
|
||||
| simple.cpp:18:9:18:9 | *#this [a_] | simple.cpp:18:22:18:23 | Store |
|
||||
| simple.cpp:19:9:19:9 | *#this [b_] | simple.cpp:19:22:19:23 | Store |
|
||||
| simple.cpp:20:19:20:19 | a | simple.cpp:20:24:20:29 | Chi [a_] |
|
||||
| simple.cpp:21:10:21:13 | *#this [a_] | simple.cpp:21:24:21:29 | Chi [a_] |
|
||||
| simple.cpp:21:19:21:19 | b | simple.cpp:21:24:21:29 | Chi [b_] |
|
||||
| simple.cpp:26:15:26:15 | *f [a_] | simple.cpp:28:10:28:10 | f indirection [a_] |
|
||||
| simple.cpp:26:15:26:15 | *f [b_] | simple.cpp:28:10:28:10 | f indirection [b_] |
|
||||
| simple.cpp:26:15:26:15 | *f [b_] | simple.cpp:29:10:29:10 | f indirection [b_] |
|
||||
| simple.cpp:28:10:28:10 | a output argument [b_] | simple.cpp:29:10:29:10 | f indirection [b_] |
|
||||
| simple.cpp:28:10:28:10 | f indirection [a_] | simple.cpp:18:9:18:9 | *#this [a_] |
|
||||
| simple.cpp:28:10:28:10 | f indirection [a_] | simple.cpp:28:12:28:12 | call to a |
|
||||
| simple.cpp:28:10:28:10 | f indirection [b_] | simple.cpp:18:9:18:9 | *#this [b_] |
|
||||
| simple.cpp:28:10:28:10 | f indirection [b_] | simple.cpp:28:10:28:10 | a output argument [b_] |
|
||||
| simple.cpp:29:10:29:10 | f indirection [b_] | simple.cpp:19:9:19:9 | *#this [b_] |
|
||||
| simple.cpp:29:10:29:10 | f indirection [b_] | simple.cpp:29:12:29:12 | call to b |
|
||||
| simple.cpp:39:5:39:5 | setA output argument [a_] | simple.cpp:45:9:45:9 | f indirection [a_] |
|
||||
| simple.cpp:39:7:39:10 | call to user_input | simple.cpp:20:19:20:19 | a |
|
||||
| simple.cpp:39:7:39:10 | call to user_input | simple.cpp:39:5:39:5 | setA output argument [a_] |
|
||||
| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:7:39:10 | call to user_input |
|
||||
| simple.cpp:40:5:40:5 | setB output argument [b_] | simple.cpp:48:9:48:9 | g indirection [b_] |
|
||||
| simple.cpp:40:7:40:10 | call to user_input | simple.cpp:21:19:21:19 | b |
|
||||
| simple.cpp:40:7:40:10 | call to user_input | simple.cpp:40:5:40:5 | setB output argument [b_] |
|
||||
| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:7:40:10 | call to user_input |
|
||||
| simple.cpp:41:5:41:5 | setA output argument [a_] | simple.cpp:42:5:42:5 | h indirection [a_] |
|
||||
| simple.cpp:41:5:41:5 | setA output argument [a_] | simple.cpp:51:9:51:9 | h indirection [a_] |
|
||||
| simple.cpp:41:7:41:10 | call to user_input | simple.cpp:20:19:20:19 | a |
|
||||
| simple.cpp:41:7:41:10 | call to user_input | simple.cpp:41:5:41:5 | setA output argument [a_] |
|
||||
| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:7:41:10 | call to user_input |
|
||||
| simple.cpp:42:5:42:5 | h indirection [a_] | simple.cpp:21:10:21:13 | *#this [a_] |
|
||||
| simple.cpp:42:5:42:5 | h indirection [a_] | simple.cpp:42:5:42:5 | setB output argument [a_] |
|
||||
| simple.cpp:42:5:42:5 | setB output argument [a_] | simple.cpp:51:9:51:9 | h indirection [a_] |
|
||||
| simple.cpp:42:5:42:5 | setB output argument [b_] | simple.cpp:51:9:51:9 | h indirection [b_] |
|
||||
| simple.cpp:42:7:42:10 | call to user_input | simple.cpp:21:19:21:19 | b |
|
||||
| simple.cpp:42:7:42:10 | call to user_input | simple.cpp:42:5:42:5 | setB output argument [b_] |
|
||||
| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:7:42:10 | call to user_input |
|
||||
| simple.cpp:45:9:45:9 | f indirection [a_] | simple.cpp:26:15:26:15 | *f [a_] |
|
||||
@@ -212,8 +288,10 @@ edges
|
||||
| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] |
|
||||
| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] |
|
||||
| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i |
|
||||
| simple.cpp:78:9:78:15 | *#this [f1] | simple.cpp:79:19:79:20 | Store |
|
||||
| simple.cpp:83:9:83:28 | Store [f1] | simple.cpp:84:14:84:20 | this indirection [f1] |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store [f1] |
|
||||
| simple.cpp:84:14:84:20 | this indirection [f1] | simple.cpp:78:9:78:15 | *#this [f1] |
|
||||
| simple.cpp:84:14:84:20 | this indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 |
|
||||
| simple.cpp:92:5:92:22 | Store [i] | simple.cpp:93:20:93:20 | Store [i] |
|
||||
| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | Store [i] |
|
||||
@@ -228,6 +306,12 @@ edges
|
||||
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a |
|
||||
| struct_init.c:36:10:36:24 | & ... indirection [a] | struct_init.c:14:24:14:25 | *ab [a] |
|
||||
nodes
|
||||
| A.cpp:23:10:23:10 | c | semmle.label | c |
|
||||
| A.cpp:25:7:25:17 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:27:17:27:17 | c | semmle.label | c |
|
||||
| A.cpp:27:22:27:32 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:28:8:28:10 | *#this [c] | semmle.label | *#this [c] |
|
||||
| A.cpp:28:29:28:29 | Store | semmle.label | Store |
|
||||
| A.cpp:55:5:55:5 | set output argument [c] | semmle.label | set output argument [c] |
|
||||
| A.cpp:55:8:55:10 | new | semmle.label | new |
|
||||
| A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... |
|
||||
@@ -251,9 +335,11 @@ nodes
|
||||
| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] |
|
||||
| A.cpp:132:13:132:13 | c | semmle.label | c |
|
||||
| A.cpp:140:13:140:13 | b | semmle.label | b |
|
||||
| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:142:14:142:20 | new | semmle.label | new |
|
||||
| A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] |
|
||||
| A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] |
|
||||
| A.cpp:143:25:143:31 | new | semmle.label | new |
|
||||
| A.cpp:150:12:150:18 | new | semmle.label | new |
|
||||
| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] |
|
||||
@@ -336,6 +422,30 @@ nodes
|
||||
| arrays.cpp:16:8:16:13 | access to array | semmle.label | access to array |
|
||||
| arrays.cpp:36:26:36:35 | call to user_input | semmle.label | call to user_input |
|
||||
| arrays.cpp:37:24:37:27 | data | semmle.label | data |
|
||||
| by_reference.cpp:11:48:11:52 | value | semmle.label | value |
|
||||
| by_reference.cpp:12:5:12:16 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:15:26:15:30 | value | semmle.label | value |
|
||||
| by_reference.cpp:16:5:16:19 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:19:28:19:32 | value | semmle.label | value |
|
||||
| by_reference.cpp:20:5:20:8 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:20:5:20:8 | setDirectly output argument [a] | semmle.label | setDirectly output argument [a] |
|
||||
| by_reference.cpp:20:11:20:21 | value | semmle.label | value |
|
||||
| by_reference.cpp:23:34:23:38 | value | semmle.label | value |
|
||||
| by_reference.cpp:24:5:24:17 | value | semmle.label | value |
|
||||
| by_reference.cpp:24:19:24:22 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:24:19:24:22 | nonMemberSetA output argument [a] | semmle.label | nonMemberSetA output argument [a] |
|
||||
| by_reference.cpp:31:46:31:46 | *s [a] | semmle.label | *s [a] |
|
||||
| by_reference.cpp:32:15:32:15 | Store | semmle.label | Store |
|
||||
| by_reference.cpp:35:9:35:19 | *#this [a] | semmle.label | *#this [a] |
|
||||
| by_reference.cpp:36:18:36:18 | Store | semmle.label | Store |
|
||||
| by_reference.cpp:39:9:39:21 | *#this [a] | semmle.label | *#this [a] |
|
||||
| by_reference.cpp:40:12:40:15 | this indirection [a] | semmle.label | this indirection [a] |
|
||||
| by_reference.cpp:40:18:40:28 | Store | semmle.label | Store |
|
||||
| by_reference.cpp:40:18:40:28 | call to getDirectly | semmle.label | call to getDirectly |
|
||||
| by_reference.cpp:43:9:43:27 | *#this [a] | semmle.label | *#this [a] |
|
||||
| by_reference.cpp:44:12:44:24 | Store | semmle.label | Store |
|
||||
| by_reference.cpp:44:12:44:24 | call to nonMemberGetA | semmle.label | call to nonMemberGetA |
|
||||
| by_reference.cpp:44:26:44:29 | this indirection [a] | semmle.label | this indirection [a] |
|
||||
| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | semmle.label | setDirectly output argument [a] |
|
||||
| by_reference.cpp:50:5:50:15 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input |
|
||||
@@ -392,6 +502,17 @@ nodes
|
||||
| by_reference.cpp:132:14:132:14 | a | semmle.label | a |
|
||||
| by_reference.cpp:134:29:134:29 | a | semmle.label | a |
|
||||
| by_reference.cpp:136:16:136:16 | a | semmle.label | a |
|
||||
| complex.cpp:9:7:9:7 | *#this [a_] | semmle.label | *#this [a_] |
|
||||
| complex.cpp:9:7:9:7 | *#this [b_] | semmle.label | *#this [b_] |
|
||||
| complex.cpp:9:20:9:21 | Store | semmle.label | Store |
|
||||
| complex.cpp:10:7:10:7 | *#this [b_] | semmle.label | *#this [b_] |
|
||||
| complex.cpp:10:20:10:21 | Store | semmle.label | Store |
|
||||
| complex.cpp:11:17:11:17 | a | semmle.label | a |
|
||||
| complex.cpp:11:22:11:27 | Chi [a_] | semmle.label | Chi [a_] |
|
||||
| complex.cpp:12:8:12:11 | *#this [a_] | semmle.label | *#this [a_] |
|
||||
| complex.cpp:12:17:12:17 | b | semmle.label | b |
|
||||
| complex.cpp:12:22:12:27 | Chi [a_] | semmle.label | Chi [a_] |
|
||||
| complex.cpp:12:22:12:27 | Chi [b_] | semmle.label | Chi [b_] |
|
||||
| complex.cpp:40:17:40:17 | *b [a_] | semmle.label | *b [a_] |
|
||||
| complex.cpp:40:17:40:17 | *b [b_] | semmle.label | *b [b_] |
|
||||
| complex.cpp:42:16:42:16 | a output argument [b_] | semmle.label | a output argument [b_] |
|
||||
@@ -418,6 +539,16 @@ nodes
|
||||
| complex.cpp:62:7:62:8 | b2 indirection [b_] | semmle.label | b2 indirection [b_] |
|
||||
| complex.cpp:65:7:65:8 | b3 indirection [a_] | semmle.label | b3 indirection [a_] |
|
||||
| complex.cpp:65:7:65:8 | b3 indirection [b_] | semmle.label | b3 indirection [b_] |
|
||||
| constructors.cpp:18:9:18:9 | *#this [a_] | semmle.label | *#this [a_] |
|
||||
| constructors.cpp:18:9:18:9 | *#this [b_] | semmle.label | *#this [b_] |
|
||||
| constructors.cpp:18:22:18:23 | Store | semmle.label | Store |
|
||||
| constructors.cpp:19:9:19:9 | *#this [b_] | semmle.label | *#this [b_] |
|
||||
| constructors.cpp:19:22:19:23 | Store | semmle.label | Store |
|
||||
| constructors.cpp:23:13:23:13 | a | semmle.label | a |
|
||||
| constructors.cpp:23:20:23:20 | b | semmle.label | b |
|
||||
| constructors.cpp:23:28:23:28 | Chi [a_] | semmle.label | Chi [a_] |
|
||||
| constructors.cpp:23:35:23:35 | Chi [a_] | semmle.label | Chi [a_] |
|
||||
| constructors.cpp:23:35:23:35 | Chi [b_] | semmle.label | Chi [b_] |
|
||||
| constructors.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] |
|
||||
| constructors.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] |
|
||||
| constructors.cpp:28:10:28:10 | a output argument [b_] | semmle.label | a output argument [b_] |
|
||||
@@ -442,6 +573,17 @@ nodes
|
||||
| constructors.cpp:43:9:43:9 | g indirection [b_] | semmle.label | g indirection [b_] |
|
||||
| constructors.cpp:46:9:46:9 | h indirection [a_] | semmle.label | h indirection [a_] |
|
||||
| constructors.cpp:46:9:46:9 | h indirection [b_] | semmle.label | h indirection [b_] |
|
||||
| simple.cpp:18:9:18:9 | *#this [a_] | semmle.label | *#this [a_] |
|
||||
| simple.cpp:18:9:18:9 | *#this [b_] | semmle.label | *#this [b_] |
|
||||
| simple.cpp:18:22:18:23 | Store | semmle.label | Store |
|
||||
| simple.cpp:19:9:19:9 | *#this [b_] | semmle.label | *#this [b_] |
|
||||
| simple.cpp:19:22:19:23 | Store | semmle.label | Store |
|
||||
| simple.cpp:20:19:20:19 | a | semmle.label | a |
|
||||
| simple.cpp:20:24:20:29 | Chi [a_] | semmle.label | Chi [a_] |
|
||||
| simple.cpp:21:10:21:13 | *#this [a_] | semmle.label | *#this [a_] |
|
||||
| simple.cpp:21:19:21:19 | b | semmle.label | b |
|
||||
| simple.cpp:21:24:21:29 | Chi [a_] | semmle.label | Chi [a_] |
|
||||
| simple.cpp:21:24:21:29 | Chi [b_] | semmle.label | Chi [b_] |
|
||||
| simple.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] |
|
||||
| simple.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] |
|
||||
| simple.cpp:28:10:28:10 | a output argument [b_] | semmle.label | a output argument [b_] |
|
||||
@@ -472,6 +614,8 @@ nodes
|
||||
| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] |
|
||||
| simple.cpp:67:13:67:13 | i | semmle.label | i |
|
||||
| simple.cpp:78:9:78:15 | *#this [f1] | semmle.label | *#this [f1] |
|
||||
| simple.cpp:79:19:79:20 | Store | semmle.label | Store |
|
||||
| simple.cpp:83:9:83:28 | Store [f1] | semmle.label | Store [f1] |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 |
|
||||
@@ -490,6 +634,49 @@ nodes
|
||||
| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:31:23:31:23 | a | semmle.label | a |
|
||||
| struct_init.c:36:10:36:24 | & ... indirection [a] | semmle.label | & ... indirection [a] |
|
||||
subpaths
|
||||
| A.cpp:55:8:55:10 | new | A.cpp:27:17:27:17 | c | A.cpp:27:22:27:32 | Chi [c] | A.cpp:55:5:55:5 | set output argument [c] |
|
||||
| A.cpp:56:10:56:10 | b indirection [c] | A.cpp:28:8:28:10 | *#this [c] | A.cpp:28:29:28:29 | Store | A.cpp:56:13:56:15 | call to get |
|
||||
| A.cpp:57:10:57:25 | new indirection [c] | A.cpp:28:8:28:10 | *#this [c] | A.cpp:28:29:28:29 | Store | A.cpp:57:28:57:30 | call to get |
|
||||
| A.cpp:57:11:57:24 | new | A.cpp:23:10:23:10 | c | A.cpp:25:7:25:17 | Chi [c] | A.cpp:57:11:57:24 | B output argument [c] |
|
||||
| A.cpp:126:8:126:10 | new | A.cpp:27:17:27:17 | c | A.cpp:27:22:27:32 | Chi [c] | A.cpp:126:5:126:5 | set output argument [c] |
|
||||
| A.cpp:151:12:151:24 | b | A.cpp:140:13:140:13 | b | A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] |
|
||||
| by_reference.cpp:20:11:20:21 | value | by_reference.cpp:15:26:15:30 | value | by_reference.cpp:16:5:16:19 | Chi [a] | by_reference.cpp:20:5:20:8 | setDirectly output argument [a] |
|
||||
| by_reference.cpp:24:5:24:17 | value | by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:16 | Chi [a] | by_reference.cpp:24:19:24:22 | nonMemberSetA output argument [a] |
|
||||
| by_reference.cpp:40:12:40:15 | this indirection [a] | by_reference.cpp:35:9:35:19 | *#this [a] | by_reference.cpp:36:18:36:18 | Store | by_reference.cpp:40:18:40:28 | call to getDirectly |
|
||||
| by_reference.cpp:44:26:44:29 | this indirection [a] | by_reference.cpp:31:46:31:46 | *s [a] | by_reference.cpp:32:15:32:15 | Store | by_reference.cpp:44:12:44:24 | call to nonMemberGetA |
|
||||
| by_reference.cpp:50:5:50:15 | call to user_input | by_reference.cpp:15:26:15:30 | value | by_reference.cpp:16:5:16:19 | Chi [a] | by_reference.cpp:50:3:50:3 | setDirectly output argument [a] |
|
||||
| by_reference.cpp:51:8:51:8 | s indirection [a] | by_reference.cpp:35:9:35:19 | *#this [a] | by_reference.cpp:36:18:36:18 | Store | by_reference.cpp:51:10:51:20 | call to getDirectly |
|
||||
| by_reference.cpp:56:5:56:17 | call to user_input | by_reference.cpp:19:28:19:32 | value | by_reference.cpp:20:5:20:8 | Chi [a] | by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] |
|
||||
| by_reference.cpp:57:8:57:8 | s indirection [a] | by_reference.cpp:39:9:39:21 | *#this [a] | by_reference.cpp:40:18:40:28 | Store | by_reference.cpp:57:10:57:22 | call to getIndirectly |
|
||||
| by_reference.cpp:62:5:62:23 | call to user_input | by_reference.cpp:23:34:23:38 | value | by_reference.cpp:24:19:24:22 | Chi [a] | by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] |
|
||||
| by_reference.cpp:63:8:63:8 | s indirection [a] | by_reference.cpp:43:9:43:27 | *#this [a] | by_reference.cpp:44:12:44:24 | Store | by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
|
||||
| by_reference.cpp:68:3:68:15 | call to user_input | by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:16 | Chi [a] | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] |
|
||||
| by_reference.cpp:69:22:69:23 | & ... indirection [a] | by_reference.cpp:31:46:31:46 | *s [a] | by_reference.cpp:32:15:32:15 | Store | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
|
||||
| complex.cpp:42:16:42:16 | f indirection [a_] | complex.cpp:9:7:9:7 | *#this [a_] | complex.cpp:9:20:9:21 | Store | complex.cpp:42:18:42:18 | call to a |
|
||||
| complex.cpp:42:16:42:16 | f indirection [b_] | complex.cpp:9:7:9:7 | *#this [b_] | complex.cpp:9:7:9:7 | *#this [b_] | complex.cpp:42:16:42:16 | a output argument [b_] |
|
||||
| complex.cpp:43:16:43:16 | f indirection [b_] | complex.cpp:10:7:10:7 | *#this [b_] | complex.cpp:10:20:10:21 | Store | complex.cpp:43:18:43:18 | call to b |
|
||||
| complex.cpp:53:14:53:17 | call to user_input | complex.cpp:11:17:11:17 | a | complex.cpp:11:22:11:27 | Chi [a_] | complex.cpp:53:12:53:12 | setA output argument [a_] |
|
||||
| complex.cpp:54:14:54:17 | call to user_input | complex.cpp:12:17:12:17 | b | complex.cpp:12:22:12:27 | Chi [b_] | complex.cpp:54:12:54:12 | setB output argument [b_] |
|
||||
| complex.cpp:55:14:55:17 | call to user_input | complex.cpp:11:17:11:17 | a | complex.cpp:11:22:11:27 | Chi [a_] | complex.cpp:55:12:55:12 | setA output argument [a_] |
|
||||
| complex.cpp:56:12:56:12 | f indirection [a_] | complex.cpp:12:8:12:11 | *#this [a_] | complex.cpp:12:22:12:27 | Chi [a_] | complex.cpp:56:12:56:12 | setB output argument [a_] |
|
||||
| complex.cpp:56:14:56:17 | call to user_input | complex.cpp:12:17:12:17 | b | complex.cpp:12:22:12:27 | Chi [b_] | complex.cpp:56:12:56:12 | setB output argument [b_] |
|
||||
| constructors.cpp:28:10:28:10 | f indirection [a_] | constructors.cpp:18:9:18:9 | *#this [a_] | constructors.cpp:18:22:18:23 | Store | constructors.cpp:28:12:28:12 | call to a |
|
||||
| constructors.cpp:28:10:28:10 | f indirection [b_] | constructors.cpp:18:9:18:9 | *#this [b_] | constructors.cpp:18:9:18:9 | *#this [b_] | constructors.cpp:28:10:28:10 | a output argument [b_] |
|
||||
| constructors.cpp:29:10:29:10 | f indirection [b_] | constructors.cpp:19:9:19:9 | *#this [b_] | constructors.cpp:19:22:19:23 | Store | constructors.cpp:29:12:29:12 | call to b |
|
||||
| constructors.cpp:34:11:34:26 | call to user_input | constructors.cpp:23:13:23:13 | a | constructors.cpp:23:35:23:35 | Chi [a_] | constructors.cpp:34:11:34:26 | Foo output argument [a_] |
|
||||
| constructors.cpp:35:11:35:26 | call to user_input | constructors.cpp:23:20:23:20 | b | constructors.cpp:23:35:23:35 | Chi [b_] | constructors.cpp:35:11:35:26 | Foo output argument [b_] |
|
||||
| constructors.cpp:36:11:36:37 | call to user_input | constructors.cpp:23:13:23:13 | a | constructors.cpp:23:35:23:35 | Chi [a_] | constructors.cpp:36:11:36:37 | Foo output argument [a_] |
|
||||
| constructors.cpp:36:11:36:37 | call to user_input | constructors.cpp:23:20:23:20 | b | constructors.cpp:23:35:23:35 | Chi [b_] | constructors.cpp:36:11:36:37 | Foo output argument [b_] |
|
||||
| simple.cpp:28:10:28:10 | f indirection [a_] | simple.cpp:18:9:18:9 | *#this [a_] | simple.cpp:18:22:18:23 | Store | simple.cpp:28:12:28:12 | call to a |
|
||||
| simple.cpp:28:10:28:10 | f indirection [b_] | simple.cpp:18:9:18:9 | *#this [b_] | simple.cpp:18:9:18:9 | *#this [b_] | simple.cpp:28:10:28:10 | a output argument [b_] |
|
||||
| simple.cpp:29:10:29:10 | f indirection [b_] | simple.cpp:19:9:19:9 | *#this [b_] | simple.cpp:19:22:19:23 | Store | simple.cpp:29:12:29:12 | call to b |
|
||||
| simple.cpp:39:7:39:10 | call to user_input | simple.cpp:20:19:20:19 | a | simple.cpp:20:24:20:29 | Chi [a_] | simple.cpp:39:5:39:5 | setA output argument [a_] |
|
||||
| simple.cpp:40:7:40:10 | call to user_input | simple.cpp:21:19:21:19 | b | simple.cpp:21:24:21:29 | Chi [b_] | simple.cpp:40:5:40:5 | setB output argument [b_] |
|
||||
| simple.cpp:41:7:41:10 | call to user_input | simple.cpp:20:19:20:19 | a | simple.cpp:20:24:20:29 | Chi [a_] | simple.cpp:41:5:41:5 | setA output argument [a_] |
|
||||
| simple.cpp:42:5:42:5 | h indirection [a_] | simple.cpp:21:10:21:13 | *#this [a_] | simple.cpp:21:24:21:29 | Chi [a_] | simple.cpp:42:5:42:5 | setB output argument [a_] |
|
||||
| simple.cpp:42:7:42:10 | call to user_input | simple.cpp:21:19:21:19 | b | simple.cpp:21:24:21:29 | Chi [b_] | simple.cpp:42:5:42:5 | setB output argument [b_] |
|
||||
| simple.cpp:84:14:84:20 | this indirection [f1] | simple.cpp:78:9:78:15 | *#this [f1] | simple.cpp:79:19:79:20 | Store | simple.cpp:84:14:84:20 | call to getf2f1 |
|
||||
#select
|
||||
| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... |
|
||||
| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new |
|
||||
|
||||
@@ -1,21 +1,46 @@
|
||||
edges
|
||||
| A.cpp:23:10:23:10 | c | A.cpp:25:7:25:17 | ... = ... |
|
||||
| A.cpp:25:7:25:17 | ... = ... | A.cpp:25:7:25:10 | this [post update] [c] |
|
||||
| A.cpp:27:17:27:17 | c | A.cpp:27:22:27:32 | ... = ... |
|
||||
| A.cpp:27:22:27:32 | ... = ... | A.cpp:27:22:27:25 | this [post update] [c] |
|
||||
| A.cpp:28:8:28:10 | this [c] | A.cpp:28:23:28:26 | this [c] |
|
||||
| A.cpp:28:23:28:26 | this [c] | A.cpp:28:29:28:29 | c |
|
||||
| A.cpp:29:23:29:23 | c | A.cpp:31:20:31:20 | c |
|
||||
| A.cpp:31:14:31:21 | call to B [c] | A.cpp:31:14:31:21 | new [c] |
|
||||
| A.cpp:31:20:31:20 | c | A.cpp:23:10:23:10 | c |
|
||||
| A.cpp:31:20:31:20 | c | A.cpp:31:14:31:21 | call to B [c] |
|
||||
| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... |
|
||||
| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c |
|
||||
| A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] |
|
||||
| A.cpp:48:20:48:20 | c | A.cpp:29:23:29:23 | c |
|
||||
| A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | call to make [c] |
|
||||
| A.cpp:49:10:49:10 | b [c] | A.cpp:49:13:49:13 | c |
|
||||
| A.cpp:55:5:55:5 | ref arg b [c] | A.cpp:56:10:56:10 | b [c] |
|
||||
| A.cpp:55:12:55:19 | new | A.cpp:27:17:27:17 | c |
|
||||
| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | ref arg b [c] |
|
||||
| A.cpp:56:10:56:10 | b [c] | A.cpp:28:8:28:10 | this [c] |
|
||||
| A.cpp:56:10:56:10 | b [c] | A.cpp:56:13:56:15 | call to get |
|
||||
| A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new [c] |
|
||||
| A.cpp:57:11:57:24 | new [c] | A.cpp:28:8:28:10 | this [c] |
|
||||
| A.cpp:57:11:57:24 | new [c] | A.cpp:57:28:57:30 | call to get |
|
||||
| A.cpp:57:17:57:23 | new | A.cpp:23:10:23:10 | c |
|
||||
| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | call to B [c] |
|
||||
| A.cpp:64:10:64:15 | call to setOnB [c] | A.cpp:66:10:66:11 | b2 [c] |
|
||||
| A.cpp:64:21:64:28 | new | A.cpp:64:10:64:15 | call to setOnB [c] |
|
||||
| A.cpp:64:21:64:28 | new | A.cpp:85:26:85:26 | c |
|
||||
| A.cpp:66:10:66:11 | b2 [c] | A.cpp:66:14:66:14 | c |
|
||||
| A.cpp:73:10:73:19 | call to setOnBWrap [c] | A.cpp:75:10:75:11 | b2 [c] |
|
||||
| A.cpp:73:25:73:32 | new | A.cpp:73:10:73:19 | call to setOnBWrap [c] |
|
||||
| A.cpp:73:25:73:32 | new | A.cpp:78:27:78:27 | c |
|
||||
| A.cpp:75:10:75:11 | b2 [c] | A.cpp:75:14:75:14 | c |
|
||||
| A.cpp:78:27:78:27 | c | A.cpp:81:21:81:21 | c |
|
||||
| A.cpp:81:10:81:15 | call to setOnB [c] | A.cpp:82:12:82:24 | ... ? ... : ... [c] |
|
||||
| A.cpp:81:21:81:21 | c | A.cpp:81:10:81:15 | call to setOnB [c] |
|
||||
| A.cpp:81:21:81:21 | c | A.cpp:85:26:85:26 | c |
|
||||
| A.cpp:85:26:85:26 | c | A.cpp:90:15:90:15 | c |
|
||||
| A.cpp:90:7:90:8 | ref arg b2 [c] | A.cpp:91:14:91:15 | b2 [c] |
|
||||
| A.cpp:90:15:90:15 | c | A.cpp:27:17:27:17 | c |
|
||||
| A.cpp:90:15:90:15 | c | A.cpp:90:7:90:8 | ref arg b2 [c] |
|
||||
| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | ... = ... |
|
||||
| A.cpp:100:5:100:6 | c1 [post update] [a] | A.cpp:101:8:101:9 | c1 [a] |
|
||||
| A.cpp:100:5:100:13 | ... = ... | A.cpp:100:5:100:6 | c1 [post update] [a] |
|
||||
@@ -25,9 +50,11 @@ edges
|
||||
| A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a |
|
||||
| A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a |
|
||||
| A.cpp:126:5:126:5 | ref arg b [c] | A.cpp:131:8:131:8 | ref arg b [c] |
|
||||
| A.cpp:126:12:126:18 | new | A.cpp:27:17:27:17 | c |
|
||||
| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | ref arg b [c] |
|
||||
| A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] |
|
||||
| A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c |
|
||||
| A.cpp:140:13:140:13 | b | A.cpp:143:7:143:31 | ... = ... |
|
||||
| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] |
|
||||
| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:151:18:151:18 | ref arg b [c] |
|
||||
| A.cpp:142:7:142:20 | ... = ... | A.cpp:142:7:142:7 | b [post update] [c] |
|
||||
@@ -35,11 +62,13 @@ edges
|
||||
| A.cpp:143:7:143:10 | this [post update] [b, c] | A.cpp:151:12:151:24 | call to D [b, c] |
|
||||
| A.cpp:143:7:143:10 | this [post update] [b] | A.cpp:151:12:151:24 | call to D [b] |
|
||||
| A.cpp:143:7:143:31 | ... = ... | A.cpp:143:7:143:10 | this [post update] [b] |
|
||||
| A.cpp:143:7:143:31 | ... = ... | A.cpp:143:7:143:10 | this [post update] [b] |
|
||||
| A.cpp:143:7:143:31 | ... = ... [c] | A.cpp:143:7:143:10 | this [post update] [b, c] |
|
||||
| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | ... = ... |
|
||||
| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b |
|
||||
| A.cpp:151:12:151:24 | call to D [b, c] | A.cpp:153:10:153:10 | d [b, c] |
|
||||
| A.cpp:151:12:151:24 | call to D [b] | A.cpp:152:10:152:10 | d [b] |
|
||||
| A.cpp:151:18:151:18 | b | A.cpp:140:13:140:13 | b |
|
||||
| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | call to D [b] |
|
||||
| A.cpp:151:18:151:18 | ref arg b [c] | A.cpp:154:10:154:10 | b [c] |
|
||||
| A.cpp:152:10:152:10 | d [b] | A.cpp:152:13:152:13 | b |
|
||||
@@ -49,11 +78,14 @@ edges
|
||||
| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b |
|
||||
| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | l1 [head] |
|
||||
| A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] |
|
||||
| A.cpp:160:29:160:29 | b | A.cpp:181:15:181:21 | newHead |
|
||||
| A.cpp:161:18:161:40 | call to MyList [next, head] | A.cpp:162:38:162:39 | l2 [next, head] |
|
||||
| A.cpp:161:38:161:39 | l1 [head] | A.cpp:161:18:161:40 | call to MyList [next, head] |
|
||||
| A.cpp:161:38:161:39 | l1 [head] | A.cpp:181:32:181:35 | next [head] |
|
||||
| A.cpp:162:18:162:40 | call to MyList [next, next, head] | A.cpp:165:10:165:11 | l3 [next, next, head] |
|
||||
| A.cpp:162:18:162:40 | call to MyList [next, next, head] | A.cpp:167:44:167:44 | l [next, next, head] |
|
||||
| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, head] |
|
||||
| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:181:32:181:35 | next [next, head] |
|
||||
| A.cpp:165:10:165:11 | l3 [next, next, head] | A.cpp:165:14:165:17 | next [next, head] |
|
||||
| A.cpp:165:14:165:17 | next [next, head] | A.cpp:165:20:165:23 | next [head] |
|
||||
| A.cpp:165:20:165:23 | next [head] | A.cpp:165:26:165:29 | head |
|
||||
@@ -62,20 +94,38 @@ edges
|
||||
| A.cpp:167:47:167:50 | next [head] | A.cpp:169:12:169:12 | l [head] |
|
||||
| A.cpp:167:47:167:50 | next [next, head] | A.cpp:167:44:167:44 | l [next, head] |
|
||||
| A.cpp:169:12:169:12 | l [head] | A.cpp:169:15:169:18 | head |
|
||||
| A.cpp:181:15:181:21 | newHead | A.cpp:183:7:183:20 | ... = ... |
|
||||
| A.cpp:181:32:181:35 | next [head] | A.cpp:184:7:184:23 | ... = ... [head] |
|
||||
| A.cpp:181:32:181:35 | next [next, head] | A.cpp:184:7:184:23 | ... = ... [next, head] |
|
||||
| A.cpp:183:7:183:20 | ... = ... | A.cpp:183:7:183:10 | this [post update] [head] |
|
||||
| A.cpp:184:7:184:23 | ... = ... [head] | A.cpp:184:7:184:10 | this [post update] [next, head] |
|
||||
| A.cpp:184:7:184:23 | ... = ... [next, head] | A.cpp:184:7:184:10 | this [post update] [next, next, head] |
|
||||
| B.cpp:6:15:6:24 | new | B.cpp:7:25:7:25 | e |
|
||||
| B.cpp:7:16:7:35 | call to Box1 [elem1] | B.cpp:8:25:8:26 | b1 [elem1] |
|
||||
| B.cpp:7:25:7:25 | e | B.cpp:7:16:7:35 | call to Box1 [elem1] |
|
||||
| B.cpp:7:25:7:25 | e | B.cpp:33:16:33:17 | e1 |
|
||||
| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | B.cpp:9:10:9:11 | b2 [box1, elem1] |
|
||||
| B.cpp:8:25:8:26 | b1 [elem1] | B.cpp:8:16:8:27 | call to Box2 [box1, elem1] |
|
||||
| B.cpp:8:25:8:26 | b1 [elem1] | B.cpp:44:16:44:17 | b1 [elem1] |
|
||||
| B.cpp:9:10:9:11 | b2 [box1, elem1] | B.cpp:9:14:9:17 | box1 [elem1] |
|
||||
| B.cpp:9:14:9:17 | box1 [elem1] | B.cpp:9:20:9:24 | elem1 |
|
||||
| B.cpp:15:15:15:27 | new | B.cpp:16:37:16:37 | e |
|
||||
| B.cpp:16:16:16:38 | call to Box1 [elem2] | B.cpp:17:25:17:26 | b1 [elem2] |
|
||||
| B.cpp:16:37:16:37 | e | B.cpp:16:16:16:38 | call to Box1 [elem2] |
|
||||
| B.cpp:16:37:16:37 | e | B.cpp:33:26:33:27 | e2 |
|
||||
| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | B.cpp:19:10:19:11 | b2 [box1, elem2] |
|
||||
| B.cpp:17:25:17:26 | b1 [elem2] | B.cpp:17:16:17:27 | call to Box2 [box1, elem2] |
|
||||
| B.cpp:17:25:17:26 | b1 [elem2] | B.cpp:44:16:44:17 | b1 [elem2] |
|
||||
| B.cpp:19:10:19:11 | b2 [box1, elem2] | B.cpp:19:14:19:17 | box1 [elem2] |
|
||||
| B.cpp:19:14:19:17 | box1 [elem2] | B.cpp:19:20:19:24 | elem2 |
|
||||
| B.cpp:33:16:33:17 | e1 | B.cpp:35:7:35:22 | ... = ... |
|
||||
| B.cpp:33:26:33:27 | e2 | B.cpp:36:7:36:22 | ... = ... |
|
||||
| B.cpp:35:7:35:22 | ... = ... | B.cpp:35:7:35:10 | this [post update] [elem1] |
|
||||
| B.cpp:36:7:36:22 | ... = ... | B.cpp:36:7:36:10 | this [post update] [elem2] |
|
||||
| B.cpp:44:16:44:17 | b1 [elem1] | B.cpp:46:7:46:21 | ... = ... [elem1] |
|
||||
| B.cpp:44:16:44:17 | b1 [elem2] | B.cpp:46:7:46:21 | ... = ... [elem2] |
|
||||
| B.cpp:46:7:46:21 | ... = ... [elem1] | B.cpp:46:7:46:10 | this [post update] [box1, elem1] |
|
||||
| B.cpp:46:7:46:21 | ... = ... [elem2] | B.cpp:46:7:46:10 | this [post update] [box1, elem2] |
|
||||
| C.cpp:18:12:18:18 | call to C [s1] | C.cpp:19:5:19:5 | c [s1] |
|
||||
| C.cpp:18:12:18:18 | call to C [s3] | C.cpp:19:5:19:5 | c [s3] |
|
||||
| C.cpp:19:5:19:5 | c [s1] | C.cpp:27:8:27:11 | this [s1] |
|
||||
@@ -89,8 +139,16 @@ edges
|
||||
| C.cpp:27:8:27:11 | this [s3] | C.cpp:31:10:31:11 | this [s3] |
|
||||
| C.cpp:29:10:29:11 | this [s1] | C.cpp:29:10:29:11 | s1 |
|
||||
| C.cpp:31:10:31:11 | this [s3] | C.cpp:31:10:31:11 | s3 |
|
||||
| D.cpp:10:11:10:17 | this [elem] | D.cpp:10:30:10:33 | this [elem] |
|
||||
| D.cpp:10:30:10:33 | this [elem] | D.cpp:10:30:10:33 | elem |
|
||||
| D.cpp:11:24:11:24 | e | D.cpp:11:29:11:36 | ... = ... |
|
||||
| D.cpp:11:29:11:36 | ... = ... | D.cpp:11:29:11:32 | this [post update] [elem] |
|
||||
| D.cpp:17:11:17:17 | this [box, elem] | D.cpp:17:30:17:32 | this [box, elem] |
|
||||
| D.cpp:17:30:17:32 | this [box, elem] | D.cpp:17:30:17:32 | box [elem] |
|
||||
| D.cpp:21:30:21:31 | b2 [box, elem] | D.cpp:22:10:22:11 | b2 [box, elem] |
|
||||
| D.cpp:22:10:22:11 | b2 [box, elem] | D.cpp:17:11:17:17 | this [box, elem] |
|
||||
| D.cpp:22:10:22:11 | b2 [box, elem] | D.cpp:22:14:22:20 | call to getBox1 [elem] |
|
||||
| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:10:11:10:17 | this [elem] |
|
||||
| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:22:25:22:31 | call to getElem |
|
||||
| D.cpp:28:15:28:24 | new | D.cpp:30:5:30:20 | ... = ... |
|
||||
| D.cpp:30:5:30:5 | b [post update] [box, elem] | D.cpp:31:14:31:14 | b [box, elem] |
|
||||
@@ -100,6 +158,7 @@ edges
|
||||
| D.cpp:35:15:35:24 | new | D.cpp:37:21:37:21 | e |
|
||||
| D.cpp:37:5:37:5 | b [post update] [box, elem] | D.cpp:38:14:38:14 | b [box, elem] |
|
||||
| D.cpp:37:8:37:10 | ref arg box [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] |
|
||||
| D.cpp:37:21:37:21 | e | D.cpp:11:24:11:24 | e |
|
||||
| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | ref arg box [elem] |
|
||||
| D.cpp:38:14:38:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] |
|
||||
| D.cpp:42:15:42:24 | new | D.cpp:44:5:44:26 | ... = ... |
|
||||
@@ -110,6 +169,7 @@ edges
|
||||
| D.cpp:49:15:49:24 | new | D.cpp:51:27:51:27 | e |
|
||||
| D.cpp:51:5:51:5 | ref arg b [box, elem] | D.cpp:52:14:52:14 | b [box, elem] |
|
||||
| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | D.cpp:51:5:51:5 | ref arg b [box, elem] |
|
||||
| D.cpp:51:27:51:27 | e | D.cpp:11:24:11:24 | e |
|
||||
| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] |
|
||||
| D.cpp:52:14:52:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] |
|
||||
| D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... |
|
||||
@@ -223,17 +283,45 @@ edges
|
||||
| arrays.cpp:44:8:44:25 | access to array [data] | arrays.cpp:44:27:44:30 | data |
|
||||
| arrays.cpp:44:10:44:17 | indirect [arr, data] | arrays.cpp:44:20:44:22 | arr [data] |
|
||||
| arrays.cpp:44:20:44:22 | arr [data] | arrays.cpp:44:8:44:25 | access to array [data] |
|
||||
| by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:16 | ... = ... |
|
||||
| by_reference.cpp:12:5:12:16 | ... = ... | by_reference.cpp:12:5:12:5 | s [post update] [a] |
|
||||
| by_reference.cpp:15:26:15:30 | value | by_reference.cpp:16:5:16:19 | ... = ... |
|
||||
| by_reference.cpp:16:5:16:19 | ... = ... | by_reference.cpp:16:5:16:8 | this [post update] [a] |
|
||||
| by_reference.cpp:19:28:19:32 | value | by_reference.cpp:20:23:20:27 | value |
|
||||
| by_reference.cpp:20:23:20:27 | value | by_reference.cpp:15:26:15:30 | value |
|
||||
| by_reference.cpp:20:23:20:27 | value | by_reference.cpp:20:5:20:8 | ref arg this [a] |
|
||||
| by_reference.cpp:23:34:23:38 | value | by_reference.cpp:24:25:24:29 | value |
|
||||
| by_reference.cpp:24:25:24:29 | value | by_reference.cpp:11:48:11:52 | value |
|
||||
| by_reference.cpp:24:25:24:29 | value | by_reference.cpp:24:19:24:22 | ref arg this [a] |
|
||||
| by_reference.cpp:31:46:31:46 | s [a] | by_reference.cpp:32:12:32:12 | s [a] |
|
||||
| by_reference.cpp:32:12:32:12 | s [a] | by_reference.cpp:32:15:32:15 | a |
|
||||
| by_reference.cpp:35:9:35:19 | this [a] | by_reference.cpp:36:12:36:15 | this [a] |
|
||||
| by_reference.cpp:36:12:36:15 | this [a] | by_reference.cpp:36:18:36:18 | a |
|
||||
| by_reference.cpp:39:9:39:21 | this [a] | by_reference.cpp:40:12:40:15 | this [a] |
|
||||
| by_reference.cpp:40:12:40:15 | this [a] | by_reference.cpp:35:9:35:19 | this [a] |
|
||||
| by_reference.cpp:40:12:40:15 | this [a] | by_reference.cpp:40:18:40:28 | call to getDirectly |
|
||||
| by_reference.cpp:43:9:43:27 | this [a] | by_reference.cpp:44:26:44:29 | this [a] |
|
||||
| by_reference.cpp:44:26:44:29 | this [a] | by_reference.cpp:31:46:31:46 | s [a] |
|
||||
| by_reference.cpp:44:26:44:29 | this [a] | by_reference.cpp:44:12:44:24 | call to nonMemberGetA |
|
||||
| by_reference.cpp:50:3:50:3 | ref arg s [a] | by_reference.cpp:51:8:51:8 | s [a] |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:15:26:15:30 | value |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] |
|
||||
| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:35:9:35:19 | this [a] |
|
||||
| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly |
|
||||
| by_reference.cpp:56:3:56:3 | ref arg s [a] | by_reference.cpp:57:8:57:8 | s [a] |
|
||||
| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:19:28:19:32 | value |
|
||||
| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | ref arg s [a] |
|
||||
| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:39:9:39:21 | this [a] |
|
||||
| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly |
|
||||
| by_reference.cpp:62:3:62:3 | ref arg s [a] | by_reference.cpp:63:8:63:8 | s [a] |
|
||||
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:23:34:23:38 | value |
|
||||
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | ref arg s [a] |
|
||||
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:43:9:43:27 | this [a] |
|
||||
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
|
||||
| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:11:48:11:52 | value |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] |
|
||||
| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:31:46:31:46 | s [a] |
|
||||
| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
|
||||
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] |
|
||||
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] |
|
||||
@@ -308,29 +396,43 @@ edges
|
||||
| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] |
|
||||
| by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a |
|
||||
| complex.cpp:9:7:9:7 | this [a_] | complex.cpp:9:20:9:21 | this [a_] |
|
||||
| complex.cpp:9:20:9:21 | this [a_] | complex.cpp:9:20:9:21 | a_ |
|
||||
| complex.cpp:10:7:10:7 | this [b_] | complex.cpp:10:20:10:21 | this [b_] |
|
||||
| complex.cpp:10:20:10:21 | this [b_] | complex.cpp:10:20:10:21 | b_ |
|
||||
| complex.cpp:11:17:11:17 | a | complex.cpp:11:22:11:27 | ... = ... |
|
||||
| complex.cpp:11:22:11:27 | ... = ... | complex.cpp:11:22:11:23 | this [post update] [a_] |
|
||||
| complex.cpp:12:17:12:17 | b | complex.cpp:12:22:12:27 | ... = ... |
|
||||
| complex.cpp:12:22:12:27 | ... = ... | complex.cpp:12:22:12:23 | this [post update] [b_] |
|
||||
| complex.cpp:40:17:40:17 | b [inner, f, a_] | complex.cpp:42:8:42:8 | b [inner, f, a_] |
|
||||
| complex.cpp:40:17:40:17 | b [inner, f, b_] | complex.cpp:43:8:43:8 | b [inner, f, b_] |
|
||||
| complex.cpp:42:8:42:8 | b [inner, f, a_] | complex.cpp:42:10:42:14 | inner [f, a_] |
|
||||
| complex.cpp:42:10:42:14 | inner [f, a_] | complex.cpp:42:16:42:16 | f [a_] |
|
||||
| complex.cpp:42:16:42:16 | f [a_] | complex.cpp:9:7:9:7 | this [a_] |
|
||||
| complex.cpp:42:16:42:16 | f [a_] | complex.cpp:42:18:42:18 | call to a |
|
||||
| complex.cpp:43:8:43:8 | b [inner, f, b_] | complex.cpp:43:10:43:14 | inner [f, b_] |
|
||||
| complex.cpp:43:10:43:14 | inner [f, b_] | complex.cpp:43:16:43:16 | f [b_] |
|
||||
| complex.cpp:43:16:43:16 | f [b_] | complex.cpp:10:7:10:7 | this [b_] |
|
||||
| complex.cpp:43:16:43:16 | f [b_] | complex.cpp:43:18:43:18 | call to b |
|
||||
| complex.cpp:53:3:53:4 | b1 [post update] [inner, f, a_] | complex.cpp:59:7:59:8 | b1 [inner, f, a_] |
|
||||
| complex.cpp:53:6:53:10 | inner [post update] [f, a_] | complex.cpp:53:3:53:4 | b1 [post update] [inner, f, a_] |
|
||||
| complex.cpp:53:12:53:12 | ref arg f [a_] | complex.cpp:53:6:53:10 | inner [post update] [f, a_] |
|
||||
| complex.cpp:53:19:53:28 | call to user_input | complex.cpp:11:17:11:17 | a |
|
||||
| complex.cpp:53:19:53:28 | call to user_input | complex.cpp:53:12:53:12 | ref arg f [a_] |
|
||||
| complex.cpp:54:3:54:4 | b2 [post update] [inner, f, b_] | complex.cpp:62:7:62:8 | b2 [inner, f, b_] |
|
||||
| complex.cpp:54:6:54:10 | inner [post update] [f, b_] | complex.cpp:54:3:54:4 | b2 [post update] [inner, f, b_] |
|
||||
| complex.cpp:54:12:54:12 | ref arg f [b_] | complex.cpp:54:6:54:10 | inner [post update] [f, b_] |
|
||||
| complex.cpp:54:19:54:28 | call to user_input | complex.cpp:12:17:12:17 | b |
|
||||
| complex.cpp:54:19:54:28 | call to user_input | complex.cpp:54:12:54:12 | ref arg f [b_] |
|
||||
| complex.cpp:55:3:55:4 | b3 [post update] [inner, f, a_] | complex.cpp:65:7:65:8 | b3 [inner, f, a_] |
|
||||
| complex.cpp:55:6:55:10 | inner [post update] [f, a_] | complex.cpp:55:3:55:4 | b3 [post update] [inner, f, a_] |
|
||||
| complex.cpp:55:12:55:12 | ref arg f [a_] | complex.cpp:55:6:55:10 | inner [post update] [f, a_] |
|
||||
| complex.cpp:55:19:55:28 | call to user_input | complex.cpp:11:17:11:17 | a |
|
||||
| complex.cpp:55:19:55:28 | call to user_input | complex.cpp:55:12:55:12 | ref arg f [a_] |
|
||||
| complex.cpp:56:3:56:4 | b3 [post update] [inner, f, b_] | complex.cpp:65:7:65:8 | b3 [inner, f, b_] |
|
||||
| complex.cpp:56:6:56:10 | inner [post update] [f, b_] | complex.cpp:56:3:56:4 | b3 [post update] [inner, f, b_] |
|
||||
| complex.cpp:56:12:56:12 | ref arg f [b_] | complex.cpp:56:6:56:10 | inner [post update] [f, b_] |
|
||||
| complex.cpp:56:19:56:28 | call to user_input | complex.cpp:12:17:12:17 | b |
|
||||
| complex.cpp:56:19:56:28 | call to user_input | complex.cpp:56:12:56:12 | ref arg f [b_] |
|
||||
| complex.cpp:59:7:59:8 | b1 [inner, f, a_] | complex.cpp:40:17:40:17 | b [inner, f, a_] |
|
||||
| complex.cpp:62:7:62:8 | b2 [inner, f, b_] | complex.cpp:40:17:40:17 | b [inner, f, b_] |
|
||||
@@ -357,22 +459,43 @@ edges
|
||||
| conflated.cpp:60:17:60:26 | call to user_input | conflated.cpp:60:3:60:28 | ... = ... |
|
||||
| conflated.cpp:61:8:61:9 | ll [next, y] | conflated.cpp:61:12:61:15 | next [y] |
|
||||
| conflated.cpp:61:12:61:15 | next [y] | conflated.cpp:61:18:61:18 | y |
|
||||
| constructors.cpp:18:9:18:9 | this [a_] | constructors.cpp:18:22:18:23 | this [a_] |
|
||||
| constructors.cpp:18:22:18:23 | this [a_] | constructors.cpp:18:22:18:23 | a_ |
|
||||
| constructors.cpp:19:9:19:9 | this [b_] | constructors.cpp:19:22:19:23 | this [b_] |
|
||||
| constructors.cpp:19:22:19:23 | this [b_] | constructors.cpp:19:22:19:23 | b_ |
|
||||
| constructors.cpp:23:13:23:13 | a | constructors.cpp:23:28:23:28 | a |
|
||||
| constructors.cpp:23:20:23:20 | b | constructors.cpp:23:35:23:35 | b |
|
||||
| constructors.cpp:23:28:23:28 | a | constructors.cpp:23:25:23:29 | constructor init of field a_ [post-this] [a_] |
|
||||
| constructors.cpp:23:35:23:35 | b | constructors.cpp:23:32:23:36 | constructor init of field b_ [post-this] [b_] |
|
||||
| constructors.cpp:26:15:26:15 | f [a_] | constructors.cpp:28:10:28:10 | f [a_] |
|
||||
| constructors.cpp:26:15:26:15 | f [b_] | constructors.cpp:29:10:29:10 | f [b_] |
|
||||
| constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:18:9:18:9 | this [a_] |
|
||||
| constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:28:12:28:12 | call to a |
|
||||
| constructors.cpp:29:10:29:10 | f [b_] | constructors.cpp:19:9:19:9 | this [b_] |
|
||||
| constructors.cpp:29:10:29:10 | f [b_] | constructors.cpp:29:12:29:12 | call to b |
|
||||
| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:23:13:23:13 | a |
|
||||
| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | call to Foo [a_] |
|
||||
| constructors.cpp:34:11:34:26 | call to Foo [a_] | constructors.cpp:40:9:40:9 | f [a_] |
|
||||
| constructors.cpp:35:11:35:26 | call to Foo [b_] | constructors.cpp:43:9:43:9 | g [b_] |
|
||||
| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:23:20:23:20 | b |
|
||||
| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | call to Foo [b_] |
|
||||
| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:23:13:23:13 | a |
|
||||
| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [a_] |
|
||||
| constructors.cpp:36:11:36:37 | call to Foo [a_] | constructors.cpp:46:9:46:9 | h [a_] |
|
||||
| constructors.cpp:36:11:36:37 | call to Foo [b_] | constructors.cpp:46:9:46:9 | h [b_] |
|
||||
| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:23:20:23:20 | b |
|
||||
| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [b_] |
|
||||
| constructors.cpp:40:9:40:9 | f [a_] | constructors.cpp:26:15:26:15 | f [a_] |
|
||||
| constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] |
|
||||
| constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] |
|
||||
| constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] |
|
||||
| qualifiers.cpp:9:21:9:25 | value | qualifiers.cpp:9:30:9:44 | ... = ... |
|
||||
| qualifiers.cpp:9:30:9:44 | ... = ... | qualifiers.cpp:9:30:9:33 | this [post update] [a] |
|
||||
| qualifiers.cpp:12:40:12:44 | value | qualifiers.cpp:12:49:12:64 | ... = ... |
|
||||
| qualifiers.cpp:12:49:12:64 | ... = ... | qualifiers.cpp:12:49:12:53 | inner [post update] [a] |
|
||||
| qualifiers.cpp:13:42:13:46 | value | qualifiers.cpp:13:51:13:65 | ... = ... |
|
||||
| qualifiers.cpp:13:51:13:55 | inner [post update] [a] | qualifiers.cpp:13:29:13:33 | inner [a] |
|
||||
| qualifiers.cpp:13:51:13:65 | ... = ... | qualifiers.cpp:13:51:13:55 | inner [post update] [a] |
|
||||
| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:22:5:22:38 | ... = ... | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] |
|
||||
| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] |
|
||||
@@ -381,17 +504,20 @@ edges
|
||||
| qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a |
|
||||
| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:9:21:9:25 | value |
|
||||
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] |
|
||||
| qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] |
|
||||
| qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a |
|
||||
| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | qualifiers.cpp:33:10:33:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:12:40:12:44 | value |
|
||||
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] |
|
||||
| qualifiers.cpp:33:10:33:14 | outer [inner, a] | qualifiers.cpp:33:16:33:20 | inner [a] |
|
||||
| qualifiers.cpp:33:16:33:20 | inner [a] | qualifiers.cpp:33:23:33:23 | a |
|
||||
| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] |
|
||||
| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | qualifiers.cpp:38:10:38:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:13:42:13:46 | value |
|
||||
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] |
|
||||
| qualifiers.cpp:38:10:38:14 | outer [inner, a] | qualifiers.cpp:38:16:38:20 | inner [a] |
|
||||
| qualifiers.cpp:38:16:38:20 | inner [a] | qualifiers.cpp:38:23:38:23 | a |
|
||||
@@ -420,17 +546,31 @@ edges
|
||||
| realistic.cpp:61:25:61:27 | bar [baz, userInput, bufferLen] | realistic.cpp:61:21:61:30 | access to array [baz, userInput, bufferLen] |
|
||||
| realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] | realistic.cpp:61:37:61:45 | userInput [bufferLen] |
|
||||
| realistic.cpp:61:37:61:45 | userInput [bufferLen] | realistic.cpp:61:47:61:55 | bufferLen |
|
||||
| simple.cpp:18:9:18:9 | this [a_] | simple.cpp:18:22:18:23 | this [a_] |
|
||||
| simple.cpp:18:22:18:23 | this [a_] | simple.cpp:18:22:18:23 | a_ |
|
||||
| simple.cpp:19:9:19:9 | this [b_] | simple.cpp:19:22:19:23 | this [b_] |
|
||||
| simple.cpp:19:22:19:23 | this [b_] | simple.cpp:19:22:19:23 | b_ |
|
||||
| simple.cpp:20:19:20:19 | a | simple.cpp:20:24:20:29 | ... = ... |
|
||||
| simple.cpp:20:24:20:29 | ... = ... | simple.cpp:20:24:20:25 | this [post update] [a_] |
|
||||
| simple.cpp:21:19:21:19 | b | simple.cpp:21:24:21:29 | ... = ... |
|
||||
| simple.cpp:21:24:21:29 | ... = ... | simple.cpp:21:24:21:25 | this [post update] [b_] |
|
||||
| simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] |
|
||||
| simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] |
|
||||
| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:18:9:18:9 | this [a_] |
|
||||
| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a |
|
||||
| simple.cpp:29:10:29:10 | f [b_] | simple.cpp:19:9:19:9 | this [b_] |
|
||||
| simple.cpp:29:10:29:10 | f [b_] | simple.cpp:29:12:29:12 | call to b |
|
||||
| simple.cpp:39:5:39:5 | ref arg f [a_] | simple.cpp:45:9:45:9 | f [a_] |
|
||||
| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:20:19:20:19 | a |
|
||||
| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | ref arg f [a_] |
|
||||
| simple.cpp:40:5:40:5 | ref arg g [b_] | simple.cpp:48:9:48:9 | g [b_] |
|
||||
| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:21:19:21:19 | b |
|
||||
| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | ref arg g [b_] |
|
||||
| simple.cpp:41:5:41:5 | ref arg h [a_] | simple.cpp:51:9:51:9 | h [a_] |
|
||||
| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:20:19:20:19 | a |
|
||||
| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | ref arg h [a_] |
|
||||
| simple.cpp:42:5:42:5 | ref arg h [b_] | simple.cpp:51:9:51:9 | h [b_] |
|
||||
| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:21:19:21:19 | b |
|
||||
| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | ref arg h [b_] |
|
||||
| simple.cpp:45:9:45:9 | f [a_] | simple.cpp:26:15:26:15 | f [a_] |
|
||||
| simple.cpp:48:9:48:9 | g [b_] | simple.cpp:26:15:26:15 | f [b_] |
|
||||
@@ -440,10 +580,14 @@ edges
|
||||
| simple.cpp:65:5:65:22 | ... = ... | simple.cpp:65:5:65:5 | a [post update] [i] |
|
||||
| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | ... = ... |
|
||||
| simple.cpp:67:10:67:11 | a2 [i] | simple.cpp:67:13:67:13 | i |
|
||||
| simple.cpp:78:9:78:15 | this [f2, f1] | simple.cpp:79:16:79:17 | this [f2, f1] |
|
||||
| simple.cpp:79:16:79:17 | f2 [f1] | simple.cpp:79:19:79:20 | f1 |
|
||||
| simple.cpp:79:16:79:17 | this [f2, f1] | simple.cpp:79:16:79:17 | f2 [f1] |
|
||||
| simple.cpp:83:9:83:10 | f2 [post update] [f1] | simple.cpp:83:9:83:10 | this [post update] [f2, f1] |
|
||||
| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | simple.cpp:84:14:84:20 | this [f2, f1] |
|
||||
| simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... |
|
||||
| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:78:9:78:15 | this [f2, f1] |
|
||||
| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 |
|
||||
| simple.cpp:92:5:92:5 | a [post update] [i] | simple.cpp:94:10:94:11 | a2 [i] |
|
||||
| simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] |
|
||||
@@ -477,6 +621,19 @@ edges
|
||||
| struct_init.c:46:10:46:14 | outer [pointerAB, a] | struct_init.c:46:16:46:24 | pointerAB [a] |
|
||||
| struct_init.c:46:16:46:24 | pointerAB [a] | struct_init.c:14:24:14:25 | ab [a] |
|
||||
nodes
|
||||
| A.cpp:23:10:23:10 | c | semmle.label | c |
|
||||
| A.cpp:25:7:25:10 | this [post update] [c] | semmle.label | this [post update] [c] |
|
||||
| A.cpp:25:7:25:17 | ... = ... | semmle.label | ... = ... |
|
||||
| A.cpp:27:17:27:17 | c | semmle.label | c |
|
||||
| A.cpp:27:22:27:25 | this [post update] [c] | semmle.label | this [post update] [c] |
|
||||
| A.cpp:27:22:27:32 | ... = ... | semmle.label | ... = ... |
|
||||
| A.cpp:28:8:28:10 | this [c] | semmle.label | this [c] |
|
||||
| A.cpp:28:23:28:26 | this [c] | semmle.label | this [c] |
|
||||
| A.cpp:28:29:28:29 | c | semmle.label | c |
|
||||
| A.cpp:29:23:29:23 | c | semmle.label | c |
|
||||
| A.cpp:31:14:31:21 | call to B [c] | semmle.label | call to B [c] |
|
||||
| A.cpp:31:14:31:21 | new [c] | semmle.label | new [c] |
|
||||
| A.cpp:31:20:31:20 | c | semmle.label | c |
|
||||
| A.cpp:41:15:41:21 | new | semmle.label | new |
|
||||
| A.cpp:43:10:43:12 | & ... | semmle.label | & ... |
|
||||
| A.cpp:47:12:47:18 | new | semmle.label | new |
|
||||
@@ -500,6 +657,14 @@ nodes
|
||||
| A.cpp:73:25:73:32 | new | semmle.label | new |
|
||||
| A.cpp:75:10:75:11 | b2 [c] | semmle.label | b2 [c] |
|
||||
| A.cpp:75:14:75:14 | c | semmle.label | c |
|
||||
| A.cpp:78:27:78:27 | c | semmle.label | c |
|
||||
| A.cpp:81:10:81:15 | call to setOnB [c] | semmle.label | call to setOnB [c] |
|
||||
| A.cpp:81:21:81:21 | c | semmle.label | c |
|
||||
| A.cpp:82:12:82:24 | ... ? ... : ... [c] | semmle.label | ... ? ... : ... [c] |
|
||||
| A.cpp:85:26:85:26 | c | semmle.label | c |
|
||||
| A.cpp:90:7:90:8 | ref arg b2 [c] | semmle.label | ref arg b2 [c] |
|
||||
| A.cpp:90:15:90:15 | c | semmle.label | c |
|
||||
| A.cpp:91:14:91:15 | b2 [c] | semmle.label | b2 [c] |
|
||||
| A.cpp:98:12:98:18 | new | semmle.label | new |
|
||||
| A.cpp:100:5:100:6 | c1 [post update] [a] | semmle.label | c1 [post update] [a] |
|
||||
| A.cpp:100:5:100:13 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -514,11 +679,14 @@ nodes
|
||||
| A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] |
|
||||
| A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] |
|
||||
| A.cpp:132:13:132:13 | c | semmle.label | c |
|
||||
| A.cpp:140:13:140:13 | b | semmle.label | b |
|
||||
| A.cpp:142:7:142:7 | b [post update] [c] | semmle.label | b [post update] [c] |
|
||||
| A.cpp:142:7:142:20 | ... = ... | semmle.label | ... = ... |
|
||||
| A.cpp:142:14:142:20 | new | semmle.label | new |
|
||||
| A.cpp:143:7:143:10 | this [post update] [b, c] | semmle.label | this [post update] [b, c] |
|
||||
| A.cpp:143:7:143:10 | this [post update] [b] | semmle.label | this [post update] [b] |
|
||||
| A.cpp:143:7:143:10 | this [post update] [b] | semmle.label | this [post update] [b] |
|
||||
| A.cpp:143:7:143:31 | ... = ... | semmle.label | ... = ... |
|
||||
| A.cpp:143:7:143:31 | ... = ... | semmle.label | ... = ... |
|
||||
| A.cpp:143:7:143:31 | ... = ... [c] | semmle.label | ... = ... [c] |
|
||||
| A.cpp:143:25:143:31 | new | semmle.label | new |
|
||||
@@ -551,6 +719,15 @@ nodes
|
||||
| A.cpp:167:47:167:50 | next [next, head] | semmle.label | next [next, head] |
|
||||
| A.cpp:169:12:169:12 | l [head] | semmle.label | l [head] |
|
||||
| A.cpp:169:15:169:18 | head | semmle.label | head |
|
||||
| A.cpp:181:15:181:21 | newHead | semmle.label | newHead |
|
||||
| A.cpp:181:32:181:35 | next [head] | semmle.label | next [head] |
|
||||
| A.cpp:181:32:181:35 | next [next, head] | semmle.label | next [next, head] |
|
||||
| A.cpp:183:7:183:10 | this [post update] [head] | semmle.label | this [post update] [head] |
|
||||
| A.cpp:183:7:183:20 | ... = ... | semmle.label | ... = ... |
|
||||
| A.cpp:184:7:184:10 | this [post update] [next, head] | semmle.label | this [post update] [next, head] |
|
||||
| A.cpp:184:7:184:10 | this [post update] [next, next, head] | semmle.label | this [post update] [next, next, head] |
|
||||
| A.cpp:184:7:184:23 | ... = ... [head] | semmle.label | ... = ... [head] |
|
||||
| A.cpp:184:7:184:23 | ... = ... [next, head] | semmle.label | ... = ... [next, head] |
|
||||
| B.cpp:6:15:6:24 | new | semmle.label | new |
|
||||
| B.cpp:7:16:7:35 | call to Box1 [elem1] | semmle.label | call to Box1 [elem1] |
|
||||
| B.cpp:7:25:7:25 | e | semmle.label | e |
|
||||
@@ -567,6 +744,18 @@ nodes
|
||||
| B.cpp:19:10:19:11 | b2 [box1, elem2] | semmle.label | b2 [box1, elem2] |
|
||||
| B.cpp:19:14:19:17 | box1 [elem2] | semmle.label | box1 [elem2] |
|
||||
| B.cpp:19:20:19:24 | elem2 | semmle.label | elem2 |
|
||||
| B.cpp:33:16:33:17 | e1 | semmle.label | e1 |
|
||||
| B.cpp:33:26:33:27 | e2 | semmle.label | e2 |
|
||||
| B.cpp:35:7:35:10 | this [post update] [elem1] | semmle.label | this [post update] [elem1] |
|
||||
| B.cpp:35:7:35:22 | ... = ... | semmle.label | ... = ... |
|
||||
| B.cpp:36:7:36:10 | this [post update] [elem2] | semmle.label | this [post update] [elem2] |
|
||||
| B.cpp:36:7:36:22 | ... = ... | semmle.label | ... = ... |
|
||||
| B.cpp:44:16:44:17 | b1 [elem1] | semmle.label | b1 [elem1] |
|
||||
| B.cpp:44:16:44:17 | b1 [elem2] | semmle.label | b1 [elem2] |
|
||||
| B.cpp:46:7:46:10 | this [post update] [box1, elem1] | semmle.label | this [post update] [box1, elem1] |
|
||||
| B.cpp:46:7:46:10 | this [post update] [box1, elem2] | semmle.label | this [post update] [box1, elem2] |
|
||||
| B.cpp:46:7:46:21 | ... = ... [elem1] | semmle.label | ... = ... [elem1] |
|
||||
| B.cpp:46:7:46:21 | ... = ... [elem2] | semmle.label | ... = ... [elem2] |
|
||||
| C.cpp:18:12:18:18 | call to C [s1] | semmle.label | call to C [s1] |
|
||||
| C.cpp:18:12:18:18 | call to C [s3] | semmle.label | call to C [s3] |
|
||||
| C.cpp:19:5:19:5 | c [s1] | semmle.label | c [s1] |
|
||||
@@ -582,6 +771,15 @@ nodes
|
||||
| C.cpp:29:10:29:11 | this [s1] | semmle.label | this [s1] |
|
||||
| C.cpp:31:10:31:11 | s3 | semmle.label | s3 |
|
||||
| C.cpp:31:10:31:11 | this [s3] | semmle.label | this [s3] |
|
||||
| D.cpp:10:11:10:17 | this [elem] | semmle.label | this [elem] |
|
||||
| D.cpp:10:30:10:33 | elem | semmle.label | elem |
|
||||
| D.cpp:10:30:10:33 | this [elem] | semmle.label | this [elem] |
|
||||
| D.cpp:11:24:11:24 | e | semmle.label | e |
|
||||
| D.cpp:11:29:11:32 | this [post update] [elem] | semmle.label | this [post update] [elem] |
|
||||
| D.cpp:11:29:11:36 | ... = ... | semmle.label | ... = ... |
|
||||
| D.cpp:17:11:17:17 | this [box, elem] | semmle.label | this [box, elem] |
|
||||
| D.cpp:17:30:17:32 | box [elem] | semmle.label | box [elem] |
|
||||
| D.cpp:17:30:17:32 | this [box, elem] | semmle.label | this [box, elem] |
|
||||
| D.cpp:21:30:21:31 | b2 [box, elem] | semmle.label | b2 [box, elem] |
|
||||
| D.cpp:22:10:22:11 | b2 [box, elem] | semmle.label | b2 [box, elem] |
|
||||
| D.cpp:22:14:22:20 | call to getBox1 [elem] | semmle.label | call to getBox1 [elem] |
|
||||
@@ -729,6 +927,30 @@ nodes
|
||||
| arrays.cpp:44:10:44:17 | indirect [arr, data] | semmle.label | indirect [arr, data] |
|
||||
| arrays.cpp:44:20:44:22 | arr [data] | semmle.label | arr [data] |
|
||||
| arrays.cpp:44:27:44:30 | data | semmle.label | data |
|
||||
| by_reference.cpp:11:48:11:52 | value | semmle.label | value |
|
||||
| by_reference.cpp:12:5:12:5 | s [post update] [a] | semmle.label | s [post update] [a] |
|
||||
| by_reference.cpp:12:5:12:16 | ... = ... | semmle.label | ... = ... |
|
||||
| by_reference.cpp:15:26:15:30 | value | semmle.label | value |
|
||||
| by_reference.cpp:16:5:16:8 | this [post update] [a] | semmle.label | this [post update] [a] |
|
||||
| by_reference.cpp:16:5:16:19 | ... = ... | semmle.label | ... = ... |
|
||||
| by_reference.cpp:19:28:19:32 | value | semmle.label | value |
|
||||
| by_reference.cpp:20:5:20:8 | ref arg this [a] | semmle.label | ref arg this [a] |
|
||||
| by_reference.cpp:20:23:20:27 | value | semmle.label | value |
|
||||
| by_reference.cpp:23:34:23:38 | value | semmle.label | value |
|
||||
| by_reference.cpp:24:19:24:22 | ref arg this [a] | semmle.label | ref arg this [a] |
|
||||
| by_reference.cpp:24:25:24:29 | value | semmle.label | value |
|
||||
| by_reference.cpp:31:46:31:46 | s [a] | semmle.label | s [a] |
|
||||
| by_reference.cpp:32:12:32:12 | s [a] | semmle.label | s [a] |
|
||||
| by_reference.cpp:32:15:32:15 | a | semmle.label | a |
|
||||
| by_reference.cpp:35:9:35:19 | this [a] | semmle.label | this [a] |
|
||||
| by_reference.cpp:36:12:36:15 | this [a] | semmle.label | this [a] |
|
||||
| by_reference.cpp:36:18:36:18 | a | semmle.label | a |
|
||||
| by_reference.cpp:39:9:39:21 | this [a] | semmle.label | this [a] |
|
||||
| by_reference.cpp:40:12:40:15 | this [a] | semmle.label | this [a] |
|
||||
| by_reference.cpp:40:18:40:28 | call to getDirectly | semmle.label | call to getDirectly |
|
||||
| by_reference.cpp:43:9:43:27 | this [a] | semmle.label | this [a] |
|
||||
| by_reference.cpp:44:12:44:24 | call to nonMemberGetA | semmle.label | call to nonMemberGetA |
|
||||
| by_reference.cpp:44:26:44:29 | this [a] | semmle.label | this [a] |
|
||||
| by_reference.cpp:50:3:50:3 | ref arg s [a] | semmle.label | ref arg s [a] |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] |
|
||||
@@ -818,6 +1040,18 @@ nodes
|
||||
| by_reference.cpp:135:27:135:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] |
|
||||
| by_reference.cpp:136:16:136:16 | a | semmle.label | a |
|
||||
| complex.cpp:9:7:9:7 | this [a_] | semmle.label | this [a_] |
|
||||
| complex.cpp:9:20:9:21 | a_ | semmle.label | a_ |
|
||||
| complex.cpp:9:20:9:21 | this [a_] | semmle.label | this [a_] |
|
||||
| complex.cpp:10:7:10:7 | this [b_] | semmle.label | this [b_] |
|
||||
| complex.cpp:10:20:10:21 | b_ | semmle.label | b_ |
|
||||
| complex.cpp:10:20:10:21 | this [b_] | semmle.label | this [b_] |
|
||||
| complex.cpp:11:17:11:17 | a | semmle.label | a |
|
||||
| complex.cpp:11:22:11:23 | this [post update] [a_] | semmle.label | this [post update] [a_] |
|
||||
| complex.cpp:11:22:11:27 | ... = ... | semmle.label | ... = ... |
|
||||
| complex.cpp:12:17:12:17 | b | semmle.label | b |
|
||||
| complex.cpp:12:22:12:23 | this [post update] [b_] | semmle.label | this [post update] [b_] |
|
||||
| complex.cpp:12:22:12:27 | ... = ... | semmle.label | ... = ... |
|
||||
| complex.cpp:40:17:40:17 | b [inner, f, a_] | semmle.label | b [inner, f, a_] |
|
||||
| complex.cpp:40:17:40:17 | b [inner, f, b_] | semmle.label | b [inner, f, b_] |
|
||||
| complex.cpp:42:8:42:8 | b [inner, f, a_] | semmle.label | b [inner, f, a_] |
|
||||
@@ -874,6 +1108,18 @@ nodes
|
||||
| conflated.cpp:61:8:61:9 | ll [next, y] | semmle.label | ll [next, y] |
|
||||
| conflated.cpp:61:12:61:15 | next [y] | semmle.label | next [y] |
|
||||
| conflated.cpp:61:18:61:18 | y | semmle.label | y |
|
||||
| constructors.cpp:18:9:18:9 | this [a_] | semmle.label | this [a_] |
|
||||
| constructors.cpp:18:22:18:23 | a_ | semmle.label | a_ |
|
||||
| constructors.cpp:18:22:18:23 | this [a_] | semmle.label | this [a_] |
|
||||
| constructors.cpp:19:9:19:9 | this [b_] | semmle.label | this [b_] |
|
||||
| constructors.cpp:19:22:19:23 | b_ | semmle.label | b_ |
|
||||
| constructors.cpp:19:22:19:23 | this [b_] | semmle.label | this [b_] |
|
||||
| constructors.cpp:23:13:23:13 | a | semmle.label | a |
|
||||
| constructors.cpp:23:20:23:20 | b | semmle.label | b |
|
||||
| constructors.cpp:23:25:23:29 | constructor init of field a_ [post-this] [a_] | semmle.label | constructor init of field a_ [post-this] [a_] |
|
||||
| constructors.cpp:23:28:23:28 | a | semmle.label | a |
|
||||
| constructors.cpp:23:32:23:36 | constructor init of field b_ [post-this] [b_] | semmle.label | constructor init of field b_ [post-this] [b_] |
|
||||
| constructors.cpp:23:35:23:35 | b | semmle.label | b |
|
||||
| constructors.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] |
|
||||
| constructors.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] |
|
||||
| constructors.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] |
|
||||
@@ -892,6 +1138,16 @@ nodes
|
||||
| constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] |
|
||||
| constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] |
|
||||
| constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] |
|
||||
| qualifiers.cpp:9:21:9:25 | value | semmle.label | value |
|
||||
| qualifiers.cpp:9:30:9:33 | this [post update] [a] | semmle.label | this [post update] [a] |
|
||||
| qualifiers.cpp:9:30:9:44 | ... = ... | semmle.label | ... = ... |
|
||||
| qualifiers.cpp:12:40:12:44 | value | semmle.label | value |
|
||||
| qualifiers.cpp:12:49:12:53 | inner [post update] [a] | semmle.label | inner [post update] [a] |
|
||||
| qualifiers.cpp:12:49:12:64 | ... = ... | semmle.label | ... = ... |
|
||||
| qualifiers.cpp:13:29:13:33 | inner [a] | semmle.label | inner [a] |
|
||||
| qualifiers.cpp:13:42:13:46 | value | semmle.label | value |
|
||||
| qualifiers.cpp:13:51:13:55 | inner [post update] [a] | semmle.label | inner [post update] [a] |
|
||||
| qualifiers.cpp:13:51:13:65 | ... = ... | semmle.label | ... = ... |
|
||||
| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:22:5:22:38 | ... = ... | semmle.label | ... = ... |
|
||||
| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] |
|
||||
@@ -946,6 +1202,18 @@ nodes
|
||||
| realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] | semmle.label | baz [userInput, bufferLen] |
|
||||
| realistic.cpp:61:37:61:45 | userInput [bufferLen] | semmle.label | userInput [bufferLen] |
|
||||
| realistic.cpp:61:47:61:55 | bufferLen | semmle.label | bufferLen |
|
||||
| simple.cpp:18:9:18:9 | this [a_] | semmle.label | this [a_] |
|
||||
| simple.cpp:18:22:18:23 | a_ | semmle.label | a_ |
|
||||
| simple.cpp:18:22:18:23 | this [a_] | semmle.label | this [a_] |
|
||||
| simple.cpp:19:9:19:9 | this [b_] | semmle.label | this [b_] |
|
||||
| simple.cpp:19:22:19:23 | b_ | semmle.label | b_ |
|
||||
| simple.cpp:19:22:19:23 | this [b_] | semmle.label | this [b_] |
|
||||
| simple.cpp:20:19:20:19 | a | semmle.label | a |
|
||||
| simple.cpp:20:24:20:25 | this [post update] [a_] | semmle.label | this [post update] [a_] |
|
||||
| simple.cpp:20:24:20:29 | ... = ... | semmle.label | ... = ... |
|
||||
| simple.cpp:21:19:21:19 | b | semmle.label | b |
|
||||
| simple.cpp:21:24:21:25 | this [post update] [b_] | semmle.label | this [post update] [b_] |
|
||||
| simple.cpp:21:24:21:29 | ... = ... | semmle.label | ... = ... |
|
||||
| simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] |
|
||||
| simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] |
|
||||
| simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] |
|
||||
@@ -969,6 +1237,10 @@ nodes
|
||||
| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:67:10:67:11 | a2 [i] | semmle.label | a2 [i] |
|
||||
| simple.cpp:67:13:67:13 | i | semmle.label | i |
|
||||
| simple.cpp:78:9:78:15 | this [f2, f1] | semmle.label | this [f2, f1] |
|
||||
| simple.cpp:79:16:79:17 | f2 [f1] | semmle.label | f2 [f1] |
|
||||
| simple.cpp:79:16:79:17 | this [f2, f1] | semmle.label | this [f2, f1] |
|
||||
| simple.cpp:79:19:79:20 | f1 | semmle.label | f1 |
|
||||
| simple.cpp:83:9:83:10 | f2 [post update] [f1] | semmle.label | f2 [post update] [f1] |
|
||||
| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | semmle.label | this [post update] [f2, f1] |
|
||||
| simple.cpp:83:9:83:28 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -1008,6 +1280,65 @@ nodes
|
||||
| struct_init.c:43:5:43:7 | & ... [a] | semmle.label | & ... [a] |
|
||||
| struct_init.c:46:10:46:14 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] |
|
||||
| struct_init.c:46:16:46:24 | pointerAB [a] | semmle.label | pointerAB [a] |
|
||||
subpaths
|
||||
| A.cpp:31:20:31:20 | c | A.cpp:23:10:23:10 | c | A.cpp:25:7:25:10 | this [post update] [c] | A.cpp:31:14:31:21 | call to B [c] |
|
||||
| A.cpp:48:20:48:20 | c | A.cpp:29:23:29:23 | c | A.cpp:31:14:31:21 | new [c] | A.cpp:48:12:48:18 | call to make [c] |
|
||||
| A.cpp:55:12:55:19 | new | A.cpp:27:17:27:17 | c | A.cpp:27:22:27:25 | this [post update] [c] | A.cpp:55:5:55:5 | ref arg b [c] |
|
||||
| A.cpp:56:10:56:10 | b [c] | A.cpp:28:8:28:10 | this [c] | A.cpp:28:29:28:29 | c | A.cpp:56:13:56:15 | call to get |
|
||||
| A.cpp:57:11:57:24 | new [c] | A.cpp:28:8:28:10 | this [c] | A.cpp:28:29:28:29 | c | A.cpp:57:28:57:30 | call to get |
|
||||
| A.cpp:57:17:57:23 | new | A.cpp:23:10:23:10 | c | A.cpp:25:7:25:10 | this [post update] [c] | A.cpp:57:11:57:24 | call to B [c] |
|
||||
| A.cpp:64:21:64:28 | new | A.cpp:85:26:85:26 | c | A.cpp:91:14:91:15 | b2 [c] | A.cpp:64:10:64:15 | call to setOnB [c] |
|
||||
| A.cpp:73:25:73:32 | new | A.cpp:78:27:78:27 | c | A.cpp:82:12:82:24 | ... ? ... : ... [c] | A.cpp:73:10:73:19 | call to setOnBWrap [c] |
|
||||
| A.cpp:81:21:81:21 | c | A.cpp:85:26:85:26 | c | A.cpp:91:14:91:15 | b2 [c] | A.cpp:81:10:81:15 | call to setOnB [c] |
|
||||
| A.cpp:90:15:90:15 | c | A.cpp:27:17:27:17 | c | A.cpp:27:22:27:25 | this [post update] [c] | A.cpp:90:7:90:8 | ref arg b2 [c] |
|
||||
| A.cpp:126:12:126:18 | new | A.cpp:27:17:27:17 | c | A.cpp:27:22:27:25 | this [post update] [c] | A.cpp:126:5:126:5 | ref arg b [c] |
|
||||
| A.cpp:151:18:151:18 | b | A.cpp:140:13:140:13 | b | A.cpp:143:7:143:10 | this [post update] [b] | A.cpp:151:12:151:24 | call to D [b] |
|
||||
| A.cpp:160:29:160:29 | b | A.cpp:181:15:181:21 | newHead | A.cpp:183:7:183:10 | this [post update] [head] | A.cpp:160:18:160:60 | call to MyList [head] |
|
||||
| A.cpp:161:38:161:39 | l1 [head] | A.cpp:181:32:181:35 | next [head] | A.cpp:184:7:184:10 | this [post update] [next, head] | A.cpp:161:18:161:40 | call to MyList [next, head] |
|
||||
| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:181:32:181:35 | next [next, head] | A.cpp:184:7:184:10 | this [post update] [next, next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, head] |
|
||||
| B.cpp:7:25:7:25 | e | B.cpp:33:16:33:17 | e1 | B.cpp:35:7:35:10 | this [post update] [elem1] | B.cpp:7:16:7:35 | call to Box1 [elem1] |
|
||||
| B.cpp:8:25:8:26 | b1 [elem1] | B.cpp:44:16:44:17 | b1 [elem1] | B.cpp:46:7:46:10 | this [post update] [box1, elem1] | B.cpp:8:16:8:27 | call to Box2 [box1, elem1] |
|
||||
| B.cpp:16:37:16:37 | e | B.cpp:33:26:33:27 | e2 | B.cpp:36:7:36:10 | this [post update] [elem2] | B.cpp:16:16:16:38 | call to Box1 [elem2] |
|
||||
| B.cpp:17:25:17:26 | b1 [elem2] | B.cpp:44:16:44:17 | b1 [elem2] | B.cpp:46:7:46:10 | this [post update] [box1, elem2] | B.cpp:17:16:17:27 | call to Box2 [box1, elem2] |
|
||||
| D.cpp:22:10:22:11 | b2 [box, elem] | D.cpp:17:11:17:17 | this [box, elem] | D.cpp:17:30:17:32 | box [elem] | D.cpp:22:14:22:20 | call to getBox1 [elem] |
|
||||
| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:10:11:10:17 | this [elem] | D.cpp:10:30:10:33 | elem | D.cpp:22:25:22:31 | call to getElem |
|
||||
| D.cpp:37:21:37:21 | e | D.cpp:11:24:11:24 | e | D.cpp:11:29:11:32 | this [post update] [elem] | D.cpp:37:8:37:10 | ref arg box [elem] |
|
||||
| D.cpp:51:27:51:27 | e | D.cpp:11:24:11:24 | e | D.cpp:11:29:11:32 | this [post update] [elem] | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] |
|
||||
| by_reference.cpp:20:23:20:27 | value | by_reference.cpp:15:26:15:30 | value | by_reference.cpp:16:5:16:8 | this [post update] [a] | by_reference.cpp:20:5:20:8 | ref arg this [a] |
|
||||
| by_reference.cpp:24:25:24:29 | value | by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:5 | s [post update] [a] | by_reference.cpp:24:19:24:22 | ref arg this [a] |
|
||||
| by_reference.cpp:40:12:40:15 | this [a] | by_reference.cpp:35:9:35:19 | this [a] | by_reference.cpp:36:18:36:18 | a | by_reference.cpp:40:18:40:28 | call to getDirectly |
|
||||
| by_reference.cpp:44:26:44:29 | this [a] | by_reference.cpp:31:46:31:46 | s [a] | by_reference.cpp:32:15:32:15 | a | by_reference.cpp:44:12:44:24 | call to nonMemberGetA |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:15:26:15:30 | value | by_reference.cpp:16:5:16:8 | this [post update] [a] | by_reference.cpp:50:3:50:3 | ref arg s [a] |
|
||||
| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:35:9:35:19 | this [a] | by_reference.cpp:36:18:36:18 | a | by_reference.cpp:51:10:51:20 | call to getDirectly |
|
||||
| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:19:28:19:32 | value | by_reference.cpp:20:5:20:8 | ref arg this [a] | by_reference.cpp:56:3:56:3 | ref arg s [a] |
|
||||
| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:39:9:39:21 | this [a] | by_reference.cpp:40:18:40:28 | call to getDirectly | by_reference.cpp:57:10:57:22 | call to getIndirectly |
|
||||
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:23:34:23:38 | value | by_reference.cpp:24:19:24:22 | ref arg this [a] | by_reference.cpp:62:3:62:3 | ref arg s [a] |
|
||||
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:43:9:43:27 | this [a] | by_reference.cpp:44:12:44:24 | call to nonMemberGetA | by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:5 | s [post update] [a] | by_reference.cpp:68:17:68:18 | ref arg & ... [a] |
|
||||
| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:31:46:31:46 | s [a] | by_reference.cpp:32:15:32:15 | a | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
|
||||
| complex.cpp:42:16:42:16 | f [a_] | complex.cpp:9:7:9:7 | this [a_] | complex.cpp:9:20:9:21 | a_ | complex.cpp:42:18:42:18 | call to a |
|
||||
| complex.cpp:43:16:43:16 | f [b_] | complex.cpp:10:7:10:7 | this [b_] | complex.cpp:10:20:10:21 | b_ | complex.cpp:43:18:43:18 | call to b |
|
||||
| complex.cpp:53:19:53:28 | call to user_input | complex.cpp:11:17:11:17 | a | complex.cpp:11:22:11:23 | this [post update] [a_] | complex.cpp:53:12:53:12 | ref arg f [a_] |
|
||||
| complex.cpp:54:19:54:28 | call to user_input | complex.cpp:12:17:12:17 | b | complex.cpp:12:22:12:23 | this [post update] [b_] | complex.cpp:54:12:54:12 | ref arg f [b_] |
|
||||
| complex.cpp:55:19:55:28 | call to user_input | complex.cpp:11:17:11:17 | a | complex.cpp:11:22:11:23 | this [post update] [a_] | complex.cpp:55:12:55:12 | ref arg f [a_] |
|
||||
| complex.cpp:56:19:56:28 | call to user_input | complex.cpp:12:17:12:17 | b | complex.cpp:12:22:12:23 | this [post update] [b_] | complex.cpp:56:12:56:12 | ref arg f [b_] |
|
||||
| constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:18:9:18:9 | this [a_] | constructors.cpp:18:22:18:23 | a_ | constructors.cpp:28:12:28:12 | call to a |
|
||||
| constructors.cpp:29:10:29:10 | f [b_] | constructors.cpp:19:9:19:9 | this [b_] | constructors.cpp:19:22:19:23 | b_ | constructors.cpp:29:12:29:12 | call to b |
|
||||
| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:23:13:23:13 | a | constructors.cpp:23:25:23:29 | constructor init of field a_ [post-this] [a_] | constructors.cpp:34:11:34:26 | call to Foo [a_] |
|
||||
| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:23:20:23:20 | b | constructors.cpp:23:32:23:36 | constructor init of field b_ [post-this] [b_] | constructors.cpp:35:11:35:26 | call to Foo [b_] |
|
||||
| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:23:13:23:13 | a | constructors.cpp:23:25:23:29 | constructor init of field a_ [post-this] [a_] | constructors.cpp:36:11:36:37 | call to Foo [a_] |
|
||||
| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:23:20:23:20 | b | constructors.cpp:23:32:23:36 | constructor init of field b_ [post-this] [b_] | constructors.cpp:36:11:36:37 | call to Foo [b_] |
|
||||
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:9:21:9:25 | value | qualifiers.cpp:9:30:9:33 | this [post update] [a] | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] |
|
||||
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:12:40:12:44 | value | qualifiers.cpp:12:49:12:53 | inner [post update] [a] | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] |
|
||||
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:13:42:13:46 | value | qualifiers.cpp:13:29:13:33 | inner [a] | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] |
|
||||
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:13:42:13:46 | value | qualifiers.cpp:13:51:13:55 | inner [post update] [a] | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] |
|
||||
| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:18:9:18:9 | this [a_] | simple.cpp:18:22:18:23 | a_ | simple.cpp:28:12:28:12 | call to a |
|
||||
| simple.cpp:29:10:29:10 | f [b_] | simple.cpp:19:9:19:9 | this [b_] | simple.cpp:19:22:19:23 | b_ | simple.cpp:29:12:29:12 | call to b |
|
||||
| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:20:19:20:19 | a | simple.cpp:20:24:20:25 | this [post update] [a_] | simple.cpp:39:5:39:5 | ref arg f [a_] |
|
||||
| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:21:19:21:19 | b | simple.cpp:21:24:21:25 | this [post update] [b_] | simple.cpp:40:5:40:5 | ref arg g [b_] |
|
||||
| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:20:19:20:19 | a | simple.cpp:20:24:20:25 | this [post update] [a_] | simple.cpp:41:5:41:5 | ref arg h [a_] |
|
||||
| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:21:19:21:19 | b | simple.cpp:21:24:21:25 | this [post update] [b_] | simple.cpp:42:5:42:5 | ref arg h [b_] |
|
||||
| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:78:9:78:15 | this [f2, f1] | simple.cpp:79:19:79:20 | f1 | simple.cpp:84:14:84:20 | call to getf2f1 |
|
||||
#select
|
||||
| A.cpp:43:10:43:12 | & ... | A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | & ... flows from $@ | A.cpp:41:15:41:21 | new | new |
|
||||
| A.cpp:49:13:49:13 | c | A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | c flows from $@ | A.cpp:47:12:47:18 | new | new |
|
||||
|
||||
4
cpp/ql/test/qlpack.lock.yml
Normal file
4
cpp/ql/test/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql-cpp-tests
|
||||
version: 0.0.0
|
||||
name: codeql/cpp-tests
|
||||
version: 0.0.2
|
||||
dependencies:
|
||||
codeql/cpp-all: "*"
|
||||
codeql/cpp-queries: "*"
|
||||
|
||||
@@ -34,6 +34,7 @@ nodes
|
||||
| test.cpp:88:21:88:22 | d2 | semmle.label | d2 |
|
||||
| test.cpp:95:21:95:21 | d | semmle.label | d |
|
||||
| test.cpp:96:21:96:23 | dss | semmle.label | dss |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:27:2:27:2 | b | test.cpp:57:19:57:19 | d | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:57:19:57:19 | d | here |
|
||||
| test.cpp:27:2:27:2 | b | test.cpp:74:19:74:21 | dss | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:74:19:74:21 | dss | here |
|
||||
|
||||
@@ -11,4 +11,15 @@
|
||||
| test.cpp:130:14:130:19 | buffer | Variable $@ may not be null terminated. | test.cpp:127:7:127:12 | buffer | buffer |
|
||||
| test.cpp:139:10:139:15 | buffer | Variable $@ may not be null terminated. | test.cpp:136:8:136:13 | buffer | buffer |
|
||||
| test.cpp:147:14:147:19 | buffer | Variable $@ may not be null terminated. | test.cpp:143:8:143:13 | buffer | buffer |
|
||||
| test.cpp:170:10:170:15 | buffer | Variable $@ may not be null terminated. | test.cpp:166:8:166:13 | buffer | buffer |
|
||||
| test.cpp:182:10:182:15 | buffer | Variable $@ may not be null terminated. | test.cpp:178:8:178:13 | buffer | buffer |
|
||||
| test.cpp:234:10:234:15 | buffer | Variable $@ may not be null terminated. | test.cpp:232:8:232:13 | buffer | buffer |
|
||||
| test.cpp:262:10:262:15 | buffer | Variable $@ may not be null terminated. | test.cpp:259:8:259:13 | buffer | buffer |
|
||||
| test.cpp:283:10:283:15 | buffer | Variable $@ may not be null terminated. | test.cpp:280:8:280:13 | buffer | buffer |
|
||||
| test.cpp:300:10:300:16 | buffer2 | Variable $@ may not be null terminated. | test.cpp:295:8:295:14 | buffer2 | buffer2 |
|
||||
| test.cpp:312:10:312:15 | buffer | Variable $@ may not be null terminated. | test.cpp:308:8:308:13 | buffer | buffer |
|
||||
| test.cpp:327:18:327:23 | buffer | Variable $@ may not be null terminated. | test.cpp:326:8:326:13 | buffer | buffer |
|
||||
| test.cpp:346:11:346:16 | buffer | Variable $@ may not be null terminated. | test.cpp:341:8:341:13 | buffer | buffer |
|
||||
| test.cpp:355:11:355:16 | buffer | Variable $@ may not be null terminated. | test.cpp:350:8:350:13 | buffer | buffer |
|
||||
| test.cpp:365:19:365:25 | buffer2 | Variable $@ may not be null terminated. | test.cpp:363:8:363:14 | buffer2 | buffer2 |
|
||||
| test.cpp:392:17:392:22 | buffer | Variable $@ may not be null terminated. | test.cpp:390:8:390:13 | buffer | buffer |
|
||||
| test.cpp:398:18:398:23 | buffer | Variable $@ may not be null terminated. | test.cpp:396:8:396:13 | buffer | buffer |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
| test.cpp:410:10:410:15 | buffer | $@ flows to here and may not be null terminated. | test.cpp:409:18:409:23 | buffer | User-provided value |
|
||||
| test.cpp:425:10:425:15 | buffer | $@ flows to here and may not be null terminated. | test.cpp:424:9:424:14 | buffer | User-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-170/ImproperNullTerminationTainted.ql
|
||||
@@ -1,16 +1,16 @@
|
||||
|
||||
typedef unsigned int size_t;
|
||||
typedef signed int ssize_t;
|
||||
typedef struct {} FILE;
|
||||
|
||||
size_t strlen(const char *s);
|
||||
char *strcpy(char *s1, const char *s2);
|
||||
char *strcat(char *s1, const char *s2);
|
||||
char *strdup(const char *s1);
|
||||
|
||||
void *malloc(size_t size);
|
||||
|
||||
void *memset(void *s, int c, size_t n);
|
||||
void *memcpy(void *s1, const void *s2, size_t n);
|
||||
|
||||
void read(int src, void *out, int num);
|
||||
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
ssize_t readlink(const char *path, char *buffer, size_t buffer_size);
|
||||
ssize_t readlinkat(int fd, const char *path, char *buffer, size_t buffer_size);
|
||||
|
||||
@@ -154,6 +154,18 @@ void test_readlink(int fd, const char *path, size_t sz)
|
||||
strdup(buffer); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
ssize_t len;
|
||||
|
||||
len = readlink(path, buffer, sizeof(buffer));
|
||||
if (len >= 0)
|
||||
{
|
||||
buffer[len - 1] = 0;
|
||||
strdup(buffer); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
@@ -209,3 +221,215 @@ void test_readlink(int fd, const char *path, size_t sz)
|
||||
strdup(buffer); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void doNothing(char *data) { };
|
||||
void doNothing2(const char *data);
|
||||
void clearBuffer(char *data, size_t size);
|
||||
|
||||
void test_strcat()
|
||||
{
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
strcat(buffer, "content"); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
buffer[0] = 0;
|
||||
strcat(buffer, "content"); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
buffer[10] = 0;
|
||||
strcat(buffer, "content"); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
buffer[0] = '\0';
|
||||
strcat(buffer, "content"); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
buffer[0] = 'a';
|
||||
strcat(buffer, "content"); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
*buffer = 0;
|
||||
strcat(buffer, "content"); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
strcpy(buffer, "con");
|
||||
strcat(buffer, "tent"); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
doNothing(buffer);
|
||||
strcat(buffer, "content"); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
doNothing2(buffer);
|
||||
strcat(buffer, "content"); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
{
|
||||
char buffer1[1024];
|
||||
char buffer2[1024];
|
||||
char *buffer_ptr = buffer1;
|
||||
|
||||
*buffer_ptr = 0;
|
||||
strcat(buffer1, "content"); // GOOD
|
||||
strcat(buffer2, "content"); // BAD
|
||||
strcat(buffer_ptr, "content"); // GOOD
|
||||
|
||||
buffer_ptr = buffer2;
|
||||
strcat(buffer_ptr, "content"); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
char *buffer_ptr = buffer;
|
||||
|
||||
*buffer_ptr = 'a';
|
||||
strcat(buffer, "content"); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
clearBuffer(buffer, 1024);
|
||||
strcat(buffer, "content"); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test_strlen(bool cond1, bool cond2)
|
||||
{
|
||||
{
|
||||
char buffer[1024];
|
||||
int i = strlen(buffer); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024] = {0};
|
||||
int i = strlen(buffer); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
char *ptr = "content";
|
||||
int i = strlen(ptr); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
if (cond1)
|
||||
buffer[0] = 0;
|
||||
if (cond1)
|
||||
strlen(buffer); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
if (cond1)
|
||||
buffer[0] = 0;
|
||||
if (cond2)
|
||||
strlen(buffer); // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void test_strcpy()
|
||||
{
|
||||
{
|
||||
char buffer1[1024];
|
||||
char buffer2[1024];
|
||||
|
||||
strcpy(buffer1, buffer2); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer1[1024];
|
||||
char buffer2[1024];
|
||||
|
||||
strcpy(buffer2, "content"); // GOOD
|
||||
strcpy(buffer1, buffer2); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void strcatWrapper(char *data, const char *with)
|
||||
{
|
||||
strcat(data, with);
|
||||
}
|
||||
|
||||
void strcatWrapper2(char *data, const char *with)
|
||||
{
|
||||
strcatWrapper(data, with);
|
||||
}
|
||||
|
||||
void test_wrappers()
|
||||
{
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
strcatWrapper(buffer, "content"); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
strcatWrapper2(buffer, "content"); // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void test_read_fread(int read_src, FILE *s)
|
||||
{
|
||||
const size_t buffer_size = 80;
|
||||
|
||||
{
|
||||
char buffer[buffer_size];
|
||||
|
||||
read(read_src, buffer, buffer_size * sizeof(char));
|
||||
strlen(buffer); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[buffer_size];
|
||||
|
||||
read(read_src, buffer, buffer_size * sizeof(char));
|
||||
buffer[buffer_size - 1] = 0;
|
||||
strlen(buffer); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[buffer_size];
|
||||
|
||||
fread(buffer, sizeof(char), buffer_size, s);
|
||||
strlen(buffer); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[buffer_size];
|
||||
|
||||
fread(buffer, sizeof(char), buffer_size, s);
|
||||
buffer[buffer_size - 1] = 0;
|
||||
strlen(buffer); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
edges
|
||||
| argvLocal.c:9:25:9:31 | correct | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | (const char *)... |
|
||||
| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | (const char *)... |
|
||||
| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array |
|
||||
@@ -13,6 +14,7 @@ edges
|
||||
| argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array |
|
||||
| argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array indirection |
|
||||
| argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array indirection |
|
||||
| argvLocal.c:96:15:96:21 | access to array indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | (const char *)... |
|
||||
| argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | (const char *)... |
|
||||
| argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | i1 |
|
||||
@@ -41,6 +43,7 @@ edges
|
||||
| argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 |
|
||||
| argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 indirection |
|
||||
| argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 indirection |
|
||||
| argvLocal.c:102:15:102:16 | i1 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | (const char *)... |
|
||||
| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | (const char *)... |
|
||||
| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array |
|
||||
@@ -69,6 +72,8 @@ edges
|
||||
| argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... |
|
||||
| argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... indirection |
|
||||
| argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... indirection |
|
||||
| argvLocal.c:107:15:107:19 | access to array indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:111:15:111:17 | * ... indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | (const char *)... |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | (const char *)... |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 |
|
||||
@@ -113,7 +118,9 @@ edges
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... indirection |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... indirection |
|
||||
| argvLocal.c:117:2:117:13 | i3 | argvLocal.c:9:25:9:31 | correct |
|
||||
| argvLocal.c:117:2:117:13 | i3 | argvLocal.c:117:15:117:16 | printWrapper output argument |
|
||||
| argvLocal.c:117:15:117:16 | i3 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:117:15:117:16 | i3 indirection | argvLocal.c:117:15:117:16 | printWrapper output argument |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | (const char *)... |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | i4 |
|
||||
@@ -129,7 +136,9 @@ edges
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... indirection |
|
||||
| argvLocal.c:122:2:122:13 | i4 | argvLocal.c:9:25:9:31 | correct |
|
||||
| argvLocal.c:122:2:122:13 | i4 | argvLocal.c:122:15:122:16 | printWrapper output argument |
|
||||
| argvLocal.c:122:15:122:16 | i4 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:122:15:122:16 | i4 indirection | argvLocal.c:122:15:122:16 | printWrapper output argument |
|
||||
| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | (const char *)... |
|
||||
| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ |
|
||||
@@ -165,7 +174,9 @@ edges
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... indirection |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... indirection |
|
||||
| argvLocal.c:128:2:128:13 | i5 | argvLocal.c:9:25:9:31 | correct |
|
||||
| argvLocal.c:128:2:128:13 | i5 | argvLocal.c:128:15:128:16 | printWrapper output argument |
|
||||
| argvLocal.c:128:15:128:16 | i5 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:128:15:128:16 | i5 indirection | argvLocal.c:128:15:128:16 | printWrapper output argument |
|
||||
| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | (const char *)... |
|
||||
| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | ... + ... |
|
||||
@@ -173,6 +184,9 @@ edges
|
||||
| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | ... + ... |
|
||||
| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | ... + ... |
|
||||
| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | ... + ... indirection |
|
||||
| argvLocal.c:132:15:132:20 | ... + ... indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:136:15:136:18 | -- ... indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:145:15:145:16 | i7 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | (const char *)... |
|
||||
| argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | (const char *)... |
|
||||
| argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 |
|
||||
@@ -187,6 +201,7 @@ edges
|
||||
| argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 |
|
||||
| argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 indirection |
|
||||
| argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 indirection |
|
||||
| argvLocal.c:151:15:151:16 | i8 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | (const char *)... |
|
||||
| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | (const char *)... |
|
||||
| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 |
|
||||
@@ -199,6 +214,7 @@ edges
|
||||
| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 |
|
||||
| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 indirection |
|
||||
| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 indirection |
|
||||
| argvLocal.c:158:15:158:16 | i9 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | (const char *)... |
|
||||
| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | (const char *)... |
|
||||
| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 |
|
||||
@@ -211,6 +227,7 @@ edges
|
||||
| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 |
|
||||
| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 indirection |
|
||||
| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 indirection |
|
||||
| argvLocal.c:165:15:165:17 | i91 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (char *)... |
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (char *)... |
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (const char *)... |
|
||||
@@ -229,6 +246,7 @@ edges
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
| argvLocal.c:170:15:170:26 | i10 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
nodes
|
||||
| argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct |
|
||||
| argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct |
|
||||
|
||||
@@ -8,8 +8,10 @@ edges
|
||||
| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r |
|
||||
| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r |
|
||||
| test.c:125:13:125:16 | call to rand | test.c:127:9:127:9 | r |
|
||||
| test.c:148:22:148:25 | call to rand | test.c:150:9:150:9 | r |
|
||||
| test.c:148:22:148:27 | (unsigned int)... | test.c:150:9:150:9 | r |
|
||||
| test.c:131:13:131:16 | call to rand | test.c:133:5:133:5 | r |
|
||||
| test.c:137:13:137:16 | call to rand | test.c:139:10:139:10 | r |
|
||||
| test.c:155:22:155:25 | call to rand | test.c:157:9:157:9 | r |
|
||||
| test.c:155:22:155:27 | (unsigned int)... | test.c:157:9:157:9 | r |
|
||||
| test.cpp:8:9:8:12 | Store | test.cpp:24:11:24:18 | call to get_rand |
|
||||
| test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store |
|
||||
| test.cpp:13:2:13:15 | Chi [[]] | test.cpp:30:13:30:14 | get_rand2 output argument [[]] |
|
||||
@@ -21,11 +23,23 @@ edges
|
||||
| test.cpp:30:13:30:14 | get_rand2 output argument [[]] | test.cpp:30:13:30:14 | Chi |
|
||||
| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r |
|
||||
| test.cpp:36:13:36:13 | get_rand3 output argument [[]] | test.cpp:36:13:36:13 | Chi |
|
||||
| test.cpp:78:10:78:13 | call to rand | test.cpp:82:10:82:10 | x |
|
||||
| test.cpp:90:10:90:13 | call to rand | test.cpp:94:10:94:10 | x |
|
||||
| test.cpp:129:10:129:13 | call to rand | test.cpp:132:10:132:10 | b |
|
||||
| test.cpp:147:11:147:14 | call to rand | test.cpp:149:11:149:16 | (int)... |
|
||||
| test.cpp:147:11:147:14 | call to rand | test.cpp:149:16:149:16 | y |
|
||||
| test.cpp:62:19:62:22 | call to rand | test.cpp:65:9:65:9 | x |
|
||||
| test.cpp:62:19:62:24 | (unsigned int)... | test.cpp:65:9:65:9 | x |
|
||||
| test.cpp:86:10:86:13 | call to rand | test.cpp:90:10:90:10 | x |
|
||||
| test.cpp:98:10:98:13 | call to rand | test.cpp:102:10:102:10 | x |
|
||||
| test.cpp:137:10:137:13 | call to rand | test.cpp:146:9:146:9 | y |
|
||||
| test.cpp:151:10:151:13 | call to rand | test.cpp:154:10:154:10 | b |
|
||||
| test.cpp:169:11:169:14 | call to rand | test.cpp:171:11:171:16 | (int)... |
|
||||
| test.cpp:169:11:169:14 | call to rand | test.cpp:171:16:171:16 | y |
|
||||
| test.cpp:189:10:189:13 | call to rand | test.cpp:196:7:196:7 | x |
|
||||
| test.cpp:189:10:189:13 | call to rand | test.cpp:198:7:198:7 | x |
|
||||
| test.cpp:189:10:189:13 | call to rand | test.cpp:199:7:199:7 | x |
|
||||
| test.cpp:190:10:190:13 | call to rand | test.cpp:204:7:204:7 | y |
|
||||
| test.cpp:190:10:190:13 | call to rand | test.cpp:205:7:205:7 | y |
|
||||
| test.cpp:190:10:190:13 | call to rand | test.cpp:208:7:208:7 | y |
|
||||
| test.cpp:215:11:215:14 | call to rand | test.cpp:219:8:219:8 | x |
|
||||
| test.cpp:223:20:223:23 | call to rand | test.cpp:227:8:227:8 | x |
|
||||
| test.cpp:223:20:223:25 | (unsigned int)... | test.cpp:227:8:227:8 | x |
|
||||
nodes
|
||||
| test.c:18:13:18:16 | call to rand | semmle.label | call to rand |
|
||||
| test.c:21:17:21:17 | r | semmle.label | r |
|
||||
@@ -43,9 +57,13 @@ nodes
|
||||
| test.c:100:5:100:5 | r | semmle.label | r |
|
||||
| test.c:125:13:125:16 | call to rand | semmle.label | call to rand |
|
||||
| test.c:127:9:127:9 | r | semmle.label | r |
|
||||
| test.c:148:22:148:25 | call to rand | semmle.label | call to rand |
|
||||
| test.c:148:22:148:27 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| test.c:150:9:150:9 | r | semmle.label | r |
|
||||
| test.c:131:13:131:16 | call to rand | semmle.label | call to rand |
|
||||
| test.c:133:5:133:5 | r | semmle.label | r |
|
||||
| test.c:137:13:137:16 | call to rand | semmle.label | call to rand |
|
||||
| test.c:139:10:139:10 | r | semmle.label | r |
|
||||
| test.c:155:22:155:25 | call to rand | semmle.label | call to rand |
|
||||
| test.c:155:22:155:27 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| test.c:157:9:157:9 | r | semmle.label | r |
|
||||
| test.cpp:8:9:8:12 | Store | semmle.label | Store |
|
||||
| test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:13:2:13:15 | Chi [[]] | semmle.label | Chi [[]] |
|
||||
@@ -60,15 +78,34 @@ nodes
|
||||
| test.cpp:36:13:36:13 | Chi | semmle.label | Chi |
|
||||
| test.cpp:36:13:36:13 | get_rand3 output argument [[]] | semmle.label | get_rand3 output argument [[]] |
|
||||
| test.cpp:37:7:37:7 | r | semmle.label | r |
|
||||
| test.cpp:78:10:78:13 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:82:10:82:10 | x | semmle.label | x |
|
||||
| test.cpp:90:10:90:13 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:94:10:94:10 | x | semmle.label | x |
|
||||
| test.cpp:129:10:129:13 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:132:10:132:10 | b | semmle.label | b |
|
||||
| test.cpp:147:11:147:14 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:149:11:149:16 | (int)... | semmle.label | (int)... |
|
||||
| test.cpp:149:16:149:16 | y | semmle.label | y |
|
||||
| test.cpp:62:19:62:22 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:62:19:62:24 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| test.cpp:65:9:65:9 | x | semmle.label | x |
|
||||
| test.cpp:86:10:86:13 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:90:10:90:10 | x | semmle.label | x |
|
||||
| test.cpp:98:10:98:13 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:102:10:102:10 | x | semmle.label | x |
|
||||
| test.cpp:137:10:137:13 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:146:9:146:9 | y | semmle.label | y |
|
||||
| test.cpp:151:10:151:13 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:154:10:154:10 | b | semmle.label | b |
|
||||
| test.cpp:169:11:169:14 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:171:11:171:16 | (int)... | semmle.label | (int)... |
|
||||
| test.cpp:171:16:171:16 | y | semmle.label | y |
|
||||
| test.cpp:189:10:189:13 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:190:10:190:13 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:196:7:196:7 | x | semmle.label | x |
|
||||
| test.cpp:198:7:198:7 | x | semmle.label | x |
|
||||
| test.cpp:199:7:199:7 | x | semmle.label | x |
|
||||
| test.cpp:204:7:204:7 | y | semmle.label | y |
|
||||
| test.cpp:205:7:205:7 | y | semmle.label | y |
|
||||
| test.cpp:208:7:208:7 | y | semmle.label | y |
|
||||
| test.cpp:215:11:215:14 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:219:8:219:8 | x | semmle.label | x |
|
||||
| test.cpp:223:20:223:23 | call to rand | semmle.label | call to rand |
|
||||
| test.cpp:223:20:223:25 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| test.cpp:227:8:227:8 | x | semmle.label | x |
|
||||
subpaths
|
||||
#select
|
||||
| test.c:21:17:21:17 | r | test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:18:13:18:16 | call to rand | Uncontrolled value |
|
||||
| test.c:35:5:35:5 | r | test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:34:13:34:18 | call to rand | Uncontrolled value |
|
||||
@@ -79,13 +116,27 @@ nodes
|
||||
| test.c:83:9:83:9 | r | test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:81:23:81:26 | call to rand | Uncontrolled value |
|
||||
| test.c:100:5:100:5 | r | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value |
|
||||
| test.c:127:9:127:9 | r | test.c:125:13:125:16 | call to rand | test.c:127:9:127:9 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:125:13:125:16 | call to rand | Uncontrolled value |
|
||||
| test.c:150:9:150:9 | r | test.c:148:22:148:25 | call to rand | test.c:150:9:150:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:148:22:148:25 | call to rand | Uncontrolled value |
|
||||
| test.c:150:9:150:9 | r | test.c:148:22:148:27 | (unsigned int)... | test.c:150:9:150:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:148:22:148:25 | call to rand | Uncontrolled value |
|
||||
| test.c:133:5:133:5 | r | test.c:131:13:131:16 | call to rand | test.c:133:5:133:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:131:13:131:16 | call to rand | Uncontrolled value |
|
||||
| test.c:139:10:139:10 | r | test.c:137:13:137:16 | call to rand | test.c:139:10:139:10 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:137:13:137:16 | call to rand | Uncontrolled value |
|
||||
| test.c:157:9:157:9 | r | test.c:155:22:155:25 | call to rand | test.c:157:9:157:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:155:22:155:25 | call to rand | Uncontrolled value |
|
||||
| test.c:157:9:157:9 | r | test.c:155:22:155:27 | (unsigned int)... | test.c:157:9:157:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:155:22:155:25 | call to rand | Uncontrolled value |
|
||||
| test.cpp:25:7:25:7 | r | test.cpp:8:9:8:12 | call to rand | test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value |
|
||||
| test.cpp:31:7:31:7 | r | test.cpp:13:10:13:13 | call to rand | test.cpp:31:7:31:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:13:10:13:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:37:7:37:7 | r | test.cpp:18:9:18:12 | call to rand | test.cpp:37:7:37:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:18:9:18:12 | call to rand | Uncontrolled value |
|
||||
| test.cpp:82:10:82:10 | x | test.cpp:78:10:78:13 | call to rand | test.cpp:82:10:82:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:78:10:78:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:94:10:94:10 | x | test.cpp:90:10:90:13 | call to rand | test.cpp:94:10:94:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:90:10:90:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:132:10:132:10 | b | test.cpp:129:10:129:13 | call to rand | test.cpp:132:10:132:10 | b | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:129:10:129:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:149:11:149:16 | (int)... | test.cpp:147:11:147:14 | call to rand | test.cpp:149:11:149:16 | (int)... | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:147:11:147:14 | call to rand | Uncontrolled value |
|
||||
| test.cpp:149:16:149:16 | y | test.cpp:147:11:147:14 | call to rand | test.cpp:149:16:149:16 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:147:11:147:14 | call to rand | Uncontrolled value |
|
||||
| test.cpp:65:9:65:9 | x | test.cpp:62:19:62:22 | call to rand | test.cpp:65:9:65:9 | x | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.cpp:62:19:62:22 | call to rand | Uncontrolled value |
|
||||
| test.cpp:65:9:65:9 | x | test.cpp:62:19:62:24 | (unsigned int)... | test.cpp:65:9:65:9 | x | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.cpp:62:19:62:22 | call to rand | Uncontrolled value |
|
||||
| test.cpp:90:10:90:10 | x | test.cpp:86:10:86:13 | call to rand | test.cpp:90:10:90:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:86:10:86:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:102:10:102:10 | x | test.cpp:98:10:98:13 | call to rand | test.cpp:102:10:102:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:98:10:98:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:146:9:146:9 | y | test.cpp:137:10:137:13 | call to rand | test.cpp:146:9:146:9 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:137:10:137:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:154:10:154:10 | b | test.cpp:151:10:151:13 | call to rand | test.cpp:154:10:154:10 | b | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:151:10:151:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:171:11:171:16 | (int)... | test.cpp:169:11:169:14 | call to rand | test.cpp:171:11:171:16 | (int)... | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:169:11:169:14 | call to rand | Uncontrolled value |
|
||||
| test.cpp:171:16:171:16 | y | test.cpp:169:11:169:14 | call to rand | test.cpp:171:16:171:16 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:169:11:169:14 | call to rand | Uncontrolled value |
|
||||
| test.cpp:196:7:196:7 | x | test.cpp:189:10:189:13 | call to rand | test.cpp:196:7:196:7 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:189:10:189:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:198:7:198:7 | x | test.cpp:189:10:189:13 | call to rand | test.cpp:198:7:198:7 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:189:10:189:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:199:7:199:7 | x | test.cpp:189:10:189:13 | call to rand | test.cpp:199:7:199:7 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:189:10:189:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:204:7:204:7 | y | test.cpp:190:10:190:13 | call to rand | test.cpp:204:7:204:7 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:190:10:190:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:205:7:205:7 | y | test.cpp:190:10:190:13 | call to rand | test.cpp:205:7:205:7 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:190:10:190:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:208:7:208:7 | y | test.cpp:190:10:190:13 | call to rand | test.cpp:208:7:208:7 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:190:10:190:13 | call to rand | Uncontrolled value |
|
||||
| test.cpp:219:8:219:8 | x | test.cpp:215:11:215:14 | call to rand | test.cpp:219:8:219:8 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:215:11:215:14 | call to rand | Uncontrolled value |
|
||||
| test.cpp:227:8:227:8 | x | test.cpp:223:20:223:23 | call to rand | test.cpp:227:8:227:8 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:223:20:223:23 | call to rand | Uncontrolled value |
|
||||
| test.cpp:227:8:227:8 | x | test.cpp:223:20:223:25 | (unsigned int)... | test.cpp:227:8:227:8 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:223:20:223:23 | call to rand | Uncontrolled value |
|
||||
|
||||
@@ -126,10 +126,17 @@ void moreTests() {
|
||||
|
||||
r = r * 100; // BAD
|
||||
}
|
||||
|
||||
{
|
||||
int r = rand();
|
||||
|
||||
r *= 100; // BAD [NOT DETECTED]
|
||||
r *= 100; // BAD
|
||||
}
|
||||
|
||||
{
|
||||
int r = rand();
|
||||
int v = 100;
|
||||
v *= r; // BAD
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -42,8 +42,8 @@ int rand(int min, int max);
|
||||
unsigned rand(int max);
|
||||
|
||||
void test_with_bounded_randomness() {
|
||||
int r = rand(0, 10);
|
||||
r++; // GOOD
|
||||
int r = rand(0, 10);
|
||||
r++; // GOOD
|
||||
|
||||
unsigned unsigned_r = rand(10);
|
||||
unsigned_r++; // GOOD
|
||||
@@ -57,6 +57,14 @@ int test_remainder_subtract()
|
||||
return x - y; // GOOD (as y <= x)
|
||||
}
|
||||
|
||||
unsigned int test_remainder_subtract_unsigned()
|
||||
{
|
||||
unsigned int x = rand();
|
||||
unsigned int y = x % 100; // y <= x
|
||||
|
||||
return x - y; // GOOD (as y <= x) [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
typedef unsigned long size_t;
|
||||
int snprintf(char *s, size_t n, const char *format, ...);
|
||||
|
||||
@@ -124,6 +132,20 @@ int test_conditional_assignment_2()
|
||||
return y * 10; // GOOD (as y <= 100)
|
||||
}
|
||||
|
||||
int test_conditional_assignment_3()
|
||||
{
|
||||
int x = rand();
|
||||
int y = 100;
|
||||
int c = 10;
|
||||
|
||||
if (x < y)
|
||||
{
|
||||
y = x;
|
||||
}
|
||||
|
||||
return y * c; // GOOD (as y <= 100) [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
int test_underflow()
|
||||
{
|
||||
int x = rand();
|
||||
@@ -161,3 +183,47 @@ void test_float()
|
||||
int z = (int)y * 5; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test_if_const_bounded()
|
||||
{
|
||||
int x = rand();
|
||||
int y = rand();
|
||||
int c = 10;
|
||||
|
||||
if (x < 1000)
|
||||
{
|
||||
x = x * 2; // GOOD
|
||||
x = x * c; // GOOD [FALSE POSITIVE]
|
||||
} else {
|
||||
x = x * 2; // BAD
|
||||
x = x * c; // BAD
|
||||
}
|
||||
|
||||
if (y > 1000)
|
||||
{
|
||||
y = y * 2; // BAD
|
||||
y = y * c; // BAD
|
||||
} else {
|
||||
y = y * 2; // GOOD
|
||||
y = y * c; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test_mod_limit()
|
||||
{
|
||||
{
|
||||
int x = rand();
|
||||
int y = 100;
|
||||
int z;
|
||||
|
||||
z = (x + y) % 1000; // BAD
|
||||
}
|
||||
|
||||
{
|
||||
unsigned int x = rand();
|
||||
unsigned int y = 100;
|
||||
unsigned int z;
|
||||
|
||||
z = (x + y) % 1000; // DUBIOUS (this could overflow but the result is controlled) [REPORTED]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This directory has its own qlpack for reasons detailed in commit 2550788598010fa2117274607c9d58f64f997f34
|
||||
name: codeql-cpp-tests-cwe-190-tainted
|
||||
version: 0.0.0
|
||||
name: codeql/cpp-tests-cwe-190-tainted
|
||||
version: 0.0.2
|
||||
dependencies:
|
||||
codeql/cpp-all: "*"
|
||||
codeql/cpp-queries: "*"
|
||||
|
||||
4
cpp/upgrades/qlpack.lock.yml
Normal file
4
cpp/upgrades/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
@@ -1,2 +1,3 @@
|
||||
name: codeql-cpp-upgrades
|
||||
name: codeql/cpp-upgrades
|
||||
upgrades: .
|
||||
version: 0.0.2
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
lgtm,codescanning
|
||||
* Generic methods return their names (`getName()`, `getQualifiedName()` and `toStringWithTypes()`) with angle brackets,
|
||||
for example `System.Linq.Enumerable.Empty<TResult>()` returns `Empty<>`, `System.Linq.Enumerable.Empty<>` and
|
||||
`Empty<TResult>()` respectively for the unbound generic method; and `Empty<Int32>`,
|
||||
`System.Linq.Enumerable.Empty<System.Int32>` and `Empty<int>()` respectively for the constructed generic case.
|
||||
* When accessing `getName()`, `getQualifiedName()` and `toStringWithTypes()` on constructed types, the type argument
|
||||
names are rendered by `getName()`, `getQualifiedName()` and `toStringWithTypes()` respectively.
|
||||
* `getUndecoratedName()` can be used to access the name without angle brackets.
|
||||
@@ -4,12 +4,6 @@ version: 1.22.1
|
||||
column_kind: "utf16"
|
||||
extra_env_vars:
|
||||
DOTNET_GENERATE_ASPNET_CERTIFICATE: "false"
|
||||
COR_ENABLE_PROFILING: "1"
|
||||
COR_PROFILER: "{A3C70A64-7D41-4A94-A3F6-FD47D9259997}"
|
||||
COR_PROFILER_PATH_64: "${env.CODEQL_EXTRACTOR_CSHARP_ROOT}/tools/${env.CODEQL_PLATFORM}/clrtracer64${env.CODEQL_PLATFORM_DLL_EXTENSION}"
|
||||
CORECLR_ENABLE_PROFILING: "1"
|
||||
CORECLR_PROFILER: "{A3C70A64-7D41-4A94-A3F6-FD47D9259997}"
|
||||
CORECLR_PROFILER_PATH_64: "${env.CODEQL_EXTRACTOR_CSHARP_ROOT}/tools/${env.CODEQL_PLATFORM}/clrtracer64${env.CODEQL_PLATFORM_DLL_EXTENSION}"
|
||||
file_types:
|
||||
- name: cs
|
||||
display_name: C# sources
|
||||
|
||||
@@ -114,25 +114,39 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
if (!body.LocalSignature.IsNil)
|
||||
{
|
||||
var locals = Context.MdReader.GetStandaloneSignature(body.LocalSignature);
|
||||
var localVariableTypes = locals.DecodeLocalSignature(Context.TypeSignatureDecoder, this);
|
||||
|
||||
this.locals = new LocalVariable[localVariableTypes.Length];
|
||||
|
||||
for (var l = 0; l < this.locals.Length; ++l)
|
||||
var localVariableTypes = System.Collections.Immutable.ImmutableArray<Type>.Empty;
|
||||
var hasError = false;
|
||||
try
|
||||
{
|
||||
var t = localVariableTypes[l];
|
||||
if (t is ByRefType brt)
|
||||
var locals = Context.MdReader.GetStandaloneSignature(body.LocalSignature);
|
||||
localVariableTypes = locals.DecodeLocalSignature(Context.TypeSignatureDecoder, this);
|
||||
}
|
||||
catch (System.BadImageFormatException exc)
|
||||
{
|
||||
Context.Extractor.Logger.Log(Util.Logging.Severity.Info,
|
||||
$"Could not decode locals in method {declaringType.GetQualifiedName()}.{name}. {exc}");
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
if (!hasError)
|
||||
{
|
||||
this.locals = new LocalVariable[localVariableTypes.Length];
|
||||
|
||||
for (var l = 0; l < this.locals.Length; ++l)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
|
||||
yield return this.locals[l];
|
||||
yield return Tuples.cil_type_annotation(this.locals[l], TypeAnnotation.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
|
||||
yield return this.locals[l];
|
||||
var t = localVariableTypes[l];
|
||||
if (t is ByRefType brt)
|
||||
{
|
||||
t = brt.ElementType;
|
||||
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
|
||||
yield return this.locals[l];
|
||||
yield return Tuples.cil_type_annotation(this.locals[l], TypeAnnotation.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
|
||||
yield return this.locals[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
// "T3,[T4, Assembly1, Version=...],T5,T6"
|
||||
string typeArgs;
|
||||
(name, _, typeArgs, _) = name.Split(firstBracketIndex, firstBracketIndex + 1, lastBracketIndex - firstBracketIndex - 1);
|
||||
(name, _, typeArgs, _) = name.Split(firstBracketIndex, firstBracketIndex + 1, lastBracketIndex);
|
||||
|
||||
var thisTypeArgCount = GenericsHelper.GetGenericTypeParameterCount(name);
|
||||
if (thisTypeArgCount == 0)
|
||||
|
||||
@@ -11,6 +11,14 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
public PointerType(Context cx, Type pointee) : base(cx)
|
||||
{
|
||||
this.pointee = pointee;
|
||||
|
||||
if (pointee is ModifiedType mt)
|
||||
{
|
||||
cx.Extractor.Logger.Log(
|
||||
Util.Logging.Severity.Info,
|
||||
$"Pointer to modified type {pointee.GetQualifiedName()} is changed to {mt.Unmodified.GetQualifiedName()}");
|
||||
this.pointee = mt.Unmodified;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Semmle.Util
|
||||
public static (string, string, string, string) Split(this string self, int index0, int index1, int index2)
|
||||
{
|
||||
var split = self.Split(new[] { index0, index1, index2 });
|
||||
return (split[0], split[1], split[2], split[4]);
|
||||
return (split[0], split[1], split[2], split[3]);
|
||||
}
|
||||
|
||||
private static List<string> Split(this string self, params int[] indices)
|
||||
|
||||
4
csharp/ql/examples/qlpack.lock.yml
Normal file
4
csharp/ql/examples/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
@@ -1,4 +1,4 @@
|
||||
name: codeql-csharp-examples
|
||||
version: 0.0.0
|
||||
version: 0.0.2
|
||||
dependencies:
|
||||
codeql/csharp-all: ^0.0.1
|
||||
codeql/csharp-all: "*"
|
||||
|
||||
4
csharp/ql/lib/qlpack.lock.yml
Normal file
4
csharp/ql/lib/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
@@ -4,3 +4,5 @@ dbscheme: semmlecode.csharp.dbscheme
|
||||
suites: codeql-suites
|
||||
extractor: csharp
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/csharp-upgrades: 0.0.2
|
||||
|
||||
@@ -81,6 +81,8 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
|
||||
|
||||
override string getName() { cil_method(this, result, _, _) }
|
||||
|
||||
override string getUndecoratedName() { result = getName() }
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override Type getDeclaringType() { cil_method(this, _, result, _) }
|
||||
|
||||
@@ -25,8 +25,6 @@ class Namespace extends DotNet::Namespace, TypeContainer, @namespace {
|
||||
|
||||
override Namespace getParentNamespace() { parent_namespace(this, result) }
|
||||
|
||||
override string getName() { namespaces(this, result) }
|
||||
|
||||
override Location getLocation() { none() }
|
||||
}
|
||||
|
||||
@@ -73,7 +71,7 @@ class Type extends DotNet::Type, Declaration, TypeContainer, @cil_type {
|
||||
predicate isSystemType(string name) {
|
||||
exists(Namespace system | this.getParent() = system |
|
||||
system.getName() = "System" and
|
||||
system.getParentNamespace() instanceof DotNet::GlobalNamespace and
|
||||
system.getParentNamespace().getName() = "" and
|
||||
name = this.getName()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class TypeParameter extends DotNet::TypeParameter, Type, @cil_typeparameter {
|
||||
class ValueOrRefType extends DotNet::ValueOrRefType, Type, @cil_valueorreftype {
|
||||
override ValueOrRefType getDeclaringType() { result = getParent() }
|
||||
|
||||
override string getUndecoratedName() { result = getName() }
|
||||
override string getUndecoratedName() { cil_type(this, result, _, _, _) }
|
||||
|
||||
override Namespace getDeclaringNamespace() { result = getNamespace() }
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ module Stages {
|
||||
|
||||
cached
|
||||
private predicate forceCachingInSameStageRev() {
|
||||
exists(SplitImpl si)
|
||||
exists(Split s)
|
||||
or
|
||||
exists(SuccessorType st)
|
||||
or
|
||||
|
||||
@@ -243,6 +243,8 @@ class Method extends Callable, Virtualizable, Attributable, @method {
|
||||
/** Gets the name of this method. */
|
||||
override string getName() { methods(this, result, _, _, _) }
|
||||
|
||||
override string getUndecoratedName() { methods(this, result, _, _, _) }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { methods(this, _, result, _, _) }
|
||||
|
||||
override Type getReturnType() { methods(this, _, _, getTypeRef(result), _) }
|
||||
@@ -448,6 +450,8 @@ class Operator extends Callable, Member, Attributable, @operator {
|
||||
|
||||
override string getName() { operators(this, _, result, _, _, _) }
|
||||
|
||||
override string getUndecoratedName() { operators(this, _, result, _, _, _) }
|
||||
|
||||
/**
|
||||
* Gets the metadata name of the operator, such as `op_implicit` or `op_RightShift`.
|
||||
*/
|
||||
@@ -989,6 +993,8 @@ class ExplicitConversionOperator extends ConversionOperator {
|
||||
class LocalFunction extends Callable, Modifiable, Attributable, @local_function {
|
||||
override string getName() { local_functions(this, result, _, _) }
|
||||
|
||||
override string getUndecoratedName() { local_functions(this, result, _, _) }
|
||||
|
||||
override LocalFunction getUnboundDeclaration() { local_functions(this, _, _, result) }
|
||||
|
||||
override Type getReturnType() { local_functions(this, _, result, _) }
|
||||
|
||||
@@ -19,6 +19,8 @@ private import TypeRef
|
||||
class Event extends DeclarationWithAccessors, @event {
|
||||
override string getName() { events(this, result, _, _, _) }
|
||||
|
||||
override string getUndecoratedName() { events(this, result, _, _, _) }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { events(this, _, result, _, _) }
|
||||
|
||||
override DelegateType getType() { events(this, _, _, getTypeRef(result), _) }
|
||||
@@ -111,6 +113,8 @@ class EventAccessor extends Accessor, @event_accessor {
|
||||
class AddEventAccessor extends EventAccessor, @add_event_accessor {
|
||||
override string getName() { result = "add" + "_" + getDeclaration().getName() }
|
||||
|
||||
override string getUndecoratedName() { result = "add" + "_" + getDeclaration().getName() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AddEventAccessor" }
|
||||
}
|
||||
|
||||
@@ -130,5 +134,7 @@ class AddEventAccessor extends EventAccessor, @add_event_accessor {
|
||||
class RemoveEventAccessor extends EventAccessor, @remove_event_accessor {
|
||||
override string getName() { result = "remove" + "_" + getDeclaration().getName() }
|
||||
|
||||
override string getUndecoratedName() { result = "remove" + "_" + getDeclaration().getName() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RemoveEventAccessor" }
|
||||
}
|
||||
|
||||
@@ -47,6 +47,18 @@ class UnboundGeneric extends DotNet::UnboundGeneric, Generic {
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the type parameters as a comma-separated string. */
|
||||
language[monotonicAggregates]
|
||||
private string getTypeParametersToString(UnboundGeneric ug) {
|
||||
result =
|
||||
strictconcat(Type t, int i | t = ug.getTypeParameter(i) | t.toStringWithTypes(), ", " order by i)
|
||||
}
|
||||
|
||||
/** Gets a string of `N` commas where `N + 1` is the number of type parameters of this unbound generic. */
|
||||
private string getTypeParameterCommas(UnboundGeneric ug) {
|
||||
result = strictconcat(int i | exists(ug.getTypeParameter(i)) | "", ",")
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructed generic.
|
||||
*
|
||||
@@ -72,6 +84,26 @@ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic {
|
||||
final AnnotatedType getAnnotatedTypeArgument(int i) { result.appliesToTypeArgument(this, i) }
|
||||
}
|
||||
|
||||
/** Gets the type arguments as a comma-separated string. */
|
||||
language[monotonicAggregates]
|
||||
private string getTypeArgumentsToString(ConstructedGeneric cg) {
|
||||
result =
|
||||
strictconcat(Type t, int i | t = cg.getTypeArgument(i) | t.toStringWithTypes(), ", " order by i)
|
||||
}
|
||||
|
||||
/** Gets the concatenation of the `getName()` of type arguments. */
|
||||
language[monotonicAggregates]
|
||||
private string getTypeArgumentsNames(ConstructedGeneric cg) {
|
||||
result = strictconcat(Type t, int i | t = cg.getTypeArgument(i) | t.getName(), "," order by i)
|
||||
}
|
||||
|
||||
/** Gets the concatenation of the `getQualifiedName()` of type arguments. */
|
||||
language[monotonicAggregates]
|
||||
private string getTypeArgumentsQualifiedNames(ConstructedGeneric cg) {
|
||||
result =
|
||||
strictconcat(Type t, int i | t = cg.getTypeArgument(i) | t.getQualifiedName(), "," order by i)
|
||||
}
|
||||
|
||||
/**
|
||||
* An unbound generic type. This is a generic type with type parameters
|
||||
* (for example `List<T>`) or elided type parameters (for example `List<>`).
|
||||
@@ -111,20 +143,16 @@ class UnboundGenericType extends ValueOrRefType, UnboundGeneric {
|
||||
|
||||
final override Type getChild(int n) { result = getTypeParameter(n) }
|
||||
|
||||
private string getTypeParameterCommas() {
|
||||
result = strictconcat(int i | exists(this.getTypeParameter(i)) | "", ",")
|
||||
}
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result = this.getUndecoratedName() + "<" + this.typeParametersToString() + ">"
|
||||
result = this.getUndecoratedName() + "<" + getTypeParametersToString(this) + ">"
|
||||
}
|
||||
|
||||
final override string getName() {
|
||||
result = this.getUndecoratedName() + "<" + this.getTypeParameterCommas() + ">"
|
||||
result = this.getUndecoratedName() + "<" + getTypeParameterCommas(this) + ">"
|
||||
}
|
||||
|
||||
final override predicate hasQualifiedName(string qualifier, string name) {
|
||||
exists(string name0 | name = name0 + "<" + this.getTypeParameterCommas() + ">" |
|
||||
exists(string name0 | name = name0 + "<" + getTypeParameterCommas(this) + ">" |
|
||||
exists(string enclosing |
|
||||
this.getDeclaringType().hasQualifiedName(qualifier, enclosing) and
|
||||
name0 = enclosing + "+" + this.getUndecoratedName()
|
||||
@@ -348,8 +376,8 @@ class UnboundGenericDelegateType extends DelegateType, UnboundGenericType {
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result =
|
||||
getUndecoratedName() + "<" + this.typeParametersToString() + ">(" + parameterTypesToString() +
|
||||
")"
|
||||
getUndecoratedName() + "<" + getTypeParametersToString(this) + ">(" + parameterTypesToString()
|
||||
+ ")"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,37 +406,16 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric {
|
||||
|
||||
final override Type getChild(int n) { result = getTypeArgument(n) }
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string getTypeArgumentsString() {
|
||||
result =
|
||||
strictconcat(Type t, int i | t = this.getTypeArgument(i) | t.toString(), ", " order by i)
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string getTypeArgumentsNames() {
|
||||
result = strictconcat(Type t, int i | t = this.getTypeArgument(i) | t.getName(), "," order by i)
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string getTypeArgumentsQualifiedNames() {
|
||||
result =
|
||||
strictconcat(Type t, int i |
|
||||
t = this.getTypeArgument(i)
|
||||
|
|
||||
t.getQualifiedName(), "," order by i
|
||||
)
|
||||
}
|
||||
|
||||
final override string toStringWithTypes() {
|
||||
result = this.getUndecoratedName() + "<" + this.getTypeArgumentsString() + ">"
|
||||
result = this.getUndecoratedName() + "<" + getTypeArgumentsToString(this) + ">"
|
||||
}
|
||||
|
||||
final override string getName() {
|
||||
result = this.getUndecoratedName() + "<" + this.getTypeArgumentsNames() + ">"
|
||||
result = this.getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">"
|
||||
}
|
||||
|
||||
final override predicate hasQualifiedName(string qualifier, string name) {
|
||||
exists(string name0 | name = name0 + "<" + this.getTypeArgumentsQualifiedNames() + ">" |
|
||||
exists(string name0 | name = name0 + "<" + getTypeArgumentsQualifiedNames(this) + ">" |
|
||||
exists(string enclosing |
|
||||
this.getDeclaringType().hasQualifiedName(qualifier, enclosing) and
|
||||
name0 = enclosing + "+" + this.getUndecoratedName()
|
||||
@@ -535,8 +542,15 @@ class UnboundGenericMethod extends Method, UnboundGeneric {
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result =
|
||||
getName() + "<" + this.typeParametersToString() + ">" + "(" + parameterTypesToString() + ")"
|
||||
getUndecoratedName() + "<" + getTypeParametersToString(this) + ">" + "(" +
|
||||
parameterTypesToString() + ")"
|
||||
}
|
||||
|
||||
final override string getName() {
|
||||
result = getUndecoratedName() + "<" + getTypeParameterCommas(this) + ">"
|
||||
}
|
||||
|
||||
final override string getUndecoratedName() { methods(this, result, _, _, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -566,12 +580,24 @@ class ConstructedMethod extends Method, ConstructedGeneric {
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result =
|
||||
getName() + "<" + this.typeArgumentsToString() + ">" + "(" + parameterTypesToString() + ")"
|
||||
getUndecoratedName() + "<" + getTypeArgumentsToString(this) + ">" + "(" +
|
||||
parameterTypesToString() + ")"
|
||||
}
|
||||
|
||||
override UnboundGenericMethod getUnboundDeclaration() {
|
||||
result = Method.super.getUnboundDeclaration()
|
||||
}
|
||||
|
||||
final override string getName() {
|
||||
result = getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">"
|
||||
}
|
||||
|
||||
override predicate hasQualifiedName(string qualifier, string name) {
|
||||
qualifier = getDeclaringType().getQualifiedName() and
|
||||
name = getUndecoratedName() + "<" + getTypeArgumentsQualifiedNames(this) + ">"
|
||||
}
|
||||
|
||||
final override string getUndecoratedName() { methods(this, result, _, _, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -125,7 +125,7 @@ private DeclarationWithAccessors getACompatibleInterfaceAccessor(DeclarationWith
|
||||
}
|
||||
|
||||
private DeclarationWithAccessors getACompatibleInterfaceAccessorCandidate(DeclarationWithAccessors d) {
|
||||
getACompatibleInterfaceAccessorAux(result, d.getDeclaringType(), d.getName()) and
|
||||
getACompatibleInterfaceAccessorAux(result, d.getDeclaringType(), d.getUndecoratedName()) and
|
||||
not d instanceof Indexer and
|
||||
d.isPublic()
|
||||
}
|
||||
@@ -135,7 +135,7 @@ private predicate getACompatibleInterfaceAccessorAux(
|
||||
DeclarationWithAccessors d, ValueOrRefType t, string name
|
||||
) {
|
||||
t = getAPossibleImplementor(d.getDeclaringType()) and
|
||||
name = d.getName()
|
||||
name = d.getUndecoratedName()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,7 +215,7 @@ private Method getACompatibleInterfaceMethod(Method m) {
|
||||
* in a type that is a possible implementor type for the interface type.
|
||||
*/
|
||||
private Method getAnInterfaceMethodCandidate(Method m) {
|
||||
getAPotentialInterfaceMethodAux(result, m.getDeclaringType(), m.getName(),
|
||||
getAPotentialInterfaceMethodAux(result, m.getDeclaringType(), m.getUndecoratedName(),
|
||||
m.getNumberOfParameters()) and
|
||||
m.isPublic()
|
||||
}
|
||||
@@ -225,7 +225,7 @@ private predicate getAPotentialInterfaceMethodAux(
|
||||
Method m, ValueOrRefType t, string name, int params
|
||||
) {
|
||||
t = getAPossibleImplementor(m.getDeclaringType()) and
|
||||
name = m.getName() and
|
||||
name = m.getUndecoratedName() and
|
||||
params = m.getNumberOfParameters()
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@ class TypeContainer extends DotNet::NamedElement, Element, @type_container { }
|
||||
* ```
|
||||
*/
|
||||
class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespace {
|
||||
/** Gets the simple name of this namespace, for example `IO` in `System.IO`. */
|
||||
override string getName() { namespaces(this, result) }
|
||||
|
||||
override Namespace getParent() { result = this.getParentNamespace() }
|
||||
|
||||
override Namespace getParentNamespace() { parent_namespace(this, result) }
|
||||
|
||||
@@ -116,6 +116,8 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE
|
||||
class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @property {
|
||||
override string getName() { properties(this, result, _, _, _) }
|
||||
|
||||
override string getUndecoratedName() { properties(this, result, _, _, _) }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { properties(this, _, result, _, _) }
|
||||
|
||||
override Type getType() { properties(this, _, _, getTypeRef(result), _) }
|
||||
@@ -251,6 +253,8 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
|
||||
class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer {
|
||||
override string getName() { indexers(this, result, _, _, _) }
|
||||
|
||||
override string getUndecoratedName() { indexers(this, result, _, _, _) }
|
||||
|
||||
/** Gets the dimension of this indexer, that is, its number of parameters. */
|
||||
int getDimension() { result = getNumberOfParameters() }
|
||||
|
||||
@@ -393,6 +397,8 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
|
||||
class Getter extends Accessor, @getter {
|
||||
override string getName() { result = "get" + "_" + getDeclaration().getName() }
|
||||
|
||||
override string getUndecoratedName() { result = "get" + "_" + getDeclaration().getName() }
|
||||
|
||||
override Type getReturnType() { result = getDeclaration().getType() }
|
||||
|
||||
/**
|
||||
@@ -440,6 +446,8 @@ class Getter extends Accessor, @getter {
|
||||
class Setter extends Accessor, @setter {
|
||||
override string getName() { result = "set" + "_" + getDeclaration().getName() }
|
||||
|
||||
override string getUndecoratedName() { result = "set" + "_" + getDeclaration().getName() }
|
||||
|
||||
override Type getReturnType() {
|
||||
exists(this) and // needed to avoid compiler warning
|
||||
result instanceof VoidType
|
||||
|
||||
@@ -10,6 +10,7 @@ private import Conversion
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.metrics.Coupling
|
||||
private import TypeRef
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
|
||||
/**
|
||||
* A type.
|
||||
@@ -407,9 +408,11 @@ class VoidType extends DotNet::ValueOrRefType, Type, @void_type {
|
||||
name = "Void"
|
||||
}
|
||||
|
||||
override string getUndecoratedName() { result = "Void" }
|
||||
final override string getName() { result = "Void" }
|
||||
|
||||
override Namespace getDeclaringNamespace() { result.hasQualifiedName("System") }
|
||||
final override string getUndecoratedName() { result = "Void" }
|
||||
|
||||
override SystemNamespace getDeclaringNamespace() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -441,7 +444,7 @@ class SimpleType extends ValueType, @simple_type {
|
||||
/** Gets the maximum integral value of this type, if any. */
|
||||
int maxValue() { none() }
|
||||
|
||||
override Namespace getDeclaringNamespace() { result.hasQualifiedName("System") }
|
||||
override SystemNamespace getDeclaringNamespace() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1020,7 +1023,9 @@ class PointerType extends DotNet::PointerType, Type, @pointer_type {
|
||||
|
||||
override Type getChild(int n) { result = getReferentType() and n = 0 }
|
||||
|
||||
override string getName() { types(this, _, result) }
|
||||
final override string getName() { types(this, _, result) }
|
||||
|
||||
final override string getUndecoratedName() { result = getReferentType().getUndecoratedName() }
|
||||
|
||||
override Location getALocation() { result = getReferentType().getALocation() }
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ module ControlFlow {
|
||||
}
|
||||
|
||||
/** Gets a successor node of a given type, if any. */
|
||||
Node getASuccessorByType(SuccessorType t) { result = getASuccessorByType(this, t) }
|
||||
Node getASuccessorByType(SuccessorType t) { result = getASuccessor(this, t) }
|
||||
|
||||
/** Gets an immediate successor, if any. */
|
||||
Node getASuccessor() { result = getASuccessorByType(_) }
|
||||
@@ -255,9 +255,15 @@ module ControlFlow {
|
||||
|
||||
override Callable getEnclosingCallable() { result = this.getCallable() }
|
||||
|
||||
override Location getLocation() { result = getCallable().getLocation() }
|
||||
private Assignable getAssignable() { this = TEntryNode(result) }
|
||||
|
||||
override string toString() { result = "enter " + getCallable().toString() }
|
||||
override Location getLocation() {
|
||||
result in [this.getCallable().getLocation(), this.getAssignable().getLocation()]
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "enter " + [this.getCallable().toString(), this.getAssignable().toString()]
|
||||
}
|
||||
}
|
||||
|
||||
/** A node for a callable exit point, annotated with the type of exit. */
|
||||
@@ -314,7 +320,7 @@ module ControlFlow {
|
||||
* different splits for the element.
|
||||
*/
|
||||
class ElementNode extends Node, TElementNode {
|
||||
private Splitting::Splits splits;
|
||||
private Splits splits;
|
||||
private ControlFlowElement cfe;
|
||||
|
||||
ElementNode() { this = TElementNode(cfe, splits) }
|
||||
|
||||
@@ -43,13 +43,22 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow
|
||||
private import Completion
|
||||
private import SuccessorType
|
||||
private import SuccessorTypes
|
||||
private import Splitting
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
private import semmle.code.csharp.commons.Compilation
|
||||
import ControlFlowGraphImplShared
|
||||
|
||||
/** An element that defines a new CFG scope. */
|
||||
class CfgScope extends Element, @top_level_exprorstmt_parent {
|
||||
CfgScope() {
|
||||
this instanceof Callable
|
||||
or
|
||||
// For now, static initializer values have their own scope. Eventually, they
|
||||
// should be treated like instance initializers.
|
||||
this.(Assignable).(Modifiable).isStatic()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A compilation.
|
||||
@@ -71,16 +80,11 @@ CompilationExt getCompilation(SourceFile f) {
|
||||
result = TBuildless()
|
||||
}
|
||||
|
||||
/** An element that defines a new CFG scope. */
|
||||
class CfgScope extends Element, @top_level_exprorstmt_parent {
|
||||
CfgScope() { not this instanceof Attribute }
|
||||
}
|
||||
|
||||
module ControlFlowTree {
|
||||
class Range_ = @callable or @control_flow_element;
|
||||
|
||||
class Range extends Element, Range_ {
|
||||
Range() { this = getAChild*(any(CfgScope scope)) }
|
||||
Range() { this = getAChild*(any(@top_level_exprorstmt_parent p | not p instanceof Attribute)) }
|
||||
}
|
||||
|
||||
Element getAChild(Element p) {
|
||||
@@ -93,61 +97,6 @@ module ControlFlowTree {
|
||||
predicate idOf(Range_ x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
}
|
||||
|
||||
abstract private class ControlFlowTree extends ControlFlowTree::Range {
|
||||
/**
|
||||
* Holds if `first` is the first element executed within this control
|
||||
* flow element.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate first(ControlFlowElement first);
|
||||
|
||||
/**
|
||||
* Holds if `last` with completion `c` is a potential last element executed
|
||||
* within this control flow element.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate last(ControlFlowElement last, Completion c);
|
||||
|
||||
/** Holds if abnormal execution of `child` should propagate upwards. */
|
||||
abstract predicate propagatesAbnormal(ControlFlowElement child);
|
||||
|
||||
/**
|
||||
* Holds if `succ` is a control flow successor for `pred`, given that `pred`
|
||||
* finishes with completion `c`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `first` is the first element executed within control flow
|
||||
* element `cft`.
|
||||
*/
|
||||
predicate first(ControlFlowTree cft, ControlFlowElement first) { cft.first(first) }
|
||||
|
||||
/**
|
||||
* Holds if `last` with completion `c` is a potential last element executed
|
||||
* within control flow element `cft`.
|
||||
*/
|
||||
predicate last(ControlFlowTree cft, ControlFlowElement last, Completion c) {
|
||||
cft.last(last, c)
|
||||
or
|
||||
exists(ControlFlowElement cfe |
|
||||
cft.propagatesAbnormal(cfe) and
|
||||
last(cfe, last, c) and
|
||||
not c instanceof NormalCompletion
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succ` is a control flow successor for `pred`, given that `pred`
|
||||
* finishes with completion `c`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
any(ControlFlowTree cft).succ(pred, succ, c)
|
||||
}
|
||||
|
||||
/** Holds if `first` is first executed when entering `scope`. */
|
||||
predicate scopeFirst(CfgScope scope, ControlFlowElement first) {
|
||||
scope =
|
||||
@@ -161,8 +110,7 @@ predicate scopeFirst(CfgScope scope, ControlFlowElement first) {
|
||||
)
|
||||
or
|
||||
expr_parent_top_level_adjusted(any(Expr e | first(e, first)), _, scope) and
|
||||
not scope instanceof Callable and
|
||||
not scope instanceof InitializerSplitting::InitializedInstanceMember
|
||||
not scope instanceof Callable
|
||||
}
|
||||
|
||||
/** Holds if `scope` is exited when `last` finishes with completion `c`. */
|
||||
@@ -204,53 +152,6 @@ private class ConstructorTree extends ControlFlowTree, Constructor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A control flow element where the children are evaluated following a
|
||||
* standard left-to-right evaluation. The actual evaluation order is
|
||||
* determined by the predicate `getChildElement()`.
|
||||
*/
|
||||
abstract private class StandardElement extends ControlFlowTree {
|
||||
/** Gets the `i`th child element, in order of evaluation, starting from 0. */
|
||||
abstract ControlFlowElement getChildElement(int i);
|
||||
|
||||
/** Gets the first child element of this element. */
|
||||
final ControlFlowElement getFirstChild() { result = this.getChildElement(0) }
|
||||
|
||||
/** Holds if this element has no children. */
|
||||
final predicate isLeafElement() { not exists(this.getFirstChild()) }
|
||||
|
||||
/** Gets the last child element of this element. */
|
||||
final ControlFlowTree getLastChild() {
|
||||
exists(int last |
|
||||
result = this.getChildElement(last) and
|
||||
not exists(this.getChildElement(last + 1))
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate propagatesAbnormal(ControlFlowElement child) {
|
||||
child = this.getChildElement(_)
|
||||
}
|
||||
|
||||
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
exists(int i |
|
||||
last(this.getChildElement(i), pred, c) and
|
||||
first(this.getChildElement(i + 1), succ) and
|
||||
c instanceof NormalCompletion
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class PreOrderTree extends ControlFlowTree {
|
||||
final override predicate first(ControlFlowElement first) { first = this }
|
||||
}
|
||||
|
||||
abstract private class PostOrderTree extends ControlFlowTree {
|
||||
override predicate last(ControlFlowElement last, Completion c) {
|
||||
last = this and
|
||||
c.isValidFor(last)
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class SwitchTree extends ControlFlowTree, Switch {
|
||||
override predicate propagatesAbnormal(ControlFlowElement child) { child = this.getExpr() }
|
||||
|
||||
@@ -368,7 +269,7 @@ module Expressions {
|
||||
)
|
||||
}
|
||||
|
||||
private class StandardExpr extends StandardElement, PostOrderTree, Expr {
|
||||
private class StandardExpr extends StandardPostOrderTree, Expr {
|
||||
StandardExpr() {
|
||||
// The following expressions need special treatment
|
||||
not this instanceof LogicalNotExpr and
|
||||
@@ -396,21 +297,6 @@ module Expressions {
|
||||
}
|
||||
|
||||
final override ControlFlowElement getChildElement(int i) { result = getExprChild(this, i) }
|
||||
|
||||
final override predicate first(ControlFlowElement first) {
|
||||
first(this.getFirstChild(), first)
|
||||
or
|
||||
not exists(this.getFirstChild()) and
|
||||
first = this
|
||||
}
|
||||
|
||||
final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
StandardElement.super.succ(pred, succ, c)
|
||||
or
|
||||
last(this.getLastChild(), pred, c) and
|
||||
succ = this and
|
||||
c instanceof NormalCompletion
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1095,7 +981,7 @@ private class PropertyPatternExprExprTree extends PostOrderTree, PropertyPattern
|
||||
}
|
||||
|
||||
module Statements {
|
||||
private class StandardStmt extends StandardElement, PreOrderTree, Stmt {
|
||||
private class StandardStmt extends StandardPreOrderTree, Stmt {
|
||||
StandardStmt() {
|
||||
// The following statements need special treatment
|
||||
not this instanceof IfStmt and
|
||||
@@ -1140,22 +1026,6 @@ module Statements {
|
||||
result =
|
||||
rank[i + 1](ControlFlowElement cfe, int j | cfe = this.getChildElement0(j) | cfe order by j)
|
||||
}
|
||||
|
||||
final override predicate last(ControlFlowElement last, Completion c) {
|
||||
last(this.getLastChild(), last, c)
|
||||
or
|
||||
this.isLeafElement() and
|
||||
last = this and
|
||||
c.isValidFor(this)
|
||||
}
|
||||
|
||||
final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
StandardElement.super.succ(pred, succ, c)
|
||||
or
|
||||
pred = this and
|
||||
first(this.getFirstChild(), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
}
|
||||
}
|
||||
|
||||
private class IfStmtTree extends PreOrderTree, IfStmt {
|
||||
@@ -1779,88 +1649,6 @@ module Statements {
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
private import semmle.code.csharp.Caching
|
||||
|
||||
private predicate isAbnormalExitType(SuccessorType t) {
|
||||
t instanceof ExceptionSuccessor or t instanceof ExitSuccessor
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal representation of control flow nodes in the control flow graph.
|
||||
* The control flow graph is pruned for unreachable nodes.
|
||||
*/
|
||||
cached
|
||||
newtype TNode =
|
||||
TEntryNode(Callable c) {
|
||||
Stages::ControlFlowStage::forceCachingInSameStage() and
|
||||
succEntrySplits(c, _, _, _)
|
||||
} or
|
||||
TAnnotatedExitNode(Callable c, boolean normal) {
|
||||
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(_) |
|
||||
succExitSplits(b.getAnElement(), _, c, t) and
|
||||
if isAbnormalExitType(t) then normal = false else normal = true
|
||||
)
|
||||
} or
|
||||
TExitNode(Callable c) {
|
||||
exists(Reachability::SameSplitsBlock b | b.isReachable(_) |
|
||||
succExitSplits(b.getAnElement(), _, c, _)
|
||||
)
|
||||
} or
|
||||
TElementNode(ControlFlowElement cfe, Splits splits) {
|
||||
exists(Reachability::SameSplitsBlock b | b.isReachable(splits) | cfe = b.getAnElement())
|
||||
}
|
||||
|
||||
/** Gets a successor node of a given flow type, if any. */
|
||||
cached
|
||||
Node getASuccessorByType(Node pred, SuccessorType t) {
|
||||
// Callable entry node -> callable body
|
||||
exists(ControlFlowElement succElement, Splits succSplits |
|
||||
result = TElementNode(succElement, succSplits)
|
||||
|
|
||||
succEntrySplits(pred.(Nodes::EntryNode).getCallable(), succElement, succSplits, t)
|
||||
)
|
||||
or
|
||||
exists(ControlFlowElement predElement, Splits predSplits |
|
||||
pred = TElementNode(predElement, predSplits)
|
||||
|
|
||||
// Element node -> callable exit (annotated)
|
||||
result =
|
||||
any(Nodes::AnnotatedExitNode exit |
|
||||
succExitSplits(predElement, predSplits, exit.getCallable(), t) and
|
||||
if isAbnormalExitType(t) then not exit.isNormal() else exit.isNormal()
|
||||
)
|
||||
or
|
||||
// Element node -> element node
|
||||
exists(ControlFlowElement succElement, Splits succSplits, Completion c |
|
||||
result = TElementNode(succElement, succSplits)
|
||||
|
|
||||
succSplits(predElement, predSplits, succElement, succSplits, c) and
|
||||
t = c.getAMatchingSuccessorType()
|
||||
)
|
||||
)
|
||||
or
|
||||
// Callable exit (annotated) -> callable exit
|
||||
pred.(Nodes::AnnotatedExitNode).getCallable() = result.(Nodes::ExitNode).getCallable() and
|
||||
t instanceof SuccessorTypes::NormalSuccessor
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a first control flow element executed within `cfe`.
|
||||
*/
|
||||
cached
|
||||
ControlFlowElement getAControlFlowEntryNode(ControlFlowElement cfe) { first(cfe, result) }
|
||||
|
||||
/**
|
||||
* Gets a potential last control flow element executed within `cfe`.
|
||||
*/
|
||||
cached
|
||||
ControlFlowElement getAControlFlowExitNode(ControlFlowElement cfe) { last(cfe, result, _) }
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
/** A control flow element that is split into multiple control flow nodes. */
|
||||
class SplitControlFlowElement extends ControlFlowElement {
|
||||
SplitControlFlowElement() { strictcount(this.getAControlFlowNode()) > 1 }
|
||||
|
||||
@@ -0,0 +1,945 @@
|
||||
/** Provides language-independent definitions for AST-to-CFG construction. */
|
||||
|
||||
private import ControlFlowGraphImplSpecific
|
||||
|
||||
/** An element with associated control flow. */
|
||||
abstract class ControlFlowTree extends ControlFlowTreeBase {
|
||||
/** Holds if `first` is the first element executed within this element. */
|
||||
pragma[nomagic]
|
||||
abstract predicate first(ControlFlowElement first);
|
||||
|
||||
/**
|
||||
* Holds if `last` with completion `c` is a potential last element executed
|
||||
* within this element.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate last(ControlFlowElement last, Completion c);
|
||||
|
||||
/** Holds if abnormal execution of `child` should propagate upwards. */
|
||||
abstract predicate propagatesAbnormal(ControlFlowElement child);
|
||||
|
||||
/**
|
||||
* Holds if `succ` is a control flow successor for `pred`, given that `pred`
|
||||
* finishes with completion `c`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `first` is the first element executed within control flow
|
||||
* element `cft`.
|
||||
*/
|
||||
predicate first(ControlFlowTree cft, ControlFlowElement first) { cft.first(first) }
|
||||
|
||||
/**
|
||||
* Holds if `last` with completion `c` is a potential last element executed
|
||||
* within control flow element `cft`.
|
||||
*/
|
||||
predicate last(ControlFlowTree cft, ControlFlowElement last, Completion c) {
|
||||
cft.last(last, c)
|
||||
or
|
||||
exists(ControlFlowElement cfe |
|
||||
cft.propagatesAbnormal(cfe) and
|
||||
last(cfe, last, c) and
|
||||
not completionIsNormal(c)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succ` is a control flow successor for `pred`, given that `pred`
|
||||
* finishes with completion `c`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
any(ControlFlowTree cft).succ(pred, succ, c)
|
||||
}
|
||||
|
||||
/** An element that is executed in pre-order. */
|
||||
abstract class PreOrderTree extends ControlFlowTree {
|
||||
final override predicate first(ControlFlowElement first) { first = this }
|
||||
}
|
||||
|
||||
/** An element that is executed in post-order. */
|
||||
abstract class PostOrderTree extends ControlFlowTree {
|
||||
override predicate last(ControlFlowElement last, Completion c) {
|
||||
last = this and
|
||||
completionIsValidFor(c, last)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An element where the children are evaluated following a standard left-to-right
|
||||
* evaluation. The actual evaluation order is determined by the predicate
|
||||
* `getChildElement()`.
|
||||
*/
|
||||
abstract class StandardTree extends ControlFlowTree {
|
||||
/** Gets the `i`th child element, in order of evaluation. */
|
||||
abstract ControlFlowElement getChildElement(int i);
|
||||
|
||||
private ControlFlowElement getChildElementRanked(int i) {
|
||||
result =
|
||||
rank[i + 1](ControlFlowElement child, int j |
|
||||
child = this.getChildElement(j)
|
||||
|
|
||||
child order by j
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the first child node of this element. */
|
||||
final ControlFlowElement getFirstChildElement() { result = this.getChildElementRanked(0) }
|
||||
|
||||
/** Gets the last child node of this node. */
|
||||
final ControlFlowElement getLastChildElement() {
|
||||
exists(int last |
|
||||
result = this.getChildElementRanked(last) and
|
||||
not exists(this.getChildElementRanked(last + 1))
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this element has no children. */
|
||||
predicate isLeafElement() { not exists(this.getFirstChildElement()) }
|
||||
|
||||
override predicate propagatesAbnormal(ControlFlowElement child) {
|
||||
child = this.getChildElement(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
exists(int i |
|
||||
last(this.getChildElementRanked(i), pred, c) and
|
||||
completionIsNormal(c) and
|
||||
first(this.getChildElementRanked(i + 1), succ)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A standard element that is executed in pre-order. */
|
||||
abstract class StandardPreOrderTree extends StandardTree, PreOrderTree {
|
||||
override predicate last(ControlFlowElement last, Completion c) {
|
||||
last(this.getLastChildElement(), last, c)
|
||||
or
|
||||
this.isLeafElement() and
|
||||
completionIsValidFor(c, this) and
|
||||
last = this
|
||||
}
|
||||
|
||||
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
StandardTree.super.succ(pred, succ, c)
|
||||
or
|
||||
pred = this and
|
||||
first(this.getFirstChildElement(), succ) and
|
||||
completionIsSimple(c)
|
||||
}
|
||||
}
|
||||
|
||||
/** A standard element that is executed in post-order. */
|
||||
abstract class StandardPostOrderTree extends StandardTree, PostOrderTree {
|
||||
override predicate first(ControlFlowElement first) {
|
||||
first(this.getFirstChildElement(), first)
|
||||
or
|
||||
not exists(this.getFirstChildElement()) and
|
||||
first = this
|
||||
}
|
||||
|
||||
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
StandardTree.super.succ(pred, succ, c)
|
||||
or
|
||||
last(this.getLastChildElement(), pred, c) and
|
||||
succ = this and
|
||||
completionIsNormal(c)
|
||||
}
|
||||
}
|
||||
|
||||
/** An element that is a leaf in the control flow graph. */
|
||||
abstract class LeafTree extends PreOrderTree, PostOrderTree {
|
||||
override predicate propagatesAbnormal(ControlFlowElement child) { none() }
|
||||
|
||||
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if split kinds `sk1` and `sk2` may overlap. That is, they may apply
|
||||
* to at least one common AST node inside `scope`.
|
||||
*/
|
||||
private predicate overlapping(CfgScope scope, SplitKind sk1, SplitKind sk2) {
|
||||
exists(ControlFlowElement e |
|
||||
sk1.appliesTo(e) and
|
||||
sk2.appliesTo(e) and
|
||||
scope = getCfgScope(e)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A split kind. Each control flow node can have at most one split of a
|
||||
* given kind.
|
||||
*/
|
||||
abstract class SplitKind extends SplitKindBase {
|
||||
/** Gets a split of this kind. */
|
||||
SplitImpl getASplit() { result.getKind() = this }
|
||||
|
||||
/** Holds if some split of this kind applies to AST node `n`. */
|
||||
predicate appliesTo(ControlFlowElement n) { this.getASplit().appliesTo(n) }
|
||||
|
||||
/**
|
||||
* Gets a unique integer representing this split kind. The integer is used
|
||||
* to represent sets of splits as ordered lists.
|
||||
*/
|
||||
abstract int getListOrder();
|
||||
|
||||
/** Gets the rank of this split kind among all overlapping kinds for `c`. */
|
||||
private int getRank(CfgScope scope) {
|
||||
this = rank[result](SplitKind sk | overlapping(scope, this, sk) | sk order by sk.getListOrder())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this split kind is enabled for AST node `n`. For performance reasons,
|
||||
* the number of splits is restricted by the `maxSplits()` predicate.
|
||||
*/
|
||||
predicate isEnabled(ControlFlowElement n) {
|
||||
this.appliesTo(n) and
|
||||
this.getRank(getCfgScope(n)) <= maxSplits()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank of this split kind among all the split kinds that apply to
|
||||
* AST node `n`. The rank is based on the order defined by `getListOrder()`.
|
||||
*/
|
||||
int getListRank(ControlFlowElement n) {
|
||||
this.isEnabled(n) and
|
||||
this = rank[result](SplitKind sk | sk.appliesTo(n) | sk order by sk.getListOrder())
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this split kind. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/** Provides the interface for implementing an entity to split on. */
|
||||
abstract class SplitImpl extends Split {
|
||||
/** Gets the kind of this split. */
|
||||
abstract SplitKind getKind();
|
||||
|
||||
/**
|
||||
* Holds if this split is entered when control passes from `pred` to `succ` with
|
||||
* completion `c`.
|
||||
*
|
||||
* Invariant: `hasEntry(pred, succ, c) implies succ(pred, succ, c)`.
|
||||
*/
|
||||
abstract predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
||||
|
||||
/**
|
||||
* Holds if this split is entered when control passes from `scope` to the entry point
|
||||
* `first`.
|
||||
*
|
||||
* Invariant: `hasEntryScope(scope, first) implies scopeFirst(scope, first)`.
|
||||
*/
|
||||
abstract predicate hasEntryScope(CfgScope scope, ControlFlowElement first);
|
||||
|
||||
/**
|
||||
* Holds if this split is left when control passes from `pred` to `succ` with
|
||||
* completion `c`.
|
||||
*
|
||||
* Invariant: `hasExit(pred, succ, c) implies succ(pred, succ, c)`.
|
||||
*/
|
||||
abstract predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
||||
|
||||
/**
|
||||
* Holds if this split is left when control passes from `last` out of the enclosing
|
||||
* scope `scope` with completion `c`.
|
||||
*
|
||||
* Invariant: `hasExitScope(scope, last, c) implies scopeLast(scope, last, c)`
|
||||
*/
|
||||
abstract predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c);
|
||||
|
||||
/**
|
||||
* Holds if this split is maintained when control passes from `pred` to `succ` with
|
||||
* completion `c`.
|
||||
*
|
||||
* Invariant: `hasSuccessor(pred, succ, c) implies succ(pred, succ, c)`
|
||||
*/
|
||||
abstract predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
||||
|
||||
/** Holds if this split applies to control flow element `cfe`. */
|
||||
final predicate appliesTo(ControlFlowElement cfe) {
|
||||
this.hasEntry(_, cfe, _)
|
||||
or
|
||||
this.hasEntryScope(_, cfe)
|
||||
or
|
||||
exists(ControlFlowElement pred | this.appliesTo(pred) | this.hasSuccessor(pred, cfe, _))
|
||||
}
|
||||
|
||||
/** The `succ` relation restricted to predecessors `pred` that this split applies to. */
|
||||
pragma[noinline]
|
||||
final predicate appliesSucc(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
this.appliesTo(pred) and
|
||||
succ(pred, succ, c)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of control flow node splits. The set is represented by a list of splits,
|
||||
* ordered by ascending rank.
|
||||
*/
|
||||
class Splits extends TSplits {
|
||||
/** Gets a textual representation of this set of splits. */
|
||||
string toString() { result = splitsToString(this) }
|
||||
|
||||
/** Gets a split belonging to this set of splits. */
|
||||
SplitImpl getASplit() {
|
||||
exists(SplitImpl head, Splits tail | this = TSplitsCons(head, tail) |
|
||||
result = head
|
||||
or
|
||||
result = tail.getASplit()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate succEntrySplitsFromRank(
|
||||
CfgScope pred, ControlFlowElement succ, Splits splits, int rnk
|
||||
) {
|
||||
splits = TSplitsNil() and
|
||||
scopeFirst(pred, succ) and
|
||||
rnk = 0
|
||||
or
|
||||
exists(SplitImpl head, Splits tail | succEntrySplitsCons(pred, succ, head, tail, rnk) |
|
||||
splits = TSplitsCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate succEntrySplitsCons(
|
||||
CfgScope pred, ControlFlowElement succ, SplitImpl head, Splits tail, int rnk
|
||||
) {
|
||||
succEntrySplitsFromRank(pred, succ, tail, rnk - 1) and
|
||||
head.hasEntryScope(pred, succ) and
|
||||
rnk = head.getKind().getListRank(succ)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succ` with splits `succSplits` is the first element that is executed
|
||||
* when entering callable `pred`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate succEntrySplits(
|
||||
CfgScope pred, ControlFlowElement succ, Splits succSplits, SuccessorType t
|
||||
) {
|
||||
exists(int rnk |
|
||||
scopeFirst(pred, succ) and
|
||||
successorTypeIsSimple(t) and
|
||||
succEntrySplitsFromRank(pred, succ, succSplits, rnk)
|
||||
|
|
||||
rnk = 0 and
|
||||
not any(SplitImpl split).hasEntryScope(pred, succ)
|
||||
or
|
||||
rnk = max(SplitImpl split | split.hasEntryScope(pred, succ) | split.getKind().getListRank(succ))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pred` with splits `predSplits` can exit the enclosing callable
|
||||
* `succ` with type `t`.
|
||||
*/
|
||||
private predicate succExitSplits(
|
||||
ControlFlowElement pred, Splits predSplits, CfgScope succ, SuccessorType t
|
||||
) {
|
||||
exists(Reachability::SameSplitsBlock b, Completion c | pred = b.getAnElement() |
|
||||
b.isReachable(predSplits) and
|
||||
t = getAMatchingSuccessorType(c) and
|
||||
scopeLast(succ, pred, c) and
|
||||
forall(SplitImpl predSplit | predSplit = predSplits.getASplit() |
|
||||
predSplit.hasExitScope(succ, pred, c)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a predicate for the successor relation with split information,
|
||||
* as well as logic used to construct the type `TSplits` representing sets
|
||||
* of splits. Only sets of splits that can be reached are constructed, hence
|
||||
* the predicates are mutually recursive.
|
||||
*
|
||||
* For the successor relation
|
||||
*
|
||||
* ```ql
|
||||
* succSplits(ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits, Completion c)
|
||||
* ```
|
||||
*
|
||||
* the following invariants are maintained:
|
||||
*
|
||||
* 1. `pred` is reachable with split set `predSplits`.
|
||||
* 2. For all `split` in `predSplits`:
|
||||
* - If `split.hasSuccessor(pred, succ, c)` then `split` in `succSplits`.
|
||||
* 3. For all `split` in `predSplits`:
|
||||
* - If `split.hasExit(pred, succ, c)` and not `split.hasEntry(pred, succ, c)` then
|
||||
* `split` not in `succSplits`.
|
||||
* 4. For all `split` with kind not in `predSplits`:
|
||||
* - If `split.hasEntry(pred, succ, c)` then `split` in `succSplits`.
|
||||
* 5. For all `split` in `succSplits`:
|
||||
* - `split.hasSuccessor(pred, succ, c)` and `split` in `predSplits`, or
|
||||
* - `split.hasEntry(pred, succ, c)`.
|
||||
*
|
||||
* The algorithm divides into four cases:
|
||||
*
|
||||
* 1. The set of splits for the successor is the same as the set of splits
|
||||
* for the predecessor:
|
||||
* a) The successor is in the same `SameSplitsBlock` as the predecessor.
|
||||
* b) The successor is *not* in the same `SameSplitsBlock` as the predecessor.
|
||||
* 2. The set of splits for the successor is different from the set of splits
|
||||
* for the predecessor:
|
||||
* a) The set of splits for the successor is *maybe* non-empty.
|
||||
* b) The set of splits for the successor is *always* empty.
|
||||
*
|
||||
* Only case 2a may introduce new sets of splits, so only predicates from
|
||||
* this case are used in the definition of `TSplits`.
|
||||
*
|
||||
* The predicates in this module are named after the cases above.
|
||||
*/
|
||||
private module SuccSplits {
|
||||
private predicate succInvariant1(
|
||||
Reachability::SameSplitsBlock b, ControlFlowElement pred, Splits predSplits,
|
||||
ControlFlowElement succ, Completion c
|
||||
) {
|
||||
pred = b.getAnElement() and
|
||||
b.isReachable(predSplits) and
|
||||
succ(pred, succ, c)
|
||||
}
|
||||
|
||||
private predicate case1b0(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c
|
||||
) {
|
||||
exists(Reachability::SameSplitsBlock b |
|
||||
// Invariant 1
|
||||
succInvariant1(b, pred, predSplits, succ, c)
|
||||
|
|
||||
(succ = b.getAnElement() implies succ = b) and
|
||||
// Invariant 4
|
||||
not exists(SplitImpl split | split.hasEntry(pred, succ, c))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Case 1b.
|
||||
*
|
||||
* Invariants 1 and 4 hold in the base case, and invariants 2, 3, and 5 are
|
||||
* maintained for all splits in `predSplits` (= `succSplits`), except
|
||||
* possibly for the splits in `except`.
|
||||
*
|
||||
* The predicate is written using explicit recursion, as opposed to a `forall`,
|
||||
* to avoid negative recursion.
|
||||
*/
|
||||
private predicate case1bForall(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, Splits except
|
||||
) {
|
||||
case1b0(pred, predSplits, succ, c) and
|
||||
except = predSplits
|
||||
or
|
||||
exists(SplitImpl split |
|
||||
case1bForallCons(pred, predSplits, succ, c, split, except) and
|
||||
split.hasSuccessor(pred, succ, c)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate case1bForallCons(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c,
|
||||
SplitImpl exceptHead, Splits exceptTail
|
||||
) {
|
||||
case1bForall(pred, predSplits, succ, c, TSplitsCons(exceptHead, exceptTail))
|
||||
}
|
||||
|
||||
private predicate case1(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c
|
||||
) {
|
||||
// Case 1a
|
||||
exists(Reachability::SameSplitsBlock b | succInvariant1(b, pred, predSplits, succ, c) |
|
||||
succ = b.getAnElement() and
|
||||
not succ = b
|
||||
)
|
||||
or
|
||||
// Case 1b
|
||||
case1bForall(pred, predSplits, succ, c, TSplitsNil())
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private SplitImpl succInvariant1GetASplit(
|
||||
Reachability::SameSplitsBlock b, ControlFlowElement pred, Splits predSplits,
|
||||
ControlFlowElement succ, Completion c
|
||||
) {
|
||||
succInvariant1(b, pred, predSplits, succ, c) and
|
||||
result = predSplits.getASplit()
|
||||
}
|
||||
|
||||
private predicate case2aux(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c
|
||||
) {
|
||||
exists(Reachability::SameSplitsBlock b |
|
||||
succInvariant1(b, pred, predSplits, succ, c) and
|
||||
(succ = b.getAnElement() implies succ = b)
|
||||
|
|
||||
succInvariant1GetASplit(b, pred, predSplits, succ, c).hasExit(pred, succ, c)
|
||||
or
|
||||
any(SplitImpl split).hasEntry(pred, succ, c)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succSplits` should not inherit a split of kind `sk` from
|
||||
* `predSplits`, except possibly because of a split in `except`.
|
||||
*
|
||||
* The predicate is written using explicit recursion, as opposed to a `forall`,
|
||||
* to avoid negative recursion.
|
||||
*/
|
||||
private predicate case2aNoneInheritedOfKindForall(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, SplitKind sk,
|
||||
Splits except
|
||||
) {
|
||||
case2aux(pred, predSplits, succ, c) and
|
||||
sk.appliesTo(succ) and
|
||||
except = predSplits
|
||||
or
|
||||
exists(Splits mid, SplitImpl split |
|
||||
case2aNoneInheritedOfKindForall(pred, predSplits, succ, c, sk, mid) and
|
||||
mid = TSplitsCons(split, except)
|
||||
|
|
||||
split.getKind() = any(SplitKind sk0 | sk0 != sk and sk0.appliesTo(succ))
|
||||
or
|
||||
split.hasExit(pred, succ, c)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate entryOfKind(
|
||||
ControlFlowElement pred, ControlFlowElement succ, Completion c, SplitImpl split, SplitKind sk
|
||||
) {
|
||||
split.hasEntry(pred, succ, c) and
|
||||
sk = split.getKind()
|
||||
}
|
||||
|
||||
/** Holds if `succSplits` should not have a split of kind `sk`. */
|
||||
pragma[nomagic]
|
||||
private predicate case2aNoneOfKind(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, SplitKind sk
|
||||
) {
|
||||
// None inherited from predecessor
|
||||
case2aNoneInheritedOfKindForall(pred, predSplits, succ, c, sk, TSplitsNil()) and
|
||||
// None newly entered into
|
||||
not entryOfKind(pred, succ, c, _, sk)
|
||||
}
|
||||
|
||||
/** Holds if `succSplits` should not have a split of kind `sk` at rank `rnk`. */
|
||||
pragma[nomagic]
|
||||
private predicate case2aNoneAtRank(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, int rnk
|
||||
) {
|
||||
exists(SplitKind sk | case2aNoneOfKind(pred, predSplits, succ, c, sk) |
|
||||
rnk = sk.getListRank(succ)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private SplitImpl case2auxGetAPredecessorSplit(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c
|
||||
) {
|
||||
case2aux(pred, predSplits, succ, c) and
|
||||
result = predSplits.getASplit()
|
||||
}
|
||||
|
||||
/** Gets a split that should be in `succSplits`. */
|
||||
pragma[nomagic]
|
||||
private SplitImpl case2aSome(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, SplitKind sk
|
||||
) {
|
||||
(
|
||||
// Inherited from predecessor
|
||||
result = case2auxGetAPredecessorSplit(pred, predSplits, succ, c) and
|
||||
result.hasSuccessor(pred, succ, c)
|
||||
or
|
||||
// Newly entered into
|
||||
exists(SplitKind sk0 |
|
||||
case2aNoneInheritedOfKindForall(pred, predSplits, succ, c, sk0, TSplitsNil())
|
||||
|
|
||||
entryOfKind(pred, succ, c, result, sk0)
|
||||
)
|
||||
) and
|
||||
sk = result.getKind()
|
||||
}
|
||||
|
||||
/** Gets a split that should be in `succSplits` at rank `rnk`. */
|
||||
pragma[nomagic]
|
||||
SplitImpl case2aSomeAtRank(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, int rnk
|
||||
) {
|
||||
exists(SplitKind sk | result = case2aSome(pred, predSplits, succ, c, sk) |
|
||||
rnk = sk.getListRank(succ)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Case 2a.
|
||||
*
|
||||
* As opposed to the other cases, in this case we need to construct a new set
|
||||
* of splits `succSplits`. Since this involves constructing the very IPA type,
|
||||
* we cannot recurse directly over the structure of `succSplits`. Instead, we
|
||||
* recurse over the ranks of all splits that *might* be in `succSplits`.
|
||||
*
|
||||
* - Invariant 1 holds in the base case,
|
||||
* - invariant 2 holds for all splits with rank at least `rnk`,
|
||||
* - invariant 3 holds for all splits in `predSplits`,
|
||||
* - invariant 4 holds for all splits in `succSplits` with rank at least `rnk`,
|
||||
* and
|
||||
* - invariant 4 holds for all splits in `succSplits` with rank at least `rnk`.
|
||||
*/
|
||||
predicate case2aFromRank(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
Completion c, int rnk
|
||||
) {
|
||||
case2aux(pred, predSplits, succ, c) and
|
||||
succSplits = TSplitsNil() and
|
||||
rnk = max(any(SplitKind sk).getListRank(succ)) + 1
|
||||
or
|
||||
case2aFromRank(pred, predSplits, succ, succSplits, c, rnk + 1) and
|
||||
case2aNoneAtRank(pred, predSplits, succ, c, rnk)
|
||||
or
|
||||
exists(Splits mid, SplitImpl split | split = case2aCons(pred, predSplits, succ, mid, c, rnk) |
|
||||
succSplits = TSplitsCons(split, mid)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private SplitImpl case2aCons(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
Completion c, int rnk
|
||||
) {
|
||||
case2aFromRank(pred, predSplits, succ, succSplits, c, rnk + 1) and
|
||||
result = case2aSomeAtRank(pred, predSplits, succ, c, rnk)
|
||||
}
|
||||
|
||||
/**
|
||||
* Case 2b.
|
||||
*
|
||||
* Invariants 1, 4, and 5 hold in the base case, and invariants 2 and 3 are
|
||||
* maintained for all splits in `predSplits`, except possibly for the splits
|
||||
* in `except`.
|
||||
*
|
||||
* The predicate is written using explicit recursion, as opposed to a `forall`,
|
||||
* to avoid negative recursion.
|
||||
*/
|
||||
private predicate case2bForall(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, Splits except
|
||||
) {
|
||||
// Invariant 1
|
||||
case2aux(pred, predSplits, succ, c) and
|
||||
// Invariants 4 and 5
|
||||
not any(SplitKind sk).appliesTo(succ) and
|
||||
except = predSplits
|
||||
or
|
||||
exists(SplitImpl split | case2bForallCons(pred, predSplits, succ, c, split, except) |
|
||||
// Invariants 2 and 3
|
||||
split.hasExit(pred, succ, c)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate case2bForallCons(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c,
|
||||
SplitImpl exceptHead, Splits exceptTail
|
||||
) {
|
||||
case2bForall(pred, predSplits, succ, c, TSplitsCons(exceptHead, exceptTail))
|
||||
}
|
||||
|
||||
private predicate case2(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
Completion c
|
||||
) {
|
||||
case2aFromRank(pred, predSplits, succ, succSplits, c, 1)
|
||||
or
|
||||
case2bForall(pred, predSplits, succ, c, TSplitsNil()) and
|
||||
succSplits = TSplitsNil()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succ` with splits `succSplits` is a successor of type `t` for `pred`
|
||||
* with splits `predSplits`.
|
||||
*/
|
||||
predicate succSplits(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
Completion c
|
||||
) {
|
||||
case1(pred, predSplits, succ, c) and
|
||||
succSplits = predSplits
|
||||
or
|
||||
case2(pred, predSplits, succ, succSplits, c)
|
||||
}
|
||||
}
|
||||
|
||||
import SuccSplits
|
||||
|
||||
/** Provides logic for calculating reachable control flow nodes. */
|
||||
private module Reachability {
|
||||
/**
|
||||
* Holds if `cfe` is a control flow element where the set of possible splits may
|
||||
* be different from the set of possible splits for one of `cfe`'s predecessors.
|
||||
* That is, `cfe` starts a new block of elements with the same set of splits.
|
||||
*/
|
||||
private predicate startsSplits(ControlFlowElement cfe) {
|
||||
scopeFirst(_, cfe)
|
||||
or
|
||||
exists(SplitImpl s |
|
||||
s.hasEntry(_, cfe, _)
|
||||
or
|
||||
s.hasExit(_, cfe, _)
|
||||
)
|
||||
or
|
||||
exists(ControlFlowElement pred, SplitImpl split, Completion c | succ(pred, cfe, c) |
|
||||
split.appliesTo(pred) and
|
||||
not split.hasSuccessor(pred, cfe, c)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate intraSplitsSucc(ControlFlowElement pred, ControlFlowElement succ) {
|
||||
succ(pred, succ, _) and
|
||||
not startsSplits(succ)
|
||||
}
|
||||
|
||||
private predicate splitsBlockContains(ControlFlowElement start, ControlFlowElement cfe) =
|
||||
fastTC(intraSplitsSucc/2)(start, cfe)
|
||||
|
||||
/**
|
||||
* A block of control flow elements where the set of splits is guaranteed
|
||||
* to remain unchanged, represented by the first element in the block.
|
||||
*/
|
||||
class SameSplitsBlock extends ControlFlowElement {
|
||||
SameSplitsBlock() { startsSplits(this) }
|
||||
|
||||
/** Gets a control flow element in this block. */
|
||||
ControlFlowElement getAnElement() {
|
||||
splitsBlockContains(this, result)
|
||||
or
|
||||
result = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private SameSplitsBlock getASuccessor(Splits predSplits, Splits succSplits) {
|
||||
exists(ControlFlowElement pred | pred = this.getAnElement() |
|
||||
succSplits(pred, predSplits, result, succSplits, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the elements of this block are reachable from a callable entry
|
||||
* point, with the splits `splits`.
|
||||
*/
|
||||
predicate isReachable(Splits splits) {
|
||||
// Base case
|
||||
succEntrySplits(_, this, splits, _)
|
||||
or
|
||||
// Recursive case
|
||||
exists(SameSplitsBlock pred, Splits predSplits | pred.isReachable(predSplits) |
|
||||
this = pred.getASuccessor(predSplits, splits)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* If needed, call this predicate from `ControlFlowGraphImplSpecific.qll` in order to
|
||||
* force a stage-dependency on the `ControlFlowGraphImplShared.qll` stage and therby
|
||||
* collapsing the two stages.
|
||||
*/
|
||||
cached
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
|
||||
cached
|
||||
newtype TSplits =
|
||||
TSplitsNil() or
|
||||
TSplitsCons(SplitImpl head, Splits tail) {
|
||||
exists(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, int rnk
|
||||
|
|
||||
case2aFromRank(pred, predSplits, succ, tail, c, rnk + 1) and
|
||||
head = case2aSomeAtRank(pred, predSplits, succ, c, rnk)
|
||||
)
|
||||
or
|
||||
succEntrySplitsCons(_, _, head, tail, _)
|
||||
}
|
||||
|
||||
cached
|
||||
string splitsToString(Splits splits) {
|
||||
splits = TSplitsNil() and
|
||||
result = ""
|
||||
or
|
||||
exists(SplitImpl head, Splits tail, string headString, string tailString |
|
||||
splits = TSplitsCons(head, tail)
|
||||
|
|
||||
headString = head.toString() and
|
||||
tailString = tail.toString() and
|
||||
if tailString = ""
|
||||
then result = headString
|
||||
else
|
||||
if headString = ""
|
||||
then result = tailString
|
||||
else result = headString + ", " + tailString
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal representation of control flow nodes in the control flow graph.
|
||||
* The control flow graph is pruned for unreachable nodes.
|
||||
*/
|
||||
cached
|
||||
newtype TNode =
|
||||
TEntryNode(CfgScope scope) { succEntrySplits(scope, _, _, _) } or
|
||||
TAnnotatedExitNode(CfgScope scope, boolean normal) {
|
||||
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(_) |
|
||||
succExitSplits(b.getAnElement(), _, scope, t) and
|
||||
if isAbnormalExitType(t) then normal = false else normal = true
|
||||
)
|
||||
} or
|
||||
TExitNode(CfgScope scope) {
|
||||
exists(Reachability::SameSplitsBlock b | b.isReachable(_) |
|
||||
succExitSplits(b.getAnElement(), _, scope, _)
|
||||
)
|
||||
} or
|
||||
TElementNode(ControlFlowElement cfe, Splits splits) {
|
||||
exists(Reachability::SameSplitsBlock b | b.isReachable(splits) | cfe = b.getAnElement())
|
||||
}
|
||||
|
||||
/** Gets a successor node of a given flow type, if any. */
|
||||
cached
|
||||
TNode getASuccessor(TNode pred, SuccessorType t) {
|
||||
// Callable entry node -> callable body
|
||||
exists(ControlFlowElement succElement, Splits succSplits, CfgScope scope |
|
||||
result = TElementNode(succElement, succSplits) and
|
||||
pred = TEntryNode(scope) and
|
||||
succEntrySplits(scope, succElement, succSplits, t)
|
||||
)
|
||||
or
|
||||
exists(ControlFlowElement predElement, Splits predSplits |
|
||||
pred = TElementNode(predElement, predSplits)
|
||||
|
|
||||
// Element node -> callable exit (annotated)
|
||||
exists(CfgScope scope, boolean normal |
|
||||
result = TAnnotatedExitNode(scope, normal) and
|
||||
succExitSplits(predElement, predSplits, scope, t) and
|
||||
if isAbnormalExitType(t) then normal = false else normal = true
|
||||
)
|
||||
or
|
||||
// Element node -> element node
|
||||
exists(ControlFlowElement succElement, Splits succSplits, Completion c |
|
||||
result = TElementNode(succElement, succSplits)
|
||||
|
|
||||
succSplits(predElement, predSplits, succElement, succSplits, c) and
|
||||
t = getAMatchingSuccessorType(c)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Callable exit (annotated) -> callable exit
|
||||
exists(CfgScope scope |
|
||||
pred = TAnnotatedExitNode(scope, _) and
|
||||
result = TExitNode(scope) and
|
||||
successorTypeIsSimple(t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a first control flow element executed within `cfe`.
|
||||
*/
|
||||
cached
|
||||
ControlFlowElement getAControlFlowEntryNode(ControlFlowElement cfe) { first(cfe, result) }
|
||||
|
||||
/**
|
||||
* Gets a potential last control flow element executed within `cfe`.
|
||||
*/
|
||||
cached
|
||||
ControlFlowElement getAControlFlowExitNode(ControlFlowElement cfe) { last(cfe, result, _) }
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Import this module into a `.ql` file of `@kind graph` to render a CFG. The
|
||||
* graph is restricted to nodes from `RelevantNode`.
|
||||
*/
|
||||
module TestOutput {
|
||||
abstract class RelevantNode extends Node { }
|
||||
|
||||
query predicate nodes(RelevantNode n, string attr, string val) {
|
||||
attr = "semmle.order" and
|
||||
val =
|
||||
any(int i |
|
||||
n =
|
||||
rank[i](RelevantNode p, Location l |
|
||||
l = p.getLocation()
|
||||
|
|
||||
p
|
||||
order by
|
||||
l.getFile().getBaseName(), l.getFile().getAbsolutePath(), l.getStartLine(),
|
||||
l.getStartColumn()
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
|
||||
query predicate edges(RelevantNode pred, RelevantNode succ, string attr, string val) {
|
||||
exists(SuccessorType t | succ = getASuccessor(pred, t) |
|
||||
attr = "semmle.label" and
|
||||
if successorTypeIsSimple(t) then val = "" else val = t.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a set of splitting-related consistency queries. */
|
||||
module Consistency {
|
||||
query predicate nonUniqueSetRepresentation(Splits s1, Splits s2) {
|
||||
forex(Split s | s = s1.getASplit() | s = s2.getASplit()) and
|
||||
forex(Split s | s = s2.getASplit() | s = s1.getASplit()) and
|
||||
s1 != s2
|
||||
}
|
||||
|
||||
query predicate breakInvariant2(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
SplitImpl split, Completion c
|
||||
) {
|
||||
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||
split = predSplits.getASplit() and
|
||||
split.hasSuccessor(pred, succ, c) and
|
||||
not split = succSplits.getASplit()
|
||||
}
|
||||
|
||||
query predicate breakInvariant3(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
SplitImpl split, Completion c
|
||||
) {
|
||||
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||
split = predSplits.getASplit() and
|
||||
split.hasExit(pred, succ, c) and
|
||||
not split.hasEntry(pred, succ, c) and
|
||||
split = succSplits.getASplit()
|
||||
}
|
||||
|
||||
query predicate breakInvariant4(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
SplitImpl split, Completion c
|
||||
) {
|
||||
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||
split.hasEntry(pred, succ, c) and
|
||||
not split.getKind() = predSplits.getASplit().getKind() and
|
||||
not split = succSplits.getASplit()
|
||||
}
|
||||
|
||||
query predicate breakInvariant5(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
SplitImpl split, Completion c
|
||||
) {
|
||||
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||
split = succSplits.getASplit() and
|
||||
not (split.hasSuccessor(pred, succ, c) and split = predSplits.getASplit()) and
|
||||
not split.hasEntry(pred, succ, c)
|
||||
}
|
||||
|
||||
query predicate multipleSuccessors(Node node, SuccessorType t, Node successor) {
|
||||
not node instanceof TEntryNode and
|
||||
strictcount(getASuccessor(node, t)) > 1 and
|
||||
successor = getASuccessor(node, t)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
private import csharp as CS
|
||||
private import ControlFlowGraphImpl as Impl
|
||||
private import Completion as Comp
|
||||
private import Splitting as Splitting
|
||||
private import SuccessorType as ST
|
||||
private import semmle.code.csharp.Caching
|
||||
|
||||
class ControlFlowTreeBase = Impl::ControlFlowTree::Range;
|
||||
|
||||
class ControlFlowElement = CS::ControlFlowElement;
|
||||
|
||||
class Completion = Comp::Completion;
|
||||
|
||||
/**
|
||||
* Hold if `c` represents normal evaluation of a statement or an
|
||||
* expression.
|
||||
*/
|
||||
predicate completionIsNormal(Completion c) { c instanceof Comp::NormalCompletion }
|
||||
|
||||
/**
|
||||
* Hold if `c` represents simple (normal) evaluation of a statement or an
|
||||
* expression.
|
||||
*/
|
||||
predicate completionIsSimple(Completion c) { c instanceof Comp::SimpleCompletion }
|
||||
|
||||
/** Holds if `c` is a valid completion for `e`. */
|
||||
predicate completionIsValidFor(Completion c, ControlFlowElement e) { c.isValidFor(e) }
|
||||
|
||||
class CfgScope = Impl::CfgScope;
|
||||
|
||||
/** Gets the CFG scope for `e`. */
|
||||
CfgScope getCfgScope(ControlFlowElement e) {
|
||||
Stages::ControlFlowStage::forceCachingInSameStage() and
|
||||
result = e.getEnclosingCallable()
|
||||
}
|
||||
|
||||
predicate scopeFirst = Impl::scopeFirst/2;
|
||||
|
||||
predicate scopeLast = Impl::scopeLast/3;
|
||||
|
||||
/** The maximum number of splits allowed for a given node. */
|
||||
int maxSplits() { result = 5 }
|
||||
|
||||
class SplitKindBase = Splitting::TSplitKind;
|
||||
|
||||
class Split = Splitting::Split;
|
||||
|
||||
class SuccessorType = ST::SuccessorType;
|
||||
|
||||
/** Gets a successor type that matches completion `c`. */
|
||||
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
|
||||
|
||||
/**
|
||||
* Hold if `c` represents simple (normal) evaluation of a statement or an
|
||||
* expression.
|
||||
*/
|
||||
predicate successorTypeIsSimple(SuccessorType t) {
|
||||
t instanceof ST::SuccessorTypes::NormalSuccessor
|
||||
}
|
||||
|
||||
/** Holds if `t` is an abnormal exit type out of a callable. */
|
||||
predicate isAbnormalExitType(SuccessorType t) {
|
||||
t instanceof ST::SuccessorTypes::ExceptionSuccessor or
|
||||
t instanceof ST::SuccessorTypes::ExitSuccessor
|
||||
}
|
||||
|
||||
class Location = CS::Location;
|
||||
|
||||
class Node = CS::ControlFlow::Node;
|
||||
@@ -11,9 +11,6 @@ private import SuccessorTypes
|
||||
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow
|
||||
private import semmle.code.csharp.controlflow.internal.PreSsa
|
||||
|
||||
/** The maximum number of splits allowed for a given node. */
|
||||
private int maxSplits() { result = 5 }
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
private import semmle.code.csharp.Caching
|
||||
@@ -51,42 +48,9 @@ private module Cached {
|
||||
branch in [false, true]
|
||||
} or
|
||||
TLoopSplit(LoopSplitting::AnalyzableLoopStmt loop)
|
||||
|
||||
cached
|
||||
newtype TSplits =
|
||||
TSplitsNil() or
|
||||
TSplitsCons(SplitImpl head, Splits tail) {
|
||||
exists(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, int rnk
|
||||
|
|
||||
case2aFromRank(pred, predSplits, succ, tail, c, rnk + 1) and
|
||||
head = case2aSomeAtRank(pred, predSplits, succ, c, rnk)
|
||||
)
|
||||
or
|
||||
succEntrySplitsCons(_, _, head, tail, _)
|
||||
}
|
||||
|
||||
cached
|
||||
string splitsToString(Splits splits) {
|
||||
splits = TSplitsNil() and
|
||||
result = ""
|
||||
or
|
||||
exists(SplitImpl head, Splits tail, string headString, string tailString |
|
||||
splits = TSplitsCons(head, tail)
|
||||
|
|
||||
headString = head.toString() and
|
||||
tailString = tail.toString() and
|
||||
if tailString = ""
|
||||
then result = headString
|
||||
else
|
||||
if headString = ""
|
||||
then result = tailString
|
||||
else result = headString + ", " + tailString
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private import Cached
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* A split for a control flow element. For example, a tag that determines how to
|
||||
@@ -97,127 +61,6 @@ class Split extends TSplit {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if split kinds `sk1` and `sk2` may overlap. That is, they may apply
|
||||
* to at least one common control flow element inside callable `c`.
|
||||
*/
|
||||
private predicate overlapping(Callable c, SplitKind sk1, SplitKind sk2) {
|
||||
exists(ControlFlowElement cfe |
|
||||
sk1.appliesTo(cfe) and
|
||||
sk2.appliesTo(cfe) and
|
||||
c = cfe.getEnclosingCallable()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A split kind. Each control flow node can have at most one split of a
|
||||
* given kind.
|
||||
*/
|
||||
abstract class SplitKind extends TSplitKind {
|
||||
/** Gets a split of this kind. */
|
||||
SplitImpl getASplit() { result.getKind() = this }
|
||||
|
||||
/** Holds if some split of this kind applies to control flow element `cfe`. */
|
||||
predicate appliesTo(ControlFlowElement cfe) { this.getASplit().appliesTo(cfe) }
|
||||
|
||||
/**
|
||||
* Gets a unique integer representing this split kind. The integer is used
|
||||
* to represent sets of splits as ordered lists.
|
||||
*/
|
||||
abstract int getListOrder();
|
||||
|
||||
/** Gets the rank of this split kind among all overlapping kinds for `c`. */
|
||||
private int getRank(Callable c) {
|
||||
this = rank[result](SplitKind sk | overlapping(c, this, sk) | sk order by sk.getListOrder())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this split kind is enabled for control flow element `cfe`. For
|
||||
* performance reasons, the number of splits is restricted by the `maxSplits()`
|
||||
* predicate.
|
||||
*/
|
||||
predicate isEnabled(ControlFlowElement cfe) {
|
||||
this.appliesTo(cfe) and
|
||||
this.getRank(cfe.getEnclosingCallable()) <= maxSplits()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank of this split kind among all the split kinds that apply to
|
||||
* control flow element `cfe`. The rank is based on the order defined by
|
||||
* `getListOrder()`.
|
||||
*/
|
||||
int getListRank(ControlFlowElement cfe) {
|
||||
this.isEnabled(cfe) and
|
||||
this = rank[result](SplitKind sk | sk.appliesTo(cfe) | sk order by sk.getListOrder())
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this split kind. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
// This class only exists to not pollute the externally visible `Split` class
|
||||
// with internal helper predicates
|
||||
abstract class SplitImpl extends Split {
|
||||
/** Gets the kind of this split. */
|
||||
abstract SplitKind getKind();
|
||||
|
||||
/**
|
||||
* Holds if this split is entered when control passes from `pred` to `succ` with
|
||||
* completion `c`.
|
||||
*
|
||||
* Invariant: `hasEntry(pred, succ, c) implies succ(pred, succ, c)`.
|
||||
*/
|
||||
abstract predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
||||
|
||||
/**
|
||||
* Holds if this split is entered when control passes from `scope` to the entry point
|
||||
* `first`.
|
||||
*
|
||||
* Invariant: `hasEntryScope(scope, first) implies scopeFirst(scope, first)`.
|
||||
*/
|
||||
abstract predicate hasEntryScope(CfgScope scope, ControlFlowElement first);
|
||||
|
||||
/**
|
||||
* Holds if this split is left when control passes from `pred` to `succ` with
|
||||
* completion `c`.
|
||||
*
|
||||
* Invariant: `hasExit(pred, succ, c) implies succ(pred, succ, c)`.
|
||||
*/
|
||||
abstract predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
||||
|
||||
/**
|
||||
* Holds if this split is left when control passes from `last` out of the enclosing
|
||||
* scope `scope` with completion `c`.
|
||||
*
|
||||
* Invariant: `hasExitScope(last, scope, c) implies scopeLast(scope, last, c)`
|
||||
*/
|
||||
abstract predicate hasExitScope(ControlFlowElement last, CfgScope scope, Completion c);
|
||||
|
||||
/**
|
||||
* Holds if this split is maintained when control passes from `pred` to `succ` with
|
||||
* completion `c`.
|
||||
*
|
||||
* Invariant: `hasSuccessor(pred, succ, c) implies succ(pred, succ, c)`
|
||||
*/
|
||||
abstract predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
||||
|
||||
/** Holds if this split applies to control flow element `cfe`. */
|
||||
final predicate appliesTo(ControlFlowElement cfe) {
|
||||
this.hasEntry(_, cfe, _)
|
||||
or
|
||||
this.hasEntryScope(_, cfe)
|
||||
or
|
||||
exists(ControlFlowElement pred | this.appliesTo(pred) | this.hasSuccessor(pred, cfe, _))
|
||||
}
|
||||
|
||||
/** The `succ` relation restricted to predecessors `pred` that this split applies to. */
|
||||
pragma[noinline]
|
||||
final predicate appliesSucc(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
this.appliesTo(pred) and
|
||||
succ(pred, succ, c)
|
||||
}
|
||||
}
|
||||
|
||||
module InitializerSplitting {
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
|
||||
@@ -382,7 +225,7 @@ module InitializerSplitting {
|
||||
succ.getEnclosingCallable() = this.getConstructor()
|
||||
}
|
||||
|
||||
override predicate hasExitScope(ControlFlowElement last, CfgScope scope, Completion c) {
|
||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
||||
this.appliesTo(last) and
|
||||
scopeLast(scope, last, c) and
|
||||
scope = this.getConstructor()
|
||||
@@ -499,7 +342,7 @@ module ConditionalCompletionSplitting {
|
||||
if c instanceof ConditionalCompletion then completion = c else any()
|
||||
}
|
||||
|
||||
override predicate hasExitScope(ControlFlowElement last, CfgScope scope, Completion c) {
|
||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
||||
this.appliesTo(last) and
|
||||
scopeLast(scope, last, c) and
|
||||
if c instanceof ConditionalCompletion then completion = c else any()
|
||||
@@ -612,7 +455,7 @@ module AssertionSplitting {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasExitScope(ControlFlowElement last, CfgScope scope, Completion c) {
|
||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
||||
this.appliesTo(last) and
|
||||
last = a and
|
||||
scopeLast(scope, last, c) and
|
||||
@@ -853,7 +696,7 @@ module FinallySplitting {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasExitScope(ControlFlowElement last, CfgScope scope, Completion c) {
|
||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
||||
scopeLast(scope, last, c) and
|
||||
(
|
||||
exit(last, c, _)
|
||||
@@ -1033,7 +876,7 @@ module ExceptionHandlerSplitting {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasExitScope(ControlFlowElement last, CfgScope scope, Completion c) {
|
||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
||||
// Exit out from last `catch` clause (no catch clauses match)
|
||||
this.hasLastExit(last, c) and
|
||||
scopeLast(scope, last, c)
|
||||
@@ -1292,7 +1135,7 @@ module BooleanSplitting {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasExitScope(ControlFlowElement last, CfgScope scope, Completion c) {
|
||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
||||
exists(PreBasicBlock bb | this.appliesToBlock(bb, c) |
|
||||
last = bb.getLastElement() and
|
||||
scopeLast(scope, last, c)
|
||||
@@ -1486,7 +1329,7 @@ module LoopSplitting {
|
||||
loop.stop(pred, succ, c)
|
||||
}
|
||||
|
||||
override predicate hasExitScope(ControlFlowElement last, CfgScope scope, Completion c) {
|
||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
||||
this.appliesToPredecessor(last, c) and
|
||||
scopeLast(scope, last, c)
|
||||
}
|
||||
@@ -1498,463 +1341,3 @@ module LoopSplitting {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of control flow node splits. The set is represented by a list of splits,
|
||||
* ordered by ascending rank.
|
||||
*/
|
||||
class Splits extends TSplits {
|
||||
/** Gets a textual representation of this set of splits. */
|
||||
string toString() { result = splitsToString(this) }
|
||||
|
||||
/** Gets a split belonging to this set of splits. */
|
||||
SplitImpl getASplit() {
|
||||
exists(SplitImpl head, Splits tail | this = TSplitsCons(head, tail) |
|
||||
result = head
|
||||
or
|
||||
result = tail.getASplit()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate succEntrySplitsFromRank(
|
||||
CfgScope pred, ControlFlowElement succ, Splits splits, int rnk
|
||||
) {
|
||||
splits = TSplitsNil() and
|
||||
scopeFirst(pred, succ) and
|
||||
rnk = 0
|
||||
or
|
||||
exists(SplitImpl head, Splits tail | succEntrySplitsCons(pred, succ, head, tail, rnk) |
|
||||
splits = TSplitsCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate succEntrySplitsCons(
|
||||
Callable pred, ControlFlowElement succ, SplitImpl head, Splits tail, int rnk
|
||||
) {
|
||||
succEntrySplitsFromRank(pred, succ, tail, rnk - 1) and
|
||||
head.hasEntryScope(pred, succ) and
|
||||
rnk = head.getKind().getListRank(succ)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succ` with splits `succSplits` is the first element that is executed
|
||||
* when entering callable `pred`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate succEntrySplits(CfgScope pred, ControlFlowElement succ, Splits succSplits, SuccessorType t) {
|
||||
exists(int rnk |
|
||||
scopeFirst(pred, succ) and
|
||||
t instanceof NormalSuccessor and
|
||||
succEntrySplitsFromRank(pred, succ, succSplits, rnk)
|
||||
|
|
||||
rnk = 0 and
|
||||
not any(SplitImpl split).hasEntryScope(pred, succ)
|
||||
or
|
||||
rnk = max(SplitImpl split | split.hasEntryScope(pred, succ) | split.getKind().getListRank(succ))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pred` with splits `predSplits` can exit the enclosing callable
|
||||
* `succ` with type `t`.
|
||||
*/
|
||||
predicate succExitSplits(ControlFlowElement pred, Splits predSplits, CfgScope succ, SuccessorType t) {
|
||||
exists(Reachability::SameSplitsBlock b, Completion c | pred = b.getAnElement() |
|
||||
b.isReachable(predSplits) and
|
||||
t = c.getAMatchingSuccessorType() and
|
||||
scopeLast(succ, pred, c) and
|
||||
forall(SplitImpl predSplit | predSplit = predSplits.getASplit() |
|
||||
predSplit.hasExitScope(pred, succ, c)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a predicate for the successor relation with split information,
|
||||
* as well as logic used to construct the type `TSplits` representing sets
|
||||
* of splits. Only sets of splits that can be reached are constructed, hence
|
||||
* the predicates are mutually recursive.
|
||||
*
|
||||
* For the successor relation
|
||||
*
|
||||
* ```ql
|
||||
* succSplits(ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits, Completion c)
|
||||
* ```
|
||||
*
|
||||
* the following invariants are maintained:
|
||||
*
|
||||
* 1. `pred` is reachable with split set `predSplits`.
|
||||
* 2. For all `split` in `predSplits`:
|
||||
* - If `split.hasSuccessor(pred, succ, c)` then `split` in `succSplits`.
|
||||
* 3. For all `split` in `predSplits`:
|
||||
* - If `split.hasExit(pred, succ, c)` and not `split.hasEntry(pred, succ, c)` then
|
||||
* `split` not in `succSplits`.
|
||||
* 4. For all `split` with kind not in `predSplits`:
|
||||
* - If `split.hasEntry(pred, succ, c)` then `split` in `succSplits`.
|
||||
* 5. For all `split` in `succSplits`:
|
||||
* - `split.hasSuccessor(pred, succ, c)` and `split` in `predSplits`, or
|
||||
* - `split.hasEntry(pred, succ, c)`.
|
||||
*
|
||||
* The algorithm divides into four cases:
|
||||
*
|
||||
* 1. The set of splits for the successor is the same as the set of splits
|
||||
* for the predecessor:
|
||||
* a) The successor is in the same `SameSplitsBlock` as the predecessor.
|
||||
* b) The successor is *not* in the same `SameSplitsBlock` as the predecessor.
|
||||
* 2. The set of splits for the successor is different from the set of splits
|
||||
* for the predecessor:
|
||||
* a) The set of splits for the successor is *maybe* non-empty.
|
||||
* b) The set of splits for the successor is *always* empty.
|
||||
*
|
||||
* Only case 2a may introduce new sets of splits, so only predicates from
|
||||
* this case are used in the definition of `TSplits`.
|
||||
*
|
||||
* The predicates in this module are named after the cases above.
|
||||
*/
|
||||
private module SuccSplits {
|
||||
private predicate succInvariant1(
|
||||
Reachability::SameSplitsBlock b, ControlFlowElement pred, Splits predSplits,
|
||||
ControlFlowElement succ, Completion c
|
||||
) {
|
||||
pred = b.getAnElement() and
|
||||
b.isReachable(predSplits) and
|
||||
succ(pred, succ, c)
|
||||
}
|
||||
|
||||
private predicate case1b0(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c
|
||||
) {
|
||||
exists(Reachability::SameSplitsBlock b |
|
||||
// Invariant 1
|
||||
succInvariant1(b, pred, predSplits, succ, c)
|
||||
|
|
||||
(succ = b.getAnElement() implies succ = b) and
|
||||
// Invariant 4
|
||||
not exists(SplitImpl split | split.hasEntry(pred, succ, c))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Case 1b.
|
||||
*
|
||||
* Invariants 1 and 4 hold in the base case, and invariants 2, 3, and 5 are
|
||||
* maintained for all splits in `predSplits` (= `succSplits`), except
|
||||
* possibly for the splits in `except`.
|
||||
*
|
||||
* The predicate is written using explicit recursion, as opposed to a `forall`,
|
||||
* to avoid negative recursion.
|
||||
*/
|
||||
private predicate case1bForall(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, Splits except
|
||||
) {
|
||||
case1b0(pred, predSplits, succ, c) and
|
||||
except = predSplits
|
||||
or
|
||||
exists(SplitImpl split |
|
||||
case1bForallCons(pred, predSplits, succ, c, split, except) and
|
||||
split.hasSuccessor(pred, succ, c)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate case1bForallCons(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c,
|
||||
SplitImpl exceptHead, Splits exceptTail
|
||||
) {
|
||||
case1bForall(pred, predSplits, succ, c, TSplitsCons(exceptHead, exceptTail))
|
||||
}
|
||||
|
||||
private predicate case1(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c
|
||||
) {
|
||||
// Case 1a
|
||||
exists(Reachability::SameSplitsBlock b | succInvariant1(b, pred, predSplits, succ, c) |
|
||||
succ = b.getAnElement() and
|
||||
not succ = b
|
||||
)
|
||||
or
|
||||
// Case 1b
|
||||
case1bForall(pred, predSplits, succ, c, TSplitsNil())
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private SplitImpl succInvariant1GetASplit(
|
||||
Reachability::SameSplitsBlock b, ControlFlowElement pred, Splits predSplits,
|
||||
ControlFlowElement succ, Completion c
|
||||
) {
|
||||
succInvariant1(b, pred, predSplits, succ, c) and
|
||||
result = predSplits.getASplit()
|
||||
}
|
||||
|
||||
private predicate case2aux(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c
|
||||
) {
|
||||
exists(Reachability::SameSplitsBlock b |
|
||||
succInvariant1(b, pred, predSplits, succ, c) and
|
||||
(succ = b.getAnElement() implies succ = b)
|
||||
|
|
||||
succInvariant1GetASplit(b, pred, predSplits, succ, c).hasExit(pred, succ, c)
|
||||
or
|
||||
any(SplitImpl split).hasEntry(pred, succ, c)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succSplits` should not inherit a split of kind `sk` from
|
||||
* `predSplits`, except possibly because of a split in `except`.
|
||||
*
|
||||
* The predicate is written using explicit recursion, as opposed to a `forall`,
|
||||
* to avoid negative recursion.
|
||||
*/
|
||||
private predicate case2aNoneInheritedOfKindForall(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, SplitKind sk,
|
||||
Splits except
|
||||
) {
|
||||
case2aux(pred, predSplits, succ, c) and
|
||||
sk.appliesTo(succ) and
|
||||
except = predSplits
|
||||
or
|
||||
exists(Splits mid, SplitImpl split |
|
||||
case2aNoneInheritedOfKindForall(pred, predSplits, succ, c, sk, mid) and
|
||||
mid = TSplitsCons(split, except)
|
||||
|
|
||||
split.getKind() = any(SplitKind sk0 | sk0 != sk and sk0.appliesTo(succ))
|
||||
or
|
||||
split.hasExit(pred, succ, c)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate entryOfKind(
|
||||
ControlFlowElement pred, ControlFlowElement succ, Completion c, SplitImpl split, SplitKind sk
|
||||
) {
|
||||
split.hasEntry(pred, succ, c) and
|
||||
sk = split.getKind()
|
||||
}
|
||||
|
||||
/** Holds if `succSplits` should not have a split of kind `sk`. */
|
||||
pragma[nomagic]
|
||||
private predicate case2aNoneOfKind(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, SplitKind sk
|
||||
) {
|
||||
// None inherited from predecessor
|
||||
case2aNoneInheritedOfKindForall(pred, predSplits, succ, c, sk, TSplitsNil()) and
|
||||
// None newly entered into
|
||||
not entryOfKind(pred, succ, c, _, sk)
|
||||
}
|
||||
|
||||
/** Holds if `succSplits` should not have a split of kind `sk` at rank `rnk`. */
|
||||
pragma[nomagic]
|
||||
private predicate case2aNoneAtRank(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, int rnk
|
||||
) {
|
||||
exists(SplitKind sk | case2aNoneOfKind(pred, predSplits, succ, c, sk) |
|
||||
rnk = sk.getListRank(succ)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private SplitImpl case2auxGetAPredecessorSplit(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c
|
||||
) {
|
||||
case2aux(pred, predSplits, succ, c) and
|
||||
result = predSplits.getASplit()
|
||||
}
|
||||
|
||||
/** Gets a split that should be in `succSplits`. */
|
||||
pragma[nomagic]
|
||||
private SplitImpl case2aSome(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, SplitKind sk
|
||||
) {
|
||||
(
|
||||
// Inherited from predecessor
|
||||
result = case2auxGetAPredecessorSplit(pred, predSplits, succ, c) and
|
||||
result.hasSuccessor(pred, succ, c)
|
||||
or
|
||||
// Newly entered into
|
||||
exists(SplitKind sk0 |
|
||||
case2aNoneInheritedOfKindForall(pred, predSplits, succ, c, sk0, TSplitsNil())
|
||||
|
|
||||
entryOfKind(pred, succ, c, result, sk0)
|
||||
)
|
||||
) and
|
||||
sk = result.getKind()
|
||||
}
|
||||
|
||||
/** Gets a split that should be in `succSplits` at rank `rnk`. */
|
||||
pragma[nomagic]
|
||||
SplitImpl case2aSomeAtRank(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, int rnk
|
||||
) {
|
||||
exists(SplitKind sk | result = case2aSome(pred, predSplits, succ, c, sk) |
|
||||
rnk = sk.getListRank(succ)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Case 2a.
|
||||
*
|
||||
* As opposed to the other cases, in this case we need to construct a new set
|
||||
* of splits `succSplits`. Since this involves constructing the very IPA type,
|
||||
* we cannot recurse directly over the structure of `succSplits`. Instead, we
|
||||
* recurse over the ranks of all splits that *might* be in `succSplits`.
|
||||
*
|
||||
* - Invariant 1 holds in the base case,
|
||||
* - invariant 2 holds for all splits with rank at least `rnk`,
|
||||
* - invariant 3 holds for all splits in `predSplits`,
|
||||
* - invariant 4 holds for all splits in `succSplits` with rank at least `rnk`,
|
||||
* and
|
||||
* - invariant 4 holds for all splits in `succSplits` with rank at least `rnk`.
|
||||
*/
|
||||
predicate case2aFromRank(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
Completion c, int rnk
|
||||
) {
|
||||
case2aux(pred, predSplits, succ, c) and
|
||||
succSplits = TSplitsNil() and
|
||||
rnk = max(any(SplitKind sk).getListRank(succ)) + 1
|
||||
or
|
||||
case2aFromRank(pred, predSplits, succ, succSplits, c, rnk + 1) and
|
||||
case2aNoneAtRank(pred, predSplits, succ, c, rnk)
|
||||
or
|
||||
exists(Splits mid, SplitImpl split | split = case2aCons(pred, predSplits, succ, mid, c, rnk) |
|
||||
succSplits = TSplitsCons(split, mid)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private SplitImpl case2aCons(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
Completion c, int rnk
|
||||
) {
|
||||
case2aFromRank(pred, predSplits, succ, succSplits, c, rnk + 1) and
|
||||
result = case2aSomeAtRank(pred, predSplits, succ, c, rnk)
|
||||
}
|
||||
|
||||
/**
|
||||
* Case 2b.
|
||||
*
|
||||
* Invariants 1, 4, and 5 hold in the base case, and invariants 2 and 3 are
|
||||
* maintained for all splits in `predSplits`, except possibly for the splits
|
||||
* in `except`.
|
||||
*
|
||||
* The predicate is written using explicit recursion, as opposed to a `forall`,
|
||||
* to avoid negative recursion.
|
||||
*/
|
||||
private predicate case2bForall(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, Splits except
|
||||
) {
|
||||
// Invariant 1
|
||||
case2aux(pred, predSplits, succ, c) and
|
||||
// Invariants 4 and 5
|
||||
not any(SplitKind sk).appliesTo(succ) and
|
||||
except = predSplits
|
||||
or
|
||||
exists(SplitImpl split | case2bForallCons(pred, predSplits, succ, c, split, except) |
|
||||
// Invariants 2 and 3
|
||||
split.hasExit(pred, succ, c)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate case2bForallCons(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c,
|
||||
SplitImpl exceptHead, Splits exceptTail
|
||||
) {
|
||||
case2bForall(pred, predSplits, succ, c, TSplitsCons(exceptHead, exceptTail))
|
||||
}
|
||||
|
||||
private predicate case2(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
Completion c
|
||||
) {
|
||||
case2aFromRank(pred, predSplits, succ, succSplits, c, 1)
|
||||
or
|
||||
case2bForall(pred, predSplits, succ, c, TSplitsNil()) and
|
||||
succSplits = TSplitsNil()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succ` with splits `succSplits` is a successor of type `t` for `pred`
|
||||
* with splits `predSplits`.
|
||||
*/
|
||||
predicate succSplits(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
Completion c
|
||||
) {
|
||||
case1(pred, predSplits, succ, c) and
|
||||
succSplits = predSplits
|
||||
or
|
||||
case2(pred, predSplits, succ, succSplits, c)
|
||||
}
|
||||
}
|
||||
|
||||
import SuccSplits
|
||||
|
||||
/** Provides logic for calculating reachable control flow nodes. */
|
||||
module Reachability {
|
||||
/**
|
||||
* Holds if `cfe` is a control flow element where the set of possible splits may
|
||||
* be different from the set of possible splits for one of `cfe`'s predecessors.
|
||||
* That is, `cfe` starts a new block of elements with the same set of splits.
|
||||
*/
|
||||
private predicate startsSplits(ControlFlowElement cfe) {
|
||||
scopeFirst(_, cfe)
|
||||
or
|
||||
exists(SplitImpl s |
|
||||
s.hasEntry(_, cfe, _)
|
||||
or
|
||||
s.hasExit(_, cfe, _)
|
||||
)
|
||||
or
|
||||
exists(ControlFlowElement pred, SplitImpl split, Completion c | succ(pred, cfe, c) |
|
||||
split.appliesTo(pred) and
|
||||
not split.hasSuccessor(pred, cfe, c)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate intraSplitsSucc(ControlFlowElement pred, ControlFlowElement succ) {
|
||||
succ(pred, succ, _) and
|
||||
not startsSplits(succ)
|
||||
}
|
||||
|
||||
private predicate splitsBlockContains(ControlFlowElement start, ControlFlowElement cfe) =
|
||||
fastTC(intraSplitsSucc/2)(start, cfe)
|
||||
|
||||
/**
|
||||
* A block of control flow elements where the set of splits is guaranteed
|
||||
* to remain unchanged, represented by the first element in the block.
|
||||
*/
|
||||
class SameSplitsBlock extends ControlFlowElement {
|
||||
SameSplitsBlock() { startsSplits(this) }
|
||||
|
||||
/** Gets a control flow element in this block. */
|
||||
ControlFlowElement getAnElement() {
|
||||
splitsBlockContains(this, result)
|
||||
or
|
||||
result = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private SameSplitsBlock getASuccessor(Splits predSplits, Splits succSplits) {
|
||||
exists(ControlFlowElement pred | pred = this.getAnElement() |
|
||||
succSplits(pred, predSplits, result, succSplits, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the elements of this block are reachable from a callable entry
|
||||
* point, with the splits `splits`.
|
||||
*/
|
||||
predicate isReachable(Splits splits) {
|
||||
// Base case
|
||||
succEntrySplits(_, this, splits, _)
|
||||
or
|
||||
// Recursive case
|
||||
exists(SameSplitsBlock pred, Splits predSplits | pred.isReachable(predSplits) |
|
||||
this = pred.getASuccessor(predSplits, splits)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,11 +252,11 @@ module CsvValidation {
|
||||
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
|
||||
msg = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
|
||||
or
|
||||
not type.regexpMatch("[a-zA-Z0-9_<>\\.\\+]+") and
|
||||
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]+") and
|
||||
msg = "Dubious type \"" + type + "\" in " + pred + " model."
|
||||
or
|
||||
not name.regexpMatch("[a-zA-Z0-9_]*") and
|
||||
msg = "Dubious name \"" + name + "\" in " + pred + " model."
|
||||
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and
|
||||
msg = "Dubious member name \"" + name + "\" in " + pred + " model."
|
||||
or
|
||||
not signature.regexpMatch("|\\([a-zA-Z0-9_<>\\.\\+,\\[\\]]*\\)") and
|
||||
msg = "Dubious signature \"" + signature + "\" in " + pred + " model."
|
||||
|
||||
@@ -772,7 +772,7 @@ class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringB
|
||||
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
|
||||
SourceDeclarationMethod m, boolean preservesValue
|
||||
) {
|
||||
exists(string name | m = this.getAMethod(name) |
|
||||
exists(string name | m = this.getAMethod() and m.hasUndecoratedName(name) |
|
||||
name = "ToString" and
|
||||
source = TCallableFlowSourceQualifier() and
|
||||
sourceAp = AccessPath::element() and
|
||||
@@ -916,7 +916,8 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
or
|
||||
exists(string name, int arity |
|
||||
arity = c.getNumberOfParameters() and
|
||||
c = this.getAMethod(name)
|
||||
c = this.getAMethod() and
|
||||
c.getUndecoratedName() = name
|
||||
|
|
||||
name = "Add" and
|
||||
arity = 1 and
|
||||
@@ -964,7 +965,9 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
SourceDeclarationMethod m
|
||||
) {
|
||||
m.(ExtensionMethod).getExtendedType().getUnboundDeclaration() = this and
|
||||
exists(string name, int arity | name = m.getName() and arity = m.getNumberOfParameters() |
|
||||
exists(string name, int arity |
|
||||
name = m.getUndecoratedName() and arity = m.getNumberOfParameters()
|
||||
|
|
||||
name = "Aggregate" and
|
||||
(
|
||||
arity = 2 and
|
||||
@@ -1464,7 +1467,7 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
|
||||
private SourceDeclarationMethod getFind() {
|
||||
exists(string name |
|
||||
name = result.getName() and
|
||||
name = result.getUndecoratedName() and
|
||||
result.getDeclaringType() = this.getABaseType*()
|
||||
|
|
||||
name.regexpMatch("Find(All|Last)?")
|
||||
@@ -1496,7 +1499,7 @@ class ICollectionFlow extends LibraryTypeDataFlow, RefType {
|
||||
) {
|
||||
preservesValue = true and
|
||||
exists(string name, int arity |
|
||||
name = c.getName() and
|
||||
name = c.getUndecoratedName() and
|
||||
arity = c.getNumberOfParameters() and
|
||||
c = this.getAMethod()
|
||||
|
|
||||
@@ -1834,7 +1837,7 @@ class SystemTupleFlow extends LibraryTypeDataFlow, ValueOrRefType {
|
||||
or
|
||||
c =
|
||||
any(ExtensionMethod m |
|
||||
m.hasName("Deconstruct") and
|
||||
m.hasUndecoratedName("Deconstruct") and
|
||||
this = m.getExtendedType().getUnboundDeclaration() and
|
||||
exists(int i |
|
||||
m.getParameter(i).isOut() and
|
||||
@@ -1889,7 +1892,7 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT
|
||||
) {
|
||||
m.getDeclaringType() = this and
|
||||
(
|
||||
m.hasName("ContinueWith") and
|
||||
m.getName().regexpMatch("ContinueWith(<>)?") and
|
||||
sourceAp = AccessPath::empty() and
|
||||
(
|
||||
// flow from supplied state to supplied delegate
|
||||
@@ -1916,13 +1919,13 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT
|
||||
)
|
||||
)
|
||||
or
|
||||
m.hasName("FromResult") and
|
||||
m.hasName("FromResult<>") and
|
||||
source = TCallableFlowSourceArg(0) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::property(any(SystemThreadingTasksTaskTClass c).getResultProperty())
|
||||
or
|
||||
m.hasName("Run") and
|
||||
m.getName().regexpMatch("Run(<>)?") and
|
||||
m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and
|
||||
m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and
|
||||
source = TCallableFlowSourceDelegateArg(0) and
|
||||
@@ -1930,7 +1933,7 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::property(any(SystemThreadingTasksTaskTClass c).getResultProperty())
|
||||
or
|
||||
m.getName().regexpMatch("WhenAll|WhenAny") and
|
||||
m.getName().regexpMatch("WhenAll(<>)?|WhenAny(<>)?") and
|
||||
m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and
|
||||
m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and
|
||||
source = getFlowSourceArg(m, _, _) and
|
||||
@@ -1999,7 +2002,7 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreading
|
||||
SourceDeclarationMethod m
|
||||
) {
|
||||
m.getDeclaringType() = this and
|
||||
m.hasName("ContinueWith") and
|
||||
m.getName().regexpMatch("ContinueWith(<>)?") and
|
||||
(
|
||||
exists(ConstructedDelegateType delegate, int i, int j |
|
||||
m.getParameter(i).getType() = delegate and
|
||||
@@ -2115,7 +2118,7 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow {
|
||||
) {
|
||||
m.getDeclaringType() = this and
|
||||
(
|
||||
m.getName().regexpMatch("ContinueWhen(All|Any)") and
|
||||
m.getUndecoratedName().regexpMatch("ContinueWhen(All|Any)") and
|
||||
(
|
||||
// flow into supplied function
|
||||
exists(ConstructedDelegateType delegate, ArrayType at, int i, int j, int k |
|
||||
@@ -2144,7 +2147,7 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow {
|
||||
)
|
||||
)
|
||||
or
|
||||
m.hasName("StartNew") and
|
||||
m.hasUndecoratedName("StartNew") and
|
||||
(
|
||||
// flow from supplied state to supplied delegate
|
||||
exists(ConstructedDelegateType delegate, int i, int j, int k |
|
||||
|
||||
@@ -8,6 +8,7 @@ private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.dispatch.RuntimeCallable
|
||||
private import semmle.code.csharp.frameworks.system.Collections
|
||||
private import semmle.code.csharp.frameworks.system.collections.Generic
|
||||
|
||||
@@ -275,6 +276,10 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
|
||||
|
||||
override DataFlowCallable getARuntimeTarget() {
|
||||
result = getCallableForDataFlow(dc.getADynamicTarget())
|
||||
or
|
||||
result = dc.getAStaticTarget().getUnboundDeclaration() and
|
||||
summarizedCallable(result) and
|
||||
not result instanceof RuntimeCallable
|
||||
}
|
||||
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -3258,24 +3258,16 @@ class PathNode extends TPathNode {
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
hiddenNode(this.(PathNodeImpl).getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.(PathNodeImpl).getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private PathNode getASuccessorIfHidden() {
|
||||
this.isHidden() and
|
||||
this.(PathNodeImpl).isHidden() and
|
||||
result = this.(PathNodeImpl).getASuccessorImpl()
|
||||
}
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
not result.isHidden()
|
||||
not this.(PathNodeImpl).isHidden() and
|
||||
not result.(PathNodeImpl).isHidden()
|
||||
}
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
@@ -3287,6 +3279,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
hiddenNode(this.getNodeEx().asNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
|
||||
private predicate directReach(PathNode n) {
|
||||
n instanceof PathNodeSink or directReach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
|
||||
/** Holds if `n` can reach a sink or is used in a subpath. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
|
||||
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
@@ -3331,6 +3336,8 @@ module PathGraph {
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
query predicate subpaths = Subpaths::subpaths/4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3622,6 +3629,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
|
||||
)
|
||||
}
|
||||
|
||||
private module Subpaths {
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths01(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
|
||||
* `kind`, `sc`, `apout`, and `innercc`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, apout) and
|
||||
out.asNode() = kind.getAnOutNode(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, apout) and
|
||||
ret.getNodeEx() = retnode and
|
||||
kind = retnode.getKind() and
|
||||
innercc = ret.getCallContext() and
|
||||
sc = ret.getSummaryCtx() and
|
||||
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
|
||||
apout = ret.getAp() and
|
||||
not ret.isHidden()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
out.getAp() = apout
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` can reach a return node in a summarized subpath.
|
||||
*/
|
||||
predicate retReach(PathNode n) {
|
||||
subpaths(_, _, n, _)
|
||||
or
|
||||
exists(PathNode mid |
|
||||
retReach(mid) and
|
||||
n.getASuccessor() = mid and
|
||||
not subpaths(_, mid, _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
|
||||
*
|
||||
|
||||
@@ -913,7 +913,7 @@ private module Internal {
|
||||
result.(Operator).getFunctionName() = getName()
|
||||
or
|
||||
not result instanceof Operator and
|
||||
result.getName() = getName()
|
||||
result.getUndecoratedName() = getName()
|
||||
}
|
||||
|
||||
// A callable is viable if the following conditions are all satisfied:
|
||||
|
||||
@@ -29,13 +29,13 @@ module NHibernate {
|
||||
/** Gets a type parameter that specifies a mapped class. */
|
||||
TypeParameter getAMappedObjectTp() {
|
||||
exists(string methodName |
|
||||
methodName = "Load"
|
||||
methodName = "Load<>"
|
||||
or
|
||||
methodName = "Merge"
|
||||
methodName = "Merge<>"
|
||||
or
|
||||
methodName = "Get"
|
||||
methodName = "Get<>"
|
||||
or
|
||||
methodName = "Query"
|
||||
methodName = "Query<>"
|
||||
|
|
||||
result = this.getAMethod(methodName).(UnboundGenericMethod).getTypeParameter(0)
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
class SystemNamespace extends Namespace {
|
||||
SystemNamespace() {
|
||||
this.getParentNamespace() instanceof GlobalNamespace and
|
||||
this.hasName("System")
|
||||
this.hasUndecoratedName("System")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ class SystemStringClass extends StringType {
|
||||
/** Gets a `Concat(...)` method. */
|
||||
Method getConcatMethod() {
|
||||
result.getDeclaringType() = this and
|
||||
result.hasName("Concat") and
|
||||
result.hasUndecoratedName("Concat") and
|
||||
result.getReturnType() instanceof StringType
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ class SystemStringClass extends StringType {
|
||||
/** Gets a `Join(...)` method. */
|
||||
Method getJoinMethod() {
|
||||
result.getDeclaringType() = this and
|
||||
result.hasName("Join") and
|
||||
result.hasUndecoratedName("Join") and
|
||||
result.getNumberOfParameters() > 1 and
|
||||
result.getReturnType() instanceof StringType
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ module SystemLinq {
|
||||
class Namespace extends csharp::Namespace {
|
||||
Namespace() {
|
||||
this.getParentNamespace() instanceof System::SystemNamespace and
|
||||
this.hasName("Linq")
|
||||
this.hasUndecoratedName("Linq")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ module SystemLinq {
|
||||
SystemLinqEnumerableClass() { this.hasName("Enumerable") }
|
||||
|
||||
/** Gets a `Count()` method. */
|
||||
csharp::ExtensionMethod getACountMethod() { result = this.getAMethod("Count") }
|
||||
csharp::ExtensionMethod getACountMethod() { result = this.getAMethod("Count<>") }
|
||||
|
||||
/** Gets an `Any()` method. */
|
||||
csharp::ExtensionMethod getAnAnyMethod() { result = this.getAMethod("Any") }
|
||||
csharp::ExtensionMethod getAnAnyMethod() { result = this.getAMethod("Any<>") }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class SystemDiagnosticsContractsContractClass extends SystemDiagnosticsContracts
|
||||
/** Gets a `Requires(bool, ...)` method. */
|
||||
Method getARequiresMethod() {
|
||||
result.getDeclaringType() = this and
|
||||
result.hasName("Requires") and
|
||||
result.hasUndecoratedName("Requires") and
|
||||
result.getParameter(0).getType() instanceof BoolType and
|
||||
result.getReturnType() instanceof VoidType
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ private predicate isPassword(string p) {
|
||||
|
||||
/** Holds if the expression `expr` uses an element with the name `name`. */
|
||||
private predicate expressionHasName(Expr expr, string name) {
|
||||
name = expr.(MethodCall).getTarget().getName()
|
||||
name = expr.(MethodCall).getTarget().getUndecoratedName()
|
||||
or
|
||||
name = expr.(MethodCall).getAnArgument().getValue()
|
||||
or
|
||||
@@ -122,7 +122,7 @@ abstract class SensitiveExpr extends Expr { }
|
||||
/** A method access that might produce sensitive data. */
|
||||
class SensitiveMethodAccess extends SensitiveExpr, MethodCall {
|
||||
SensitiveMethodAccess() {
|
||||
this.getTarget() instanceof SensitiveDataMethod
|
||||
this.getTarget().getUnboundDeclaration() instanceof SensitiveDataMethod
|
||||
or
|
||||
// This is particularly to pick up methods with an argument like "password", which
|
||||
// may indicate a lookup.
|
||||
@@ -194,5 +194,7 @@ class SendingMethod extends SensitiveExecutionMethod {
|
||||
|
||||
/** A call to a method that sends data, and so should not be run conditionally on user input. */
|
||||
class SensitiveExecutionMethodCall extends MethodCall {
|
||||
SensitiveExecutionMethodCall() { this.getTarget() instanceof SensitiveExecutionMethod }
|
||||
SensitiveExecutionMethodCall() {
|
||||
this.getTarget().getUnboundDeclaration() instanceof SensitiveExecutionMethod
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ private predicate conditionControlsCall(
|
||||
exists(ControlFlow::SuccessorTypes::BooleanSuccessor s | cond = s.getValue() |
|
||||
conditionControlsCall0(call, e, s)
|
||||
) and
|
||||
def = call.getTarget()
|
||||
def = call.getTarget().getUnboundDeclaration()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,7 +98,7 @@ private class BinaryFormatterClass extends Class {
|
||||
class BinaryFormatterDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
BinaryFormatterDeserializeMethod() {
|
||||
this.getDeclaringType() instanceof BinaryFormatterClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ class BinaryFormatterDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
class BinaryFormatterUnsafeDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
BinaryFormatterUnsafeDeserializeMethod() {
|
||||
this.getDeclaringType() instanceof BinaryFormatterClass and
|
||||
this.hasName("UnsafeDeserialize")
|
||||
this.hasUndecoratedName("UnsafeDeserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ class BinaryFormatterUnsafeDeserializeMethod extends Method, UnsafeDeserializer
|
||||
class BinaryFormatterUnsafeDeserializeMethodResponseMethod extends Method, UnsafeDeserializer {
|
||||
BinaryFormatterUnsafeDeserializeMethodResponseMethod() {
|
||||
this.getDeclaringType() instanceof BinaryFormatterClass and
|
||||
this.hasName("UnsafeDeserializeMethodResponse")
|
||||
this.hasUndecoratedName("UnsafeDeserializeMethodResponse")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ private class SoapFormatterClass extends Class {
|
||||
class SoapFormatterDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
SoapFormatterDeserializeMethod() {
|
||||
this.getDeclaringType() instanceof SoapFormatterClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ private class ObjectStateFormatterClass extends Class {
|
||||
class ObjectStateFormatterDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
ObjectStateFormatterDeserializeMethod() {
|
||||
this.getDeclaringType() instanceof ObjectStateFormatterClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ class NetDataContractSerializerClass extends Class {
|
||||
class NetDataContractSerializerDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
NetDataContractSerializerDeserializeMethod() {
|
||||
this.getDeclaringType() instanceof NetDataContractSerializerClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ class NetDataContractSerializerDeserializeMethod extends Method, UnsafeDeseriali
|
||||
class NetDataContractSerializerReadObjectMethod extends Method, UnsafeDeserializer {
|
||||
NetDataContractSerializerReadObjectMethod() {
|
||||
this.getDeclaringType() instanceof NetDataContractSerializerClass and
|
||||
this.hasName("ReadObject")
|
||||
this.hasUndecoratedName("ReadObject")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ class DataContractJsonSerializerClass extends Class {
|
||||
class DataContractJsonSerializerReadObjectMethod extends Method, UnsafeDeserializer {
|
||||
DataContractJsonSerializerReadObjectMethod() {
|
||||
this.getDeclaringType() instanceof DataContractJsonSerializerClass and
|
||||
this.hasName("ReadObject")
|
||||
this.hasUndecoratedName("ReadObject")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ class JavaScriptSerializerClass extends Class {
|
||||
class JavaScriptSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
JavaScriptSerializerClassDeserializeMethod() {
|
||||
this.getDeclaringType() instanceof JavaScriptSerializerClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ class JavaScriptSerializerClassDeserializeMethod extends Method, UnsafeDeseriali
|
||||
class JavaScriptSerializerClassDeserializeObjectMethod extends Method, UnsafeDeserializer {
|
||||
JavaScriptSerializerClassDeserializeObjectMethod() {
|
||||
this.getDeclaringType() instanceof JavaScriptSerializerClass and
|
||||
this.hasName("DeserializeObject")
|
||||
this.hasUndecoratedName("DeserializeObject")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ class XmlObjectSerializerClass extends Class {
|
||||
class XmlObjectSerializerReadObjectMethod extends Method, UnsafeDeserializer {
|
||||
XmlObjectSerializerReadObjectMethod() {
|
||||
this.getDeclaringType() instanceof XmlObjectSerializerClass and
|
||||
this.hasName("ReadObject")
|
||||
this.hasUndecoratedName("ReadObject")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ class XmlSerializerClass extends Class {
|
||||
class XmlSerializerDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
XmlSerializerDeserializeMethod() {
|
||||
this.getDeclaringType() instanceof XmlSerializerClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ class DataContractSerializerClass extends Class {
|
||||
class DataContractSerializerReadObjectMethod extends Method, UnsafeDeserializer {
|
||||
DataContractSerializerReadObjectMethod() {
|
||||
this.getDeclaringType() instanceof DataContractSerializerClass and
|
||||
this.hasName("ReadObject")
|
||||
this.hasUndecoratedName("ReadObject")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ class XmlMessageFormatterClass extends Class {
|
||||
class XmlMessageFormatterReadMethod extends Method, UnsafeDeserializer {
|
||||
XmlMessageFormatterReadMethod() {
|
||||
this.getDeclaringType() instanceof XmlMessageFormatterClass and
|
||||
this.hasName("Read")
|
||||
this.hasUndecoratedName("Read")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ private class LosFormatterClass extends Class {
|
||||
class LosFormatterDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
LosFormatterDeserializeMethod() {
|
||||
this.getDeclaringType() instanceof LosFormatterClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ private class FastJsonClass extends Class {
|
||||
class FastJsonClassToObjectMethod extends Method, UnsafeDeserializer {
|
||||
FastJsonClassToObjectMethod() {
|
||||
this.getDeclaringType() instanceof FastJsonClass and
|
||||
this.hasName("ToObject") and
|
||||
this.hasUndecoratedName("ToObject") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -299,7 +299,7 @@ private class ActivityClass extends Class {
|
||||
class ActivityLoadMethod extends Method, UnsafeDeserializer {
|
||||
ActivityLoadMethod() {
|
||||
this.getDeclaringType() instanceof ActivityClass and
|
||||
this.hasName("Load")
|
||||
this.hasUndecoratedName("Load")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ private class BinaryMessageFormatterClass extends Class {
|
||||
class BinaryMessageFormatterReadMethod extends Method, UnsafeDeserializer {
|
||||
BinaryMessageFormatterReadMethod() {
|
||||
this.getDeclaringType() instanceof BinaryMessageFormatterClass and
|
||||
this.hasName("Read")
|
||||
this.hasUndecoratedName("Read")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ private class XamlReaderClass extends Class {
|
||||
class XamlReaderParseMethod extends Method, UnsafeDeserializer {
|
||||
XamlReaderParseMethod() {
|
||||
this.getDeclaringType() instanceof XamlReaderClass and
|
||||
this.hasName("Parse") and
|
||||
this.hasUndecoratedName("Parse") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -347,7 +347,7 @@ class XamlReaderParseMethod extends Method, UnsafeDeserializer {
|
||||
class XamlReaderLoadMethod extends Method, UnsafeDeserializer {
|
||||
XamlReaderLoadMethod() {
|
||||
this.getDeclaringType() instanceof XamlReaderClass and
|
||||
this.hasName("Load") and
|
||||
this.hasUndecoratedName("Load") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -356,7 +356,7 @@ class XamlReaderLoadMethod extends Method, UnsafeDeserializer {
|
||||
class XamlReaderLoadAsyncMethod extends Method, UnsafeDeserializer {
|
||||
XamlReaderLoadAsyncMethod() {
|
||||
this.getDeclaringType() instanceof XamlReaderClass and
|
||||
this.hasName("LoadAsync")
|
||||
this.hasUndecoratedName("LoadAsync")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ private class ProxyObjectClass extends Class {
|
||||
class ProxyObjectDecodeValueMethod extends Method, UnsafeDeserializer {
|
||||
ProxyObjectDecodeValueMethod() {
|
||||
this.getDeclaringType() instanceof ProxyObjectClass and
|
||||
this.hasName("DecodeValue")
|
||||
this.hasUndecoratedName("DecodeValue")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ class ProxyObjectDecodeValueMethod extends Method, UnsafeDeserializer {
|
||||
class ProxyObjectDecodeSerializedObjectMethod extends Method, UnsafeDeserializer {
|
||||
ProxyObjectDecodeSerializedObjectMethod() {
|
||||
this.getDeclaringType() instanceof ProxyObjectClass and
|
||||
this.hasName("DecodeSerializedObject")
|
||||
this.hasUndecoratedName("DecodeSerializedObject")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +390,7 @@ private class JaysonConverterClass extends Class {
|
||||
class JaysonConverterToObjectMethod extends Method, UnsafeDeserializer {
|
||||
JaysonConverterToObjectMethod() {
|
||||
this.getDeclaringType() instanceof JaysonConverterClass and
|
||||
this.hasName("ToObject") and
|
||||
this.hasUndecoratedName("ToObject") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -406,7 +406,7 @@ private class ServiceStackTextJsonSerializerClass extends Class {
|
||||
class ServiceStackTextJsonSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextJsonSerializerDeserializeFromStringMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextJsonSerializerClass and
|
||||
this.hasName("DeserializeFromString") and
|
||||
this.hasUndecoratedName("DeserializeFromString") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -415,7 +415,7 @@ class ServiceStackTextJsonSerializerDeserializeFromStringMethod extends Method,
|
||||
class ServiceStackTextJsonSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextJsonSerializerDeserializeFromReaderMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextJsonSerializerClass and
|
||||
this.hasName("DeserializeFromReader") and
|
||||
this.hasUndecoratedName("DeserializeFromReader") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -424,7 +424,7 @@ class ServiceStackTextJsonSerializerDeserializeFromReaderMethod extends Method,
|
||||
class ServiceStackTextJsonSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextJsonSerializerDeserializeFromStreamMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextJsonSerializerClass and
|
||||
this.hasName("DeserializeFromStream") and
|
||||
this.hasUndecoratedName("DeserializeFromStream") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -440,7 +440,7 @@ private class ServiceStackTextTypeSerializerClass extends Class {
|
||||
class ServiceStackTextTypeSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextTypeSerializerDeserializeFromStringMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextTypeSerializerClass and
|
||||
this.hasName("DeserializeFromString") and
|
||||
this.hasUndecoratedName("DeserializeFromString") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -449,7 +449,7 @@ class ServiceStackTextTypeSerializerDeserializeFromStringMethod extends Method,
|
||||
class ServiceStackTextTypeSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextTypeSerializerDeserializeFromReaderMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextTypeSerializerClass and
|
||||
this.hasName("DeserializeFromReader") and
|
||||
this.hasUndecoratedName("DeserializeFromReader") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -458,7 +458,7 @@ class ServiceStackTextTypeSerializerDeserializeFromReaderMethod extends Method,
|
||||
class ServiceStackTextTypeSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextTypeSerializerDeserializeFromStreamMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextTypeSerializerClass and
|
||||
this.hasName("DeserializeFromStream") and
|
||||
this.hasUndecoratedName("DeserializeFromStream") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -472,7 +472,7 @@ private class ServiceStackTextCsvSerializerClass extends Class {
|
||||
class ServiceStackTextCsvSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextCsvSerializerDeserializeFromStringMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextCsvSerializerClass and
|
||||
this.hasName("DeserializeFromString") and
|
||||
this.hasUndecoratedName("DeserializeFromString") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -481,7 +481,7 @@ class ServiceStackTextCsvSerializerDeserializeFromStringMethod extends Method, U
|
||||
class ServiceStackTextCsvSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextCsvSerializerDeserializeFromReaderMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextCsvSerializerClass and
|
||||
this.hasName("DeserializeFromReader") and
|
||||
this.hasUndecoratedName("DeserializeFromReader") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -490,7 +490,7 @@ class ServiceStackTextCsvSerializerDeserializeFromReaderMethod extends Method, U
|
||||
class ServiceStackTextCsvSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextCsvSerializerDeserializeFromStreamMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextCsvSerializerClass and
|
||||
this.hasName("DeserializeFromStream") and
|
||||
this.hasUndecoratedName("DeserializeFromStream") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -504,7 +504,7 @@ private class ServiceStackTextXmlSerializerClass extends Class {
|
||||
class ServiceStackTextXmlSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextXmlSerializerDeserializeFromStringMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextXmlSerializerClass and
|
||||
this.hasName("DeserializeFromString") and
|
||||
this.hasUndecoratedName("DeserializeFromString") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -513,7 +513,7 @@ class ServiceStackTextXmlSerializerDeserializeFromStringMethod extends Method, U
|
||||
class ServiceStackTextXmlSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextXmlSerializerDeserializeFromReaderMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextXmlSerializerClass and
|
||||
this.hasName("DeserializeFromReader") and
|
||||
this.hasUndecoratedName("DeserializeFromReader") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -522,7 +522,7 @@ class ServiceStackTextXmlSerializerDeserializeFromReaderMethod extends Method, U
|
||||
class ServiceStackTextXmlSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
|
||||
ServiceStackTextXmlSerializerDeserializeFromStreamMethod() {
|
||||
this.getDeclaringType() instanceof ServiceStackTextXmlSerializerClass and
|
||||
this.hasName("DeserializeFromStream") and
|
||||
this.hasUndecoratedName("DeserializeFromStream") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
@@ -536,7 +536,7 @@ private class FsPicklerSerializerClass extends Class {
|
||||
class FsPicklerSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
FsPicklerSerializerClassDeserializeMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,7 +544,7 @@ class FsPicklerSerializerClassDeserializeMethod extends Method, UnsafeDeserializ
|
||||
class FsPicklerSerializerClassDeserializeSequenceMethod extends Method, UnsafeDeserializer {
|
||||
FsPicklerSerializerClassDeserializeSequenceMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
|
||||
this.hasName("DeserializeSequence")
|
||||
this.hasUndecoratedName("DeserializeSequence")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,7 +552,7 @@ class FsPicklerSerializerClassDeserializeSequenceMethod extends Method, UnsafeDe
|
||||
class FsPicklerSerializerClasDeserializeSiftedMethod extends Method, UnsafeDeserializer {
|
||||
FsPicklerSerializerClasDeserializeSiftedMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
|
||||
this.hasName("DeserializeSifted")
|
||||
this.hasUndecoratedName("DeserializeSifted")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ class FsPicklerSerializerClasDeserializeSiftedMethod extends Method, UnsafeDeser
|
||||
class FsPicklerSerializerClassUnPickleMethod extends Method, UnsafeDeserializer {
|
||||
FsPicklerSerializerClassUnPickleMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
|
||||
this.hasName("UnPickle")
|
||||
this.hasUndecoratedName("UnPickle")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,7 +568,7 @@ class FsPicklerSerializerClassUnPickleMethod extends Method, UnsafeDeserializer
|
||||
class FsPicklerSerializerClassUnPickleSiftedMethod extends Method, UnsafeDeserializer {
|
||||
FsPicklerSerializerClassUnPickleSiftedMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
|
||||
this.hasName("UnPickleSifted")
|
||||
this.hasUndecoratedName("UnPickleSifted")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,7 +576,7 @@ class FsPicklerSerializerClassUnPickleSiftedMethod extends Method, UnsafeDeseria
|
||||
class FsPicklerSerializerClassDeserializeUntypedMethod extends Method, UnsafeDeserializer {
|
||||
FsPicklerSerializerClassDeserializeUntypedMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
|
||||
this.hasName("DeserializeUntyped")
|
||||
this.hasUndecoratedName("DeserializeUntyped")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,7 +584,7 @@ class FsPicklerSerializerClassDeserializeUntypedMethod extends Method, UnsafeDes
|
||||
class FsPicklerSerializerClassDeserializeSequenceUntypedMethod extends Method, UnsafeDeserializer {
|
||||
FsPicklerSerializerClassDeserializeSequenceUntypedMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
|
||||
this.hasName("DeserializeSequenceUntyped")
|
||||
this.hasUndecoratedName("DeserializeSequenceUntyped")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,7 +592,7 @@ class FsPicklerSerializerClassDeserializeSequenceUntypedMethod extends Method, U
|
||||
class FsPicklerSerializerClassUnPickleUntypedMethod extends Method, UnsafeDeserializer {
|
||||
FsPicklerSerializerClassUnPickleUntypedMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
|
||||
this.hasName("UnPickleUntyped")
|
||||
this.hasUndecoratedName("UnPickleUntyped")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,7 +605,7 @@ private class CsPicklerSerializerClass extends Class {
|
||||
class CsPicklerSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
CsPicklerSerializerClassDeserializeMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof CsPicklerSerializerClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,7 +613,7 @@ class CsPicklerSerializerClassDeserializeMethod extends Method, UnsafeDeserializ
|
||||
class CsPicklerSerializerClassUnPickleMethod extends Method, UnsafeDeserializer {
|
||||
CsPicklerSerializerClassUnPickleMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof CsPicklerSerializerClass and
|
||||
this.hasName("UnPickle")
|
||||
this.hasUndecoratedName("UnPickle")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,7 +628,7 @@ private class CsPicklerTextSerializerClass extends Class {
|
||||
class CsPicklerSerializerClassUnPickleOfStringMethod extends Method, UnsafeDeserializer {
|
||||
CsPicklerSerializerClassUnPickleOfStringMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof CsPicklerTextSerializerClass and
|
||||
this.hasName("UnPickleOfString")
|
||||
this.hasUndecoratedName("UnPickleOfString")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,7 +641,7 @@ private class SharpSerializerClass extends Class {
|
||||
class SharpSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
|
||||
SharpSerializerClassDeserializeMethod() {
|
||||
this.getDeclaringType().getBaseClass*() instanceof SharpSerializerClass and
|
||||
this.hasName("Deserialize")
|
||||
this.hasUndecoratedName("Deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +655,7 @@ class YamlDotNetDeserializerClasseserializeMethod extends Method, UnsafeDeserial
|
||||
YamlDotNetDeserializerClasseserializeMethod() {
|
||||
exists(YamlDotNetDeserializerClass c |
|
||||
this.getDeclaringType().getBaseClass*() = c and
|
||||
this.hasName("Deserialize") and
|
||||
this.hasUndecoratedName("Deserialize") and
|
||||
c.getALocation().(Assembly).getVersion().getMajor() < 5
|
||||
)
|
||||
}
|
||||
@@ -665,7 +665,7 @@ class YamlDotNetDeserializerClasseserializeMethod extends Method, UnsafeDeserial
|
||||
class NewtonsoftJsonConvertClassDeserializeObjectMethod extends Method, UnsafeDeserializer {
|
||||
NewtonsoftJsonConvertClassDeserializeObjectMethod() {
|
||||
this.getDeclaringType() instanceof JsonConvertClass and
|
||||
this.hasName("DeserializeObject") and
|
||||
this.hasUndecoratedName("DeserializeObject") and
|
||||
this.isStatic()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +80,6 @@ class Callable extends Parameterizable, @dotnet_callable {
|
||||
not exists(this.getReturnType()) and result = "System.Void"
|
||||
}
|
||||
|
||||
override string getUndecoratedName() { result = getName() }
|
||||
|
||||
/** Gets the return type of this callable. */
|
||||
Type getReturnType() { none() }
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ class Declaration extends NamedElement, @dotnet_declaration {
|
||||
/** Gets the name of this declaration, without additional decoration such as `<...>`. */
|
||||
string getUndecoratedName() { none() }
|
||||
|
||||
/** Holds if this element has undecorated name 'name'. */
|
||||
final predicate hasUndecoratedName(string name) { name = getUndecoratedName() }
|
||||
|
||||
/** Gets the type containing this declaration, if any. */
|
||||
Type getDeclaringType() { none() }
|
||||
|
||||
|
||||
@@ -24,17 +24,6 @@ abstract class UnboundGeneric extends Generic {
|
||||
|
||||
/** Gets the total number of type parameters. */
|
||||
int getNumberOfTypeParameters() { result = count(int i | exists(this.getTypeParameter(i))) }
|
||||
|
||||
/** Gets the type parameters as a comma-separated string. */
|
||||
language[monotonicAggregates]
|
||||
string typeParametersToString() {
|
||||
result =
|
||||
concat(int i |
|
||||
exists(this.getTypeParameter(i))
|
||||
|
|
||||
this.getTypeParameter(i).toStringWithTypes(), ", " order by i
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A constructed generic. */
|
||||
@@ -53,17 +42,6 @@ abstract class ConstructedGeneric extends Generic {
|
||||
|
||||
/** Gets the total number of type arguments. */
|
||||
int getNumberOfTypeArguments() { result = count(int i | exists(this.getTypeArgument(i))) }
|
||||
|
||||
/** Gets the type arguments as a comma-separated string. */
|
||||
language[monotonicAggregates]
|
||||
string typeArgumentsToString() {
|
||||
result =
|
||||
concat(int i |
|
||||
exists(this.getTypeArgument(i))
|
||||
|
|
||||
this.getTypeArgument(i).toStringWithTypes(), ", " order by i
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,11 @@ class Namespace extends Declaration, @namespace {
|
||||
|
||||
/** Holds if this is the global namespace. */
|
||||
final predicate isGlobalNamespace() { getName() = "" }
|
||||
|
||||
/** Gets the simple name of this namespace, for example `IO` in `System.IO`. */
|
||||
final override string getName() { namespaces(this, result) }
|
||||
|
||||
final override string getUndecoratedName() { namespaces(this, result) }
|
||||
}
|
||||
|
||||
/** The global namespace. */
|
||||
|
||||
@@ -34,21 +34,21 @@ class StaticCall extends Call {
|
||||
pragma[nomagic]
|
||||
predicate hasInstanceCallable(ValueOrRefType t, InstanceCallable c, string name) {
|
||||
t.hasMember(c) and
|
||||
name = c.getName()
|
||||
name = c.getUndecoratedName()
|
||||
}
|
||||
|
||||
/** Holds if extension method `m` is a method on `t` with name `name`. */
|
||||
pragma[nomagic]
|
||||
predicate hasExtensionMethod(ValueOrRefType t, ExtensionMethod m, string name) {
|
||||
t.isImplicitlyConvertibleTo(m.getExtendedType()) and
|
||||
name = m.getName()
|
||||
name = m.getUndecoratedName()
|
||||
}
|
||||
|
||||
/** Holds `t` has static callable `c` as a member, with name `name`. */
|
||||
pragma[noinline]
|
||||
predicate hasStaticCallable(ValueOrRefType t, StaticCallable c, string name) {
|
||||
t.hasMember(c) and
|
||||
name = c.getName()
|
||||
name = c.getUndecoratedName()
|
||||
}
|
||||
|
||||
/** Gets the minimum number of arguments required to call `c`. */
|
||||
@@ -106,7 +106,7 @@ class ExplicitUpcast extends ExplicitCast {
|
||||
private predicate isDisambiguatingInstanceCall(InstanceCallable other, int args) {
|
||||
exists(Call c, InstanceCallable target, ValueOrRefType t | this.isArgument(c, target) |
|
||||
t = c.(QualifiableExpr).getQualifier().getType() and
|
||||
hasInstanceCallable(t, other, target.getName()) and
|
||||
hasInstanceCallable(t, other, target.getUndecoratedName()) and
|
||||
args = c.getNumberOfArguments() and
|
||||
other != target
|
||||
)
|
||||
@@ -120,7 +120,7 @@ class ExplicitUpcast extends ExplicitCast {
|
||||
|
|
||||
not c.isOrdinaryStaticCall() and
|
||||
t = target.getParameter(0).getType() and
|
||||
hasExtensionMethod(t, other, target.getName()) and
|
||||
hasExtensionMethod(t, other, target.getUndecoratedName()) and
|
||||
args = c.getNumberOfArguments() and
|
||||
other != target
|
||||
)
|
||||
@@ -131,7 +131,7 @@ class ExplicitUpcast extends ExplicitCast {
|
||||
StaticCall c, StaticCallable target, string name, ValueOrRefType t
|
||||
) {
|
||||
this.isArgument(c, target) and
|
||||
name = target.getName() and
|
||||
name = target.getUndecoratedName() and
|
||||
(
|
||||
t = c.(QualifiableExpr).getQualifier().getType()
|
||||
or
|
||||
|
||||
@@ -15,7 +15,7 @@ import csharp
|
||||
predicate isDefinitelyPositive(Expr e) {
|
||||
e.getValue().toInt() >= 0 or
|
||||
e.(PropertyAccess).getTarget().hasName("Length") or
|
||||
e.(MethodCall).getTarget().hasName("Count")
|
||||
e.(MethodCall).getTarget().hasUndecoratedName("Count")
|
||||
}
|
||||
|
||||
from BinaryOperation t, RemExpr lhs, IntegerLiteral rhs, string parity
|
||||
|
||||
@@ -125,9 +125,9 @@ predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is) {
|
||||
class AnyCall extends MethodCall {
|
||||
AnyCall() {
|
||||
exists(Method m |
|
||||
m = getTarget() and
|
||||
m = getTarget().getUnboundDeclaration() and
|
||||
isEnumerableType(m.getDeclaringType()) and
|
||||
m.hasName("Any")
|
||||
m.hasName("Any<>")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -136,9 +136,9 @@ class AnyCall extends MethodCall {
|
||||
class CountCall extends MethodCall {
|
||||
CountCall() {
|
||||
exists(Method m |
|
||||
m = getTarget() and
|
||||
m = getTarget().getUnboundDeclaration() and
|
||||
isEnumerableType(m.getDeclaringType()) and
|
||||
m.hasName("Count")
|
||||
m.hasName("Count<>")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -152,9 +152,9 @@ class IEnumerableSequence extends Variable {
|
||||
class SelectCall extends ExtensionMethodCall {
|
||||
SelectCall() {
|
||||
exists(Method m |
|
||||
m = getTarget() and
|
||||
m = getTarget().getUnboundDeclaration() and
|
||||
isEnumerableType(m.getDeclaringType()) and
|
||||
m.hasName("Select")
|
||||
m.hasName("Select<,>")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
19
csharp/ql/src/Stubs/README.md
Normal file
19
csharp/ql/src/Stubs/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generate stubs
|
||||
|
||||
Stubs can be generated from Nuget packages with the `make_stubs_nuget.py` script.
|
||||
|
||||
The following calls generate stubs for `Newtonsoft.Json`:
|
||||
|
||||
```
|
||||
python make_stubs_nuget.py Newtonsoft.Json
|
||||
python make_stubs_nuget.py Newtonsoft.Json latest
|
||||
python make_stubs_nuget.py Newtonsoft.Json 13.0.1
|
||||
python make_stubs_nuget.py Newtonsoft.Json 13.0.1 /Users/tmp/working-dir
|
||||
```
|
||||
|
||||
The output stubs are found in the `[DIR]/output/stubs` folder and can be copied over to `csharp/ql/test/resources/stubs`.
|
||||
|
||||
In some more involved cases the output files need to be edited. For example `ServiceStack` has Nuget dependencies, which
|
||||
are included in the `Microsoft.NETCore.App` framework stub. These dependencies generate empty packages, which can be
|
||||
removed. The `ProjectReference` entries referencing these removed empty packages also need to be deleted from the
|
||||
`.csproj` files.
|
||||
@@ -169,7 +169,7 @@ abstract private class GeneratedType extends Type, GeneratedElement {
|
||||
t = this.getAnInterestingBaseType() and
|
||||
(if t instanceof Class then i = 0 else i = 1)
|
||||
|
|
||||
stubClassName(t), ", " order by i
|
||||
stubClassName(t), ", " order by i, t.getQualifiedName()
|
||||
)
|
||||
else result = ""
|
||||
}
|
||||
@@ -180,7 +180,7 @@ abstract private class GeneratedType extends Type, GeneratedElement {
|
||||
concat(GeneratedMember m |
|
||||
m = this.getAGeneratedMember(assembly)
|
||||
|
|
||||
stubMember(m, assembly) order by m.getName()
|
||||
stubMember(m, assembly) order by m.getQualifiedNameWithTypes()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -759,7 +759,7 @@ private string stubMethod(Method m, Assembly assembly) {
|
||||
then
|
||||
result =
|
||||
" " + stubModifiers(m) + stubClassName(m.(Method).getReturnType()) + " " +
|
||||
stubExplicitImplementation(m) + m.getName() + stubGenericMethodParams(m) + "(" +
|
||||
stubExplicitImplementation(m) + m.getUndecoratedName() + stubGenericMethodParams(m) + "(" +
|
||||
stubParameters(m) + ")" + stubTypeParametersConstraints(m) + stubImplementation(m) + ";\n"
|
||||
else result = " // Stub generator skipped method: " + m.getName() + "\n"
|
||||
}
|
||||
|
||||
4
csharp/ql/src/qlpack.lock.yml
Normal file
4
csharp/ql/src/qlpack.lock.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
dependencies: {}
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
@@ -3,5 +3,5 @@ version: 0.0.2
|
||||
suites: codeql-suites
|
||||
extractor: csharp
|
||||
dependencies:
|
||||
codeql/csharp-all: ^0.0.2
|
||||
codeql/suite-helpers: ^0.0.2
|
||||
codeql/csharp-all: "*"
|
||||
codeql/suite-helpers: "*"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
edges
|
||||
nodes
|
||||
subpaths
|
||||
#select
|
||||
|
||||
@@ -214,10 +214,10 @@ collections.cs:
|
||||
# 12| 4: [BlockStmt] {...}
|
||||
# 13| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 13| 0: [LocalVariableDeclAndInitExpr] Dictionary<Int32,MyClass> dict = ...
|
||||
# 13| -1: [TypeMention] Dictionary<Int32, MyClass>
|
||||
# 13| -1: [TypeMention] Dictionary<int, MyClass>
|
||||
# 13| 0: [LocalVariableAccess] access to local variable dict
|
||||
# 13| 1: [ObjectCreation] object creation of type Dictionary<Int32,MyClass>
|
||||
# 13| -2: [TypeMention] Dictionary<Int32, MyClass>
|
||||
# 13| -2: [TypeMention] Dictionary<int, MyClass>
|
||||
# 13| 1: [TypeMention] int
|
||||
# 13| 2: [TypeMention] MyClass
|
||||
# 14| -1: [CollectionInitializer] { ..., ... }
|
||||
|
||||
@@ -22,18 +22,18 @@
|
||||
| Assignables.cs:27:9:27:21 | ...++ | Assignables.cs:27:9:27:21 | ...++ |
|
||||
| Assignables.cs:28:17:28:24 | access to local variable variable | Assignables.cs:28:9:28:25 | call to method Out |
|
||||
| Assignables.cs:29:17:29:21 | access to field Field | Assignables.cs:29:9:29:22 | call to method Out |
|
||||
| Assignables.cs:30:34:30:38 | access to field Field | Assignables.cs:30:9:30:45 | call to method RefCertain |
|
||||
| Assignables.cs:30:34:30:38 | access to field Field | Assignables.cs:30:9:30:45 | call to method RefCertain<Int32> |
|
||||
| Assignables.cs:31:36:31:40 | access to field Field | Assignables.cs:31:9:31:41 | call to method RefUncertain |
|
||||
| Assignables.cs:32:37:32:41 | access to field Field | Assignables.cs:32:9:32:42 | call to method RefUncertain2 |
|
||||
| Assignables.cs:34:29:34:33 | access to field Field | Assignables.cs:34:9:34:45 | call to method RefCertainOneOf |
|
||||
| Assignables.cs:34:40:34:44 | access to field Field | Assignables.cs:34:9:34:45 | call to method RefCertainOneOf |
|
||||
| Assignables.cs:37:22:37:22 | o | Assignables.cs:37:10:37:12 | enter Out |
|
||||
| Assignables.cs:39:9:39:13 | ... = ... | Assignables.cs:39:9:39:13 | ... = ... |
|
||||
| Assignables.cs:42:26:42:26 | x | Assignables.cs:42:10:42:22 | enter RefCertain |
|
||||
| Assignables.cs:42:35:42:35 | y | Assignables.cs:42:10:42:22 | enter RefCertain |
|
||||
| Assignables.cs:42:43:42:43 | b | Assignables.cs:42:10:42:22 | enter RefCertain |
|
||||
| Assignables.cs:42:26:42:26 | x | Assignables.cs:42:10:42:22 | enter RefCertain<> |
|
||||
| Assignables.cs:42:35:42:35 | y | Assignables.cs:42:10:42:22 | enter RefCertain<> |
|
||||
| Assignables.cs:42:43:42:43 | b | Assignables.cs:42:10:42:22 | enter RefCertain<> |
|
||||
| Assignables.cs:45:13:45:17 | ... = ... | Assignables.cs:45:13:45:17 | ... = ... |
|
||||
| Assignables.cs:47:31:47:31 | access to parameter y | Assignables.cs:47:13:47:38 | call to method RefCertain |
|
||||
| Assignables.cs:47:31:47:31 | access to parameter y | Assignables.cs:47:13:47:38 | call to method RefCertain<> |
|
||||
| Assignables.cs:50:27:50:27 | x | Assignables.cs:50:10:50:21 | enter RefUncertain |
|
||||
| Assignables.cs:50:38:50:38 | y | Assignables.cs:50:10:50:21 | enter RefUncertain |
|
||||
| Assignables.cs:53:13:53:17 | ... = ... | Assignables.cs:53:13:53:17 | ... = ... |
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
edges
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint2 : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint3 : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint5 : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint6 : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of TaintIndirect : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 2 of Taint1 : String | DataFlow.dll:0:0:0:0 | ldarg.2 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 2 of TaintIndirect : String | DataFlow.dll:0:0:0:0 | ldarg.2 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint5 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint6 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.2 : String | DataFlow.dll:0:0:0:0 | Parameter 2 of Taint1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.2 : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.2 : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| dataflow.cs:16:18:16:26 | "tainted" : String | dataflow.cs:16:18:16:37 | call to method ToString |
|
||||
| dataflow.cs:18:27:18:27 | 2 : Int32 | dataflow.cs:18:18:18:31 | call to method Max |
|
||||
| dataflow.cs:18:30:18:30 | 3 : Int32 | dataflow.cs:18:18:18:31 | call to method Max |
|
||||
@@ -6,12 +25,19 @@ edges
|
||||
| dataflow.cs:20:45:20:53 | "tainted" : String | dataflow.cs:20:18:20:54 | call to method GetFullPath |
|
||||
| dataflow.cs:27:44:27:46 | 1 : Double | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
|
||||
| dataflow.cs:27:49:27:51 | 2 : Double | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
|
||||
| dataflow.cs:38:34:38:37 | "d1" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String |
|
||||
| dataflow.cs:38:34:38:37 | "d1" : String | dataflow.cs:38:18:38:38 | call to method Taint1 |
|
||||
| dataflow.cs:39:34:39:37 | "d2" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint2 : String |
|
||||
| dataflow.cs:39:34:39:37 | "d2" : String | dataflow.cs:39:18:39:38 | call to method Taint2 |
|
||||
| dataflow.cs:40:34:40:37 | "d3" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint3 : String |
|
||||
| dataflow.cs:40:34:40:37 | "d3" : String | dataflow.cs:40:18:40:38 | call to method Taint3 |
|
||||
| dataflow.cs:44:28:44:32 | "t1a" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String |
|
||||
| dataflow.cs:44:28:44:32 | "t1a" : String | dataflow.cs:44:18:44:40 | call to method Taint1 |
|
||||
| dataflow.cs:44:35:44:39 | "t1b" : String | DataFlow.dll:0:0:0:0 | Parameter 2 of Taint1 : String |
|
||||
| dataflow.cs:44:35:44:39 | "t1b" : String | dataflow.cs:44:18:44:40 | call to method Taint1 |
|
||||
| dataflow.cs:47:35:47:38 | "t6" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of TaintIndirect : String |
|
||||
| dataflow.cs:47:35:47:38 | "t6" : String | dataflow.cs:47:18:47:45 | call to method TaintIndirect |
|
||||
| dataflow.cs:47:41:47:44 | "t6" : String | DataFlow.dll:0:0:0:0 | Parameter 2 of TaintIndirect : String |
|
||||
| dataflow.cs:47:41:47:44 | "t6" : String | dataflow.cs:47:18:47:45 | call to method TaintIndirect |
|
||||
| dataflow.cs:72:21:72:34 | call to method NullFunction : null | dataflow.cs:72:21:72:52 | ... ?? ... |
|
||||
| dataflow.cs:72:39:72:52 | call to method IndirectNull : null | dataflow.cs:72:21:72:52 | ... ?? ... |
|
||||
@@ -24,6 +50,30 @@ edges
|
||||
| dataflow.cs:108:16:108:16 | access to local variable x : null | dataflow.cs:72:21:72:34 | call to method NullFunction : null |
|
||||
| dataflow.cs:108:16:108:16 | access to local variable x : null | dataflow.cs:87:31:87:44 | call to method NullFunction : null |
|
||||
nodes
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String | semmle.label | Parameter 1 of Taint1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String | semmle.label | Parameter 1 of Taint1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint2 : String | semmle.label | Parameter 1 of Taint2 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint3 : String | semmle.label | Parameter 1 of Taint3 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint5 : String | semmle.label | Parameter 1 of Taint5 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of Taint6 : String | semmle.label | Parameter 1 of Taint6 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 1 of TaintIndirect : String | semmle.label | Parameter 1 of TaintIndirect : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 2 of Taint1 : String | semmle.label | Parameter 2 of Taint1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | Parameter 2 of TaintIndirect : String | semmle.label | Parameter 2 of TaintIndirect : String |
|
||||
| DataFlow.dll:0:0:0:0 | call : String | semmle.label | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | call : String | semmle.label | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | call : String | semmle.label | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | call : String | semmle.label | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | call : String | semmle.label | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | call : String | semmle.label | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | semmle.label | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | semmle.label | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | semmle.label | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | semmle.label | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | semmle.label | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | semmle.label | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | semmle.label | ldarg.1 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.2 : String | semmle.label | ldarg.2 : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.2 : String | semmle.label | ldarg.2 : String |
|
||||
| dataflow.cs:16:18:16:26 | "tainted" : String | semmle.label | "tainted" : String |
|
||||
| dataflow.cs:16:18:16:37 | call to method ToString | semmle.label | call to method ToString |
|
||||
| dataflow.cs:18:18:18:31 | call to method Max | semmle.label | call to method Max |
|
||||
@@ -58,6 +108,18 @@ nodes
|
||||
| dataflow.cs:106:20:106:33 | call to method IndirectNull : null | semmle.label | call to method IndirectNull : null |
|
||||
| dataflow.cs:107:23:107:26 | null : null | semmle.label | null : null |
|
||||
| dataflow.cs:108:16:108:16 | access to local variable x : null | semmle.label | access to local variable x : null |
|
||||
subpaths
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String | DataFlow.dll:0:0:0:0 | call : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint5 : String | DataFlow.dll:0:0:0:0 | call : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint6 : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| DataFlow.dll:0:0:0:0 | ldarg.2 : String | DataFlow.dll:0:0:0:0 | Parameter 2 of Taint1 : String | DataFlow.dll:0:0:0:0 | call : String | DataFlow.dll:0:0:0:0 | call : String |
|
||||
| dataflow.cs:38:34:38:37 | "d1" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String | dataflow.cs:38:18:38:38 | call to method Taint1 : String |
|
||||
| dataflow.cs:39:34:39:37 | "d2" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint2 : String | DataFlow.dll:0:0:0:0 | call : String | dataflow.cs:39:18:39:38 | call to method Taint2 : String |
|
||||
| dataflow.cs:40:34:40:37 | "d3" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint3 : String | DataFlow.dll:0:0:0:0 | ldarg.1 : String | dataflow.cs:40:18:40:38 | call to method Taint3 : String |
|
||||
| dataflow.cs:44:28:44:32 | "t1a" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of Taint1 : String | DataFlow.dll:0:0:0:0 | call : String | dataflow.cs:44:18:44:40 | call to method Taint1 : String |
|
||||
| dataflow.cs:44:35:44:39 | "t1b" : String | DataFlow.dll:0:0:0:0 | Parameter 2 of Taint1 : String | DataFlow.dll:0:0:0:0 | call : String | dataflow.cs:44:18:44:40 | call to method Taint1 : String |
|
||||
| dataflow.cs:47:35:47:38 | "t6" : String | DataFlow.dll:0:0:0:0 | Parameter 1 of TaintIndirect : String | DataFlow.dll:0:0:0:0 | call : String | dataflow.cs:47:18:47:45 | call to method TaintIndirect : String |
|
||||
| dataflow.cs:47:41:47:44 | "t6" : String | DataFlow.dll:0:0:0:0 | Parameter 2 of TaintIndirect : String | DataFlow.dll:0:0:0:0 | call : String | dataflow.cs:47:18:47:45 | call to method TaintIndirect : String |
|
||||
#select
|
||||
| dataflow.cs:16:18:16:26 | "tainted" : String | dataflow.cs:16:18:16:37 | call to method ToString | dataflow.cs:16:18:16:37 | call to method ToString | $@ | dataflow.cs:16:18:16:37 | call to method ToString | call to method ToString |
|
||||
| dataflow.cs:18:27:18:27 | 2 : Int32 | dataflow.cs:18:18:18:31 | call to method Max | dataflow.cs:18:18:18:31 | call to method Max | $@ | dataflow.cs:18:18:18:31 | call to method Max | call to method Max |
|
||||
|
||||
@@ -4,7 +4,33 @@
|
||||
|
||||
import csharp
|
||||
import DataFlow
|
||||
import DataFlow::PathGraph
|
||||
|
||||
private predicate relevantPathNode(PathNode n) {
|
||||
exists(File f | f = n.getNode().getLocation().getFile() |
|
||||
f.fromSource()
|
||||
or
|
||||
f.getBaseName() = "DataFlow.dll"
|
||||
)
|
||||
}
|
||||
|
||||
query predicate edges(PathNode a, PathNode b) {
|
||||
PathGraph::edges(a, b) and
|
||||
relevantPathNode(a) and
|
||||
relevantPathNode(b)
|
||||
}
|
||||
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
PathGraph::nodes(n, key, val) and
|
||||
relevantPathNode(n)
|
||||
}
|
||||
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
PathGraph::subpaths(arg, par, ret, out) and
|
||||
relevantPathNode(arg) and
|
||||
relevantPathNode(par) and
|
||||
relevantPathNode(ret) and
|
||||
relevantPathNode(out)
|
||||
}
|
||||
|
||||
class FlowConfig extends Configuration {
|
||||
FlowConfig() { this = "FlowConfig" }
|
||||
@@ -16,6 +42,6 @@ class FlowConfig extends Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, FlowConfig config
|
||||
from PathNode source, PathNode sink, FlowConfig config
|
||||
where config.hasFlowPath(source, sink)
|
||||
select source, sink, sink, "$@", sink, sink.toString()
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
| comments2.cs:106:5:106:8 | // ... | comments2.cs:107:20:107:20 | E | E |
|
||||
| comments2.cs:107:23:108:26 | // ... | comments2.cs:110:10:110:12 | gen | E |
|
||||
| comments2.cs:118:5:118:21 | // ... | comments2.cs:119:11:119:25 | GenericClass<> | GenericClass<> |
|
||||
| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | GenericFn |
|
||||
| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn<> | GenericFn |
|
||||
| comments2.cs:127:20:127:23 | // ... | comments2.cs:128:9:128:17 | return ...; | x |
|
||||
| trivia.cs:1:1:3:15 | // ... | trivia.cs:14:7:14:9 | Tr1 | |
|
||||
| trivia.cs:13:89:13:103 | // ... | trivia.cs:14:7:14:9 | Tr1 | New checksum |
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
| comments2.cs:107:23:108:26 | // ... | comments2.cs:107:20:107:20 | E | E |
|
||||
| comments2.cs:118:5:118:21 | // ... | comments2.cs:119:11:119:25 | GenericClass<> | GenericClass<> |
|
||||
| comments2.cs:121:17:121:20 | // ... | comments2.cs:121:13:121:13 | f | f |
|
||||
| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | GenericFn |
|
||||
| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn<> | GenericFn |
|
||||
| comments2.cs:127:20:127:23 | // ... | comments2.cs:127:9:127:18 | ... ...; | x |
|
||||
| trivia.cs:13:89:13:103 | // ... | trivia.cs:14:7:14:9 | Tr1 | New checksum |
|
||||
| trivia.cs:25:14:25:38 | // ... | trivia.cs:17:5:29:5 | {...} | numbering not affected |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| comments2.cs:118:5:118:21 | // ... | comments2.cs:119:11:119:25 | GenericClass<> |
|
||||
| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn |
|
||||
| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn<> |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user