Merge branch main into rc/3.6

This commit is contained in:
Edoardo Pirovano
2022-06-21 11:15:25 +01:00
1296 changed files with 64800 additions and 9671 deletions

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* An `isBraced` predicate was added to the `Initializer` class which holds when a C++ braced initializer was used in the initialization.

View File

@@ -168,7 +168,7 @@ private predicate callsVariadicFormatter(
) {
// calls a variadic formatter with `formatParamIndex`, `outputParamIndex` linked
exists(FunctionCall fc, int format, int output |
variadicFormatter(fc.getTarget(), type, format, output) and
variadicFormatter(pragma[only_bind_into](fc.getTarget()), type, format, output) and
fc.getEnclosingFunction() = f and
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
fc.getArgument(output) = f.getParameter(outputParamIndex).getAnAccess()
@@ -176,7 +176,7 @@ private predicate callsVariadicFormatter(
or
// calls a variadic formatter with only `formatParamIndex` linked
exists(FunctionCall fc, string calledType, int format, int output |
variadicFormatter(fc.getTarget(), calledType, format, output) and
variadicFormatter(pragma[only_bind_into](fc.getTarget()), calledType, format, output) and
fc.getEnclosingFunction() = f and
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
not fc.getArgument(output) = f.getParameter(_).getAnAccess() and

View File

@@ -3854,16 +3854,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3866,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3920,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** 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) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3939,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4057,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4373,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4383,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = 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
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4398,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -3854,16 +3854,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3866,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3920,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** 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) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3939,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4057,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4373,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4383,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = 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
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4398,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -3854,16 +3854,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3866,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3920,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** 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) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3939,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4057,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4373,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4383,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = 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
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4398,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -3854,16 +3854,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3866,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3920,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** 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) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3939,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4057,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4373,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4383,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = 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
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4398,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -3854,16 +3854,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3866,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3920,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** 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) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3939,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4057,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4373,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4383,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = 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
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4398,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -49,6 +49,9 @@ class Expr extends StmtParent, @expr {
/** Gets the enclosing variable of this expression, if any. */
Variable getEnclosingVariable() { result = exprEnclosingElement(this) }
/** Gets the enclosing variable or function of this expression. */
Declaration getEnclosingDeclaration() { result = exprEnclosingElement(this) }
/** Gets a child of this expression. */
Expr getAChild() { exists(int n | result = this.getChild(n)) }

View File

@@ -3854,16 +3854,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3866,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3920,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** 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) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3939,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4057,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4373,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4383,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = 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
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4398,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -3854,16 +3854,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3866,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3920,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** 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) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3939,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4057,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4373,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4383,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = 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
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4398,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -3854,16 +3854,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3866,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3920,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** 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) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3939,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4057,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4373,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4383,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = 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
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4398,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -3854,16 +3854,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3866,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3920,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** 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) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3939,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4057,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4373,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4383,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = 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
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4398,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -100,7 +100,7 @@ class Node extends TIRDataFlowNode {
Declaration getEnclosingCallable() { none() } // overridden in subclasses
/** Gets the function to which this node belongs, if any. */
Function getFunction() { none() } // overridden in subclasses
Declaration getFunction() { none() } // overridden in subclasses
/** Gets the type of this node. */
IRType getType() { none() } // overridden in subclasses
@@ -196,7 +196,7 @@ class InstructionNode extends Node, TInstructionNode {
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = instr.getEnclosingFunction() }
override Declaration getFunction() { result = instr.getEnclosingFunction() }
override IRType getType() { result = instr.getResultIRType() }
@@ -222,7 +222,7 @@ class OperandNode extends Node, TOperandNode {
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = op.getUse().getEnclosingFunction() }
override Declaration getFunction() { result = op.getUse().getEnclosingFunction() }
override IRType getType() { result = op.getIRType() }
@@ -274,7 +274,7 @@ class StoreNodeInstr extends StoreNode, TStoreNodeInstr {
/** Gets the underlying instruction. */
Instruction getInstruction() { result = instr }
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
override IRType getType() { result = this.getInstruction().getResultIRType() }
@@ -328,7 +328,7 @@ class StoreNodeOperand extends StoreNode, TStoreNodeOperand {
/** Gets the underlying operand. */
Operand getOperand() { result = operand }
override Function getFunction() { result = operand.getDef().getEnclosingFunction() }
override Declaration getFunction() { result = operand.getDef().getEnclosingFunction() }
override IRType getType() { result = operand.getIRType() }
@@ -384,7 +384,7 @@ class ReadNode extends Node, TReadNode {
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
override IRType getType() { result = this.getInstruction().getResultIRType() }
@@ -436,7 +436,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
override IRType getType() { result instanceof IRVoidType }
@@ -673,7 +673,7 @@ class VariableNode extends Node, TVariableNode {
/** Gets the variable corresponding to this node. */
Variable getVariable() { result = v }
override Function getFunction() { none() }
override Declaration getFunction() { none() }
override Declaration getEnclosingCallable() {
// When flow crosses from one _enclosing callable_ to another, the

View File

@@ -16,7 +16,7 @@ class IRConfiguration extends TIRConfiguration {
/**
* Holds if IR should be created for function `func`. By default, holds for all functions.
*/
predicate shouldCreateIRForFunction(Language::Function func) { any() }
predicate shouldCreateIRForFunction(Language::Declaration func) { any() }
/**
* Holds if the strings used as part of an IR dump should be generated for function `func`.
@@ -25,7 +25,7 @@ class IRConfiguration extends TIRConfiguration {
* of debug strings for IR that will not be dumped. We still generate the actual IR for these
* functions, however, to preserve the results of any interprocedural analysis.
*/
predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() }
predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) { any() }
}
private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration()

View File

@@ -97,7 +97,7 @@ class IRBlockBase extends TIRBlock {
/**
* Gets the `Function` that contains this block.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = getFirstInstruction(this).getEnclosingFunction()
}
}

View File

@@ -524,4 +524,23 @@ module InstructionConsistency {
"' has a `this` argument operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
query predicate nonUniqueIRVariable(
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
exists(VariableInstruction vi, IRVariable v1, IRVariable v2 |
instr = vi and vi.getIRVariable() = v1 and vi.getIRVariable() = v2 and v1 != v2
) and
message =
"Variable instruction '" + instr.toString() +
"' has multiple associated variables, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
or
instr.getOpcode() instanceof Opcode::VariableAddress and
not instr instanceof VariableInstruction and
message =
"Variable address instruction '" + instr.toString() +
"' has no associated variable, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
}

View File

@@ -18,7 +18,7 @@ private import Imports::IRType
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
Language::Function func;
Language::Declaration func;
IRVariable() {
this = TIRUserVariable(_, _, func) or
@@ -79,7 +79,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the function that references this variable.
*/
final Language::Function getEnclosingFunction() { result = func }
final Language::Declaration getEnclosingFunction() { result = func }
}
/**
@@ -246,7 +246,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
final override string toString() { result = "#ellipsis" }
final override int getIndex() { result = func.getNumberOfParameters() }
final override int getIndex() { result = func.(Language::Function).getNumberOfParameters() }
}
/**

View File

@@ -194,7 +194,7 @@ class Instruction extends Construction::TStageInstruction {
/**
* Gets the function that contains this instruction.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = this.getEnclosingIRFunction().getFunction()
}

View File

@@ -26,20 +26,20 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
* Holds if the IR for `func` should be printed. By default, holds for all
* functions.
*/
predicate shouldPrintFunction(Language::Function func) { any() }
predicate shouldPrintFunction(Language::Declaration decl) { any() }
}
/**
* Override of `IRConfiguration` to only evaluate debug strings for the functions that are to be dumped.
*/
private class FilteredIRConfiguration extends IRConfiguration {
override predicate shouldEvaluateDebugStringsForFunction(Language::Function func) {
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
shouldPrintFunction(func)
}
}
private predicate shouldPrintFunction(Language::Function func) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(func))
private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
}
private string getAdditionalInstructionProperty(Instruction instr, string key) {

View File

@@ -5,23 +5,28 @@
private import IRFunctionBaseInternal
private newtype TIRFunction =
MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) }
TFunctionIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } or
TVarInitIRFunction(Language::GlobalVariable var) { IRConstruction::Raw::varHasIRFunc(var) }
/**
* The IR for a function. This base class contains only the predicates that are the same between all
* phases of the IR. Each instantiation of `IRFunction` extends this class.
*/
class IRFunctionBase extends TIRFunction {
Language::Function func;
Language::Declaration decl;
IRFunctionBase() { this = MkIRFunction(func) }
IRFunctionBase() {
this = TFunctionIRFunction(decl)
or
this = TVarInitIRFunction(decl)
}
/** Gets a textual representation of this element. */
final string toString() { result = "IR: " + func.toString() }
final string toString() { result = "IR: " + decl.toString() }
/** Gets the function whose IR is represented. */
final Language::Function getFunction() { result = func }
final Language::Declaration getFunction() { result = decl }
/** Gets the location of the function. */
final Language::Location getLocation() { result = func.getLocation() }
final Language::Location getLocation() { result = decl.getLocation() }
}

View File

@@ -2,21 +2,21 @@ private import TIRVariableInternal
private import Imports::TempVariableTag
newtype TIRVariable =
TIRUserVariable(Language::Variable var, Language::LanguageType type, Language::Function func) {
TIRUserVariable(Language::Variable var, Language::LanguageType type, Language::Declaration func) {
Construction::hasUserVariable(func, var, type)
} or
TIRTempVariable(
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
Language::Declaration func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
Construction::hasTempVariable(func, ast, tag, type)
} or
TIRDynamicInitializationFlag(
Language::Function func, Language::Variable var, Language::LanguageType type
Language::Declaration func, Language::Variable var, Language::LanguageType type
) {
Construction::hasDynamicInitializationFlag(func, var, type)
} or
TIRStringLiteral(
Language::Function func, Language::AST ast, Language::LanguageType type,
Language::Declaration func, Language::AST ast, Language::LanguageType type,
Language::StringLiteral literal
) {
Construction::hasStringLiteral(func, ast, type, literal)

View File

@@ -97,7 +97,7 @@ class IRBlockBase extends TIRBlock {
/**
* Gets the `Function` that contains this block.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = getFirstInstruction(this).getEnclosingFunction()
}
}

View File

@@ -524,4 +524,23 @@ module InstructionConsistency {
"' has a `this` argument operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
query predicate nonUniqueIRVariable(
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
exists(VariableInstruction vi, IRVariable v1, IRVariable v2 |
instr = vi and vi.getIRVariable() = v1 and vi.getIRVariable() = v2 and v1 != v2
) and
message =
"Variable instruction '" + instr.toString() +
"' has multiple associated variables, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
or
instr.getOpcode() instanceof Opcode::VariableAddress and
not instr instanceof VariableInstruction and
message =
"Variable address instruction '" + instr.toString() +
"' has no associated variable, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
}

View File

@@ -18,7 +18,7 @@ private import Imports::IRType
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
Language::Function func;
Language::Declaration func;
IRVariable() {
this = TIRUserVariable(_, _, func) or
@@ -79,7 +79,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the function that references this variable.
*/
final Language::Function getEnclosingFunction() { result = func }
final Language::Declaration getEnclosingFunction() { result = func }
}
/**
@@ -246,7 +246,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
final override string toString() { result = "#ellipsis" }
final override int getIndex() { result = func.getNumberOfParameters() }
final override int getIndex() { result = func.(Language::Function).getNumberOfParameters() }
}
/**

View File

@@ -194,7 +194,7 @@ class Instruction extends Construction::TStageInstruction {
/**
* Gets the function that contains this instruction.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = this.getEnclosingIRFunction().getFunction()
}

View File

@@ -26,20 +26,20 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
* Holds if the IR for `func` should be printed. By default, holds for all
* functions.
*/
predicate shouldPrintFunction(Language::Function func) { any() }
predicate shouldPrintFunction(Language::Declaration decl) { any() }
}
/**
* Override of `IRConfiguration` to only evaluate debug strings for the functions that are to be dumped.
*/
private class FilteredIRConfiguration extends IRConfiguration {
override predicate shouldEvaluateDebugStringsForFunction(Language::Function func) {
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
shouldPrintFunction(func)
}
}
private predicate shouldPrintFunction(Language::Function func) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(func))
private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
}
private string getAdditionalInstructionProperty(Instruction instr, string key) {

View File

@@ -13,6 +13,7 @@ private import TranslatedElement
private import TranslatedExpr
private import TranslatedStmt
private import TranslatedFunction
private import TranslatedGlobalVar
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
instruction = TRawInstruction(result, _)
@@ -35,29 +36,41 @@ module Raw {
cached
predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) }
cached
predicate varHasIRFunc(GlobalOrNamespaceVariable var) {
var.hasInitializer() and
(
not var.getType().isDeeplyConst()
or
var.getInitializer().getExpr() instanceof StringLiteral
)
}
cached
predicate hasInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _)
}
cached
predicate hasUserVariable(Function func, Variable var, CppType type) {
getTranslatedFunction(func).hasUserVariable(var, type)
predicate hasUserVariable(Declaration decl, Variable var, CppType type) {
getTranslatedFunction(decl).hasUserVariable(var, type)
or
getTranslatedVarInit(decl).hasUserVariable(var, type)
}
cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
predicate hasTempVariable(Declaration decl, Locatable ast, TempVariableTag tag, CppType type) {
exists(TranslatedElement element |
element.getAst() = ast and
func = element.getFunction() and
decl = element.getFunction() and
element.hasTempVariable(tag, type)
)
}
cached
predicate hasStringLiteral(Function func, Locatable ast, CppType type, StringLiteral literal) {
predicate hasStringLiteral(Declaration decl, Locatable ast, CppType type, StringLiteral literal) {
literal = ast and
literal.getEnclosingFunction() = func and
literal.getEnclosingDeclaration() = decl and
getTypeForPRValue(literal.getType()) = type
}

View File

@@ -180,7 +180,7 @@ abstract class TranslatedSideEffects extends TranslatedElement {
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = getAst() }
final override Function getFunction() { result = getExpr().getEnclosingFunction() }
final override Declaration getFunction() { result = getExpr().getEnclosingDeclaration() }
final override TranslatedElement getChild(int i) {
result =
@@ -375,7 +375,7 @@ abstract class TranslatedSideEffect extends TranslatedElement {
kind instanceof GotoEdge
}
final override Function getFunction() { result = getParent().getFunction() }
final override Declaration getFunction() { result = getParent().getFunction() }
final override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
tag = OnlyInstructionTag() and
@@ -436,13 +436,6 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
result = index
}
/**
* Gets the `TranslatedFunction` containing this expression.
*/
final TranslatedFunction getEnclosingFunction() {
result = getTranslatedFunction(call.getEnclosingFunction())
}
final override predicate sideEffectInstruction(Opcode opcode, CppType type) {
opcode = sideEffectOpcode and
(

View File

@@ -25,9 +25,9 @@ private Element getRealParent(Expr expr) {
result.(Destructor).getADestruction() = expr
}
IRUserVariable getIRUserVariable(Function func, Variable var) {
IRUserVariable getIRUserVariable(Declaration decl, Variable var) {
result.getVariable() = var and
result.getEnclosingFunction() = func
result.getEnclosingFunction() = decl
}
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
@@ -67,7 +67,8 @@ private predicate ignoreExprAndDescendants(Expr expr) {
exists(Initializer init, StaticStorageDurationVariable var |
init = var.getInitializer() and
not var.hasDynamicInitialization() and
expr = init.getExpr().getFullyConverted()
expr = init.getExpr().getFullyConverted() and
not var instanceof GlobalOrNamespaceVariable
)
or
// Ignore descendants of `__assume` expressions, since we translated these to `NoOp`.
@@ -117,7 +118,8 @@ private predicate ignoreExprOnly(Expr expr) {
// should not be translated.
exists(NewOrNewArrayExpr new | expr = new.getAllocatorCall().getArgument(0))
or
not translateFunction(expr.getEnclosingFunction())
not translateFunction(expr.getEnclosingFunction()) and
not Raw::varHasIRFunc(expr.getEnclosingVariable())
or
// We do not yet translate destructors properly, so for now we ignore the
// destructor call. We do, however, translate the expression being
@@ -662,7 +664,8 @@ newtype TTranslatedElement =
opcode = getASideEffectOpcode(call, -1)
} or
// The side effect that initializes newly-allocated memory.
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) }
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) } or
TTranslatedGlobalOrNamespaceVarInit(GlobalOrNamespaceVariable var) { Raw::varHasIRFunc(var) }
/**
* Gets the index of the first explicitly initialized element in `initList`
@@ -792,7 +795,7 @@ abstract class TranslatedElement extends TTranslatedElement {
/**
* Gets the `Function` that contains this element.
*/
abstract Function getFunction();
abstract Declaration getFunction();
/**
* Gets the successor instruction of the instruction that was generated by
@@ -942,3 +945,14 @@ abstract class TranslatedElement extends TTranslatedElement {
*/
final TranslatedElement getParent() { result.getAChild() = this }
}
/**
* Represents the IR translation of a root element, either a function or a global variable.
*/
abstract class TranslatedRootElement extends TranslatedElement {
TranslatedRootElement() {
this instanceof TTranslatedFunction
or
this instanceof TTranslatedGlobalOrNamespaceVarInit
}
}

View File

@@ -12,6 +12,7 @@ private import TranslatedElement
private import TranslatedFunction
private import TranslatedInitialization
private import TranslatedStmt
private import TranslatedGlobalVar
import TranslatedCall
/**
@@ -78,7 +79,7 @@ abstract class TranslatedExpr extends TranslatedElement {
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Function getFunction() { result = expr.getEnclosingFunction() }
final override Declaration getFunction() { result = expr.getEnclosingDeclaration() }
/**
* Gets the expression from which this `TranslatedExpr` is generated.
@@ -88,8 +89,10 @@ abstract class TranslatedExpr extends TranslatedElement {
/**
* Gets the `TranslatedFunction` containing this expression.
*/
final TranslatedFunction getEnclosingFunction() {
final TranslatedRootElement getEnclosingFunction() {
result = getTranslatedFunction(expr.getEnclosingFunction())
or
result = getTranslatedVarInit(expr.getEnclosingVariable())
}
}
@@ -787,7 +790,7 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = ThisAddressTag() and
result = this.getEnclosingFunction().getThisVariable()
result = this.getEnclosingFunction().(TranslatedFunction).getThisVariable()
}
}
@@ -838,7 +841,7 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = getIRUserVariable(expr.getEnclosingFunction(), expr.getTarget())
result = getIRUserVariable(expr.getEnclosingDeclaration(), expr.getTarget())
}
}
@@ -2522,7 +2525,7 @@ class TranslatedVarArgsStart extends TranslatedNonConstantExpr {
final override IRVariable getInstructionVariable(InstructionTag tag) {
tag = VarArgsStartEllipsisAddressTag() and
result = this.getEnclosingFunction().getEllipsisVariable()
result = this.getEnclosingFunction().(TranslatedFunction).getEllipsisVariable()
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {

View File

@@ -58,7 +58,7 @@ predicate hasReturnValue(Function func) { not func.getUnspecifiedType() instance
* Represents the IR translation of a function. This is the root elements for
* all other elements associated with this function.
*/
class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
Function func;
TranslatedFunction() { this = TTranslatedFunction(func) }

View File

@@ -0,0 +1,132 @@
import semmle.code.cpp.ir.implementation.raw.internal.TranslatedElement
private import cpp
private import semmle.code.cpp.ir.implementation.IRType
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import TranslatedInitialization
private import InstructionTag
private import semmle.code.cpp.ir.internal.IRUtilities
class TranslatedGlobalOrNamespaceVarInit extends TranslatedRootElement,
TTranslatedGlobalOrNamespaceVarInit, InitializationContext {
GlobalOrNamespaceVariable var;
TranslatedGlobalOrNamespaceVarInit() { this = TTranslatedGlobalOrNamespaceVarInit(var) }
override string toString() { result = var.toString() }
final override GlobalOrNamespaceVariable getAst() { result = var }
final override Declaration getFunction() { result = var }
final Location getLocation() { result = var.getLocation() }
override Instruction getFirstInstruction() { result = this.getInstruction(EnterFunctionTag()) }
override TranslatedElement getChild(int n) {
n = 1 and
result = getTranslatedInitialization(var.getInitializer().getExpr().getFullyConverted())
}
override predicate hasInstruction(Opcode op, InstructionTag tag, CppType type) {
op instanceof Opcode::EnterFunction and
tag = EnterFunctionTag() and
type = getVoidType()
or
op instanceof Opcode::AliasedDefinition and
tag = AliasedDefinitionTag() and
type = getUnknownType()
or
op instanceof Opcode::VariableAddress and
tag = InitializerVariableAddressTag() and
type = getTypeForGLValue(var.getType())
or
op instanceof Opcode::ReturnVoid and
tag = ReturnTag() and
type = getVoidType()
or
op instanceof Opcode::AliasedUse and
tag = AliasedUseTag() and
type = getVoidType()
or
op instanceof Opcode::ExitFunction and
tag = ExitFunctionTag() and
type = getVoidType()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
(
tag = EnterFunctionTag() and
result = this.getInstruction(AliasedDefinitionTag())
or
tag = AliasedDefinitionTag() and
result = this.getInstruction(InitializerVariableAddressTag())
or
tag = InitializerVariableAddressTag() and
result = getChild(1).getFirstInstruction()
or
tag = ReturnTag() and
result = this.getInstruction(AliasedUseTag())
or
tag = AliasedUseTag() and
result = this.getInstruction(ExitFunctionTag())
)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getChild(1) and
result = this.getInstruction(ReturnTag())
}
final override CppType getInstructionMemoryOperandType(
InstructionTag tag, TypedOperandTag operandTag
) {
tag = AliasedUseTag() and
operandTag instanceof SideEffectOperandTag and
result = getUnknownType()
}
override IRUserVariable getInstructionVariable(InstructionTag tag) {
tag = InitializerVariableAddressTag() and
result.getVariable() = var and
result.getEnclosingFunction() = var
}
override Instruction getTargetAddress() {
result = this.getInstruction(InitializerVariableAddressTag())
}
override Type getTargetType() { result = var.getUnspecifiedType() }
/**
* Holds if this variable defines or accesses variable `var` with type `type`. This includes all
* parameters and local variables, plus any global variables or static data members that are
* directly accessed by the function.
*/
final predicate hasUserVariable(Variable varUsed, CppType type) {
(
(
varUsed instanceof GlobalOrNamespaceVariable
or
varUsed instanceof MemberVariable and not varUsed instanceof Field
) and
exists(VariableAccess access |
access.getTarget() = varUsed and
access.getEnclosingVariable() = var
)
or
var = varUsed
or
varUsed.(LocalScopeVariable).getEnclosingElement*() = var
or
varUsed.(Parameter).getCatchBlock().getEnclosingElement*() = var
) and
type = getTypeForPRValue(getVariableType(varUsed))
}
}
TranslatedGlobalOrNamespaceVarInit getTranslatedVarInit(GlobalOrNamespaceVariable var) {
result.getAst() = var
}

View File

@@ -137,7 +137,10 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
final override string toString() { result = "init: " + expr.toString() }
final override Function getFunction() { result = expr.getEnclosingFunction() }
final override Declaration getFunction() {
result = expr.getEnclosingFunction() or
result = expr.getEnclosingVariable().(GlobalOrNamespaceVariable)
}
final override Locatable getAst() { result = expr }
@@ -486,7 +489,10 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = getAst() }
final override Function getFunction() { result = ast.getEnclosingFunction() }
final override Declaration getFunction() {
result = ast.getEnclosingFunction() or
result = ast.getEnclosingVariable().(GlobalOrNamespaceVariable)
}
final override Instruction getFirstInstruction() { result = getInstruction(getFieldAddressTag()) }
@@ -633,7 +639,11 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = getAst() }
final override Function getFunction() { result = initList.getEnclosingFunction() }
final override Declaration getFunction() {
result = initList.getEnclosingFunction()
or
result = initList.getEnclosingVariable().(GlobalOrNamespaceVariable)
}
final override Instruction getFirstInstruction() { result = getInstruction(getElementIndexTag()) }

View File

@@ -97,7 +97,7 @@ class IRBlockBase extends TIRBlock {
/**
* Gets the `Function` that contains this block.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = getFirstInstruction(this).getEnclosingFunction()
}
}

View File

@@ -524,4 +524,23 @@ module InstructionConsistency {
"' has a `this` argument operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
query predicate nonUniqueIRVariable(
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
exists(VariableInstruction vi, IRVariable v1, IRVariable v2 |
instr = vi and vi.getIRVariable() = v1 and vi.getIRVariable() = v2 and v1 != v2
) and
message =
"Variable instruction '" + instr.toString() +
"' has multiple associated variables, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
or
instr.getOpcode() instanceof Opcode::VariableAddress and
not instr instanceof VariableInstruction and
message =
"Variable address instruction '" + instr.toString() +
"' has no associated variable, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
}

View File

@@ -18,7 +18,7 @@ private import Imports::IRType
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
Language::Function func;
Language::Declaration func;
IRVariable() {
this = TIRUserVariable(_, _, func) or
@@ -79,7 +79,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the function that references this variable.
*/
final Language::Function getEnclosingFunction() { result = func }
final Language::Declaration getEnclosingFunction() { result = func }
}
/**
@@ -246,7 +246,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
final override string toString() { result = "#ellipsis" }
final override int getIndex() { result = func.getNumberOfParameters() }
final override int getIndex() { result = func.(Language::Function).getNumberOfParameters() }
}
/**

View File

@@ -194,7 +194,7 @@ class Instruction extends Construction::TStageInstruction {
/**
* Gets the function that contains this instruction.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = this.getEnclosingIRFunction().getFunction()
}

View File

@@ -26,20 +26,20 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
* Holds if the IR for `func` should be printed. By default, holds for all
* functions.
*/
predicate shouldPrintFunction(Language::Function func) { any() }
predicate shouldPrintFunction(Language::Declaration decl) { any() }
}
/**
* Override of `IRConfiguration` to only evaluate debug strings for the functions that are to be dumped.
*/
private class FilteredIRConfiguration extends IRConfiguration {
override predicate shouldEvaluateDebugStringsForFunction(Language::Function func) {
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
shouldPrintFunction(func)
}
}
private predicate shouldPrintFunction(Language::Function func) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(func))
private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
}
private string getAdditionalInstructionProperty(Instruction instr, string key) {

View File

@@ -50,12 +50,16 @@ class AutomaticVariable = Cpp::StackVariable;
class StaticVariable = Cpp::Variable;
class GlobalVariable = Cpp::GlobalOrNamespaceVariable;
class Parameter = Cpp::Parameter;
class Field = Cpp::Field;
class BuiltInOperation = Cpp::BuiltInOperation;
class Declaration = Cpp::Declaration;
// TODO: Remove necessity for these.
class Expr = Cpp::Expr;

View File

@@ -17,6 +17,36 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
/**
* A Linux system call.
*/
class SystemCallFunction extends Function {
SystemCallFunction() {
exists(MacroInvocation m |
m.getMacro().getName().matches("SYSCALL\\_DEFINE%") and
this = m.getEnclosingFunction()
)
}
}
/**
* A value that comes from a Linux system call (sources).
*/
class SystemCallSource extends DataFlow::Node {
SystemCallSource() {
exists(FunctionCall fc |
fc.getTarget() instanceof SystemCallFunction and
(
this.asDefiningArgument() = fc.getAnArgument().getAChild*() or
this.asExpr() = fc
)
)
}
}
/**
* Macros used to check the value (barriers).
*/
class WriteAccessCheckMacro extends Macro {
VariableAccess va;
@@ -28,6 +58,9 @@ class WriteAccessCheckMacro extends Macro {
VariableAccess getArgument() { result = va }
}
/**
* The `unsafe_put_user` macro and its uses (sinks).
*/
class UnSafePutUserMacro extends Macro {
PointerDereferenceExpr writeUserPtr;
@@ -42,15 +75,13 @@ class UnSafePutUserMacro extends Macro {
}
}
class ExploitableUserModePtrParam extends Parameter {
class ExploitableUserModePtrParam extends SystemCallSource {
ExploitableUserModePtrParam() {
not exists(WriteAccessCheckMacro writeAccessCheck |
DataFlow::localFlow(DataFlow::parameterNode(this),
DataFlow::exprNode(writeAccessCheck.getArgument()))
) and
exists(UnSafePutUserMacro unsafePutUser |
DataFlow::localFlow(DataFlow::parameterNode(this),
DataFlow::exprNode(unsafePutUser.getUserModePtr()))
DataFlow::localFlow(this, DataFlow::exprNode(unsafePutUser.getUserModePtr()))
) and
not exists(WriteAccessCheckMacro writeAccessCheck |
DataFlow::localFlow(this, DataFlow::exprNode(writeAccessCheck.getArgument()))
)
}
}

View File

@@ -239,12 +239,24 @@ private string getColumnString(TColumn column) {
/**
* RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or
* more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character
* must not be a digit), optionally followed by `=` and the expected value.
* more comma-separated tags optionally followed by `=` and the expected value.
*
* Tags must be only letters, digits, `-` and `_` (note that the first character
* must not be a digit), but can contain anything enclosed in a single set of
* square brackets.
*
* Examples:
* - `tag`
* - `tag=value`
* - `tag,tag2=value`
* - `tag[foo bar]=value`
*
* Not allowed:
* - `tag[[[foo bar]`
*/
private string expectationPattern() {
exists(string tag, string tags, string value |
tag = "[A-Za-z-_][A-Za-z-_0-9]*" and
tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]\\]]*\\])*" and
tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and
// In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`.
// For example, `b"foo"`.

View File

@@ -1 +1,3 @@
| test.cpp:14:16:14:16 | p | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:14:16:14:16 | p | p |
| test.cpp:20:21:20:22 | ref arg & ... | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:20:21:20:22 | ref arg & ... | ref arg & ... |
| test.cpp:41:21:41:22 | ref arg & ... | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:41:21:41:22 | ref arg & ... | ref arg & ... |
| test.cpp:69:21:69:27 | ref arg & ... | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:69:21:69:27 | ref arg & ... | ref arg & ... |

View File

@@ -1,7 +1,11 @@
typedef unsigned long size_t;
void SYSC_SOMESYSTEMCALL(void *param);
#define SYSCALL_DEFINE(name, ...) \
void do_sys_##name(); \
void sys_##name(...) { do_sys_##name(); } \
void do_sys_##name()
SYSCALL_DEFINE(somesystemcall, void *param) {};
bool user_access_begin_impl(const void *where, size_t sz);
void user_access_end_impl();
@@ -13,14 +17,14 @@ void unsafe_put_user_impl(int what, const void *where, size_t sz);
void test1(int p)
{
SYSC_SOMESYSTEMCALL(&p);
sys_somesystemcall(&p);
unsafe_put_user(123, &p); // BAD
}
void test2(int p)
{
SYSC_SOMESYSTEMCALL(&p);
sys_somesystemcall(&p);
if (user_access_begin(&p, sizeof(p)))
{
@@ -34,16 +38,16 @@ void test3()
{
int v;
SYSC_SOMESYSTEMCALL(&v);
sys_somesystemcall(&v);
unsafe_put_user(123, &v); // BAD [NOT DETECTED]
unsafe_put_user(123, &v); // BAD
}
void test4()
{
int v;
SYSC_SOMESYSTEMCALL(&v);
sys_somesystemcall(&v);
if (user_access_begin(&v, sizeof(v)))
{
@@ -62,16 +66,16 @@ void test5()
{
data myData;
SYSC_SOMESYSTEMCALL(&myData);
sys_somesystemcall(&myData);
unsafe_put_user(123, &(myData.x)); // BAD [NOT DETECTED]
unsafe_put_user(123, &(myData.x)); // BAD
}
void test6()
{
data myData;
SYSC_SOMESYSTEMCALL(&myData);
sys_somesystemcall(&myData);
if (user_access_begin(&myData, sizeof(myData)))
{

View File

@@ -0,0 +1,49 @@
int *global_ptr;
const char *global_string = "hello, world";
void test1(int *ptr, int &ref)
{
const char *str;
int v, *p;
char c;
v = *ptr; // `ptr` dereferenced
v = ptr[0]; // `ptr` dereferenced
p = ptr;
*ptr = 0; // `ptr` dereferenced
ptr[0] = 0; // `ptr` dereferenced
ptr = 0;
(*ptr)++; // `ptr`, `*ptr` dereferenced
*(ptr++); // `ptr++` dereferenced
ptr++;
v = ref; // (`ref` implicitly dereferenced, not detected)
p = &ref;
ref = 0; // (`ref` implicitly dereferenced, not detected)
ref++; // (`ref` implicitly dereferenced, not detected)
*global_ptr; // `global_ptr` dereferenced
str = global_string;
c = global_string[5]; // `global_string` dereferenced
}
struct myStruct
{
int x;
void f() {};
void (*g)();
};
void test1(myStruct *ms)
{
void (*h)();
ms;
ms->x; // `ms` dereferenced
ms->f(); // `ms` dereferenced
ms->g(); // `ms` dereferenced
h = ms->g; // `ms` dereferenced
}

View File

@@ -0,0 +1,13 @@
| dereferenced.cpp:11:6:11:9 | * ... | dereferenced.cpp:11:7:11:9 | ptr |
| dereferenced.cpp:12:6:12:11 | access to array | dereferenced.cpp:12:6:12:8 | ptr |
| dereferenced.cpp:15:2:15:5 | * ... | dereferenced.cpp:15:3:15:5 | ptr |
| dereferenced.cpp:16:2:16:7 | access to array | dereferenced.cpp:16:2:16:4 | ptr |
| dereferenced.cpp:19:3:19:6 | * ... | dereferenced.cpp:19:4:19:6 | ptr |
| dereferenced.cpp:19:4:19:6 | ptr | dereferenced.cpp:19:3:19:6 | * ... |
| dereferenced.cpp:20:2:20:9 | * ... | dereferenced.cpp:20:4:20:8 | ... ++ |
| dereferenced.cpp:28:2:28:12 | * ... | dereferenced.cpp:28:3:28:12 | global_ptr |
| dereferenced.cpp:30:6:30:21 | access to array | dereferenced.cpp:30:6:30:18 | global_string |
| dereferenced.cpp:45:6:45:6 | x | dereferenced.cpp:45:2:45:3 | ms |
| dereferenced.cpp:46:6:46:6 | call to f | dereferenced.cpp:46:2:46:3 | ms |
| dereferenced.cpp:47:6:47:6 | g | dereferenced.cpp:47:2:47:3 | ms |
| dereferenced.cpp:48:10:48:10 | g | dereferenced.cpp:48:6:48:7 | ms |

View File

@@ -0,0 +1,6 @@
import cpp
import semmle.code.cpp.controlflow.Dereferenced
from Expr op, Expr e
where dereferencedByOperation(op, e) // => dereferenced(e)
select op, e

View File

@@ -199,7 +199,9 @@ postWithInFlow
| example.c:28:22:28:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:23:28:25 | pos [post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:5:9:5:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:9:5:9:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:13:5:13:19 | flowTestGlobal1 [post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:16:12:16:26 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:23:5:23:19 | flowTestGlobal2 [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:8:6:8:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:9:6:9:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -218,10 +220,10 @@ postWithInFlow
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:3 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:14 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:14 | v [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:15:23:15 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:7:28:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:10:31:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:10:31:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -12,4 +12,11 @@ predicate locationIsInStandardHeaders(Location loc) {
*
* This predicate excludes functions defined in standard headers.
*/
predicate shouldDumpFunction(Function func) { not locationIsInStandardHeaders(func.getLocation()) }
predicate shouldDumpFunction(Declaration decl) {
not locationIsInStandardHeaders(decl.getLocation()) and
(
not decl instanceof Variable
or
decl.(GlobalOrNamespaceVariable).hasInitializer()
)
}

View File

@@ -23,6 +23,7 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -23,6 +23,7 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -1816,4 +1816,18 @@ void switch_initialization(int x) {
}
}
int global_1;
int global_2 = 1;
const int global_3 = 2;
constructor_only global_4(1);
constructor_only global_5 = constructor_only(2);
char *global_string = "global string";
int global_6 = global_2;
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -4743,6 +4743,14 @@
| ir.cpp:1034:6:1034:20 | ChiTotal | total:m1034_2 |
| ir.cpp:1034:6:1034:20 | SideEffect | m1034_3 |
| ir.cpp:1035:15:1035:15 | Address | &:r1035_1 |
| ir.cpp:1038:6:1038:8 | Address | &:r1038_3 |
| ir.cpp:1038:6:1038:8 | SideEffect | ~m1038_8 |
| ir.cpp:1038:12:1038:18 | Address | &:r1038_4 |
| ir.cpp:1038:12:1038:18 | Address | &:r1038_4 |
| ir.cpp:1038:12:1038:18 | ChiPartial | partial:m1038_7 |
| ir.cpp:1038:12:1038:18 | ChiTotal | total:m1038_2 |
| ir.cpp:1038:12:1038:18 | Load | m1038_5 |
| ir.cpp:1038:12:1038:18 | StoreValue | r1038_6 |
| ir.cpp:1038:14:1038:14 | Address | &:r1038_5 |
| ir.cpp:1038:14:1038:14 | Address | &:r1038_5 |
| ir.cpp:1038:14:1038:14 | Address | &:r1038_5 |
@@ -4833,6 +4841,9 @@
| ir.cpp:1043:24:1043:24 | SideEffect | ~m1043_20 |
| ir.cpp:1043:31:1043:31 | Address | &:r1043_9 |
| ir.cpp:1043:36:1043:55 | Address | &:r1043_11 |
| ir.cpp:1043:43:1043:43 | Address | &:r1043_16 |
| ir.cpp:1043:43:1043:43 | Arg(this) | this:r1043_16 |
| ir.cpp:1043:43:1043:43 | SideEffect | ~m1043_20 |
| ir.cpp:1043:43:1043:54 | Address | &:r1043_22 |
| ir.cpp:1043:43:1043:54 | Address | &:r1043_24 |
| ir.cpp:1043:43:1043:54 | Address | &:r1043_25 |
@@ -4853,11 +4864,8 @@
| ir.cpp:1043:45:1043:49 | SideEffect | ~m1043_4 |
| ir.cpp:1043:45:1043:49 | Unary | r1043_13 |
| ir.cpp:1043:45:1043:49 | Unary | r1043_15 |
| ir.cpp:1043:52:1043:52 | Address | &:r1043_16 |
| ir.cpp:1043:52:1043:52 | Arg(this) | this:r1043_16 |
| ir.cpp:1043:52:1043:52 | SideEffect | ~m1043_20 |
| ir.cpp:1043:54:1043:54 | Load | ~m1043_20 |
| ir.cpp:1043:54:1043:54 | Right | r1043_26 |
| ir.cpp:1043:53:1043:53 | Load | ~m1043_20 |
| ir.cpp:1043:53:1043:53 | Right | r1043_26 |
| ir.cpp:1043:58:1043:58 | ChiPartial | partial:m1043_9 |
| ir.cpp:1043:58:1043:58 | ChiTotal | total:m1043_3 |
| ir.cpp:1043:58:1043:58 | StoreValue | r1043_8 |
@@ -4972,6 +4980,9 @@
| ir.cpp:1047:34:1047:34 | SideEffect | ~m1047_20 |
| ir.cpp:1047:41:1047:41 | Address | &:r1047_9 |
| ir.cpp:1047:46:1047:65 | Address | &:r1047_11 |
| ir.cpp:1047:53:1047:53 | Address | &:r1047_16 |
| ir.cpp:1047:53:1047:53 | Arg(this) | this:r1047_16 |
| ir.cpp:1047:53:1047:53 | SideEffect | ~m1047_20 |
| ir.cpp:1047:53:1047:64 | Address | &:r1047_23 |
| ir.cpp:1047:53:1047:64 | Load | ~m1047_20 |
| ir.cpp:1047:53:1047:64 | StoreValue | r1047_24 |
@@ -4986,9 +4997,6 @@
| ir.cpp:1047:55:1047:59 | SideEffect | ~m1047_4 |
| ir.cpp:1047:55:1047:59 | Unary | r1047_13 |
| ir.cpp:1047:55:1047:59 | Unary | r1047_15 |
| ir.cpp:1047:62:1047:62 | Address | &:r1047_16 |
| ir.cpp:1047:62:1047:62 | Arg(this) | this:r1047_16 |
| ir.cpp:1047:62:1047:62 | SideEffect | ~m1047_20 |
| ir.cpp:1047:63:1047:63 | Right | r1047_22 |
| ir.cpp:1047:68:1047:68 | StoreValue | r1047_8 |
| ir.cpp:1047:68:1047:68 | Unary | r1047_7 |
@@ -5097,6 +5105,9 @@
| ir.cpp:1051:39:1051:39 | SideEffect | ~m1051_20 |
| ir.cpp:1051:46:1051:46 | Address | &:r1051_9 |
| ir.cpp:1051:51:1051:70 | Address | &:r1051_11 |
| ir.cpp:1051:58:1051:58 | Address | &:r1051_16 |
| ir.cpp:1051:58:1051:58 | Arg(this) | this:r1051_16 |
| ir.cpp:1051:58:1051:58 | SideEffect | ~m1051_20 |
| ir.cpp:1051:58:1051:69 | Address | &:r1051_22 |
| ir.cpp:1051:58:1051:69 | Address | &:r1051_24 |
| ir.cpp:1051:58:1051:69 | Address | &:r1051_26 |
@@ -5117,9 +5128,6 @@
| ir.cpp:1051:60:1051:64 | SideEffect | ~m1051_4 |
| ir.cpp:1051:60:1051:64 | Unary | r1051_13 |
| ir.cpp:1051:60:1051:64 | Unary | r1051_15 |
| ir.cpp:1051:67:1051:67 | Address | &:r1051_16 |
| ir.cpp:1051:67:1051:67 | Arg(this) | this:r1051_16 |
| ir.cpp:1051:67:1051:67 | SideEffect | ~m1051_20 |
| ir.cpp:1051:73:1051:73 | ChiPartial | partial:m1051_9 |
| ir.cpp:1051:73:1051:73 | ChiTotal | total:m1051_3 |
| ir.cpp:1051:73:1051:73 | StoreValue | r1051_8 |
@@ -5184,6 +5192,9 @@
| ir.cpp:1054:49:1054:49 | SideEffect | ~m1054_20 |
| ir.cpp:1054:56:1054:56 | Address | &:r1054_9 |
| ir.cpp:1054:61:1054:88 | Address | &:r1054_11 |
| ir.cpp:1054:68:1054:68 | Address | &:r1054_16 |
| ir.cpp:1054:68:1054:68 | Arg(this) | this:r1054_16 |
| ir.cpp:1054:68:1054:68 | SideEffect | ~m1054_20 |
| ir.cpp:1054:68:1054:87 | Address | &:r1054_37 |
| ir.cpp:1054:68:1054:87 | Load | ~m1054_20 |
| ir.cpp:1054:68:1054:87 | StoreValue | r1054_38 |
@@ -5198,9 +5209,6 @@
| ir.cpp:1054:70:1054:74 | SideEffect | ~m1054_4 |
| ir.cpp:1054:70:1054:74 | Unary | r1054_13 |
| ir.cpp:1054:70:1054:74 | Unary | r1054_15 |
| ir.cpp:1054:77:1054:77 | Address | &:r1054_16 |
| ir.cpp:1054:77:1054:77 | Arg(this) | this:r1054_16 |
| ir.cpp:1054:77:1054:77 | SideEffect | ~m1054_20 |
| ir.cpp:1054:78:1054:82 | Address | &:r1054_22 |
| ir.cpp:1054:78:1054:82 | Address | &:r1054_24 |
| ir.cpp:1054:78:1054:82 | Left | r1054_25 |
@@ -8457,6 +8465,45 @@
| ir.cpp:1815:14:1815:15 | Address | &:r1815_1 |
| ir.cpp:1815:14:1815:15 | Load | m1813_4 |
| ir.cpp:1815:14:1815:15 | Right | r1815_2 |
| ir.cpp:1821:5:1821:12 | Address | &:r1821_3 |
| ir.cpp:1821:5:1821:12 | SideEffect | ~m1821_6 |
| ir.cpp:1821:16:1821:16 | ChiPartial | partial:m1821_5 |
| ir.cpp:1821:16:1821:16 | ChiTotal | total:m1821_2 |
| ir.cpp:1821:16:1821:16 | StoreValue | r1821_4 |
| ir.cpp:1825:18:1825:25 | Address | &:r1825_3 |
| ir.cpp:1825:18:1825:25 | Arg(this) | this:r1825_3 |
| ir.cpp:1825:18:1825:25 | SideEffect | ~m1825_10 |
| ir.cpp:1825:27:1825:27 | Arg(0) | 0:r1825_5 |
| ir.cpp:1825:27:1825:28 | CallTarget | func:r1825_4 |
| ir.cpp:1825:27:1825:28 | ChiPartial | partial:m1825_7 |
| ir.cpp:1825:27:1825:28 | ChiPartial | partial:m1825_9 |
| ir.cpp:1825:27:1825:28 | ChiTotal | total:m1825_2 |
| ir.cpp:1825:27:1825:28 | ChiTotal | total:m1825_8 |
| ir.cpp:1825:27:1825:28 | SideEffect | ~m1825_2 |
| ir.cpp:1827:18:1827:25 | Address | &:r1827_3 |
| ir.cpp:1827:18:1827:25 | Arg(this) | this:r1827_3 |
| ir.cpp:1827:18:1827:25 | SideEffect | ~m1827_10 |
| ir.cpp:1827:28:1827:47 | CallTarget | func:r1827_4 |
| ir.cpp:1827:28:1827:47 | ChiPartial | partial:m1827_7 |
| ir.cpp:1827:28:1827:47 | ChiPartial | partial:m1827_9 |
| ir.cpp:1827:28:1827:47 | ChiTotal | total:m1827_2 |
| ir.cpp:1827:28:1827:47 | ChiTotal | total:m1827_8 |
| ir.cpp:1827:28:1827:47 | SideEffect | ~m1827_2 |
| ir.cpp:1827:46:1827:46 | Arg(0) | 0:r1827_5 |
| ir.cpp:1829:7:1829:19 | Address | &:r1829_3 |
| ir.cpp:1829:7:1829:19 | SideEffect | ~m1829_8 |
| ir.cpp:1829:23:1829:37 | ChiPartial | partial:m1829_7 |
| ir.cpp:1829:23:1829:37 | ChiTotal | total:m1829_2 |
| ir.cpp:1829:23:1829:37 | StoreValue | r1829_6 |
| ir.cpp:1829:23:1829:37 | Unary | r1829_4 |
| ir.cpp:1829:23:1829:37 | Unary | r1829_5 |
| ir.cpp:1831:5:1831:12 | Address | &:r1831_3 |
| ir.cpp:1831:5:1831:12 | SideEffect | ~m1831_7 |
| ir.cpp:1831:16:1831:23 | Address | &:r1831_4 |
| ir.cpp:1831:16:1831:23 | ChiPartial | partial:m1831_6 |
| ir.cpp:1831:16:1831:23 | ChiTotal | total:m1831_2 |
| ir.cpp:1831:16:1831:23 | Load | ~m1831_2 |
| ir.cpp:1831:16:1831:23 | StoreValue | r1831_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |
@@ -8700,6 +8747,34 @@
| smart_ptr.cpp:47:43:47:63 | SideEffect | ~m47_16 |
| smart_ptr.cpp:47:43:47:63 | Unary | r47_5 |
| smart_ptr.cpp:47:43:47:63 | Unary | r47_6 |
| struct_init.cpp:9:13:9:25 | Left | r9_3 |
| struct_init.cpp:9:13:9:25 | Left | r9_3 |
| struct_init.cpp:9:13:9:25 | SideEffect | ~m11_10 |
| struct_init.cpp:9:31:12:1 | Right | r9_4 |
| struct_init.cpp:9:31:12:1 | Right | r9_6 |
| struct_init.cpp:9:31:12:1 | Unary | r9_5 |
| struct_init.cpp:9:31:12:1 | Unary | r9_5 |
| struct_init.cpp:9:31:12:1 | Unary | r9_7 |
| struct_init.cpp:9:31:12:1 | Unary | r9_7 |
| struct_init.cpp:10:5:10:21 | Address | &:r10_1 |
| struct_init.cpp:10:5:10:21 | Address | &:r10_6 |
| struct_init.cpp:10:7:10:9 | ChiPartial | partial:m10_4 |
| struct_init.cpp:10:7:10:9 | ChiTotal | total:m9_2 |
| struct_init.cpp:10:7:10:9 | StoreValue | r10_3 |
| struct_init.cpp:10:7:10:9 | Unary | r10_2 |
| struct_init.cpp:10:12:10:19 | ChiPartial | partial:m10_8 |
| struct_init.cpp:10:12:10:19 | ChiTotal | total:m10_5 |
| struct_init.cpp:10:12:10:19 | StoreValue | r10_7 |
| struct_init.cpp:11:5:11:22 | Address | &:r11_1 |
| struct_init.cpp:11:5:11:22 | Address | &:r11_6 |
| struct_init.cpp:11:7:11:9 | ChiPartial | partial:m11_4 |
| struct_init.cpp:11:7:11:9 | ChiTotal | total:m10_9 |
| struct_init.cpp:11:7:11:9 | StoreValue | r11_3 |
| struct_init.cpp:11:7:11:9 | Unary | r11_2 |
| struct_init.cpp:11:12:11:20 | ChiPartial | partial:m11_9 |
| struct_init.cpp:11:12:11:20 | ChiTotal | total:m11_5 |
| struct_init.cpp:11:12:11:20 | StoreValue | r11_8 |
| struct_init.cpp:11:13:11:20 | Unary | r11_7 |
| struct_init.cpp:16:6:16:20 | ChiPartial | partial:m16_3 |
| struct_init.cpp:16:6:16:20 | ChiTotal | total:m16_2 |
| struct_init.cpp:16:6:16:20 | SideEffect | ~m17_5 |

View File

@@ -27,6 +27,7 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -5650,6 +5650,19 @@ ir.cpp:
# 1034| v1034_5(void) = AliasedUse : ~m?
# 1034| v1034_6(void) = ExitFunction :
# 1038| (lambda [] type at line 1038, col. 12) lam
# 1038| Block 0
# 1038| v1038_1(void) = EnterFunction :
# 1038| mu1038_2(unknown) = AliasedDefinition :
# 1038| r1038_3(glval<decltype([...](...){...})>) = VariableAddress[lam] :
# 1038| r1038_4(glval<decltype([...](...){...})>) = VariableAddress[#temp1038:12] :
# 1038| mu1038_5(decltype([...](...){...})) = Uninitialized[#temp1038:12] : &:r1038_4
# 1038| r1038_6(decltype([...](...){...})) = Load[#temp1038:12] : &:r1038_4, ~m?
# 1038| mu1038_7(decltype([...](...){...})) = Store[lam] : &:r1038_3, r1038_6
# 1038| v1038_8(void) = ReturnVoid :
# 1038| v1038_9(void) = AliasedUse : ~m?
# 1038| v1038_10(void) = ExitFunction :
# 1038| void (lambda [] type at line 1038, col. 12)::operator()() const
# 1038| Block 0
# 1038| v1038_1(void) = EnterFunction :
@@ -9720,6 +9733,70 @@ ir.cpp:
# 1785| v1785_7(void) = AliasedUse : ~m?
# 1785| v1785_8(void) = ExitFunction :
# 1821| int global_2
# 1821| Block 0
# 1821| v1821_1(void) = EnterFunction :
# 1821| mu1821_2(unknown) = AliasedDefinition :
# 1821| r1821_3(glval<int>) = VariableAddress[global_2] :
# 1821| r1821_4(int) = Constant[1] :
# 1821| mu1821_5(int) = Store[global_2] : &:r1821_3, r1821_4
# 1821| v1821_6(void) = ReturnVoid :
# 1821| v1821_7(void) = AliasedUse : ~m?
# 1821| v1821_8(void) = ExitFunction :
# 1825| constructor_only global_4
# 1825| Block 0
# 1825| v1825_1(void) = EnterFunction :
# 1825| mu1825_2(unknown) = AliasedDefinition :
# 1825| r1825_3(glval<constructor_only>) = VariableAddress[global_4] :
# 1825| r1825_4(glval<unknown>) = FunctionAddress[constructor_only] :
# 1825| r1825_5(int) = Constant[1] :
# 1825| v1825_6(void) = Call[constructor_only] : func:r1825_4, this:r1825_3, 0:r1825_5
# 1825| mu1825_7(unknown) = ^CallSideEffect : ~m?
# 1825| mu1825_8(constructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1825_3
# 1825| v1825_9(void) = ReturnVoid :
# 1825| v1825_10(void) = AliasedUse : ~m?
# 1825| v1825_11(void) = ExitFunction :
# 1827| constructor_only global_5
# 1827| Block 0
# 1827| v1827_1(void) = EnterFunction :
# 1827| mu1827_2(unknown) = AliasedDefinition :
# 1827| r1827_3(glval<constructor_only>) = VariableAddress[global_5] :
# 1827| r1827_4(glval<unknown>) = FunctionAddress[constructor_only] :
# 1827| r1827_5(int) = Constant[2] :
# 1827| v1827_6(void) = Call[constructor_only] : func:r1827_4, this:r1827_3, 0:r1827_5
# 1827| mu1827_7(unknown) = ^CallSideEffect : ~m?
# 1827| mu1827_8(constructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1827_3
# 1827| v1827_9(void) = ReturnVoid :
# 1827| v1827_10(void) = AliasedUse : ~m?
# 1827| v1827_11(void) = ExitFunction :
# 1829| char* global_string
# 1829| Block 0
# 1829| v1829_1(void) = EnterFunction :
# 1829| mu1829_2(unknown) = AliasedDefinition :
# 1829| r1829_3(glval<char *>) = VariableAddress[global_string] :
# 1829| r1829_4(glval<char[14]>) = StringConstant["global string"] :
# 1829| r1829_5(char *) = Convert : r1829_4
# 1829| r1829_6(char *) = Convert : r1829_5
# 1829| mu1829_7(char *) = Store[global_string] : &:r1829_3, r1829_6
# 1829| v1829_8(void) = ReturnVoid :
# 1829| v1829_9(void) = AliasedUse : ~m?
# 1829| v1829_10(void) = ExitFunction :
# 1831| int global_6
# 1831| Block 0
# 1831| v1831_1(void) = EnterFunction :
# 1831| mu1831_2(unknown) = AliasedDefinition :
# 1831| r1831_3(glval<int>) = VariableAddress[global_6] :
# 1831| r1831_4(glval<int>) = VariableAddress[global_2] :
# 1831| r1831_5(int) = Load[global_2] : &:r1831_4, ~m?
# 1831| mu1831_6(int) = Store[global_6] : &:r1831_3, r1831_5
# 1831| v1831_7(void) = ReturnVoid :
# 1831| v1831_8(void) = AliasedUse : ~m?
# 1831| v1831_9(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0
@@ -9941,6 +10018,34 @@ smart_ptr.cpp:
# 28| v28_6(void) = ExitFunction :
struct_init.cpp:
# 9| Info infos_in_file[]
# 9| Block 0
# 9| v9_1(void) = EnterFunction :
# 9| mu9_2(unknown) = AliasedDefinition :
# 9| r9_3(glval<Info[]>) = VariableAddress[infos_in_file] :
# 9| r9_4(int) = Constant[0] :
# 9| r9_5(glval<Info>) = PointerAdd[16] : r9_3, r9_4
# 10| r10_1(glval<char *>) = FieldAddress[name] : r9_5
# 10| r10_2(glval<char[2]>) = StringConstant["1"] :
# 10| r10_3(char *) = Convert : r10_2
# 10| mu10_4(char *) = Store[?] : &:r10_1, r10_3
# 10| r10_5(glval<..(*)(..)>) = FieldAddress[handler] : r9_5
# 10| r10_6(..(*)(..)) = FunctionAddress[handler1] :
# 10| mu10_7(..(*)(..)) = Store[?] : &:r10_5, r10_6
# 9| r9_6(int) = Constant[1] :
# 9| r9_7(glval<Info>) = PointerAdd[16] : r9_3, r9_6
# 11| r11_1(glval<char *>) = FieldAddress[name] : r9_7
# 11| r11_2(glval<char[2]>) = StringConstant["3"] :
# 11| r11_3(char *) = Convert : r11_2
# 11| mu11_4(char *) = Store[?] : &:r11_1, r11_3
# 11| r11_5(glval<..(*)(..)>) = FieldAddress[handler] : r9_7
# 11| r11_6(glval<..()(..)>) = FunctionAddress[handler2] :
# 11| r11_7(..(*)(..)) = CopyValue : r11_6
# 11| mu11_8(..(*)(..)) = Store[?] : &:r11_5, r11_7
# 9| v9_8(void) = ReturnVoid :
# 9| v9_9(void) = AliasedUse : ~m?
# 9| v9_10(void) = ExitFunction :
# 16| void let_info_escape(Info*)
# 16| Block 0
# 16| v16_1(void) = EnterFunction :

View File

@@ -7,5 +7,5 @@ private import semmle.code.cpp.ir.implementation.raw.PrintIR
private import PrintConfig
private class PrintConfig extends PrintIRConfiguration {
override predicate shouldPrintFunction(Function func) { shouldDumpFunction(func) }
override predicate shouldPrintFunction(Declaration decl) { shouldDumpFunction(decl) }
}

View File

@@ -23,6 +23,7 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -23,6 +23,7 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -23,6 +23,7 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -23,6 +23,7 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -23,6 +23,7 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -23,6 +23,7 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
nonUniqueIRVariable
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -156,10 +156,10 @@
| captures.cpp:23:12:23:16 | x |
| captures.cpp:23:12:23:16 | y |
| captures.cpp:23:12:23:20 | ... + ... |
| captures.cpp:23:16:23:16 | (reference dereference) |
| captures.cpp:23:16:23:16 | definition of y |
| captures.cpp:23:16:23:16 | y |
| captures.cpp:23:16:23:16 | y |
| captures.cpp:23:18:23:18 | (reference dereference) |
| captures.cpp:23:20:23:20 | z |
| captures.cpp:26:3:26:24 | return ... |
| captures.cpp:26:10:26:17 | (const lambda [] type at line 22, col. 19)... |

View File

@@ -98,6 +98,9 @@ thisArgumentIsNonPointer
| pmcallexpr.cpp:8:2:8:15 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() |
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
nonUniqueIRVariable
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -1622,6 +1622,7 @@ postWithInFlow
| cpp11.cpp:28:21:28:34 | temporary object [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:29:7:29:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:31:5:31:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:36:5:36:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:56:14:56:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:56:14:56:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:60:15:60:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2230,6 +2231,8 @@ postWithInFlow
| ltrbinopexpr.c:37:5:37:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ltrbinopexpr.c:39:5:39:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ltrbinopexpr.c:40:5:40:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:10:5:10:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:11:5:11:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:18:5:18:5 | i [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:19:5:19:5 | i [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:20:7:20:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -2289,6 +2292,7 @@ postWithInFlow
| misc.c:200:24:200:27 | args [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:200:24:200:27 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:208:1:208:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:210:5:210:20 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:216:3:216:26 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:220:3:220:5 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| misc.c:220:4:220:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -148,6 +148,9 @@ thisArgumentIsNonPointer
| pmcallexpr.cpp:8:2:8:15 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() |
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
nonUniqueIRVariable
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -98,6 +98,9 @@ thisArgumentIsNonPointer
| pmcallexpr.cpp:8:2:8:15 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() |
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
nonUniqueIRVariable
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -1,18 +1,15 @@
| test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only |
| test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only |
| test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only |
| test.cpp:10:16:10:16 | 1 | test.cpp:10:16:10:16 | 1 | AST only |
| test.cpp:16:3:16:24 | ... = ... | test.cpp:16:3:16:24 | ... = ... | AST only |
| test.cpp:17:3:17:24 | ... = ... | test.cpp:17:3:17:24 | ... = ... | AST only |
| test.cpp:18:3:18:7 | ... = ... | test.cpp:18:3:18:7 | ... = ... | AST only |
| test.cpp:21:16:21:16 | 2 | test.cpp:21:16:21:16 | 2 | AST only |
| test.cpp:29:3:29:3 | x | test.cpp:31:3:31:3 | x | IR only |
| test.cpp:29:3:29:24 | ... = ... | test.cpp:29:3:29:24 | ... = ... | AST only |
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:30:3:30:17 | call to change_global02 | AST only |
| test.cpp:31:3:31:3 | x | test.cpp:29:3:29:3 | x | IR only |
| test.cpp:31:3:31:24 | ... = ... | test.cpp:31:3:31:24 | ... = ... | AST only |
| test.cpp:32:3:32:7 | ... = ... | test.cpp:32:3:32:7 | ... = ... | AST only |
| test.cpp:35:16:35:16 | 3 | test.cpp:35:16:35:16 | 3 | AST only |
| test.cpp:43:3:43:3 | x | test.cpp:45:3:45:3 | x | IR only |
| test.cpp:43:3:43:24 | ... = ... | test.cpp:43:3:43:24 | ... = ... | AST only |
| test.cpp:43:7:43:24 | ... + ... | test.cpp:45:7:45:24 | ... + ... | IR only |

View File

@@ -69,6 +69,23 @@ test.cpp:
# 1| v1_10(void) = AliasedUse : m1_3
# 1| v1_11(void) = ExitFunction :
# 10| int global01
# 10| Block 0
# 10| v10_1(void) = EnterFunction :
# 10| m10_2(unknown) = AliasedDefinition :
# 10| valnum = unique
# 10| r10_3(glval<int>) = VariableAddress[global01] :
# 10| valnum = unique
# 10| r10_4(int) = Constant[1] :
# 10| valnum = m10_5, r10_4
# 10| m10_5(int) = Store[global01] : &:r10_3, r10_4
# 10| valnum = m10_5, r10_4
# 10| m10_6(unknown) = Chi : total:m10_2, partial:m10_5
# 10| valnum = unique
# 10| v10_7(void) = ReturnVoid :
# 10| v10_8(void) = AliasedUse : ~m10_6
# 10| v10_9(void) = ExitFunction :
# 12| void test01(int, int)
# 12| Block 0
# 12| v12_1(void) = EnterFunction :
@@ -151,6 +168,23 @@ test.cpp:
# 12| v12_10(void) = AliasedUse : m12_3
# 12| v12_11(void) = ExitFunction :
# 21| int global02
# 21| Block 0
# 21| v21_1(void) = EnterFunction :
# 21| m21_2(unknown) = AliasedDefinition :
# 21| valnum = unique
# 21| r21_3(glval<int>) = VariableAddress[global02] :
# 21| valnum = unique
# 21| r21_4(int) = Constant[2] :
# 21| valnum = m21_5, r21_4
# 21| m21_5(int) = Store[global02] : &:r21_3, r21_4
# 21| valnum = m21_5, r21_4
# 21| m21_6(unknown) = Chi : total:m21_2, partial:m21_5
# 21| valnum = unique
# 21| v21_7(void) = ReturnVoid :
# 21| v21_8(void) = AliasedUse : ~m21_6
# 21| v21_9(void) = ExitFunction :
# 25| void test02(int, int)
# 25| Block 0
# 25| v25_1(void) = EnterFunction :
@@ -240,6 +274,23 @@ test.cpp:
# 25| v25_10(void) = AliasedUse : ~m30_4
# 25| v25_11(void) = ExitFunction :
# 35| int global03
# 35| Block 0
# 35| v35_1(void) = EnterFunction :
# 35| m35_2(unknown) = AliasedDefinition :
# 35| valnum = unique
# 35| r35_3(glval<int>) = VariableAddress[global03] :
# 35| valnum = unique
# 35| r35_4(int) = Constant[3] :
# 35| valnum = m35_5, r35_4
# 35| m35_5(int) = Store[global03] : &:r35_3, r35_4
# 35| valnum = m35_5, r35_4
# 35| m35_6(unknown) = Chi : total:m35_2, partial:m35_5
# 35| valnum = unique
# 35| v35_7(void) = ReturnVoid :
# 35| v35_8(void) = AliasedUse : ~m35_6
# 35| v35_9(void) = ExitFunction :
# 39| void test03(int, int, int*)
# 39| Block 0
# 39| v39_1(void) = EnterFunction :

View File

@@ -1,3 +1,4 @@
#include "a.h"
#include "c.h"

View File

@@ -0,0 +1,12 @@
int js[] = { 1, 2, 3, 4 };
int ks[4] = { 1, 2, 3, 4 };
int ls[4] = { 1, 2, 3, 4 };
int iss[4][2] = { { 1, 2 }, { 3, 4 }, { 1, 2 }, { 3, 4 } };
typedef int int_alias;
int_alias i;

View File

@@ -0,0 +1,10 @@
extern int js[];
extern int ks[];
extern int ls[4];
extern int iss[][2];
extern int i;

View File

@@ -1,5 +1,15 @@
| a.c:4:5:4:6 | definition of is | array of {int} | 1 |
| a.h:2:12:2:13 | declaration of is | array of 4 {int} | 1 |
| c.c:2:5:2:6 | definition of js | array of {int} | 1 |
| c.c:4:5:4:6 | definition of ks | array of 4 {int} | 1 |
| c.c:6:5:6:6 | definition of ls | array of 4 {int} | 1 |
| c.c:8:5:8:7 | definition of iss | array of 4 {array of 2 {int}} | 1 |
| c.c:12:11:12:11 | definition of i | typedef {int} as "int_alias" | 1 |
| c.h:2:12:2:13 | declaration of js | array of {int} | 1 |
| c.h:4:12:4:13 | declaration of ks | array of {int} | 1 |
| c.h:6:12:6:13 | declaration of ls | array of 4 {int} | 1 |
| c.h:8:12:8:14 | declaration of iss | array of {array of 2 {int}} | 1 |
| c.h:10:12:10:12 | declaration of i | int | 1 |
| file://:0:0:0:0 | definition of fp_offset | unsigned int | 1 |
| file://:0:0:0:0 | definition of gp_offset | unsigned int | 1 |
| file://:0:0:0:0 | definition of overflow_arg_area | pointer to {void} | 1 |

View File

@@ -1,4 +1,12 @@
| a.c:4:5:4:6 | is | array of {int} | 1 |
| c.c:2:5:2:6 | js | array of {int} | 1 |
| c.c:4:5:4:6 | ks | array of 4 {int} | 1 |
| c.c:6:5:6:6 | ls | array of 4 {int} | 1 |
| c.c:8:5:8:7 | iss | array of 4 {array of 2 {int}} | 1 |
| c.c:12:11:12:11 | i | typedef {int} as "int_alias" | 1 |
| c.h:4:12:4:13 | ks | array of {int} | 1 |
| c.h:8:12:8:14 | iss | array of {array of 2 {int}} | 1 |
| c.h:10:12:10:12 | i | int | 1 |
| file://:0:0:0:0 | fp_offset | unsigned int | 1 |
| file://:0:0:0:0 | gp_offset | unsigned int | 1 |
| file://:0:0:0:0 | overflow_arg_area | pointer to {void} | 1 |