Merge pull request #11060 from hvitved/dataflow/path-node-reach-charpred

Data flow: Restrict public `PathNode`s to those that may reach a sink
This commit is contained in:
Tom Hvitved
2022-11-04 10:17:09 +01:00
committed by GitHub
58 changed files with 2946 additions and 2765 deletions

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2,43 +2,21 @@ edges
| test.cpp:4:15:4:20 | call to malloc | test.cpp:5:15:5:15 | Load | | test.cpp:4:15:4:20 | call to malloc | test.cpp:5:15:5:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... | | test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... | | test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store | | test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store | | test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... | | test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load | | test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store | | test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store |
| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store | | test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store |
@@ -116,7 +94,6 @@ edges
| test.cpp:8:16:8:16 | Load | test.cpp:11:16:11:16 | Load | | test.cpp:8:16:8:16 | Load | test.cpp:11:16:11:16 | Load |
| test.cpp:8:16:8:16 | Load | test.cpp:12:16:12:16 | Load | | test.cpp:8:16:8:16 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:9:16:9:16 | Load | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:9:16:9:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
@@ -139,62 +116,30 @@ edges
| test.cpp:11:16:11:16 | Load | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:11:16:11:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:11:16:11:16 | Load | test.cpp:12:16:12:16 | Load | | test.cpp:11:16:11:16 | Load | test.cpp:12:16:12:16 | Load |
| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
| test.cpp:16:15:16:20 | call to malloc | test.cpp:17:15:17:15 | Load | | test.cpp:16:15:16:20 | call to malloc | test.cpp:17:15:17:15 | Load |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... | | test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... | | test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... | | test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... | | test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
| test.cpp:28:15:28:20 | call to malloc | test.cpp:29:15:29:15 | Load | | test.cpp:28:15:28:20 | call to malloc | test.cpp:29:15:29:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... | | test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... | | test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store | | test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store | | test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... | | test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load | | test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store | | test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store |
| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store | | test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store |
@@ -272,7 +217,6 @@ edges
| test.cpp:32:16:32:16 | Load | test.cpp:35:16:35:16 | Load | | test.cpp:32:16:32:16 | Load | test.cpp:35:16:35:16 | Load |
| test.cpp:32:16:32:16 | Load | test.cpp:36:16:36:16 | Load | | test.cpp:32:16:32:16 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:33:16:33:16 | Load | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:33:16:33:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
@@ -295,49 +239,25 @@ edges
| test.cpp:35:16:35:16 | Load | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:35:16:35:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:35:16:35:16 | Load | test.cpp:36:16:36:16 | Load | | test.cpp:35:16:35:16 | Load | test.cpp:36:16:36:16 | Load |
| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
| test.cpp:40:15:40:20 | call to malloc | test.cpp:41:15:41:15 | Load | | test.cpp:40:15:40:20 | call to malloc | test.cpp:41:15:41:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... | | test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... | | test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store | | test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store | | test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... | | test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load | | test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store | | test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store |
| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store | | test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store |
@@ -415,7 +335,6 @@ edges
| test.cpp:44:16:44:16 | Load | test.cpp:47:16:47:16 | Load | | test.cpp:44:16:44:16 | Load | test.cpp:47:16:47:16 | Load |
| test.cpp:44:16:44:16 | Load | test.cpp:48:16:48:16 | Load | | test.cpp:44:16:44:16 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:45:16:45:16 | Load | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:45:16:45:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
@@ -438,8 +357,6 @@ edges
| test.cpp:47:16:47:16 | Load | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:47:16:47:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:47:16:47:16 | Load | test.cpp:48:16:48:16 | Load | | test.cpp:47:16:47:16 | Load | test.cpp:48:16:48:16 | Load |
| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:62:39:62:39 | Load | | test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:62:39:62:39 | Load |
| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:66:39:66:39 | Load | | test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:66:39:66:39 | Load |
@@ -449,18 +366,13 @@ edges
| test.cpp:52:19:52:24 | call to malloc | test.cpp:53:12:53:16 | Load | | test.cpp:52:19:52:24 | call to malloc | test.cpp:53:12:53:16 | Load |
| test.cpp:53:5:53:23 | Store | test.cpp:51:33:51:35 | Load indirection | | test.cpp:53:5:53:23 | Store | test.cpp:51:33:51:35 | Load indirection |
| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store | | test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store |
| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store |
| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... |
| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... | | test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... |
| test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | Load indirection | | test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | Load indirection |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:62:32:62:34 | Load | | test.cpp:60:34:60:37 | mk_array output argument | test.cpp:62:32:62:34 | Load |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:66:32:66:34 | Load | | test.cpp:60:34:60:37 | mk_array output argument | test.cpp:66:32:66:34 | Load |
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:70:31:70:33 | Load | | test.cpp:60:34:60:37 | mk_array output argument | test.cpp:70:31:70:33 | Load |
| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... | | test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... | | test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... | | test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:91:20:91:22 | arr indirection [begin] | | test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:91:20:91:22 | arr indirection [begin] |
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:95:20:95:22 | arr indirection [begin] | | test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:95:20:95:22 | arr indirection [begin] |
@@ -479,8 +391,6 @@ edges
| test.cpp:83:15:83:17 | arr indirection [begin] | test.cpp:83:19:83:23 | begin | | test.cpp:83:15:83:17 | arr indirection [begin] | test.cpp:83:19:83:23 | begin |
| test.cpp:83:15:83:30 | ... + ... | test.cpp:83:5:83:30 | Store | | test.cpp:83:15:83:30 | ... + ... | test.cpp:83:5:83:30 | Store |
| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store | | test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store |
| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store |
| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... |
| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... | | test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... |
| test.cpp:83:19:83:23 | begin | test.cpp:83:19:83:23 | Load | | test.cpp:83:19:83:23 | begin | test.cpp:83:19:83:23 | Load |
| test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin | | test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin |
@@ -488,21 +398,18 @@ edges
| test.cpp:91:24:91:28 | begin | test.cpp:91:47:91:47 | Load | | test.cpp:91:24:91:28 | begin | test.cpp:91:47:91:47 | Load |
| test.cpp:91:36:91:38 | arr indirection [end] | test.cpp:91:40:91:42 | end | | test.cpp:91:36:91:38 | arr indirection [end] | test.cpp:91:40:91:42 | end |
| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... | | test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:91:40:91:42 | end | test.cpp:91:40:91:42 | Load | | test.cpp:91:40:91:42 | end | test.cpp:91:40:91:42 | Load |
| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:24:95:28 | begin | | test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:24:95:28 | begin |
| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:47:95:47 | Load | | test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:47:95:47 | Load |
| test.cpp:95:24:95:28 | begin | test.cpp:95:47:95:47 | Load | | test.cpp:95:24:95:28 | begin | test.cpp:95:47:95:47 | Load |
| test.cpp:95:36:95:38 | arr indirection [end] | test.cpp:95:40:95:42 | end | | test.cpp:95:36:95:38 | arr indirection [end] | test.cpp:95:40:95:42 | end |
| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... | | test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:95:40:95:42 | end | test.cpp:95:40:95:42 | Load | | test.cpp:95:40:95:42 | end | test.cpp:95:40:95:42 | Load |
| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:24:99:28 | begin | | test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:24:99:28 | begin |
| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:46:99:46 | Load | | test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:46:99:46 | Load |
| test.cpp:99:24:99:28 | begin | test.cpp:99:46:99:46 | Load | | test.cpp:99:24:99:28 | begin | test.cpp:99:46:99:46 | Load |
| test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end | | test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end |
| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... | | test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
| test.cpp:99:39:99:41 | end | test.cpp:99:39:99:41 | Load | | test.cpp:99:39:99:41 | end | test.cpp:99:39:99:41 | Load |
| test.cpp:104:27:104:29 | arr [begin] | test.cpp:105:20:105:22 | arr indirection [begin] | | test.cpp:104:27:104:29 | arr [begin] | test.cpp:105:20:105:22 | arr indirection [begin] |
| test.cpp:104:27:104:29 | arr [begin] | test.cpp:109:20:109:22 | arr indirection [begin] | | test.cpp:104:27:104:29 | arr [begin] | test.cpp:109:20:109:22 | arr indirection [begin] |
@@ -515,21 +422,18 @@ edges
| test.cpp:105:24:105:28 | begin | test.cpp:105:47:105:47 | Load | | test.cpp:105:24:105:28 | begin | test.cpp:105:47:105:47 | Load |
| test.cpp:105:36:105:38 | arr indirection [end] | test.cpp:105:40:105:42 | end | | test.cpp:105:36:105:38 | arr indirection [end] | test.cpp:105:40:105:42 | end |
| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... | | test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:105:40:105:42 | end | test.cpp:105:40:105:42 | Load | | test.cpp:105:40:105:42 | end | test.cpp:105:40:105:42 | Load |
| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:24:109:28 | begin | | test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:24:109:28 | begin |
| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:47:109:47 | Load | | test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:47:109:47 | Load |
| test.cpp:109:24:109:28 | begin | test.cpp:109:47:109:47 | Load | | test.cpp:109:24:109:28 | begin | test.cpp:109:47:109:47 | Load |
| test.cpp:109:36:109:38 | arr indirection [end] | test.cpp:109:40:109:42 | end | | test.cpp:109:36:109:38 | arr indirection [end] | test.cpp:109:40:109:42 | end |
| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... | | test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:109:40:109:42 | end | test.cpp:109:40:109:42 | Load | | test.cpp:109:40:109:42 | end | test.cpp:109:40:109:42 | Load |
| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:24:113:28 | begin | | test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:24:113:28 | begin |
| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:46:113:46 | Load | | test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:46:113:46 | Load |
| test.cpp:113:24:113:28 | begin | test.cpp:113:46:113:46 | Load | | test.cpp:113:24:113:28 | begin | test.cpp:113:46:113:46 | Load |
| test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end | | test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end |
| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... | | test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
| test.cpp:113:39:113:41 | end | test.cpp:113:39:113:41 | Load | | test.cpp:113:39:113:41 | end | test.cpp:113:39:113:41 | Load |
| test.cpp:119:18:119:25 | call to mk_array [begin] | test.cpp:104:27:104:29 | arr [begin] | | test.cpp:119:18:119:25 | call to mk_array [begin] | test.cpp:104:27:104:29 | arr [begin] |
| test.cpp:119:18:119:25 | call to mk_array [end] | test.cpp:104:27:104:29 | arr [end] | | test.cpp:119:18:119:25 | call to mk_array [end] | test.cpp:104:27:104:29 | arr [end] |
@@ -558,8 +462,6 @@ edges
| test.cpp:144:16:144:18 | Load indirection [begin] | test.cpp:144:21:144:25 | begin | | test.cpp:144:16:144:18 | Load indirection [begin] | test.cpp:144:21:144:25 | begin |
| test.cpp:144:16:144:32 | ... + ... | test.cpp:144:5:144:32 | Store | | test.cpp:144:16:144:32 | ... + ... | test.cpp:144:5:144:32 | Store |
| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store | | test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store |
| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store |
| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... |
| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... | | test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... |
| test.cpp:144:21:144:25 | begin | test.cpp:144:21:144:25 | Load | | test.cpp:144:21:144:25 | begin | test.cpp:144:21:144:25 | Load |
| test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:152:20:152:22 | Load indirection [begin] | | test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:152:20:152:22 | Load indirection [begin] |
@@ -574,7 +476,6 @@ edges
| test.cpp:156:25:156:29 | begin | test.cpp:156:49:156:49 | Load | | test.cpp:156:25:156:29 | begin | test.cpp:156:49:156:49 | Load |
| test.cpp:156:37:156:39 | Load indirection [end] | test.cpp:156:42:156:44 | end | | test.cpp:156:37:156:39 | Load indirection [end] | test.cpp:156:42:156:44 | end |
| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... | | test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... |
| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... |
| test.cpp:156:42:156:44 | end | test.cpp:156:42:156:44 | Load | | test.cpp:156:42:156:44 | end | test.cpp:156:42:156:44 | Load |
| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:25:160:29 | begin | | test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:25:160:29 | begin |
| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:48:160:48 | Load | | test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:48:160:48 | Load |
@@ -590,21 +491,18 @@ edges
| test.cpp:166:25:166:29 | begin | test.cpp:166:49:166:49 | Load | | test.cpp:166:25:166:29 | begin | test.cpp:166:49:166:49 | Load |
| test.cpp:166:37:166:39 | Load indirection [end] | test.cpp:166:42:166:44 | end | | test.cpp:166:37:166:39 | Load indirection [end] | test.cpp:166:42:166:44 | end |
| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... | | test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:166:42:166:44 | end | test.cpp:166:42:166:44 | Load | | test.cpp:166:42:166:44 | end | test.cpp:166:42:166:44 | Load |
| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:25:170:29 | begin | | test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:25:170:29 | begin |
| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:49:170:49 | Load | | test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:49:170:49 | Load |
| test.cpp:170:25:170:29 | begin | test.cpp:170:49:170:49 | Load | | test.cpp:170:25:170:29 | begin | test.cpp:170:49:170:49 | Load |
| test.cpp:170:37:170:39 | Load indirection [end] | test.cpp:170:42:170:44 | end | | test.cpp:170:37:170:39 | Load indirection [end] | test.cpp:170:42:170:44 | end |
| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... | | test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:170:42:170:44 | end | test.cpp:170:42:170:44 | Load | | test.cpp:170:42:170:44 | end | test.cpp:170:42:170:44 | Load |
| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:25:174:29 | begin | | test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:25:174:29 | begin |
| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:48:174:48 | Load | | test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:48:174:48 | Load |
| test.cpp:174:25:174:29 | begin | test.cpp:174:48:174:48 | Load | | test.cpp:174:25:174:29 | begin | test.cpp:174:48:174:48 | Load |
| test.cpp:174:36:174:38 | Load indirection [end] | test.cpp:174:41:174:43 | end | | test.cpp:174:36:174:38 | Load indirection [end] | test.cpp:174:41:174:43 | end |
| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... | | test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
| test.cpp:174:41:174:43 | end | test.cpp:174:41:174:43 | Load | | test.cpp:174:41:174:43 | end | test.cpp:174:41:174:43 | Load |
| test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | test.cpp:165:29:165:31 | arr indirection [begin] | | test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | test.cpp:165:29:165:31 | arr indirection [begin] |
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] | | test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] |
@@ -614,19 +512,9 @@ edges
| test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:5 | Load | | test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:5 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... | | test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... | | test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store | | test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store | | test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load | | test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array | | test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store | | test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store |
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store | | test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store |
@@ -637,29 +525,15 @@ edges
| test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... | | test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... | | test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:197:20:197:22 | Load | test.cpp:201:5:201:19 | Store: ... = ... | | test.cpp:197:20:197:22 | Load | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:197:20:197:22 | Load | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:201:5:201:12 | access to array | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:201:5:201:12 | access to array | test.cpp:201:5:201:19 | Store: ... = ... | | test.cpp:201:5:201:12 | access to array | test.cpp:201:5:201:19 | Store: ... = ... |
| test.cpp:205:23:205:28 | call to malloc | test.cpp:206:17:206:17 | Load | | test.cpp:205:23:205:28 | call to malloc | test.cpp:206:17:206:17 | Load |
| test.cpp:205:23:205:28 | call to malloc | test.cpp:208:15:208:15 | Load | | test.cpp:205:23:205:28 | call to malloc | test.cpp:208:15:208:15 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... | | test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... | | test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store | | test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store | | test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load | | test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... | | test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load | | test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load | | test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
| test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | Store | | test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | Store |
@@ -671,8 +545,6 @@ edges
| test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... | | test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... | | test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:209:12:209:14 | Load | test.cpp:213:5:213:13 | Store: ... = ... | | test.cpp:209:12:209:14 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:209:12:209:14 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:213:5:213:6 | * ... | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:213:5:213:6 | * ... | test.cpp:213:5:213:13 | Store: ... = ... | | test.cpp:213:5:213:6 | * ... | test.cpp:213:5:213:13 | Store: ... = ... |
| test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:6 | * ... | | test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:6 | * ... |
| test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:13 | Store: ... = ... | | test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:13 | Store: ... = ... |

View File

@@ -12,11 +12,8 @@ nodes
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | semmle.label | ... + ... | | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | semmle.label | ... + ... |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | semmle.label | fgets output argument | | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | semmle.label | fgets output argument |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... | | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data | | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data | | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection | | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
#select #select
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | This argument to a file access function is derived from $@ and then passed to fopen(filename). | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | user input (fgets) | | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | This argument to a file access function is derived from $@ and then passed to fopen(filename). | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | user input (fgets) |

View File

@@ -12,11 +12,8 @@ nodes
| test.c:9:23:9:26 | argv | semmle.label | argv | | test.c:9:23:9:26 | argv | semmle.label | argv |
| test.c:9:23:9:26 | argv | semmle.label | argv | | test.c:9:23:9:26 | argv | semmle.label | argv |
| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... | | test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... |
| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... |
| test.c:17:11:17:18 | fileName | semmle.label | fileName | | test.c:17:11:17:18 | fileName | semmle.label | fileName |
| test.c:17:11:17:18 | fileName | semmle.label | fileName | | test.c:17:11:17:18 | fileName | semmle.label | fileName |
| test.c:17:11:17:18 | fileName | semmle.label | fileName |
| test.c:17:11:17:18 | fileName indirection | semmle.label | fileName indirection |
| test.c:17:11:17:18 | fileName indirection | semmle.label | fileName indirection | | test.c:17:11:17:18 | fileName indirection | semmle.label | fileName indirection |
#select #select
| test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:9:23:9:26 | argv | user input (argv) | | test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:9:23:9:26 | argv | user input (argv) |

View File

@@ -29,18 +29,13 @@ nodes
| search.c:14:24:14:28 | *query | semmle.label | *query | | search.c:14:24:14:28 | *query | semmle.label | *query |
| search.c:14:24:14:28 | query | semmle.label | query | | search.c:14:24:14:28 | query | semmle.label | query |
| search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... | | search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... |
| search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... |
| search.c:17:8:17:12 | query | semmle.label | query | | search.c:17:8:17:12 | query | semmle.label | query |
| search.c:17:8:17:12 | query | semmle.label | query | | search.c:17:8:17:12 | query | semmle.label | query |
| search.c:17:8:17:12 | query | semmle.label | query |
| search.c:17:8:17:12 | query indirection | semmle.label | query indirection |
| search.c:17:8:17:12 | query indirection | semmle.label | query indirection | | search.c:17:8:17:12 | query indirection | semmle.label | query indirection |
| search.c:22:24:22:28 | *query | semmle.label | *query | | search.c:22:24:22:28 | *query | semmle.label | *query |
| search.c:22:24:22:28 | query | semmle.label | query | | search.c:22:24:22:28 | query | semmle.label | query |
| search.c:23:39:23:43 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query |
| search.c:23:39:23:43 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query |
| search.c:23:39:23:43 | query | semmle.label | query |
| search.c:23:39:23:43 | query indirection | semmle.label | query indirection |
| search.c:23:39:23:43 | query indirection | semmle.label | query indirection | | search.c:23:39:23:43 | query indirection | semmle.label | query indirection |
| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv | | search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv |
| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv | | search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv |

View File

@@ -18,18 +18,13 @@ nodes
| test.c:15:20:15:23 | argv | semmle.label | argv | | test.c:15:20:15:23 | argv | semmle.label | argv |
| test.c:15:20:15:23 | argv | semmle.label | argv | | test.c:15:20:15:23 | argv | semmle.label | argv |
| test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... | | test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... |
| test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... |
| test.c:21:18:21:23 | query1 | semmle.label | query1 | | test.c:21:18:21:23 | query1 | semmle.label | query1 |
| test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection | | test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection |
| test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection |
| test.cpp:43:27:43:30 | argv | semmle.label | argv | | test.cpp:43:27:43:30 | argv | semmle.label | argv |
| test.cpp:43:27:43:30 | argv | semmle.label | argv | | test.cpp:43:27:43:30 | argv | semmle.label | argv |
| test.cpp:43:27:43:33 | (const char *)... | semmle.label | (const char *)... | | test.cpp:43:27:43:33 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:43:27:43:33 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:43:27:43:33 | access to array | semmle.label | access to array | | test.cpp:43:27:43:33 | access to array | semmle.label | access to array |
| test.cpp:43:27:43:33 | access to array | semmle.label | access to array | | test.cpp:43:27:43:33 | access to array | semmle.label | access to array |
| test.cpp:43:27:43:33 | access to array | semmle.label | access to array |
| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection |
| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection | | test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection |
#select #select
| test.c:21:18:21:23 | query1 | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:15:20:15:23 | argv | user input (argv) | | test.c:21:18:21:23 | query1 | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg). | test.c:15:20:15:23 | argv | user input (argv) |

View File

@@ -17,11 +17,8 @@ nodes
| test.cpp:37:73:37:76 | *data | semmle.label | *data | | test.cpp:37:73:37:76 | *data | semmle.label | *data |
| test.cpp:37:73:37:76 | data | semmle.label | data | | test.cpp:37:73:37:76 | data | semmle.label | data |
| test.cpp:43:32:43:35 | (LPCSTR)... | semmle.label | (LPCSTR)... | | test.cpp:43:32:43:35 | (LPCSTR)... | semmle.label | (LPCSTR)... |
| test.cpp:43:32:43:35 | (LPCSTR)... | semmle.label | (LPCSTR)... |
| test.cpp:43:32:43:35 | data | semmle.label | data | | test.cpp:43:32:43:35 | data | semmle.label | data |
| test.cpp:43:32:43:35 | data | semmle.label | data | | test.cpp:43:32:43:35 | data | semmle.label | data |
| test.cpp:43:32:43:35 | data | semmle.label | data |
| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection | | test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv | | test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv | | test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |

View File

@@ -79,15 +79,11 @@ nodes
| test.cpp:24:30:24:36 | command | semmle.label | command | | test.cpp:24:30:24:36 | command | semmle.label | command |
| test.cpp:26:10:26:16 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command |
| test.cpp:26:10:26:16 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command |
| test.cpp:26:10:26:16 | command | semmle.label | command |
| test.cpp:26:10:26:16 | command indirection | semmle.label | command indirection |
| test.cpp:26:10:26:16 | command indirection | semmle.label | command indirection | | test.cpp:26:10:26:16 | command indirection | semmle.label | command indirection |
| test.cpp:29:30:29:36 | *command | semmle.label | *command | | test.cpp:29:30:29:36 | *command | semmle.label | *command |
| test.cpp:29:30:29:36 | command | semmle.label | command | | test.cpp:29:30:29:36 | command | semmle.label | command |
| test.cpp:31:10:31:16 | command | semmle.label | command | | test.cpp:31:10:31:16 | command | semmle.label | command |
| test.cpp:31:10:31:16 | command | semmle.label | command | | test.cpp:31:10:31:16 | command | semmle.label | command |
| test.cpp:31:10:31:16 | command | semmle.label | command |
| test.cpp:31:10:31:16 | command indirection | semmle.label | command indirection |
| test.cpp:31:10:31:16 | command indirection | semmle.label | command indirection | | test.cpp:31:10:31:16 | command indirection | semmle.label | command indirection |
| test.cpp:42:18:42:23 | call to getenv | semmle.label | call to getenv | | test.cpp:42:18:42:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:42:18:42:34 | (const char *)... | semmle.label | (const char *)... | | test.cpp:42:18:42:34 | (const char *)... | semmle.label | (const char *)... |
@@ -100,54 +96,36 @@ nodes
| test.cpp:56:12:56:17 | buffer | semmle.label | buffer | | test.cpp:56:12:56:17 | buffer | semmle.label | buffer |
| test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument | | test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument |
| test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... | | test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:62:10:62:15 | buffer | semmle.label | buffer | | test.cpp:62:10:62:15 | buffer | semmle.label | buffer |
| test.cpp:62:10:62:15 | buffer indirection | semmle.label | buffer indirection | | test.cpp:62:10:62:15 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:62:10:62:15 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... | | test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:63:10:63:13 | data | semmle.label | data | | test.cpp:63:10:63:13 | data | semmle.label | data |
| test.cpp:63:10:63:13 | data | semmle.label | data | | test.cpp:63:10:63:13 | data | semmle.label | data |
| test.cpp:63:10:63:13 | data | semmle.label | data |
| test.cpp:63:10:63:13 | data indirection | semmle.label | data indirection |
| test.cpp:63:10:63:13 | data indirection | semmle.label | data indirection | | test.cpp:63:10:63:13 | data indirection | semmle.label | data indirection |
| test.cpp:64:10:64:16 | (const char *)... | semmle.label | (const char *)... | | test.cpp:64:10:64:16 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:64:10:64:16 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:64:10:64:16 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:64:10:64:16 | (reference dereference) | semmle.label | (reference dereference) | | test.cpp:64:10:64:16 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref | | test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref | | test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
| test.cpp:64:10:64:16 | dataref indirection | semmle.label | dataref indirection |
| test.cpp:64:10:64:16 | dataref indirection | semmle.label | dataref indirection | | test.cpp:64:10:64:16 | dataref indirection | semmle.label | dataref indirection |
| test.cpp:65:10:65:14 | (const char *)... | semmle.label | (const char *)... | | test.cpp:65:10:65:14 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:65:10:65:14 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:65:10:65:14 | data2 | semmle.label | data2 | | test.cpp:65:10:65:14 | data2 | semmle.label | data2 |
| test.cpp:65:10:65:14 | data2 | semmle.label | data2 | | test.cpp:65:10:65:14 | data2 | semmle.label | data2 |
| test.cpp:65:10:65:14 | data2 | semmle.label | data2 |
| test.cpp:65:10:65:14 | data2 indirection | semmle.label | data2 indirection |
| test.cpp:65:10:65:14 | data2 indirection | semmle.label | data2 indirection | | test.cpp:65:10:65:14 | data2 indirection | semmle.label | data2 indirection |
| test.cpp:76:12:76:17 | buffer | semmle.label | buffer | | test.cpp:76:12:76:17 | buffer | semmle.label | buffer |
| test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument | | test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument |
| test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... | | test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:78:10:78:15 | buffer | semmle.label | buffer | | test.cpp:78:10:78:15 | buffer | semmle.label | buffer |
| test.cpp:78:10:78:15 | buffer indirection | semmle.label | buffer indirection | | test.cpp:78:10:78:15 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:78:10:78:15 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:98:17:98:22 | buffer | semmle.label | buffer | | test.cpp:98:17:98:22 | buffer | semmle.label | buffer |
| test.cpp:98:17:98:22 | recv output argument | semmle.label | recv output argument | | test.cpp:98:17:98:22 | recv output argument | semmle.label | recv output argument |
| test.cpp:99:15:99:20 | (const char *)... | semmle.label | (const char *)... | | test.cpp:99:15:99:20 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:99:15:99:20 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:99:15:99:20 | buffer | semmle.label | buffer | | test.cpp:99:15:99:20 | buffer | semmle.label | buffer |
| test.cpp:99:15:99:20 | buffer indirection | semmle.label | buffer indirection | | test.cpp:99:15:99:20 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:99:15:99:20 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:106:17:106:22 | buffer | semmle.label | buffer | | test.cpp:106:17:106:22 | buffer | semmle.label | buffer |
| test.cpp:106:17:106:22 | recv output argument | semmle.label | recv output argument | | test.cpp:106:17:106:22 | recv output argument | semmle.label | recv output argument |
| test.cpp:107:15:107:20 | (const char *)... | semmle.label | (const char *)... | | test.cpp:107:15:107:20 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:107:15:107:20 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:107:15:107:20 | buffer | semmle.label | buffer | | test.cpp:107:15:107:20 | buffer | semmle.label | buffer |
| test.cpp:107:15:107:20 | buffer indirection | semmle.label | buffer indirection | | test.cpp:107:15:107:20 | buffer indirection | semmle.label | buffer indirection |
| test.cpp:107:15:107:20 | buffer indirection | semmle.label | buffer indirection |
#select #select
| test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:42:18:42:23 | call to getenv | call to getenv | | test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:42:18:42:23 | call to getenv | call to getenv |
| test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:43:18:43:23 | call to getenv | call to getenv | | test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:43:18:43:23 | call to getenv | call to getenv |

View File

@@ -56,42 +56,30 @@ nodes
| tests.c:28:22:28:25 | argv | semmle.label | argv | | tests.c:28:22:28:25 | argv | semmle.label | argv |
| tests.c:28:22:28:25 | argv | semmle.label | argv | | tests.c:28:22:28:25 | argv | semmle.label | argv |
| tests.c:28:22:28:28 | (const char *)... | semmle.label | (const char *)... | | tests.c:28:22:28:28 | (const char *)... | semmle.label | (const char *)... |
| tests.c:28:22:28:28 | (const char *)... | semmle.label | (const char *)... |
| tests.c:28:22:28:28 | access to array | semmle.label | access to array | | tests.c:28:22:28:28 | access to array | semmle.label | access to array |
| tests.c:28:22:28:28 | access to array | semmle.label | access to array | | tests.c:28:22:28:28 | access to array | semmle.label | access to array |
| tests.c:28:22:28:28 | access to array | semmle.label | access to array |
| tests.c:28:22:28:28 | access to array indirection | semmle.label | access to array indirection |
| tests.c:28:22:28:28 | access to array indirection | semmle.label | access to array indirection | | tests.c:28:22:28:28 | access to array indirection | semmle.label | access to array indirection |
| tests.c:29:28:29:31 | argv | semmle.label | argv | | tests.c:29:28:29:31 | argv | semmle.label | argv |
| tests.c:29:28:29:31 | argv | semmle.label | argv | | tests.c:29:28:29:31 | argv | semmle.label | argv |
| tests.c:29:28:29:34 | access to array | semmle.label | access to array | | tests.c:29:28:29:34 | access to array | semmle.label | access to array |
| tests.c:29:28:29:34 | access to array | semmle.label | access to array | | tests.c:29:28:29:34 | access to array | semmle.label | access to array |
| tests.c:29:28:29:34 | access to array | semmle.label | access to array |
| tests.c:29:28:29:34 | access to array indirection | semmle.label | access to array indirection |
| tests.c:29:28:29:34 | access to array indirection | semmle.label | access to array indirection | | tests.c:29:28:29:34 | access to array indirection | semmle.label | access to array indirection |
| tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion |
| tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion |
| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | | tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 |
| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | | tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 |
| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 |
| tests.c:31:15:31:23 | buffer100 indirection | semmle.label | buffer100 indirection |
| tests.c:31:15:31:23 | buffer100 indirection | semmle.label | buffer100 indirection | | tests.c:31:15:31:23 | buffer100 indirection | semmle.label | buffer100 indirection |
| tests.c:31:15:31:23 | scanf output argument | semmle.label | scanf output argument | | tests.c:31:15:31:23 | scanf output argument | semmle.label | scanf output argument |
| tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion |
| tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion |
| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 | | tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 |
| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 | | tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 |
| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 |
| tests.c:33:21:33:29 | buffer100 indirection | semmle.label | buffer100 indirection |
| tests.c:33:21:33:29 | buffer100 indirection | semmle.label | buffer100 indirection | | tests.c:33:21:33:29 | buffer100 indirection | semmle.label | buffer100 indirection |
| tests.c:34:10:34:13 | argv | semmle.label | argv | | tests.c:34:10:34:13 | argv | semmle.label | argv |
| tests.c:34:10:34:13 | argv | semmle.label | argv | | tests.c:34:10:34:13 | argv | semmle.label | argv |
| tests.c:34:10:34:16 | (const char *)... | semmle.label | (const char *)... | | tests.c:34:10:34:16 | (const char *)... | semmle.label | (const char *)... |
| tests.c:34:10:34:16 | (const char *)... | semmle.label | (const char *)... |
| tests.c:34:10:34:16 | access to array | semmle.label | access to array | | tests.c:34:10:34:16 | access to array | semmle.label | access to array |
| tests.c:34:10:34:16 | access to array | semmle.label | access to array | | tests.c:34:10:34:16 | access to array | semmle.label | access to array |
| tests.c:34:10:34:16 | access to array | semmle.label | access to array |
| tests.c:34:10:34:16 | access to array indirection | semmle.label | access to array indirection |
| tests.c:34:10:34:16 | access to array indirection | semmle.label | access to array indirection | | tests.c:34:10:34:16 | access to array indirection | semmle.label | access to array indirection |
#select #select
| tests.c:28:3:28:9 | call to sprintf | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv | | tests.c:28:3:28:9 | call to sprintf | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv |

View File

@@ -27,26 +27,18 @@ nodes
| char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | semmle.label | ... + ... | | char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | semmle.label | ... + ... |
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data | | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data |
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data | | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data |
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data |
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection | semmle.label | data indirection |
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection | semmle.label | data indirection | | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection | semmle.label | data indirection |
| char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | semmle.label | ... + ... | | char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | semmle.label | ... + ... |
| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | semmle.label | fgets output argument | | char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | semmle.label | fgets output argument |
| char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... | semmle.label | (const char *)... | | char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... | semmle.label | (const char *)... |
| char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... | semmle.label | (const char *)... |
| char_console_fprintf_01_bad.c:49:21:49:24 | data | semmle.label | data | | char_console_fprintf_01_bad.c:49:21:49:24 | data | semmle.label | data |
| char_console_fprintf_01_bad.c:49:21:49:24 | data | semmle.label | data | | char_console_fprintf_01_bad.c:49:21:49:24 | data | semmle.label | data |
| char_console_fprintf_01_bad.c:49:21:49:24 | data | semmle.label | data |
| char_console_fprintf_01_bad.c:49:21:49:24 | data indirection | semmle.label | data indirection |
| char_console_fprintf_01_bad.c:49:21:49:24 | data indirection | semmle.label | data indirection | | char_console_fprintf_01_bad.c:49:21:49:24 | data indirection | semmle.label | data indirection |
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | semmle.label | call to getenv | | char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | semmle.label | call to getenv |
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | semmle.label | call to getenv | | char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | semmle.label | call to getenv |
| char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... | semmle.label | (const char *)... | | char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... | semmle.label | (const char *)... |
| char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... | semmle.label | (const char *)... |
| char_environment_fprintf_01_bad.c:36:21:36:24 | data | semmle.label | data | | char_environment_fprintf_01_bad.c:36:21:36:24 | data | semmle.label | data |
| char_environment_fprintf_01_bad.c:36:21:36:24 | data | semmle.label | data | | char_environment_fprintf_01_bad.c:36:21:36:24 | data | semmle.label | data |
| char_environment_fprintf_01_bad.c:36:21:36:24 | data | semmle.label | data |
| char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection | semmle.label | data indirection |
| char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection | semmle.label | data indirection | | char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection | semmle.label | data indirection |
#select #select
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | The value of this argument may come from $@ and is being used as a formatting argument to badVaSink(data), which calls vsnprintf(format). | char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | recv | | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | The value of this argument may come from $@ and is being used as a formatting argument to badVaSink(data), which calls vsnprintf(format). | char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | recv |

View File

@@ -272,29 +272,20 @@ nodes
| argvLocal.c:95:9:95:12 | argv | semmle.label | argv | | argvLocal.c:95:9:95:12 | argv | semmle.label | argv |
| argvLocal.c:95:9:95:12 | argv | semmle.label | argv | | argvLocal.c:95:9:95:12 | argv | semmle.label | argv |
| argvLocal.c:95:9:95:15 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:95:9:95:15 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:95:9:95:15 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:95:9:95:15 | access to array | semmle.label | access to array | | argvLocal.c:95:9:95:15 | access to array | semmle.label | access to array |
| argvLocal.c:95:9:95:15 | access to array | semmle.label | access to array | | argvLocal.c:95:9:95:15 | access to array | semmle.label | access to array |
| argvLocal.c:95:9:95:15 | access to array | semmle.label | access to array |
| argvLocal.c:95:9:95:15 | access to array indirection | semmle.label | access to array indirection |
| argvLocal.c:95:9:95:15 | access to array indirection | semmle.label | access to array indirection | | argvLocal.c:95:9:95:15 | access to array indirection | semmle.label | access to array indirection |
| argvLocal.c:96:15:96:18 | argv | semmle.label | argv | | argvLocal.c:96:15:96:18 | argv | semmle.label | argv |
| argvLocal.c:96:15:96:18 | argv | semmle.label | argv | | argvLocal.c:96:15:96:18 | argv | semmle.label | argv |
| argvLocal.c:96:15:96:21 | access to array | semmle.label | access to array | | argvLocal.c:96:15:96:21 | access to array | semmle.label | access to array |
| argvLocal.c:96:15:96:21 | access to array | semmle.label | access to array | | argvLocal.c:96:15:96:21 | access to array | semmle.label | access to array |
| argvLocal.c:96:15:96:21 | access to array | semmle.label | access to array |
| argvLocal.c:96:15:96:21 | access to array indirection | semmle.label | access to array indirection |
| argvLocal.c:96:15:96:21 | access to array indirection | semmle.label | access to array indirection | | argvLocal.c:96:15:96:21 | access to array indirection | semmle.label | access to array indirection |
| argvLocal.c:100:7:100:10 | argv | semmle.label | argv | | argvLocal.c:100:7:100:10 | argv | semmle.label | argv |
| argvLocal.c:100:7:100:10 | argv | semmle.label | argv | | argvLocal.c:100:7:100:10 | argv | semmle.label | argv |
| argvLocal.c:101:9:101:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:101:9:101:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:101:9:101:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:101:9:101:10 | i1 | semmle.label | i1 |
| argvLocal.c:101:9:101:10 | i1 | semmle.label | i1 | | argvLocal.c:101:9:101:10 | i1 | semmle.label | i1 |
| argvLocal.c:101:9:101:10 | i1 | semmle.label | i1 | | argvLocal.c:101:9:101:10 | i1 | semmle.label | i1 |
| argvLocal.c:101:9:101:10 | i1 indirection | semmle.label | i1 indirection | | argvLocal.c:101:9:101:10 | i1 indirection | semmle.label | i1 indirection |
| argvLocal.c:101:9:101:10 | i1 indirection | semmle.label | i1 indirection |
| argvLocal.c:102:15:102:16 | i1 | semmle.label | i1 |
| argvLocal.c:102:15:102:16 | i1 | semmle.label | i1 | | argvLocal.c:102:15:102:16 | i1 | semmle.label | i1 |
| argvLocal.c:102:15:102:16 | i1 | semmle.label | i1 | | argvLocal.c:102:15:102:16 | i1 | semmle.label | i1 |
| argvLocal.c:102:15:102:16 | i1 indirection | semmle.label | i1 indirection | | argvLocal.c:102:15:102:16 | i1 indirection | semmle.label | i1 indirection |
@@ -303,51 +294,35 @@ nodes
| argvLocal.c:105:14:105:17 | argv | semmle.label | argv | | argvLocal.c:105:14:105:17 | argv | semmle.label | argv |
| argvLocal.c:105:14:105:17 | argv | semmle.label | argv | | argvLocal.c:105:14:105:17 | argv | semmle.label | argv |
| argvLocal.c:106:9:106:13 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:106:9:106:13 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:106:9:106:13 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:106:9:106:13 | access to array | semmle.label | access to array |
| argvLocal.c:106:9:106:13 | access to array | semmle.label | access to array | | argvLocal.c:106:9:106:13 | access to array | semmle.label | access to array |
| argvLocal.c:106:9:106:13 | access to array | semmle.label | access to array | | argvLocal.c:106:9:106:13 | access to array | semmle.label | access to array |
| argvLocal.c:106:9:106:13 | access to array indirection | semmle.label | access to array indirection | | argvLocal.c:106:9:106:13 | access to array indirection | semmle.label | access to array indirection |
| argvLocal.c:106:9:106:13 | access to array indirection | semmle.label | access to array indirection |
| argvLocal.c:107:15:107:19 | access to array | semmle.label | access to array |
| argvLocal.c:107:15:107:19 | access to array | semmle.label | access to array | | argvLocal.c:107:15:107:19 | access to array | semmle.label | access to array |
| argvLocal.c:107:15:107:19 | access to array | semmle.label | access to array | | argvLocal.c:107:15:107:19 | access to array | semmle.label | access to array |
| argvLocal.c:107:15:107:19 | access to array indirection | semmle.label | access to array indirection | | argvLocal.c:107:15:107:19 | access to array indirection | semmle.label | access to array indirection |
| argvLocal.c:107:15:107:19 | access to array indirection | semmle.label | access to array indirection | | argvLocal.c:107:15:107:19 | access to array indirection | semmle.label | access to array indirection |
| argvLocal.c:107:15:107:19 | printWrapper output argument | semmle.label | printWrapper output argument | | argvLocal.c:107:15:107:19 | printWrapper output argument | semmle.label | printWrapper output argument |
| argvLocal.c:110:9:110:11 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:110:9:110:11 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:110:9:110:11 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:110:9:110:11 | * ... | semmle.label | * ... |
| argvLocal.c:110:9:110:11 | * ... | semmle.label | * ... | | argvLocal.c:110:9:110:11 | * ... | semmle.label | * ... |
| argvLocal.c:110:9:110:11 | * ... | semmle.label | * ... | | argvLocal.c:110:9:110:11 | * ... | semmle.label | * ... |
| argvLocal.c:110:9:110:11 | * ... indirection | semmle.label | * ... indirection | | argvLocal.c:110:9:110:11 | * ... indirection | semmle.label | * ... indirection |
| argvLocal.c:110:9:110:11 | * ... indirection | semmle.label | * ... indirection |
| argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... |
| argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... |
| argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... |
| argvLocal.c:111:15:111:17 | * ... indirection | semmle.label | * ... indirection | | argvLocal.c:111:15:111:17 | * ... indirection | semmle.label | * ... indirection |
| argvLocal.c:111:15:111:17 | * ... indirection | semmle.label | * ... indirection |
| argvLocal.c:115:13:115:16 | argv | semmle.label | argv | | argvLocal.c:115:13:115:16 | argv | semmle.label | argv |
| argvLocal.c:115:13:115:16 | argv | semmle.label | argv | | argvLocal.c:115:13:115:16 | argv | semmle.label | argv |
| argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:116:9:116:10 | i3 | semmle.label | i3 | | argvLocal.c:116:9:116:10 | i3 | semmle.label | i3 |
| argvLocal.c:116:9:116:10 | i3 indirection | semmle.label | i3 indirection | | argvLocal.c:116:9:116:10 | i3 indirection | semmle.label | i3 indirection |
| argvLocal.c:116:9:116:10 | i3 indirection | semmle.label | i3 indirection |
| argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion |
| argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion | | argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion |
| argvLocal.c:117:15:117:16 | i3 | semmle.label | i3 | | argvLocal.c:117:15:117:16 | i3 | semmle.label | i3 |
| argvLocal.c:117:15:117:16 | i3 indirection | semmle.label | i3 indirection | | argvLocal.c:117:15:117:16 | i3 indirection | semmle.label | i3 indirection |
| argvLocal.c:117:15:117:16 | i3 indirection | semmle.label | i3 indirection | | argvLocal.c:117:15:117:16 | i3 indirection | semmle.label | i3 indirection |
| argvLocal.c:117:15:117:16 | printWrapper output argument | semmle.label | printWrapper output argument | | argvLocal.c:117:15:117:16 | printWrapper output argument | semmle.label | printWrapper output argument |
| argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 |
| argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 | | argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 |
| argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 | | argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 |
| argvLocal.c:121:9:121:10 | i4 indirection | semmle.label | i4 indirection | | argvLocal.c:121:9:121:10 | i4 indirection | semmle.label | i4 indirection |
| argvLocal.c:121:9:121:10 | i4 indirection | semmle.label | i4 indirection |
| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 |
| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | | argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 |
| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | | argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 |
| argvLocal.c:122:15:122:16 | i4 indirection | semmle.label | i4 indirection | | argvLocal.c:122:15:122:16 | i4 indirection | semmle.label | i4 indirection |
@@ -356,108 +331,69 @@ nodes
| argvLocal.c:126:10:126:13 | argv | semmle.label | argv | | argvLocal.c:126:10:126:13 | argv | semmle.label | argv |
| argvLocal.c:126:10:126:13 | argv | semmle.label | argv | | argvLocal.c:126:10:126:13 | argv | semmle.label | argv |
| argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:127:9:127:10 | i5 | semmle.label | i5 | | argvLocal.c:127:9:127:10 | i5 | semmle.label | i5 |
| argvLocal.c:127:9:127:10 | i5 indirection | semmle.label | i5 indirection | | argvLocal.c:127:9:127:10 | i5 indirection | semmle.label | i5 indirection |
| argvLocal.c:127:9:127:10 | i5 indirection | semmle.label | i5 indirection |
| argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion |
| argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion | | argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion |
| argvLocal.c:128:15:128:16 | i5 | semmle.label | i5 | | argvLocal.c:128:15:128:16 | i5 | semmle.label | i5 |
| argvLocal.c:128:15:128:16 | i5 indirection | semmle.label | i5 indirection | | argvLocal.c:128:15:128:16 | i5 indirection | semmle.label | i5 indirection |
| argvLocal.c:128:15:128:16 | i5 indirection | semmle.label | i5 indirection | | argvLocal.c:128:15:128:16 | i5 indirection | semmle.label | i5 indirection |
| argvLocal.c:128:15:128:16 | printWrapper output argument | semmle.label | printWrapper output argument | | argvLocal.c:128:15:128:16 | printWrapper output argument | semmle.label | printWrapper output argument |
| argvLocal.c:131:9:131:14 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:131:9:131:14 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:131:9:131:14 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:131:9:131:14 | ... + ... | semmle.label | ... + ... | | argvLocal.c:131:9:131:14 | ... + ... | semmle.label | ... + ... |
| argvLocal.c:131:9:131:14 | ... + ... indirection | semmle.label | ... + ... indirection | | argvLocal.c:131:9:131:14 | ... + ... indirection | semmle.label | ... + ... indirection |
| argvLocal.c:131:9:131:14 | ... + ... indirection | semmle.label | ... + ... indirection |
| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... |
| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | | argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... |
| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | | argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... |
| argvLocal.c:132:15:132:20 | ... + ... indirection | semmle.label | ... + ... indirection | | argvLocal.c:132:15:132:20 | ... + ... indirection | semmle.label | ... + ... indirection |
| argvLocal.c:132:15:132:20 | ... + ... indirection | semmle.label | ... + ... indirection |
| argvLocal.c:135:9:135:10 | i4 | semmle.label | i4 |
| argvLocal.c:135:9:135:10 | i4 | semmle.label | i4 | | argvLocal.c:135:9:135:10 | i4 | semmle.label | i4 |
| argvLocal.c:135:9:135:12 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:135:9:135:12 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:135:9:135:12 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:135:9:135:12 | ... ++ | semmle.label | ... ++ |
| argvLocal.c:135:9:135:12 | ... ++ | semmle.label | ... ++ | | argvLocal.c:135:9:135:12 | ... ++ | semmle.label | ... ++ |
| argvLocal.c:135:9:135:12 | ... ++ | semmle.label | ... ++ | | argvLocal.c:135:9:135:12 | ... ++ | semmle.label | ... ++ |
| argvLocal.c:135:9:135:12 | ... ++ indirection | semmle.label | ... ++ indirection | | argvLocal.c:135:9:135:12 | ... ++ indirection | semmle.label | ... ++ indirection |
| argvLocal.c:135:9:135:12 | ... ++ indirection | semmle.label | ... ++ indirection |
| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... |
| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... | | argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... |
| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... | | argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... |
| argvLocal.c:136:15:136:18 | -- ... indirection | semmle.label | -- ... indirection | | argvLocal.c:136:15:136:18 | -- ... indirection | semmle.label | -- ... indirection |
| argvLocal.c:136:15:136:18 | -- ... indirection | semmle.label | -- ... indirection |
| argvLocal.c:136:17:136:18 | i4 | semmle.label | i4 |
| argvLocal.c:136:17:136:18 | i4 | semmle.label | i4 | | argvLocal.c:136:17:136:18 | i4 | semmle.label | i4 |
| argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 |
| argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 | | argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 |
| argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 | | argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 |
| argvLocal.c:144:9:144:10 | i7 indirection | semmle.label | i7 indirection | | argvLocal.c:144:9:144:10 | i7 indirection | semmle.label | i7 indirection |
| argvLocal.c:144:9:144:10 | i7 indirection | semmle.label | i7 indirection |
| argvLocal.c:145:15:145:16 | i7 | semmle.label | i7 | | argvLocal.c:145:15:145:16 | i7 | semmle.label | i7 |
| argvLocal.c:145:15:145:16 | i7 | semmle.label | i7 | | argvLocal.c:145:15:145:16 | i7 | semmle.label | i7 |
| argvLocal.c:145:15:145:16 | i7 | semmle.label | i7 |
| argvLocal.c:145:15:145:16 | i7 indirection | semmle.label | i7 indirection |
| argvLocal.c:145:15:145:16 | i7 indirection | semmle.label | i7 indirection | | argvLocal.c:145:15:145:16 | i7 indirection | semmle.label | i7 indirection |
| argvLocal.c:149:11:149:14 | argv | semmle.label | argv | | argvLocal.c:149:11:149:14 | argv | semmle.label | argv |
| argvLocal.c:149:11:149:14 | argv | semmle.label | argv | | argvLocal.c:149:11:149:14 | argv | semmle.label | argv |
| argvLocal.c:150:9:150:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:150:9:150:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:150:9:150:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:150:9:150:10 | i8 | semmle.label | i8 |
| argvLocal.c:150:9:150:10 | i8 | semmle.label | i8 | | argvLocal.c:150:9:150:10 | i8 | semmle.label | i8 |
| argvLocal.c:150:9:150:10 | i8 | semmle.label | i8 | | argvLocal.c:150:9:150:10 | i8 | semmle.label | i8 |
| argvLocal.c:150:9:150:10 | i8 indirection | semmle.label | i8 indirection | | argvLocal.c:150:9:150:10 | i8 indirection | semmle.label | i8 indirection |
| argvLocal.c:150:9:150:10 | i8 indirection | semmle.label | i8 indirection |
| argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 |
| argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | | argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 |
| argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | | argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 |
| argvLocal.c:151:15:151:16 | i8 indirection | semmle.label | i8 indirection | | argvLocal.c:151:15:151:16 | i8 indirection | semmle.label | i8 indirection |
| argvLocal.c:151:15:151:16 | i8 indirection | semmle.label | i8 indirection |
| argvLocal.c:156:23:156:26 | argv | semmle.label | argv | | argvLocal.c:156:23:156:26 | argv | semmle.label | argv |
| argvLocal.c:156:23:156:26 | argv | semmle.label | argv | | argvLocal.c:156:23:156:26 | argv | semmle.label | argv |
| argvLocal.c:157:9:157:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:157:9:157:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:157:9:157:10 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:157:9:157:10 | i9 | semmle.label | i9 | | argvLocal.c:157:9:157:10 | i9 | semmle.label | i9 |
| argvLocal.c:157:9:157:10 | i9 indirection | semmle.label | i9 indirection | | argvLocal.c:157:9:157:10 | i9 indirection | semmle.label | i9 indirection |
| argvLocal.c:157:9:157:10 | i9 indirection | semmle.label | i9 indirection |
| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 |
| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 | | argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 |
| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 | | argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 |
| argvLocal.c:158:15:158:16 | i9 indirection | semmle.label | i9 indirection | | argvLocal.c:158:15:158:16 | i9 indirection | semmle.label | i9 indirection |
| argvLocal.c:158:15:158:16 | i9 indirection | semmle.label | i9 indirection |
| argvLocal.c:163:22:163:25 | argv | semmle.label | argv | | argvLocal.c:163:22:163:25 | argv | semmle.label | argv |
| argvLocal.c:163:22:163:25 | argv | semmle.label | argv | | argvLocal.c:163:22:163:25 | argv | semmle.label | argv |
| argvLocal.c:164:9:164:11 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:164:9:164:11 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:164:9:164:11 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:164:9:164:11 | i91 | semmle.label | i91 | | argvLocal.c:164:9:164:11 | i91 | semmle.label | i91 |
| argvLocal.c:164:9:164:11 | i91 indirection | semmle.label | i91 indirection | | argvLocal.c:164:9:164:11 | i91 indirection | semmle.label | i91 indirection |
| argvLocal.c:164:9:164:11 | i91 indirection | semmle.label | i91 indirection |
| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 | | argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 |
| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 | | argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 |
| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 |
| argvLocal.c:165:15:165:17 | i91 indirection | semmle.label | i91 indirection |
| argvLocal.c:165:15:165:17 | i91 indirection | semmle.label | i91 indirection | | argvLocal.c:165:15:165:17 | i91 indirection | semmle.label | i91 indirection |
| argvLocal.c:168:18:168:21 | argv | semmle.label | argv | | argvLocal.c:168:18:168:21 | argv | semmle.label | argv |
| argvLocal.c:168:18:168:21 | argv | semmle.label | argv | | argvLocal.c:168:18:168:21 | argv | semmle.label | argv |
| argvLocal.c:169:9:169:20 | (char *)... | semmle.label | (char *)... | | argvLocal.c:169:9:169:20 | (char *)... | semmle.label | (char *)... |
| argvLocal.c:169:9:169:20 | (char *)... | semmle.label | (char *)... |
| argvLocal.c:169:9:169:20 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:169:9:169:20 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:169:9:169:20 | (const char *)... | semmle.label | (const char *)... |
| argvLocal.c:169:9:169:20 | i10 indirection | semmle.label | i10 indirection | | argvLocal.c:169:9:169:20 | i10 indirection | semmle.label | i10 indirection |
| argvLocal.c:169:9:169:20 | i10 indirection | semmle.label | i10 indirection |
| argvLocal.c:169:18:169:20 | i10 | semmle.label | i10 |
| argvLocal.c:169:18:169:20 | i10 | semmle.label | i10 | | argvLocal.c:169:18:169:20 | i10 | semmle.label | i10 |
| argvLocal.c:169:18:169:20 | i10 | semmle.label | i10 | | argvLocal.c:169:18:169:20 | i10 | semmle.label | i10 |
| argvLocal.c:170:15:170:26 | (char *)... | semmle.label | (char *)... | | argvLocal.c:170:15:170:26 | (char *)... | semmle.label | (char *)... |
| argvLocal.c:170:15:170:26 | (char *)... | semmle.label | (char *)... |
| argvLocal.c:170:15:170:26 | i10 indirection | semmle.label | i10 indirection | | argvLocal.c:170:15:170:26 | i10 indirection | semmle.label | i10 indirection |
| argvLocal.c:170:15:170:26 | i10 indirection | semmle.label | i10 indirection |
| argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 |
| argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 | | argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 |
| argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 | | argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 |
#select #select

View File

@@ -83,70 +83,50 @@ nodes
| funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument | | funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument |
| funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 | | funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 |
| funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:17:9:17:10 | i1 | semmle.label | i1 | | funcsLocal.c:17:9:17:10 | i1 | semmle.label | i1 |
| funcsLocal.c:17:9:17:10 | i1 indirection | semmle.label | i1 indirection | | funcsLocal.c:17:9:17:10 | i1 indirection | semmle.label | i1 indirection |
| funcsLocal.c:17:9:17:10 | i1 indirection | semmle.label | i1 indirection |
| funcsLocal.c:26:8:26:9 | fgets output argument | semmle.label | fgets output argument | | funcsLocal.c:26:8:26:9 | fgets output argument | semmle.label | fgets output argument |
| funcsLocal.c:26:8:26:9 | i3 | semmle.label | i3 | | funcsLocal.c:26:8:26:9 | i3 | semmle.label | i3 |
| funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:27:9:27:10 | i3 | semmle.label | i3 | | funcsLocal.c:27:9:27:10 | i3 | semmle.label | i3 |
| funcsLocal.c:27:9:27:10 | i3 indirection | semmle.label | i3 indirection | | funcsLocal.c:27:9:27:10 | i3 indirection | semmle.label | i3 indirection |
| funcsLocal.c:27:9:27:10 | i3 indirection | semmle.label | i3 indirection |
| funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | | funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets |
| funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | | funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets |
| funcsLocal.c:31:19:31:21 | fgets output argument | semmle.label | fgets output argument | | funcsLocal.c:31:19:31:21 | fgets output argument | semmle.label | fgets output argument |
| funcsLocal.c:31:19:31:21 | i41 | semmle.label | i41 | | funcsLocal.c:31:19:31:21 | i41 | semmle.label | i41 |
| funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 |
| funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 |
| funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 |
| funcsLocal.c:32:9:32:10 | i4 indirection | semmle.label | i4 indirection |
| funcsLocal.c:32:9:32:10 | i4 indirection | semmle.label | i4 indirection | | funcsLocal.c:32:9:32:10 | i4 indirection | semmle.label | i4 indirection |
| funcsLocal.c:36:7:36:8 | gets output argument | semmle.label | gets output argument | | funcsLocal.c:36:7:36:8 | gets output argument | semmle.label | gets output argument |
| funcsLocal.c:36:7:36:8 | i5 | semmle.label | i5 | | funcsLocal.c:36:7:36:8 | i5 | semmle.label | i5 |
| funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:37:9:37:10 | i5 | semmle.label | i5 | | funcsLocal.c:37:9:37:10 | i5 | semmle.label | i5 |
| funcsLocal.c:37:9:37:10 | i5 indirection | semmle.label | i5 indirection | | funcsLocal.c:37:9:37:10 | i5 indirection | semmle.label | i5 indirection |
| funcsLocal.c:37:9:37:10 | i5 indirection | semmle.label | i5 indirection |
| funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | | funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets |
| funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | | funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets |
| funcsLocal.c:41:18:41:20 | gets output argument | semmle.label | gets output argument | | funcsLocal.c:41:18:41:20 | gets output argument | semmle.label | gets output argument |
| funcsLocal.c:41:18:41:20 | i61 | semmle.label | i61 | | funcsLocal.c:41:18:41:20 | i61 | semmle.label | i61 |
| funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 |
| funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 |
| funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 |
| funcsLocal.c:42:9:42:10 | i6 indirection | semmle.label | i6 indirection |
| funcsLocal.c:42:9:42:10 | i6 indirection | semmle.label | i6 indirection | | funcsLocal.c:42:9:42:10 | i6 indirection | semmle.label | i6 indirection |
| funcsLocal.c:46:7:46:9 | * ... | semmle.label | * ... | | funcsLocal.c:46:7:46:9 | * ... | semmle.label | * ... |
| funcsLocal.c:46:7:46:9 | * ... | semmle.label | * ... | | funcsLocal.c:46:7:46:9 | * ... | semmle.label | * ... |
| funcsLocal.c:46:7:46:9 | gets output argument | semmle.label | gets output argument | | funcsLocal.c:46:7:46:9 | gets output argument | semmle.label | gets output argument |
| funcsLocal.c:47:9:47:11 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:47:9:47:11 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:47:9:47:11 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:47:9:47:11 | * ... | semmle.label | * ... | | funcsLocal.c:47:9:47:11 | * ... | semmle.label | * ... |
| funcsLocal.c:47:9:47:11 | * ... | semmle.label | * ... | | funcsLocal.c:47:9:47:11 | * ... | semmle.label | * ... |
| funcsLocal.c:47:9:47:11 | * ... | semmle.label | * ... |
| funcsLocal.c:47:9:47:11 | * ... indirection | semmle.label | * ... indirection |
| funcsLocal.c:47:9:47:11 | * ... indirection | semmle.label | * ... indirection | | funcsLocal.c:47:9:47:11 | * ... indirection | semmle.label | * ... indirection |
| funcsLocal.c:52:8:52:11 | call to gets | semmle.label | call to gets | | funcsLocal.c:52:8:52:11 | call to gets | semmle.label | call to gets |
| funcsLocal.c:52:8:52:11 | call to gets | semmle.label | call to gets | | funcsLocal.c:52:8:52:11 | call to gets | semmle.label | call to gets |
| funcsLocal.c:53:9:53:11 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:53:9:53:11 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:53:9:53:11 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:53:9:53:11 | * ... | semmle.label | * ... |
| funcsLocal.c:53:9:53:11 | * ... | semmle.label | * ... | | funcsLocal.c:53:9:53:11 | * ... | semmle.label | * ... |
| funcsLocal.c:53:9:53:11 | * ... | semmle.label | * ... | | funcsLocal.c:53:9:53:11 | * ... | semmle.label | * ... |
| funcsLocal.c:53:9:53:11 | * ... indirection | semmle.label | * ... indirection | | funcsLocal.c:53:9:53:11 | * ... indirection | semmle.label | * ... indirection |
| funcsLocal.c:53:9:53:11 | * ... indirection | semmle.label | * ... indirection |
| funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... |
| funcsLocal.c:58:9:58:10 | e1 | semmle.label | e1 | | funcsLocal.c:58:9:58:10 | e1 | semmle.label | e1 |
| funcsLocal.c:58:9:58:10 | e1 indirection | semmle.label | e1 indirection | | funcsLocal.c:58:9:58:10 | e1 indirection | semmle.label | e1 indirection |
| funcsLocal.c:58:9:58:10 | e1 indirection | semmle.label | e1 indirection |
#select #select
| funcsLocal.c:17:9:17:10 | i1 | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | funcsLocal.c:16:8:16:9 | i1 | fread | | funcsLocal.c:17:9:17:10 | i1 | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | funcsLocal.c:16:8:16:9 | i1 | fread |
| funcsLocal.c:27:9:27:10 | i3 | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | funcsLocal.c:26:8:26:9 | i3 | fgets | | funcsLocal.c:27:9:27:10 | i3 | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | funcsLocal.c:26:8:26:9 | i3 | fgets |

View File

@@ -90,12 +90,10 @@ nodes
| globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv | semmle.label | argv |
| globalVars.c:24:11:24:14 | argv indirection | semmle.label | argv indirection | | globalVars.c:24:11:24:14 | argv indirection | semmle.label | argv indirection |
| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy |
| globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy |
| globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy |
| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | | globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection |
| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection |
| globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy |
| globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy |
| globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy |
@@ -106,12 +104,10 @@ nodes
| globalVars.c:35:11:35:14 | copy | semmle.label | copy | | globalVars.c:35:11:35:14 | copy | semmle.label | copy |
| globalVars.c:35:11:35:14 | copy | semmle.label | copy | | globalVars.c:35:11:35:14 | copy | semmle.label | copy |
| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection |
| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection |
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
@@ -120,12 +116,10 @@ nodes
| globalVars.c:41:15:41:19 | printWrapper output argument | semmle.label | printWrapper output argument | | globalVars.c:41:15:41:19 | printWrapper output argument | semmle.label | printWrapper output argument |
| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | | globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection |
| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection |
#select #select
| globalVars.c:27:9:27:12 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:27:9:27:12 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv | | globalVars.c:27:9:27:12 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:27:9:27:12 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:30:15:30:18 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:30:15:30:18 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:24:11:24:14 | argv | argv | | globalVars.c:30:15:30:18 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:30:15:30:18 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:24:11:24:14 | argv | argv |

View File

@@ -90,12 +90,10 @@ nodes
| globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv | semmle.label | argv |
| globalVars.c:24:11:24:14 | argv indirection | semmle.label | argv indirection | | globalVars.c:24:11:24:14 | argv indirection | semmle.label | argv indirection |
| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy |
| globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy |
| globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy |
| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | | globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection |
| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection |
| globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy |
| globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy |
| globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy |
@@ -106,12 +104,10 @@ nodes
| globalVars.c:35:11:35:14 | copy | semmle.label | copy | | globalVars.c:35:11:35:14 | copy | semmle.label | copy |
| globalVars.c:35:11:35:14 | copy | semmle.label | copy | | globalVars.c:35:11:35:14 | copy | semmle.label | copy |
| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 |
| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection |
| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection |
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 |
@@ -120,12 +116,10 @@ nodes
| globalVars.c:41:15:41:19 | printWrapper output argument | semmle.label | printWrapper output argument | | globalVars.c:41:15:41:19 | printWrapper output argument | semmle.label | printWrapper output argument |
| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | | globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... |
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 |
| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection |
| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection |
#select #select
| globalVars.c:27:9:27:12 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:27:9:27:12 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv | | globalVars.c:27:9:27:12 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:27:9:27:12 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:30:15:30:18 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:30:15:30:18 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:24:11:24:14 | argv | argv | | globalVars.c:30:15:30:18 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:30:15:30:18 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:24:11:24:14 | argv | argv |

View File

@@ -92,101 +92,68 @@ nodes
| ifs.c:61:8:61:11 | argv | semmle.label | argv | | ifs.c:61:8:61:11 | argv | semmle.label | argv |
| ifs.c:61:8:61:11 | argv | semmle.label | argv | | ifs.c:61:8:61:11 | argv | semmle.label | argv |
| ifs.c:62:9:62:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:62:9:62:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:62:9:62:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:62:9:62:10 | c7 | semmle.label | c7 | | ifs.c:62:9:62:10 | c7 | semmle.label | c7 |
| ifs.c:62:9:62:10 | c7 | semmle.label | c7 | | ifs.c:62:9:62:10 | c7 | semmle.label | c7 |
| ifs.c:62:9:62:10 | c7 | semmle.label | c7 |
| ifs.c:62:9:62:10 | c7 indirection | semmle.label | c7 indirection |
| ifs.c:62:9:62:10 | c7 indirection | semmle.label | c7 indirection | | ifs.c:62:9:62:10 | c7 indirection | semmle.label | c7 indirection |
| ifs.c:68:8:68:11 | argv | semmle.label | argv | | ifs.c:68:8:68:11 | argv | semmle.label | argv |
| ifs.c:68:8:68:11 | argv | semmle.label | argv | | ifs.c:68:8:68:11 | argv | semmle.label | argv |
| ifs.c:69:9:69:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:69:9:69:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:69:9:69:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:69:9:69:10 | c8 | semmle.label | c8 | | ifs.c:69:9:69:10 | c8 | semmle.label | c8 |
| ifs.c:69:9:69:10 | c8 | semmle.label | c8 | | ifs.c:69:9:69:10 | c8 | semmle.label | c8 |
| ifs.c:69:9:69:10 | c8 | semmle.label | c8 |
| ifs.c:69:9:69:10 | c8 indirection | semmle.label | c8 indirection |
| ifs.c:69:9:69:10 | c8 indirection | semmle.label | c8 indirection | | ifs.c:69:9:69:10 | c8 indirection | semmle.label | c8 indirection |
| ifs.c:74:8:74:11 | argv | semmle.label | argv | | ifs.c:74:8:74:11 | argv | semmle.label | argv |
| ifs.c:74:8:74:11 | argv | semmle.label | argv | | ifs.c:74:8:74:11 | argv | semmle.label | argv |
| ifs.c:75:9:75:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:75:9:75:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:75:9:75:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:75:9:75:10 | i1 | semmle.label | i1 | | ifs.c:75:9:75:10 | i1 | semmle.label | i1 |
| ifs.c:75:9:75:10 | i1 | semmle.label | i1 | | ifs.c:75:9:75:10 | i1 | semmle.label | i1 |
| ifs.c:75:9:75:10 | i1 | semmle.label | i1 |
| ifs.c:75:9:75:10 | i1 indirection | semmle.label | i1 indirection |
| ifs.c:75:9:75:10 | i1 indirection | semmle.label | i1 indirection | | ifs.c:75:9:75:10 | i1 indirection | semmle.label | i1 indirection |
| ifs.c:80:8:80:11 | argv | semmle.label | argv | | ifs.c:80:8:80:11 | argv | semmle.label | argv |
| ifs.c:80:8:80:11 | argv | semmle.label | argv | | ifs.c:80:8:80:11 | argv | semmle.label | argv |
| ifs.c:81:9:81:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:81:9:81:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:81:9:81:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:81:9:81:10 | i2 | semmle.label | i2 | | ifs.c:81:9:81:10 | i2 | semmle.label | i2 |
| ifs.c:81:9:81:10 | i2 | semmle.label | i2 | | ifs.c:81:9:81:10 | i2 | semmle.label | i2 |
| ifs.c:81:9:81:10 | i2 | semmle.label | i2 |
| ifs.c:81:9:81:10 | i2 indirection | semmle.label | i2 indirection |
| ifs.c:81:9:81:10 | i2 indirection | semmle.label | i2 indirection | | ifs.c:81:9:81:10 | i2 indirection | semmle.label | i2 indirection |
| ifs.c:86:8:86:11 | argv | semmle.label | argv | | ifs.c:86:8:86:11 | argv | semmle.label | argv |
| ifs.c:86:8:86:11 | argv | semmle.label | argv | | ifs.c:86:8:86:11 | argv | semmle.label | argv |
| ifs.c:87:9:87:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:87:9:87:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:87:9:87:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:87:9:87:10 | i3 | semmle.label | i3 | | ifs.c:87:9:87:10 | i3 | semmle.label | i3 |
| ifs.c:87:9:87:10 | i3 | semmle.label | i3 | | ifs.c:87:9:87:10 | i3 | semmle.label | i3 |
| ifs.c:87:9:87:10 | i3 | semmle.label | i3 |
| ifs.c:87:9:87:10 | i3 indirection | semmle.label | i3 indirection |
| ifs.c:87:9:87:10 | i3 indirection | semmle.label | i3 indirection | | ifs.c:87:9:87:10 | i3 indirection | semmle.label | i3 indirection |
| ifs.c:92:8:92:11 | argv | semmle.label | argv | | ifs.c:92:8:92:11 | argv | semmle.label | argv |
| ifs.c:92:8:92:11 | argv | semmle.label | argv | | ifs.c:92:8:92:11 | argv | semmle.label | argv |
| ifs.c:93:9:93:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:93:9:93:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:93:9:93:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:93:9:93:10 | i4 | semmle.label | i4 | | ifs.c:93:9:93:10 | i4 | semmle.label | i4 |
| ifs.c:93:9:93:10 | i4 | semmle.label | i4 | | ifs.c:93:9:93:10 | i4 | semmle.label | i4 |
| ifs.c:93:9:93:10 | i4 | semmle.label | i4 |
| ifs.c:93:9:93:10 | i4 indirection | semmle.label | i4 indirection |
| ifs.c:93:9:93:10 | i4 indirection | semmle.label | i4 indirection | | ifs.c:93:9:93:10 | i4 indirection | semmle.label | i4 indirection |
| ifs.c:98:8:98:11 | argv | semmle.label | argv | | ifs.c:98:8:98:11 | argv | semmle.label | argv |
| ifs.c:98:8:98:11 | argv | semmle.label | argv | | ifs.c:98:8:98:11 | argv | semmle.label | argv |
| ifs.c:99:9:99:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:99:9:99:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:99:9:99:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:99:9:99:10 | i5 | semmle.label | i5 | | ifs.c:99:9:99:10 | i5 | semmle.label | i5 |
| ifs.c:99:9:99:10 | i5 | semmle.label | i5 | | ifs.c:99:9:99:10 | i5 | semmle.label | i5 |
| ifs.c:99:9:99:10 | i5 | semmle.label | i5 |
| ifs.c:99:9:99:10 | i5 indirection | semmle.label | i5 indirection |
| ifs.c:99:9:99:10 | i5 indirection | semmle.label | i5 indirection | | ifs.c:99:9:99:10 | i5 indirection | semmle.label | i5 indirection |
| ifs.c:105:8:105:11 | argv | semmle.label | argv | | ifs.c:105:8:105:11 | argv | semmle.label | argv |
| ifs.c:105:8:105:11 | argv | semmle.label | argv | | ifs.c:105:8:105:11 | argv | semmle.label | argv |
| ifs.c:106:9:106:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:106:9:106:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:106:9:106:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:106:9:106:10 | i6 | semmle.label | i6 | | ifs.c:106:9:106:10 | i6 | semmle.label | i6 |
| ifs.c:106:9:106:10 | i6 | semmle.label | i6 | | ifs.c:106:9:106:10 | i6 | semmle.label | i6 |
| ifs.c:106:9:106:10 | i6 | semmle.label | i6 |
| ifs.c:106:9:106:10 | i6 indirection | semmle.label | i6 indirection |
| ifs.c:106:9:106:10 | i6 indirection | semmle.label | i6 indirection | | ifs.c:106:9:106:10 | i6 indirection | semmle.label | i6 indirection |
| ifs.c:111:8:111:11 | argv | semmle.label | argv | | ifs.c:111:8:111:11 | argv | semmle.label | argv |
| ifs.c:111:8:111:11 | argv | semmle.label | argv | | ifs.c:111:8:111:11 | argv | semmle.label | argv |
| ifs.c:112:9:112:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:112:9:112:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:112:9:112:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:112:9:112:10 | i7 | semmle.label | i7 | | ifs.c:112:9:112:10 | i7 | semmle.label | i7 |
| ifs.c:112:9:112:10 | i7 | semmle.label | i7 | | ifs.c:112:9:112:10 | i7 | semmle.label | i7 |
| ifs.c:112:9:112:10 | i7 | semmle.label | i7 |
| ifs.c:112:9:112:10 | i7 indirection | semmle.label | i7 indirection |
| ifs.c:112:9:112:10 | i7 indirection | semmle.label | i7 indirection | | ifs.c:112:9:112:10 | i7 indirection | semmle.label | i7 indirection |
| ifs.c:117:8:117:11 | argv | semmle.label | argv | | ifs.c:117:8:117:11 | argv | semmle.label | argv |
| ifs.c:117:8:117:11 | argv | semmle.label | argv | | ifs.c:117:8:117:11 | argv | semmle.label | argv |
| ifs.c:118:9:118:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:118:9:118:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:118:9:118:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:118:9:118:10 | i8 | semmle.label | i8 | | ifs.c:118:9:118:10 | i8 | semmle.label | i8 |
| ifs.c:118:9:118:10 | i8 | semmle.label | i8 | | ifs.c:118:9:118:10 | i8 | semmle.label | i8 |
| ifs.c:118:9:118:10 | i8 | semmle.label | i8 |
| ifs.c:118:9:118:10 | i8 indirection | semmle.label | i8 indirection |
| ifs.c:118:9:118:10 | i8 indirection | semmle.label | i8 indirection | | ifs.c:118:9:118:10 | i8 indirection | semmle.label | i8 indirection |
| ifs.c:123:8:123:11 | argv | semmle.label | argv | | ifs.c:123:8:123:11 | argv | semmle.label | argv |
| ifs.c:123:8:123:11 | argv | semmle.label | argv | | ifs.c:123:8:123:11 | argv | semmle.label | argv |
| ifs.c:124:9:124:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:124:9:124:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:124:9:124:10 | (const char *)... | semmle.label | (const char *)... |
| ifs.c:124:9:124:10 | i9 | semmle.label | i9 | | ifs.c:124:9:124:10 | i9 | semmle.label | i9 |
| ifs.c:124:9:124:10 | i9 | semmle.label | i9 | | ifs.c:124:9:124:10 | i9 | semmle.label | i9 |
| ifs.c:124:9:124:10 | i9 | semmle.label | i9 |
| ifs.c:124:9:124:10 | i9 indirection | semmle.label | i9 indirection |
| ifs.c:124:9:124:10 | i9 indirection | semmle.label | i9 indirection | | ifs.c:124:9:124:10 | i9 indirection | semmle.label | i9 indirection |
#select #select
| ifs.c:62:9:62:10 | c7 | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | ifs.c:61:8:61:11 | argv | argv | | ifs.c:62:9:62:10 | c7 | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | ifs.c:61:8:61:11 | argv | argv |

View File

@@ -9,6 +9,5 @@ nodes
| examples.cpp:63:26:63:30 | fscanf output argument | semmle.label | fscanf output argument | | examples.cpp:63:26:63:30 | fscanf output argument | semmle.label | fscanf output argument |
| examples.cpp:66:11:66:14 | data | semmle.label | data | | examples.cpp:66:11:66:14 | data | semmle.label | data |
| examples.cpp:66:11:66:14 | data | semmle.label | data | | examples.cpp:66:11:66:14 | data | semmle.label | data |
| examples.cpp:66:11:66:14 | data | semmle.label | data |
#select #select
| examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | examples.cpp:63:26:63:30 | & ... | User-provided value | | examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | examples.cpp:63:26:63:30 | & ... | User-provided value |

View File

@@ -28,7 +28,6 @@ nodes
| test2.cpp:12:21:12:21 | v | semmle.label | v | | test2.cpp:12:21:12:21 | v | semmle.label | v |
| test2.cpp:14:11:14:11 | v | semmle.label | v | | test2.cpp:14:11:14:11 | v | semmle.label | v |
| test2.cpp:14:11:14:11 | v | semmle.label | v | | test2.cpp:14:11:14:11 | v | semmle.label | v |
| test2.cpp:14:11:14:11 | v | semmle.label | v |
| test2.cpp:25:22:25:23 | & ... | semmle.label | & ... | | test2.cpp:25:22:25:23 | & ... | semmle.label | & ... |
| test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument | | test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument |
| test2.cpp:27:13:27:13 | v | semmle.label | v | | test2.cpp:27:13:27:13 | v | semmle.label | v |
@@ -37,26 +36,21 @@ nodes
| test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument | | test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument |
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt | | test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt | | test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt | | test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:19:6:19:6 | y | semmle.label | y | | test5.cpp:19:6:19:6 | y | semmle.label | y |
| test5.cpp:19:6:19:6 | y | semmle.label | y | | test5.cpp:19:6:19:6 | y | semmle.label | y |
| test5.cpp:19:6:19:6 | y | semmle.label | y |
| test.c:11:29:11:32 | argv | semmle.label | argv | | test.c:11:29:11:32 | argv | semmle.label | argv |
| test.c:11:29:11:32 | argv | semmle.label | argv | | test.c:11:29:11:32 | argv | semmle.label | argv |
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections | | test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections | | test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
| test.c:41:17:41:20 | argv | semmle.label | argv | | test.c:41:17:41:20 | argv | semmle.label | argv |
| test.c:41:17:41:20 | argv | semmle.label | argv | | test.c:41:17:41:20 | argv | semmle.label | argv |
| test.c:44:7:44:10 | len2 | semmle.label | len2 | | test.c:44:7:44:10 | len2 | semmle.label | len2 |
| test.c:44:7:44:10 | len2 | semmle.label | len2 | | test.c:44:7:44:10 | len2 | semmle.label | len2 |
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
| test.c:51:17:51:20 | argv | semmle.label | argv | | test.c:51:17:51:20 | argv | semmle.label | argv |
| test.c:51:17:51:20 | argv | semmle.label | argv | | test.c:51:17:51:20 | argv | semmle.label | argv |
| test.c:54:7:54:10 | len3 | semmle.label | len3 | | test.c:54:7:54:10 | len3 | semmle.label | len3 |
| test.c:54:7:54:10 | len3 | semmle.label | len3 | | test.c:54:7:54:10 | len3 | semmle.label | len3 |
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
#select #select
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value | | test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |

View File

@@ -23,22 +23,16 @@ nodes
| test.cpp:16:25:16:42 | (const char *)... | semmle.label | (const char *)... | | test.cpp:16:25:16:42 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:20:14:20:20 | address | semmle.label | address | | test.cpp:20:14:20:20 | address | semmle.label | address |
| test.cpp:20:14:20:20 | address | semmle.label | address | | test.cpp:20:14:20:20 | address | semmle.label | address |
| test.cpp:20:14:20:20 | address | semmle.label | address |
| test.cpp:20:14:20:20 | address indirection | semmle.label | address indirection |
| test.cpp:20:14:20:20 | address indirection | semmle.label | address indirection | | test.cpp:20:14:20:20 | address indirection | semmle.label | address indirection |
| test.cpp:27:25:27:30 | call to getenv | semmle.label | call to getenv | | test.cpp:27:25:27:30 | call to getenv | semmle.label | call to getenv |
| test.cpp:27:25:27:42 | (const char *)... | semmle.label | (const char *)... | | test.cpp:27:25:27:42 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:31:14:31:20 | address | semmle.label | address | | test.cpp:31:14:31:20 | address | semmle.label | address |
| test.cpp:31:14:31:20 | address | semmle.label | address | | test.cpp:31:14:31:20 | address | semmle.label | address |
| test.cpp:31:14:31:20 | address | semmle.label | address |
| test.cpp:31:14:31:20 | address indirection | semmle.label | address indirection |
| test.cpp:31:14:31:20 | address indirection | semmle.label | address indirection | | test.cpp:31:14:31:20 | address indirection | semmle.label | address indirection |
| test.cpp:38:25:38:30 | call to getenv | semmle.label | call to getenv | | test.cpp:38:25:38:30 | call to getenv | semmle.label | call to getenv |
| test.cpp:38:25:38:42 | (const char *)... | semmle.label | (const char *)... | | test.cpp:38:25:38:42 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:42:14:42:20 | address | semmle.label | address | | test.cpp:42:14:42:20 | address | semmle.label | address |
| test.cpp:42:14:42:20 | address | semmle.label | address | | test.cpp:42:14:42:20 | address | semmle.label | address |
| test.cpp:42:14:42:20 | address | semmle.label | address |
| test.cpp:42:14:42:20 | address indirection | semmle.label | address indirection |
| test.cpp:42:14:42:20 | address indirection | semmle.label | address indirection | | test.cpp:42:14:42:20 | address indirection | semmle.label | address indirection |
#select #select
| test.cpp:20:7:20:12 | call to strcmp | test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:16:25:16:30 | call to getenv | call to getenv | | test.cpp:20:7:20:12 | call to strcmp | test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:16:25:16:30 | call to getenv | call to getenv |

View File

@@ -9,6 +9,5 @@ nodes
| test.cpp:20:29:20:47 | (const char *)... | semmle.label | (const char *)... | | test.cpp:20:29:20:47 | (const char *)... | semmle.label | (const char *)... |
| test.cpp:24:10:24:35 | ! ... | semmle.label | ! ... | | test.cpp:24:10:24:35 | ! ... | semmle.label | ! ... |
| test.cpp:24:11:24:16 | call to strcmp | semmle.label | call to strcmp | | test.cpp:24:11:24:16 | call to strcmp | semmle.label | call to strcmp |
| test.cpp:24:11:24:16 | call to strcmp | semmle.label | call to strcmp |
#select #select
| test.cpp:24:10:24:35 | ! ... | test.cpp:20:29:20:34 | call to getenv | test.cpp:24:10:24:35 | ! ... | Reliance on untrusted input $@ to raise privilege at $@. | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:25:9:25:27 | ... = ... | ... = ... | | test.cpp:24:10:24:35 | ! ... | test.cpp:20:29:20:34 | call to getenv | test.cpp:24:10:24:35 | ! ... | Reliance on untrusted input $@ to raise privilege at $@. | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:25:9:25:27 | ... = ... | ... = ... |

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -1 +1 @@
| test.cs:31:9:31:74 | call to method InitiateSystemShutdownExW | Call to an external method 'InitiateSystemShutdownExW'. | | test.cs:32:9:32:74 | call to method InitiateSystemShutdownExW | Call to an external method 'InitiateSystemShutdownExW'. |

View File

@@ -1,23 +1,17 @@
edges edges
| test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:36:70:48 | access to local variable lastWriteTime | | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:36:71:48 | access to local variable lastWriteTime |
| test.cs:70:13:70:71 | call to method CompareTo : Int32 | test.cs:70:13:70:76 | ... >= ... | | test.cs:71:13:71:71 | call to method CompareTo : Int32 | test.cs:71:13:71:76 | ... >= ... |
| test.cs:70:36:70:48 | access to local variable lastWriteTime | test.cs:70:36:70:70 | call to method AddHours | | test.cs:71:36:71:48 | access to local variable lastWriteTime | test.cs:71:36:71:70 | call to method AddHours |
| test.cs:70:36:70:48 | access to local variable lastWriteTime | test.cs:70:36:70:70 | call to method AddHours : DateTime | | test.cs:71:36:71:70 | call to method AddHours | test.cs:71:13:71:71 | call to method CompareTo |
| test.cs:70:36:70:48 | access to local variable lastWriteTime : DateTime | test.cs:70:36:70:70 | call to method AddHours | | test.cs:71:36:71:70 | call to method AddHours | test.cs:71:13:71:71 | call to method CompareTo : Int32 |
| test.cs:70:36:70:48 | access to local variable lastWriteTime : DateTime | test.cs:70:36:70:70 | call to method AddHours : DateTime |
| test.cs:70:36:70:70 | call to method AddHours | test.cs:70:13:70:71 | call to method CompareTo |
| test.cs:70:36:70:70 | call to method AddHours | test.cs:70:13:70:71 | call to method CompareTo : Int32 |
| test.cs:70:36:70:70 | call to method AddHours : DateTime | test.cs:70:13:70:71 | call to method CompareTo |
| test.cs:70:36:70:70 | call to method AddHours : DateTime | test.cs:70:13:70:71 | call to method CompareTo : Int32 |
#select #select
| test.cs:70:9:73:9 | if (...) ... | test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:13:70:71 | call to method CompareTo | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:70:13:70:71 | call to method CompareTo | call to method CompareTo | test.cs:70:36:70:70 | call to method AddHours | offset | test.cs:68:34:68:76 | call to method GetLastWriteTime | last modification time of a file | | test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:71 | call to method CompareTo | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file |
| test.cs:70:9:73:9 | if (...) ... | test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:13:70:71 | call to method CompareTo : Int32 | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:70:13:70:71 | call to method CompareTo | call to method CompareTo | test.cs:70:36:70:70 | call to method AddHours | offset | test.cs:68:34:68:76 | call to method GetLastWriteTime | last modification time of a file | | test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:71 | call to method CompareTo : Int32 | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file |
| test.cs:70:9:73:9 | if (...) ... | test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:13:70:76 | ... >= ... | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:70:13:70:71 | call to method CompareTo | call to method CompareTo | test.cs:70:36:70:70 | call to method AddHours | offset | test.cs:68:34:68:76 | call to method GetLastWriteTime | last modification time of a file | | test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:76 | ... >= ... | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file |
| test.cs:70:9:73:9 | if (...) ... | test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:13:70:76 | ... >= ... : Boolean | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:70:13:70:71 | call to method CompareTo | call to method CompareTo | test.cs:70:36:70:70 | call to method AddHours | offset | test.cs:68:34:68:76 | call to method GetLastWriteTime | last modification time of a file |
nodes nodes
| test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | semmle.label | call to method GetLastWriteTime : DateTime | | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | semmle.label | call to method GetLastWriteTime : DateTime |
| test.cs:70:13:70:71 | call to method CompareTo | semmle.label | call to method CompareTo | | test.cs:71:13:71:71 | call to method CompareTo | semmle.label | call to method CompareTo |
| test.cs:70:13:70:71 | call to method CompareTo : Int32 | semmle.label | call to method CompareTo : Int32 | | test.cs:71:13:71:71 | call to method CompareTo : Int32 | semmle.label | call to method CompareTo : Int32 |
| test.cs:70:13:70:76 | ... >= ... | semmle.label | ... >= ... | | test.cs:71:13:71:76 | ... >= ... | semmle.label | ... >= ... |
| test.cs:70:36:70:48 | access to local variable lastWriteTime | semmle.label | access to local variable lastWriteTime | | test.cs:71:36:71:48 | access to local variable lastWriteTime | semmle.label | access to local variable lastWriteTime |
| test.cs:70:36:70:70 | call to method AddHours | semmle.label | call to method AddHours | | test.cs:71:36:71:70 | call to method AddHours | semmle.label | call to method AddHours |

View File

@@ -21,7 +21,8 @@ namespace System.Diagnostics
} }
} }
class External { class External
{
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InitiateSystemShutdownExW([In] string lpMachineName, [In] string lpMessage, [In] uint dwTimeout, [MarshalAs(UnmanagedType.Bool)][In] bool bForceAppsClosed, [MarshalAs(UnmanagedType.Bool)][In] bool bRebootAfterShutdown, [In] uint dwReason); public static extern bool InitiateSystemShutdownExW([In] string lpMachineName, [In] string lpMessage, [In] uint dwTimeout, [MarshalAs(UnmanagedType.Bool)][In] bool bForceAppsClosed, [MarshalAs(UnmanagedType.Bool)][In] bool bRebootAfterShutdown, [In] uint dwReason);
@@ -67,7 +68,7 @@ class External {
{ {
DateTime lastWriteTime = System.IO.File.GetLastWriteTime("someFile"); DateTime lastWriteTime = System.IO.File.GetLastWriteTime("someFile");
int num = new Random().Next(288, 336); int num = new Random().Next(288, 336);
if (DateTime.Now.CompareTo(lastWriteTime.AddHours((double)num)) >= 0) // BUG : Potential time bomb if (DateTime.Now.CompareTo(lastWriteTime.AddHours((double)num)) >= 0) // BUG : Potential time bomb, currently not detected
{ {
// Some code here // Some code here
} }

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**

View File

@@ -2874,54 +2874,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
} }
} }
/** abstract private class PathNodeImpl extends TPathNode {
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source are generated.
*/
class PathNode extends TPathNode {
/** Gets a textual representation of this element. */
string toString() { none() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
string toStringWithContext() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets the underlying `Node`. */
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */ /** Gets the `FlowState` of this node. */
FlowState getState() { none() } abstract FlowState getState();
/** Gets the associated configuration. */ /** Gets the associated configuration. */
Configuration getConfiguration() { none() } abstract Configuration getConfiguration();
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */ /** Holds if this node is a source. */
predicate isSource() { none() } abstract predicate isSource();
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNodeImpl getASuccessorImpl(); abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() { private PathNodeImpl getASuccessorIfHidden() {
@@ -2967,13 +2929,23 @@ abstract private class PathNodeImpl extends PathNode {
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
} }
override string toString() { result = this.getNodeEx().toString() + this.ppAp() } /** Gets a textual representation of this element. */
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
override string toStringWithContext() { /**
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() * Gets a textual representation of this element, including a textual
} * representation of the call context.
*/
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
override predicate hasLocationInfo( /**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
@@ -2986,14 +2958,59 @@ private predicate directReach(PathNodeImpl n) {
} }
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */ /** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) } private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNodeImpl n1, PathNode n2) { private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2) n1.getANonHiddenSuccessor() = n2 and directReach(n2)
} }
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
/**
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode instanceof PathNodeImpl {
PathNode() { reach(this) }
/** Gets a textual representation of this element. */
final string toString() { result = super.toString() }
/**
* Gets a textual representation of this element, including a textual
* representation of the call context.
*/
final string toStringWithContext() { result = super.toStringWithContext() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
final predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
final Node getNode() { super.getNodeEx().projectToNode() = result }
/** Gets the `FlowState` of this node. */
final FlowState getState() { result = super.getState() }
/** Gets the associated configuration. */
final Configuration getConfiguration() { result = super.getConfiguration() }
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
/** Holds if this node is a source. */
final predicate isSource() { super.isSource() }
}
/** /**
* Provides the query predicates needed to include a graph in a path-problem query. * Provides the query predicates needed to include a graph in a path-problem query.
@@ -3004,7 +3021,7 @@ module PathGraph {
/** Holds if `n` is a node in the graph of data flow path explanations. */ /** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) { query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString() key = "semmle.label" and val = n.toString()
} }
/** /**
@@ -3013,11 +3030,7 @@ module PathGraph {
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Subpaths::subpaths(arg, par, ret, out) and Subpaths::subpaths(arg, par, ret, out)
reach(arg) and
reach(par) and
reach(ret) and
reach(out)
} }
} }
@@ -3399,7 +3412,7 @@ private module Subpaths {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths02( private predicate subpaths02(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, FlowState sout, AccessPath apout NodeEx out, FlowState sout, AccessPath apout
) { ) {
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3407,14 +3420,14 @@ private module Subpaths {
} }
pragma[nomagic] pragma[nomagic]
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() } private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
/** /**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple. * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate subpaths03( private predicate subpaths03(
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
) { ) {
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode | exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
@@ -3444,7 +3457,7 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`. * `ret -> out` is summarized as the edge `arg -> out`.
*/ */
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) { predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 | exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
@@ -3460,7 +3473,7 @@ private module Subpaths {
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink. * Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/ */
predicate retReach(PathNodeImpl n) { predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out)) exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or or
exists(PathNodeImpl mid | exists(PathNodeImpl mid |
retReach(mid) and retReach(mid) and
@@ -3477,11 +3490,12 @@ private module Subpaths {
* sinks. * sinks.
*/ */
private predicate flowsTo( private predicate flowsTo(
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
Configuration configuration
) { ) {
flowsource.isSource() and flowsource.isSource() and
flowsource.getConfiguration() = configuration and flowsource.getConfiguration() = configuration and
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and flowsource.getNodeEx().asNode() = source and
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
flowsink.getNodeEx().asNode() = sink flowsink.getNodeEx().asNode() = sink
} }
@@ -3504,14 +3518,14 @@ private predicate finalStats(
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
tuples = count(PathNode pn) tuples = count(PathNodeImpl pn)
or or
fwd = false and fwd = false and
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
tuples = count(PathNode pn | reach(pn)) tuples = count(PathNode pn)
} }
/** /**