Merge tag 'codeql-cli/latest'

Compatible with the latest released version of the CodeQL CLI
This commit is contained in:
Dilan
2023-08-25 17:41:23 +00:00
541 changed files with 34164 additions and 57955 deletions

View File

@@ -1,3 +1,18 @@
## 0.9.0
### Breaking Changes
* The `shouldPrintFunction` predicate from `PrintAstConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
* The `shouldPrintFunction` predicate from `PrintIRConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
### Major Analysis Improvements
* The `PrintAST` library now also prints global and namespace variables and their initializers.
### Minor Analysis Improvements
* The `_Float128x` type is no longer exposed as a builtin type. As this type could not occur any code base, this should only affect queries that explicitly looked at the builtin types.
## 0.8.1
### Deprecated APIs

View File

@@ -0,0 +1,14 @@
## 0.9.0
### Breaking Changes
* The `shouldPrintFunction` predicate from `PrintAstConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
* The `shouldPrintFunction` predicate from `PrintIRConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
### Major Analysis Improvements
* The `PrintAST` library now also prints global and namespace variables and their initializers.
### Minor Analysis Improvements
* The `_Float128x` type is no longer exposed as a builtin type. As this type could not occur any code base, this should only affect queries that explicitly looked at the builtin types.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.8.1
lastReleaseVersion: 0.9.0

View File

@@ -18,10 +18,10 @@ external string selectedSourceFile();
class Cfg extends PrintAstConfiguration {
/**
* Holds if the AST for `func` should be printed.
* Print All functions from the selected file.
* Holds if the AST for `decl` should be printed.
* Print All declarations from the selected file.
*/
override predicate shouldPrintFunction(Function func) {
func.getFile() = getFileBySourceArchiveName(selectedSourceFile())
override predicate shouldPrintDeclaration(Declaration decl) {
decl.getFile() = getFileBySourceArchiveName(selectedSourceFile())
}
}

View File

@@ -1,11 +1,12 @@
name: codeql/cpp-all
version: 0.8.1
version: 0.9.0
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
library: true
upgrades: upgrades
dependencies:
codeql/dataflow: ${workspace}
codeql/ssa: ${workspace}
codeql/tutorial: ${workspace}
codeql/util: ${workspace}

View File

@@ -6,11 +6,9 @@ private import PrintAST
* that requests that function, or no `PrintASTConfiguration` exists.
*/
private predicate shouldPrintDeclaration(Declaration decl) {
not decl instanceof Function
not (decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
or
not exists(PrintAstConfiguration c)
or
exists(PrintAstConfiguration config | config.shouldPrintFunction(decl))
exists(PrintAstConfiguration config | config.shouldPrintDeclaration(decl))
}
/**

View File

@@ -9,13 +9,13 @@ import cpp
import PrintAST
/**
* Temporarily tweak this class or make a copy to control which functions are
* Temporarily tweak this class or make a copy to control which declarations are
* printed.
*/
class Cfg extends PrintAstConfiguration {
/**
* TWEAK THIS PREDICATE AS NEEDED.
* Holds if the AST for `func` should be printed.
* Holds if the AST for `decl` should be printed.
*/
override predicate shouldPrintFunction(Function func) { any() }
override predicate shouldPrintDeclaration(Declaration decl) { any() }
}

View File

@@ -1,9 +1,9 @@
/**
* Provides queries to pretty-print a C++ AST as a graph.
*
* By default, this will print the AST for all functions in the database. To change this behavior,
* extend `PrintASTConfiguration` and override `shouldPrintFunction` to hold for only the functions
* you wish to view the AST for.
* By default, this will print the AST for all functions and global and namespace variables in
* the database. To change this behavior, extend `PrintASTConfiguration` and override
* `shouldPrintDeclaration` to hold for only the declarations you wish to view the AST for.
*/
import cpp
@@ -12,7 +12,7 @@ private import semmle.code.cpp.Print
private newtype TPrintAstConfiguration = MkPrintAstConfiguration()
/**
* The query can extend this class to control which functions are printed.
* The query can extend this class to control which declarations are printed.
*/
class PrintAstConfiguration extends TPrintAstConfiguration {
/**
@@ -21,14 +21,16 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
string toString() { result = "PrintASTConfiguration" }
/**
* Holds if the AST for `func` should be printed. By default, holds for all
* functions.
* Holds if the AST for `decl` should be printed. By default, holds for all
* functions and global and namespace variables. Currently, does not support any
* other declaration types.
*/
predicate shouldPrintFunction(Function func) { any() }
predicate shouldPrintDeclaration(Declaration decl) { any() }
}
private predicate shouldPrintFunction(Function func) {
exists(PrintAstConfiguration config | config.shouldPrintFunction(func))
private predicate shouldPrintDeclaration(Declaration decl) {
exists(PrintAstConfiguration config | config.shouldPrintDeclaration(decl)) and
(decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
}
bindingset[s]
@@ -69,7 +71,7 @@ private predicate locationSortKeys(Locatable ast, string file, int line, int col
)
}
private Function getEnclosingFunction(Locatable ast) {
private Declaration getAnEnclosingDeclaration(Locatable ast) {
result = ast.(Expr).getEnclosingFunction()
or
result = ast.(Stmt).getEnclosingFunction()
@@ -78,6 +80,10 @@ private Function getEnclosingFunction(Locatable ast) {
or
result = ast.(Parameter).getFunction()
or
result = ast.(Expr).getEnclosingDeclaration()
or
result = ast.(Initializer).getDeclaration()
or
result = ast
}
@@ -86,21 +92,21 @@ private Function getEnclosingFunction(Locatable ast) {
* nodes for things like parameter lists and constructor init lists.
*/
private newtype TPrintAstNode =
TAstNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
TAstNode(Locatable ast) { shouldPrintDeclaration(getAnEnclosingDeclaration(ast)) } or
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
// multiple parents due to extractor bug CPP-413.
stmt.getADeclarationEntry() = entry and
shouldPrintFunction(stmt.getEnclosingFunction())
shouldPrintDeclaration(stmt.getEnclosingFunction())
} or
TParametersNode(Function func) { shouldPrintFunction(func) } or
TParametersNode(Function func) { shouldPrintDeclaration(func) } or
TConstructorInitializersNode(Constructor ctor) {
ctor.hasEntryPoint() and
shouldPrintFunction(ctor)
shouldPrintDeclaration(ctor)
} or
TDestructorDestructionsNode(Destructor dtor) {
dtor.hasEntryPoint() and
shouldPrintFunction(dtor)
shouldPrintDeclaration(dtor)
}
/**
@@ -158,10 +164,10 @@ class PrintAstNode extends TPrintAstNode {
/**
* Holds if this node should be printed in the output. By default, all nodes
* within a function are printed, but the query can override
* `PrintASTConfiguration.shouldPrintFunction` to filter the output.
* within functions and global and namespace variables are printed, but the query
* can override `PrintASTConfiguration.shouldPrintDeclaration` to filter the output.
*/
final predicate shouldPrint() { shouldPrintFunction(this.getEnclosingFunction()) }
final predicate shouldPrint() { shouldPrintDeclaration(this.getEnclosingDeclaration()) }
/**
* Gets the children of this node.
@@ -229,10 +235,15 @@ class PrintAstNode extends TPrintAstNode {
abstract string getChildAccessorPredicateInternal(int childIndex);
/**
* Gets the `Function` that contains this node.
* Gets the `Declaration` that contains this node.
*/
private Function getEnclosingFunction() {
result = this.getParent*().(FunctionNode).getFunction()
private Declaration getEnclosingDeclaration() { result = this.getParent*().getDeclaration() }
/**
* Gets the `Declaration` this node represents.
*/
private Declaration getDeclaration() {
result = this.(AstNode).getAst() and shouldPrintDeclaration(result)
}
}
@@ -571,16 +582,53 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
final Destructor getDestructor() { result = dtor }
}
abstract private class FunctionOrGlobalOrNamespaceVariableNode extends AstNode {
override string toString() { result = qlClass(ast) + getIdentityString(ast) }
private int getOrder() {
this =
rank[result](FunctionOrGlobalOrNamespaceVariableNode node, Declaration decl, string file,
int line, int column |
node.getAst() = decl and
locationSortKeys(decl, file, line, column)
|
node order by file, line, column, getIdentityString(decl)
)
}
override string getProperty(string key) {
result = super.getProperty(key)
or
key = "semmle.order" and result = this.getOrder().toString()
}
}
/**
* A node representing a `GlobalOrNamespaceVariable`.
*/
class GlobalOrNamespaceVariableNode extends FunctionOrGlobalOrNamespaceVariableNode {
GlobalOrNamespaceVariable var;
GlobalOrNamespaceVariableNode() { var = ast }
override PrintAstNode getChildInternal(int childIndex) {
childIndex = 0 and
result.(AstNode).getAst() = var.getInitializer()
}
override string getChildAccessorPredicateInternal(int childIndex) {
childIndex = 0 and result = "getInitializer()"
}
}
/**
* A node representing a `Function`.
*/
class FunctionNode extends AstNode {
class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
Function func;
FunctionNode() { func = ast }
override string toString() { result = qlClass(func) + getIdentityString(func) }
override PrintAstNode getChildInternal(int childIndex) {
childIndex = 0 and
result.(ParametersNode).getFunction() = func
@@ -604,31 +652,10 @@ class FunctionNode extends AstNode {
or
childIndex = 3 and result = "<destructions>"
}
private int getOrder() {
this =
rank[result](FunctionNode node, Function function, string file, int line, int column |
node.getAst() = function and
locationSortKeys(function, file, line, column)
|
node order by file, line, column, getIdentityString(function)
)
}
override string getProperty(string key) {
result = super.getProperty(key)
or
key = "semmle.order" and result = this.getOrder().toString()
}
/**
* Gets the `Function` this node represents.
*/
final Function getFunction() { result = func }
}
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
shouldPrintFunction(getEnclosingFunction(parent)) and
shouldPrintDeclaration(getAnEnclosingDeclaration(parent)) and
(
exists(Stmt s | s = parent |
namedStmtChildPredicates(s, child, result)
@@ -647,7 +674,7 @@ private string getChildAccessorWithoutConversions(Locatable parent, Element chil
}
private predicate namedStmtChildPredicates(Locatable s, Element e, string pred) {
shouldPrintFunction(getEnclosingFunction(s)) and
shouldPrintDeclaration(getAnEnclosingDeclaration(s)) and
(
exists(int n | s.(BlockStmt).getStmt(n) = e and pred = "getStmt(" + n + ")")
or
@@ -735,7 +762,7 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
}
private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) {
shouldPrintFunction(expr.getEnclosingFunction()) and
shouldPrintDeclaration(expr.getEnclosingDeclaration()) and
(
expr.(Access).getTarget() = ele and pred = "getTarget()"
or

View File

@@ -814,9 +814,6 @@ private predicate floatingPointTypeMapping(
// _Float128
kind = 49 and base = 2 and domain = TRealDomain() and realKind = 49 and extended = false
or
// _Float128x
kind = 50 and base = 2 and domain = TRealDomain() and realKind = 50 and extended = true
or
// _Float16
kind = 52 and base = 2 and domain = TRealDomain() and realKind = 52 and extended = false
or

View File

@@ -26,6 +26,8 @@ import cpp
* global (inter-procedural) data flow analyses.
*/
deprecated module DataFlow {
import semmle.code.cpp.dataflow.internal.DataFlow
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
private import codeql.dataflow.DataFlow
import DataFlowMake<CppOldDataFlow>
import semmle.code.cpp.dataflow.internal.DataFlowImpl1
}

View File

@@ -1,433 +0,0 @@
/**
* Provides an implementation of global (interprocedural) data flow. This file
* re-exports the local (intraprocedural) data flow analysis from
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
* through the `Global` and `GlobalWithState` modules.
*/
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
private import DataFlowImpl
/** An input configuration for data flow. */
signature module ConfigSig {
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(Node source);
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(Node sink);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Holds if `node` should never be skipped over in the `PathGraph` and in path
* explanations.
*/
default predicate neverSkip(Node node) {
isAdditionalFlowStep(node, _) or isAdditionalFlowStep(_, node)
}
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `flowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `flowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/** An input configuration for data flow using flow state. */
signature module StateConfigSig {
bindingset[this]
class FlowState;
/**
* Holds if `source` is a relevant data flow source with the given initial
* `state`.
*/
predicate isSource(Node source, FlowState state);
/**
* Holds if `sink` is a relevant data flow sink accepting `state`.
*/
predicate isSink(Node sink, FlowState state);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/**
* Holds if data flow through `node` is prohibited when the flow state is
* `state`.
*/
default predicate isBarrier(Node node, FlowState state) { none() }
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
default predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
none()
}
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Holds if `node` should never be skipped over in the `PathGraph` and in path
* explanations.
*/
default predicate neverSkip(Node node) {
isAdditionalFlowStep(node, _) or
isAdditionalFlowStep(_, node) or
isAdditionalFlowStep(node, _, _, _) or
isAdditionalFlowStep(_, _, node, _)
}
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `flowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `flowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/**
* Gets the exploration limit for `partialFlow` and `partialFlowRev`
* measured in approximate number of interprocedural steps.
*/
signature int explorationLimitSig();
/**
* The output of a global data flow computation.
*/
signature module GlobalFlowSig {
/**
* A `Node` augmented with a call context (except for sinks) and an access path.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode;
/**
* Holds if data can flow from `source` to `sink`.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate flowPath(PathNode source, PathNode sink);
/**
* Holds if data can flow from `source` to `sink`.
*/
predicate flow(Node source, Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate flowTo(Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate flowToExpr(DataFlowExpr sink);
}
/**
* Constructs a global data flow computation.
*/
module Global<ConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
}
import Impl<C>
}
/** DEPRECATED: Use `Global` instead. */
deprecated module Make<ConfigSig Config> implements GlobalFlowSig {
import Global<Config>
}
/**
* Constructs a global data flow computation using flow state.
*/
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import Config
}
import Impl<C>
}
/** DEPRECATED: Use `GlobalWithState` instead. */
deprecated module MakeWithState<StateConfigSig Config> implements GlobalFlowSig {
import GlobalWithState<Config>
}
signature class PathNodeSig {
/** Gets a textual representation of this element. */
string toString();
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
);
/** Gets the underlying `Node`. */
Node getNode();
}
signature module PathGraphSig<PathNodeSig PathNode> {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
predicate edges(PathNode a, PathNode b);
/** Holds if `n` is a node in the graph of data flow path explanations. */
predicate nodes(PathNode n, string key, string val);
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
}
/**
* Constructs a `PathGraph` from two `PathGraph`s by disjoint union.
*/
module MergePathGraph<
PathNodeSig PathNode1, PathNodeSig PathNode2, PathGraphSig<PathNode1> Graph1,
PathGraphSig<PathNode2> Graph2>
{
private newtype TPathNode =
TPathNode1(PathNode1 p) or
TPathNode2(PathNode2 p)
/** A node in a graph of path explanations that is formed by disjoint union of the two given graphs. */
class PathNode extends TPathNode {
/** Gets this as a projection on the first given `PathGraph`. */
PathNode1 asPathNode1() { this = TPathNode1(result) }
/** Gets this as a projection on the second given `PathGraph`. */
PathNode2 asPathNode2() { this = TPathNode2(result) }
/** Gets a textual representation of this element. */
string toString() {
result = this.asPathNode1().toString() or
result = this.asPathNode2().toString()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or
this.asPathNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
Node getNode() {
result = this.asPathNode1().getNode() or
result = this.asPathNode2().getNode()
}
}
/**
* Provides the query predicates needed to include a graph in a path-problem query.
*/
module PathGraph implements PathGraphSig<PathNode> {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) {
Graph1::edges(a.asPathNode1(), b.asPathNode1()) or
Graph2::edges(a.asPathNode2(), b.asPathNode2())
}
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
Graph1::nodes(n.asPathNode1(), key, val) or
Graph2::nodes(n.asPathNode2(), key, val)
}
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Graph1::subpaths(arg.asPathNode1(), par.asPathNode1(), ret.asPathNode1(), out.asPathNode1()) or
Graph2::subpaths(arg.asPathNode2(), par.asPathNode2(), ret.asPathNode2(), out.asPathNode2())
}
}
}
/**
* Constructs a `PathGraph` from three `PathGraph`s by disjoint union.
*/
module MergePathGraph3<
PathNodeSig PathNode1, PathNodeSig PathNode2, PathNodeSig PathNode3,
PathGraphSig<PathNode1> Graph1, PathGraphSig<PathNode2> Graph2, PathGraphSig<PathNode3> Graph3>
{
private module MergedInner = MergePathGraph<PathNode1, PathNode2, Graph1, Graph2>;
private module Merged =
MergePathGraph<MergedInner::PathNode, PathNode3, MergedInner::PathGraph, Graph3>;
/** A node in a graph of path explanations that is formed by disjoint union of the three given graphs. */
class PathNode instanceof Merged::PathNode {
/** Gets this as a projection on the first given `PathGraph`. */
PathNode1 asPathNode1() { result = super.asPathNode1().asPathNode1() }
/** Gets this as a projection on the second given `PathGraph`. */
PathNode2 asPathNode2() { result = super.asPathNode1().asPathNode2() }
/** Gets this as a projection on the third given `PathGraph`. */
PathNode3 asPathNode3() { result = super.asPathNode2() }
/** Gets a textual representation of this element. */
string toString() { result = super.toString() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
Node getNode() { result = super.getNode() }
}
/**
* Provides the query predicates needed to include a graph in a path-problem query.
*/
module PathGraph = Merged::PathGraph;
}

View File

@@ -5,8 +5,8 @@ private import DataFlowUtil
/**
* Gets a function that might be called by `call`.
*/
Function viableCallable(Call call) {
result = call.getTarget()
Function viableCallable(DataFlowCall call) {
result = call.(Call).getTarget()
or
// If the target of the call does not have a body in the snapshot, it might
// be because the target is just a header declaration, and the real target
@@ -58,13 +58,13 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
predicate mayBenefitFromCallContext(Call call, Function f) { none() }
predicate mayBenefitFromCallContext(DataFlowCall call, Function f) { none() }
/**
* Gets a viable dispatch target of `call` in the context `ctx`. This is
* restricted to those `call`s for which a context might make a difference.
*/
Function viableImplInCallContext(Call call, Call ctx) { none() }
Function viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() }
/** A parameter position represented by an integer. */
class ParameterPosition extends int {

File diff suppressed because it is too large Load Diff

View File

@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink) { none() }
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or

View File

@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink) { none() }
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or

View File

@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink) { none() }
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or

View File

@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink) { none() }
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or

View File

@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink) { none() }
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or

View File

@@ -1,6 +1,9 @@
/**
* Provides C++-specific definitions for use in the data flow library.
*/
private import codeql.dataflow.DataFlow
module Private {
import DataFlowPrivate
import DataFlowDispatch
@@ -9,3 +12,10 @@ module Private {
module Public {
import DataFlowUtil
}
module CppOldDataFlow implements InputSig {
import Private
import Public
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
}

View File

@@ -153,10 +153,11 @@ predicate jumpStep(Node n1, Node n2) { none() }
* Thus, `node2` references an object with a field `f` that contains the
* value of `node1`.
*/
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
predicate storeStep(Node node1, ContentSet f, Node node2) {
exists(ClassAggregateLiteral aggr, Field field |
// The following line requires `node2` to be both an `ExprNode` and a
// The following lines requires `node2` to be both an `ExprNode` and a
// `PostUpdateNode`, which means it must be an `ObjectInitializerNode`.
node2 instanceof PostUpdateNode and
node2.asExpr() = aggr and
f.(FieldContent).getField() = field and
aggr.getAFieldExpr(field) = node1.asExpr()
@@ -167,12 +168,13 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
node1.asExpr() = a and
a.getLValue() = fa
) and
node2.getPreUpdateNode().asExpr() = fa.getQualifier() and
node2.(PostUpdateNode).getPreUpdateNode().asExpr() = fa.getQualifier() and
f.(FieldContent).getField() = fa.getTarget()
)
or
exists(ConstructorFieldInit cfi |
node2.getPreUpdateNode().(PreConstructorInitThis).getConstructorFieldInit() = cfi and
node2.(PostUpdateNode).getPreUpdateNode().(PreConstructorInitThis).getConstructorFieldInit() =
cfi and
f.(FieldContent).getField() = cfi.getTarget() and
node1.asExpr() = cfi.getExpr()
)
@@ -183,7 +185,7 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
predicate readStep(Node node1, Content f, Node node2) {
predicate readStep(Node node1, ContentSet f, Node node2) {
exists(FieldAccess fr |
node1.asExpr() = fr.getQualifier() and
fr.getTarget() = f.(FieldContent).getField() and
@@ -195,7 +197,7 @@ predicate readStep(Node node1, Content f, Node node2) {
/**
* Holds if values stored inside content `c` are cleared at node `n`.
*/
predicate clearsContent(Node n, Content c) {
predicate clearsContent(Node n, ContentSet c) {
none() // stub implementation
}
@@ -235,12 +237,6 @@ class CastNode extends Node {
CastNode() { none() } // stub implementation
}
/**
* Holds if `n` should never be skipped over in the `PathGraph` and in path
* explanations.
*/
predicate neverSkipInPathGraph(Node n) { none() }
class DataFlowCallable = Function;
class DataFlowExpr = Expr;
@@ -265,8 +261,6 @@ class DataFlowCall extends Expr instanceof Call {
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
int accessPathLimit() { result = 5 }
/**
* Holds if access paths with `c` at their head always should be tracked at high
* precision. This disables adaptive access path precision for such access paths.

View File

@@ -24,6 +24,7 @@ private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> imp
Config::allowImplicitRead(node, c)
or
(
Config::isSink(node) or
Config::isSink(node, _) or
Config::isAdditionalFlowStep(node, _) or
Config::isAdditionalFlowStep(node, _, _, _)

View File

@@ -26,6 +26,8 @@ import cpp
* global (inter-procedural) data flow analyses.
*/
module DataFlow {
import semmle.code.cpp.ir.dataflow.internal.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
private import codeql.dataflow.DataFlow
import DataFlowMake<CppDataFlow>
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
}

View File

@@ -152,7 +152,19 @@ class Expr extends StmtParent, @expr {
else result = this.getValue()
}
/** Holds if this expression has a value that can be determined at compile time. */
/**
* Holds if this expression has a value that can be determined at compile time.
*
* An expression has a value that can be determined at compile time when:
* - it is a compile-time constant, e.g., a literal value or the result of a constexpr
* compile-time constant;
* - it is an address of a (member) function, an address of a constexpr variable
* initialized to a constant address, or an address of an lvalue, or any of the
* previous with a constant value added to or subtracted from the address;
* - it is a reference to a (member) function, a reference to a constexpr variable
* initialized to a constant address, or a reference to an lvalue;
* - it is a non-template parameter of a uninstantiated template.
*/
cached
predicate isConstant() {
valuebind(_, underlyingElement(this))

View File

@@ -4,8 +4,8 @@
* This file contains the actual implementation of `PrintIR.ql`. For test cases and very small
* databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
* `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to
* dump.
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
* to dump.
*/
import implementation.aliased_ssa.PrintIR

View File

@@ -22,6 +22,8 @@
import cpp
module DataFlow {
import semmle.code.cpp.ir.dataflow.internal.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
private import codeql.dataflow.DataFlow
import DataFlowMake<CppDataFlow>
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
}

View File

@@ -1,433 +0,0 @@
/**
* Provides an implementation of global (interprocedural) data flow. This file
* re-exports the local (intraprocedural) data flow analysis from
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
* through the `Global` and `GlobalWithState` modules.
*/
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
private import DataFlowImpl
/** An input configuration for data flow. */
signature module ConfigSig {
/**
* Holds if `source` is a relevant data flow source.
*/
predicate isSource(Node source);
/**
* Holds if `sink` is a relevant data flow sink.
*/
predicate isSink(Node sink);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Holds if `node` should never be skipped over in the `PathGraph` and in path
* explanations.
*/
default predicate neverSkip(Node node) {
isAdditionalFlowStep(node, _) or isAdditionalFlowStep(_, node)
}
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `flowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `flowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/** An input configuration for data flow using flow state. */
signature module StateConfigSig {
bindingset[this]
class FlowState;
/**
* Holds if `source` is a relevant data flow source with the given initial
* `state`.
*/
predicate isSource(Node source, FlowState state);
/**
* Holds if `sink` is a relevant data flow sink accepting `state`.
*/
predicate isSink(Node sink, FlowState state);
/**
* Holds if data flow through `node` is prohibited. This completely removes
* `node` from the data flow graph.
*/
default predicate isBarrier(Node node) { none() }
/**
* Holds if data flow through `node` is prohibited when the flow state is
* `state`.
*/
default predicate isBarrier(Node node, FlowState state) { none() }
/** Holds if data flow into `node` is prohibited. */
default predicate isBarrierIn(Node node) { none() }
/** Holds if data flow out of `node` is prohibited. */
default predicate isBarrierOut(Node node) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
*/
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
default predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
none()
}
/**
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Holds if `node` should never be skipped over in the `PathGraph` and in path
* explanations.
*/
default predicate neverSkip(Node node) {
isAdditionalFlowStep(node, _) or
isAdditionalFlowStep(_, node) or
isAdditionalFlowStep(node, _, _, _) or
isAdditionalFlowStep(_, _, node, _)
}
/**
* Gets the virtual dispatch branching limit when calculating field flow.
* This can be overridden to a smaller value to improve performance (a
* value of 0 disables field flow), or a larger value to get more results.
*/
default int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*
* These features are generally not relevant for typical end-to-end data flow
* queries, but should only be used for constructing paths that need to
* somehow be pluggable in another path context.
*/
default FlowFeature getAFeature() { none() }
/** Holds if sources should be grouped in the result of `flowPath`. */
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
/** Holds if sinks should be grouped in the result of `flowPath`. */
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
/**
* Holds if hidden nodes should be included in the data flow graph.
*
* This feature should only be used for debugging or when the data flow graph
* is not visualized (as it is in a `path-problem` query).
*/
default predicate includeHiddenNodes() { none() }
}
/**
* Gets the exploration limit for `partialFlow` and `partialFlowRev`
* measured in approximate number of interprocedural steps.
*/
signature int explorationLimitSig();
/**
* The output of a global data flow computation.
*/
signature module GlobalFlowSig {
/**
* A `Node` augmented with a call context (except for sinks) and an access path.
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
*/
class PathNode;
/**
* Holds if data can flow from `source` to `sink`.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate flowPath(PathNode source, PathNode sink);
/**
* Holds if data can flow from `source` to `sink`.
*/
predicate flow(Node source, Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate flowTo(Node sink);
/**
* Holds if data can flow from some source to `sink`.
*/
predicate flowToExpr(DataFlowExpr sink);
}
/**
* Constructs a global data flow computation.
*/
module Global<ConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
}
import Impl<C>
}
/** DEPRECATED: Use `Global` instead. */
deprecated module Make<ConfigSig Config> implements GlobalFlowSig {
import Global<Config>
}
/**
* Constructs a global data flow computation using flow state.
*/
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import Config
}
import Impl<C>
}
/** DEPRECATED: Use `GlobalWithState` instead. */
deprecated module MakeWithState<StateConfigSig Config> implements GlobalFlowSig {
import GlobalWithState<Config>
}
signature class PathNodeSig {
/** Gets a textual representation of this element. */
string toString();
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
);
/** Gets the underlying `Node`. */
Node getNode();
}
signature module PathGraphSig<PathNodeSig PathNode> {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
predicate edges(PathNode a, PathNode b);
/** Holds if `n` is a node in the graph of data flow path explanations. */
predicate nodes(PathNode n, string key, string val);
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
}
/**
* Constructs a `PathGraph` from two `PathGraph`s by disjoint union.
*/
module MergePathGraph<
PathNodeSig PathNode1, PathNodeSig PathNode2, PathGraphSig<PathNode1> Graph1,
PathGraphSig<PathNode2> Graph2>
{
private newtype TPathNode =
TPathNode1(PathNode1 p) or
TPathNode2(PathNode2 p)
/** A node in a graph of path explanations that is formed by disjoint union of the two given graphs. */
class PathNode extends TPathNode {
/** Gets this as a projection on the first given `PathGraph`. */
PathNode1 asPathNode1() { this = TPathNode1(result) }
/** Gets this as a projection on the second given `PathGraph`. */
PathNode2 asPathNode2() { this = TPathNode2(result) }
/** Gets a textual representation of this element. */
string toString() {
result = this.asPathNode1().toString() or
result = this.asPathNode2().toString()
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or
this.asPathNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
Node getNode() {
result = this.asPathNode1().getNode() or
result = this.asPathNode2().getNode()
}
}
/**
* Provides the query predicates needed to include a graph in a path-problem query.
*/
module PathGraph implements PathGraphSig<PathNode> {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) {
Graph1::edges(a.asPathNode1(), b.asPathNode1()) or
Graph2::edges(a.asPathNode2(), b.asPathNode2())
}
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
Graph1::nodes(n.asPathNode1(), key, val) or
Graph2::nodes(n.asPathNode2(), key, val)
}
/**
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
Graph1::subpaths(arg.asPathNode1(), par.asPathNode1(), ret.asPathNode1(), out.asPathNode1()) or
Graph2::subpaths(arg.asPathNode2(), par.asPathNode2(), ret.asPathNode2(), out.asPathNode2())
}
}
}
/**
* Constructs a `PathGraph` from three `PathGraph`s by disjoint union.
*/
module MergePathGraph3<
PathNodeSig PathNode1, PathNodeSig PathNode2, PathNodeSig PathNode3,
PathGraphSig<PathNode1> Graph1, PathGraphSig<PathNode2> Graph2, PathGraphSig<PathNode3> Graph3>
{
private module MergedInner = MergePathGraph<PathNode1, PathNode2, Graph1, Graph2>;
private module Merged =
MergePathGraph<MergedInner::PathNode, PathNode3, MergedInner::PathGraph, Graph3>;
/** A node in a graph of path explanations that is formed by disjoint union of the three given graphs. */
class PathNode instanceof Merged::PathNode {
/** Gets this as a projection on the first given `PathGraph`. */
PathNode1 asPathNode1() { result = super.asPathNode1().asPathNode1() }
/** Gets this as a projection on the second given `PathGraph`. */
PathNode2 asPathNode2() { result = super.asPathNode1().asPathNode2() }
/** Gets this as a projection on the third given `PathGraph`. */
PathNode3 asPathNode3() { result = super.asPathNode2() }
/** Gets a textual representation of this element. */
string toString() { result = super.toString() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets the underlying `Node`. */
Node getNode() { result = super.getNode() }
}
/**
* Provides the query predicates needed to include a graph in a path-problem query.
*/
module PathGraph = Merged::PathGraph;
}

View File

@@ -9,7 +9,7 @@ private import DataFlowImplCommon as DataFlowImplCommon
* Gets a function that might be called by `call`.
*/
cached
Function viableCallable(CallInstruction call) {
DataFlowCallable viableCallable(DataFlowCall call) {
DataFlowImplCommon::forceCachingInSameStage() and
result = call.getStaticCallTarget()
or
@@ -235,7 +235,7 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
predicate mayBenefitFromCallContext(CallInstruction call, Function f) {
predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable f) {
mayBenefitFromCallContext(call, f, _)
}
@@ -259,7 +259,7 @@ private predicate mayBenefitFromCallContext(
* Gets a viable dispatch target of `call` in the context `ctx`. This is
* restricted to those `call`s for which a context might make a difference.
*/
Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
result = viableCallable(call) and
exists(int i, Function f |
mayBenefitFromCallContext(pragma[only_bind_into](call), f, i) and

View File

@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink) { none() }
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or

View File

@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink) { none() }
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or

View File

@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink) { none() }
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or

View File

@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
}
predicate isSink(Node sink) { none() }
predicate isSink(Node sink, FlowState state) {
getConfig(state).isSink(sink, getState(state))
or

View File

@@ -1,6 +1,9 @@
/**
* Provides IR-specific definitions for use in the data flow library.
*/
private import codeql.dataflow.DataFlow
module Private {
import DataFlowPrivate
import DataFlowDispatch
@@ -9,3 +12,10 @@ module Private {
module Public {
import DataFlowUtil
}
module CppDataFlow implements InputSig {
import Private
import Public
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
}

View File

@@ -681,9 +681,7 @@ predicate storeStepImpl(Node node1, Content c, PostFieldUpdateNode node2, boolea
* Thus, `node2` references an object with a field `f` that contains the
* value of `node1`.
*/
predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) {
storeStepImpl(node1, c, node2, _)
}
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
/**
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
@@ -744,7 +742,7 @@ predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex)
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
predicate readStep(Node node1, Content c, Node node2) {
predicate readStep(Node node1, ContentSet c, Node node2) {
exists(FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2 |
nodeHasOperand(node2, operand, indirectionIndex2) and
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
@@ -767,7 +765,7 @@ predicate readStep(Node node1, Content c, Node node2) {
/**
* Holds if values stored inside content `c` are cleared at node `n`.
*/
predicate clearsContent(Node n, Content c) {
predicate clearsContent(Node n, ContentSet c) {
n =
any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun)
.getPreUpdateNode() and
@@ -792,7 +790,7 @@ predicate clearsContent(Node n, Content c) {
storeStepImpl(_, d, pun, true) and
pun.getPreUpdateNode() = n
|
c.getIndirectionIndex() = d.getIndirectionIndex()
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
)
)
}
@@ -833,12 +831,6 @@ class CastNode extends Node {
CastNode() { none() } // stub implementation
}
/**
* Holds if `n` should never be skipped over in the `PathGraph` and in path
* explanations.
*/
predicate neverSkipInPathGraph(Node n) { none() }
/**
* A function that may contain code or a variable that may contain itself. When
* flow crosses from one _enclosing callable_ to another, the interprocedural
@@ -853,7 +845,7 @@ class DataFlowType = Type;
/** A function call relevant for data flow. */
class DataFlowCall extends CallInstruction {
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() }
}
module IsUnreachableInCall {
@@ -924,8 +916,6 @@ module IsUnreachableInCall {
import IsUnreachableInCall
int accessPathLimit() { result = 5 }
/**
* Holds if access paths with `c` at their head always should be tracked at high
* precision. This disables adaptive access path precision for such access paths.

View File

@@ -24,6 +24,7 @@ private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> imp
Config::allowImplicitRead(node, c)
or
(
Config::isSink(node) or
Config::isSink(node, _) or
Config::isAdditionalFlowStep(node, _) or
Config::isAdditionalFlowStep(node, _, _, _)

View File

@@ -4,8 +4,8 @@
* This file contains the actual implementation of `PrintIR.ql`. For test cases and very small
* databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
* `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to
* dump.
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
* to dump.
*/
private import internal.IRInternal
@@ -16,7 +16,7 @@ import Imports::IRConfiguration
private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
/**
* The query can extend this class to control which functions are printed.
* The query can extend this class to control which declarations are printed.
*/
class PrintIRConfiguration extends TPrintIRConfiguration {
/** Gets a textual representation of this configuration. */
@@ -24,9 +24,9 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
/**
* Holds if the IR for `func` should be printed. By default, holds for all
* functions.
* functions, global and namespace variables, and static local variables.
*/
predicate shouldPrintFunction(Language::Declaration decl) { any() }
predicate shouldPrintDeclaration(Language::Declaration decl) { any() }
}
/**
@@ -34,12 +34,12 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
*/
private class FilteredIRConfiguration extends IRConfiguration {
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
shouldPrintFunction(func)
shouldPrintDeclaration(func)
}
}
private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
private predicate shouldPrintDeclaration(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintDeclaration(decl))
}
private predicate shouldPrintInstruction(Instruction i) {
@@ -90,10 +90,10 @@ private string getOperandPropertyString(Operand operand) {
}
private newtype TPrintableIRNode =
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
TPrintableIRFunction(IRFunction irFunc) { shouldPrintDeclaration(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintDeclaration(block.getEnclosingFunction()) } or
TPrintableInstruction(Instruction instr) {
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
shouldPrintInstruction(instr) and shouldPrintDeclaration(instr.getEnclosingFunction())
}
/**

View File

@@ -4,8 +4,8 @@
* This file contains the actual implementation of `PrintIR.ql`. For test cases and very small
* databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
* `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to
* dump.
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
* to dump.
*/
private import internal.IRInternal
@@ -16,7 +16,7 @@ import Imports::IRConfiguration
private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
/**
* The query can extend this class to control which functions are printed.
* The query can extend this class to control which declarations are printed.
*/
class PrintIRConfiguration extends TPrintIRConfiguration {
/** Gets a textual representation of this configuration. */
@@ -24,9 +24,9 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
/**
* Holds if the IR for `func` should be printed. By default, holds for all
* functions.
* functions, global and namespace variables, and static local variables.
*/
predicate shouldPrintFunction(Language::Declaration decl) { any() }
predicate shouldPrintDeclaration(Language::Declaration decl) { any() }
}
/**
@@ -34,12 +34,12 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
*/
private class FilteredIRConfiguration extends IRConfiguration {
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
shouldPrintFunction(func)
shouldPrintDeclaration(func)
}
}
private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
private predicate shouldPrintDeclaration(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintDeclaration(decl))
}
private predicate shouldPrintInstruction(Instruction i) {
@@ -90,10 +90,10 @@ private string getOperandPropertyString(Operand operand) {
}
private newtype TPrintableIRNode =
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
TPrintableIRFunction(IRFunction irFunc) { shouldPrintDeclaration(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintDeclaration(block.getEnclosingFunction()) } or
TPrintableInstruction(Instruction instr) {
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
shouldPrintInstruction(instr) and shouldPrintDeclaration(instr.getEnclosingFunction())
}
/**

View File

@@ -4,8 +4,8 @@
* This file contains the actual implementation of `PrintIR.ql`. For test cases and very small
* databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
* `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to
* dump.
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
* to dump.
*/
private import internal.IRInternal
@@ -16,7 +16,7 @@ import Imports::IRConfiguration
private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
/**
* The query can extend this class to control which functions are printed.
* The query can extend this class to control which declarations are printed.
*/
class PrintIRConfiguration extends TPrintIRConfiguration {
/** Gets a textual representation of this configuration. */
@@ -24,9 +24,9 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
/**
* Holds if the IR for `func` should be printed. By default, holds for all
* functions.
* functions, global and namespace variables, and static local variables.
*/
predicate shouldPrintFunction(Language::Declaration decl) { any() }
predicate shouldPrintDeclaration(Language::Declaration decl) { any() }
}
/**
@@ -34,12 +34,12 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
*/
private class FilteredIRConfiguration extends IRConfiguration {
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
shouldPrintFunction(func)
shouldPrintDeclaration(func)
}
}
private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
private predicate shouldPrintDeclaration(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintDeclaration(decl))
}
private predicate shouldPrintInstruction(Instruction i) {
@@ -90,10 +90,10 @@ private string getOperandPropertyString(Operand operand) {
}
private newtype TPrintableIRNode =
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
TPrintableIRFunction(IRFunction irFunc) { shouldPrintDeclaration(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintDeclaration(block.getEnclosingFunction()) } or
TPrintableInstruction(Instruction instr) {
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
shouldPrintInstruction(instr) and shouldPrintDeclaration(instr.getEnclosingFunction())
}
/**

View File

@@ -1,6 +1,54 @@
/**
* This file provides the first phase of the `cpp/invalid-pointer-deref` query that identifies flow
* from an allocation to a pointer-arithmetic instruction that constructs a pointer that is out of bounds.
*
* Consider the following snippet:
* ```cpp
* 1. char* base = (char*)malloc(size);
* 2. char* end = base + size;
* 3. for(int *p = base; p <= end; p++) {
* 4. use(*p); // BUG: Should have been bounded by `p < end`.
* 5. }
* ```
* this file identifies the flow from `new int[size]` to `base + size`.
*
* This is done using the product-flow library. The configuration tracks flow from the pair
* `(allocation, size of allocation)` to a pair `(a, b)` where there exists a pointer-arithmetic instruction
* `pai = a + r` such that `b` is a dataflow node where `b <= r`. Because there will be a dataflow-path from
* `allocation` to `a` this means that the `pai` will compute a pointer that is some number of elements beyond
* the end position of the allocation. See `pointerAddInstructionHasBounds` for the implementation of this.
*
* In the above example, the pair `(a, b)` is `(base, size)` with `base` and `size` coming from the expression
* `base + size` on line 2, which is also the pointer-arithmetic instruction. In general, the pair does not necessarily
* correspond directly to the operands of the pointer-arithmetic instruction.
* In the following example, the pair is again `(base, size)`, but with `base` coming from line 3 and `size` from line 2,
* and the pointer-arithmetic instruction being `base + n` on line 3:
* ```cpp
* 1. int* base = new int[size];
* 2. if(n <= size) {
* 3. int* end = base + n;
* 4. for(int* p = base; p <= end; ++p) {
* 5. *p = 0; // BUG: Should have been bounded by `p < end`.
* 6. }
* 7. }
* ```
*
* Handling false positives:
*
* Consider a snippet such as:
* ```cpp
* 1. int* base = new int[size];
* 2. int n = condition() ? size : 0;
* 3. if(n >= size) return;
* 4. int* end = base + n;
* 5. for(int* p = base; p <= end; ++p) {
* 6. *p = 0; // This is fine since `end < base + size`
* 7. }
* ```
* In order to remove this false positive we define a barrier (see `SizeBarrier::SizeBarrierConfig`) that finds the
* possible guards that compares a value to the size of the allocation. In the above example, this is the `(n >= size)`
* guard on line 3. `SizeBarrier::getABarrierNode` then defines any node that is guarded by such a guard as a barrier
* in the dataflow configuration.
*/
private import cpp
@@ -42,16 +90,14 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
* ```
* In this case, the sink pair identified by the product flow library (without any additional barriers)
* would be `(p, n)` (where `n` is the `n` in `p[n]`), because there exists a pointer-arithmetic
* instruction `pai` such that:
* 1. The left-hand of `pai` flows from the allocation, and
* 2. The right-hand of `pai` is non-strictly upper bounded by `n` (where `n` is the `n` in `p[n]`)
* instruction `pai = a + b` such that:
* 1. the allocation flows to `a`, and
* 2. `b <= n` where `n` is the `n` in `p[n]`
* but because there's a strict comparison that compares `n` against the size of the allocation this
* snippet is fine.
*/
module Barrier2 {
private class FlowState2 = int;
private module BarrierConfig2 implements DataFlow::ConfigSig {
module SizeBarrier {
private module SizeBarrierConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
// The sources is the same as in the sources for the second
// projection in the `AllocToInvalidPointerConfig` module.
@@ -59,19 +105,19 @@ module Barrier2 {
}
additional predicate isSink(
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, FlowState2 state,
boolean testIsTrue
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int k, boolean testIsTrue
) {
// The sink is any "large" side of a relational comparison.
g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue)
// The sink is any "large" side of a relational comparison. i.e., the `right` expression
// in a guard such as `left < right + k`.
g.comparesLt(left.asOperand(), right.asOperand(), k, true, testIsTrue)
}
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
}
private import DataFlow::Global<BarrierConfig2>
private import DataFlow::Global<SizeBarrierConfig>
private FlowState2 getAFlowStateForNode(DataFlow::Node node) {
private int getAFlowStateForNode(DataFlow::Node node) {
exists(DataFlow::Node source |
flow(source, node) and
hasSize(_, source, result)
@@ -79,14 +125,14 @@ module Barrier2 {
}
private predicate operandGuardChecks(
IRGuardCondition g, Operand left, Operand right, FlowState2 state, boolean edge
IRGuardCondition g, Operand left, Operand right, int state, boolean edge
) {
exists(DataFlow::Node nLeft, DataFlow::Node nRight, FlowState2 state0 |
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int k |
nRight.asOperand() = right and
nLeft.asOperand() = left and
BarrierConfig2::isSink(nLeft, nRight, g, state0, edge) and
SizeBarrierConfig::isSink(nLeft, nRight, g, k, edge) and
state = getAFlowStateForNode(nRight) and
state0 <= state
k <= state
)
}
@@ -94,7 +140,7 @@ module Barrier2 {
* Gets an instruction that is guarded by a guard condition which ensures that
* the value of the instruction is upper-bounded by size of some allocation.
*/
Instruction getABarrierInstruction(FlowState2 state) {
Instruction getABarrierInstruction(int state) {
exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge |
use = value.getAUse() and
operandGuardChecks(pragma[only_bind_into](g), pragma[only_bind_into](use), _,
@@ -108,7 +154,7 @@ module Barrier2 {
* Gets a `DataFlow::Node` that is guarded by a guard condition which ensures that
* the value of the node is upper-bounded by size of some allocation.
*/
DataFlow::Node getABarrierNode(FlowState2 state) {
DataFlow::Node getABarrierNode(int state) {
result.asOperand() = getABarrierInstruction(state).getAUse()
}
@@ -116,9 +162,7 @@ module Barrier2 {
* Gets the block of a node that is guarded (see `getABarrierInstruction` or
* `getABarrierNode` for the definition of what it means to be guarded).
*/
IRBlock getABarrierBlock(FlowState2 state) {
result.getAnInstruction() = getABarrierInstruction(state)
}
IRBlock getABarrierBlock(int state) { result.getAnInstruction() = getABarrierInstruction(state) }
}
private module InterestingPointerAddInstruction {
@@ -151,24 +195,8 @@ private module InterestingPointerAddInstruction {
}
/**
* A product-flow configuration for flow from an (allocation, size) pair to a
* pointer-arithmetic operation that is non-strictly upper-bounded by `allocation + size`.
*
* The goal of this query is to find patterns such as:
* ```cpp
* 1. char* begin = (char*)malloc(size);
* 2. char* end = begin + size;
* 3. for(int *p = begin; p <= end; p++) {
* 4. use(*p);
* 5. }
* ```
*
* We do this by splitting the task up into two configurations:
* 1. `AllocToInvalidPointerConfig` find flow from `malloc(size)` to `begin + size`, and
* 2. `InvalidPointerToDerefConfig` finds flow from `begin + size` to an `end` (on line 3).
*
* Finally, the range-analysis library will find a load from (or store to) an address that
* is non-strictly upper-bounded by `end` (which in this case is `*p`).
* A product-flow configuration for flow from an `(allocation, size)` pair to a
* pointer-arithmetic operation `pai` such that `pai <= allocation + size`.
*/
private module Config implements ProductFlow::StateConfigSig {
class FlowState1 = Unit;
@@ -176,7 +204,7 @@ private module Config implements ProductFlow::StateConfigSig {
class FlowState2 = int;
predicate isSourcePair(
DataFlow::Node source1, FlowState1 state1, DataFlow::Node source2, FlowState2 state2
DataFlow::Node allocSource, FlowState1 unit, DataFlow::Node sizeSource, FlowState2 sizeAddend
) {
// In the case of an allocation like
// ```cpp
@@ -184,21 +212,21 @@ private module Config implements ProductFlow::StateConfigSig {
// ```
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
// to the size of the allocation. This state is then checked in `isSinkPair`.
exists(state1) and
hasSize(source1.asConvertedExpr(), source2, state2)
exists(unit) and
hasSize(allocSource.asConvertedExpr(), sizeSource, sizeAddend)
}
predicate isSinkPair(
DataFlow::Node sink1, FlowState1 state1, DataFlow::Node sink2, FlowState2 state2
DataFlow::Node allocSink, FlowState1 unit, DataFlow::Node sizeSink, FlowState2 sizeAddend
) {
exists(state1) and
exists(unit) and
// We check that the delta computed by the range analysis matches the
// state value that we set in `isSourcePair`.
pointerAddInstructionHasBounds0(_, sink1, sink2, state2)
pointerAddInstructionHasBounds0(_, allocSink, sizeSink, sizeAddend)
}
predicate isBarrier2(DataFlow::Node node, FlowState2 state) {
node = Barrier2::getABarrierNode(state)
node = SizeBarrier::getABarrierNode(state)
}
predicate isBarrierIn1(DataFlow::Node node) { isSourcePair(node, _, _, _) }
@@ -211,7 +239,7 @@ private module Config implements ProductFlow::StateConfigSig {
private module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState<Config>;
/**
* Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the
* Holds if `pai` is non-strictly upper bounded by `sizeSink + delta` and `allocSink` is the
* left operand of the pointer-arithmetic operation.
*
* For example in,
@@ -220,37 +248,37 @@ private module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState<Config>;
* ```
* We will have:
* - `pai` is `p + (size + 1)`,
* - `sink1` is `p`
* - `sink2` is `size`
* - `allocSink` is `p`
* - `sizeSink` is `size`
* - `delta` is `1`.
*/
pragma[nomagic]
private predicate pointerAddInstructionHasBounds0(
PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta
PointerAddInstruction pai, DataFlow::Node allocSink, DataFlow::Node sizeSink, int delta
) {
InterestingPointerAddInstruction::isInteresting(pragma[only_bind_into](pai)) and
exists(Instruction right, Instruction instr2 |
exists(Instruction right, Instruction sizeInstr |
pai.getRight() = right and
pai.getLeft() = sink1.asInstruction() and
instr2 = sink2.asInstruction() and
// pai.getRight() <= sink2 + delta
bounded1(right, instr2, delta) and
not right = Barrier2::getABarrierInstruction(delta) and
not instr2 = Barrier2::getABarrierInstruction(delta)
pai.getLeft() = allocSink.asInstruction() and
sizeInstr = sizeSink.asInstruction() and
// pai.getRight() <= sizeSink + delta
bounded1(right, sizeInstr, delta) and
not right = SizeBarrier::getABarrierInstruction(delta) and
not sizeInstr = SizeBarrier::getABarrierInstruction(delta)
)
}
/**
* Holds if `allocation` flows to `sink1` and `sink1` represents the left-hand
* side of the pointer-arithmetic instruction `pai`, and the right-hand side of `pai`
* is non-strictly upper bounded by the size of `alllocation` + `delta`.
* Holds if `allocation` flows to `allocSink` and `allocSink` represents the left operand
* of the pointer-arithmetic instruction `pai = a + b` (i.e., `allocSink = a`), and
* `b <= allocation + delta`.
*/
pragma[nomagic]
predicate pointerAddInstructionHasBounds(
DataFlow::Node allocation, PointerAddInstruction pai, DataFlow::Node sink1, int delta
DataFlow::Node allocation, PointerAddInstruction pai, DataFlow::Node allocSink, int delta
) {
exists(DataFlow::Node sink2 |
AllocToInvalidPointerFlow::flow(allocation, _, sink1, sink2) and
pointerAddInstructionHasBounds0(pai, sink1, sink2, delta)
exists(DataFlow::Node sizeSink |
AllocToInvalidPointerFlow::flow(allocation, _, allocSink, sizeSink) and
pointerAddInstructionHasBounds0(pai, allocSink, sizeSink, delta)
)
}

View File

@@ -2,6 +2,75 @@
* This file provides the second phase of the `cpp/invalid-pointer-deref` query that identifies flow
* from the out-of-bounds pointer identified by the `AllocationToInvalidPointer.qll` library to
* a dereference of the out-of-bounds pointer.
*
* Consider the following snippet:
* ```cpp
* 1. char* base = (char*)malloc(size);
* 2. char* end = base + size;
* 3. for(char *p = base; p <= end; p++) {
* 4. use(*p); // BUG: Should have been bounded by `p < end`.
* 5. }
* ```
* this file identifies the flow from `base + size` to `end`. We call `base + size` the "dereference source" and `end`
* the "dereference sink" (even though `end` is not actually dereferenced we will use this term because we will perform
* dataflow to find a use of a pointer `x` such that `x <= end` which is dereferenced. In the above example, `x` is `p`
* on line 4).
*
* Merely _constructing_ a pointer that's out-of-bounds is fine if the pointer is never dereferenced (in reality, the
* standard only guarantees that it is safe to move the pointer one element past the last element, but we ignore that
* here). So this step is about identifying which of the out-of-bounds pointers found by `pointerAddInstructionHasBounds`
* in `AllocationToInvalidPointer.qll` are actually being dereferenced. We do this using a regular dataflow
* configuration (see `InvalidPointerToDerefConfig`).
*
* The dataflow traversal defines the set of sources as any dataflow node `n` such that there exists a pointer-arithmetic
* instruction `pai` found by `AllocationToInvalidPointer.qll` and a `n.asInstruction() >= pai + deltaDerefSourceAndPai`.
* Here, `deltaDerefSourceAndPai` is the constant difference between the source we track for finding a dereference and the
* pointer-arithmetic instruction.
*
* The set of sinks is defined as any dataflow node `n` such that `addr <= n.asInstruction() + deltaDerefSinkAndDerefAddress`
* for some address operand `addr` and constant difference `deltaDerefSinkAndDerefAddress`. Since an address operand is
* always consumed by an instruction that performs a dereference this lets us identify a "bad dereference". We call the
* instruction that consumes the address operand the "operation".
*
* For example, consider the flow from `base + size` to `end` above. The sink is `end` on line 3 because
* `p <= end.asInstruction() + deltaDerefSinkAndDerefAddress`, where `p` is the address operand in `use(*p)` and
* `deltaDerefSinkAndDerefAddress >= 0`. The load attached to `*p` is the "operation". To ensure that the path makes
* intuitive sense, we only pick operations that are control-flow reachable from the dereference sink.
*
* To compute how many elements the dereference is beyond the end position of the allocation, we sum the two deltas
* `deltaDerefSourceAndPai` and `deltaDerefSinkAndDerefAddress`. This is done in the `operationIsOffBy` predicate
* (which is the only predicate exposed by this file).
*
* Handling false positives:
*
* Consider the following snippet:
* ```cpp
* 1. char *p = new char[size];
* 2. char *end = p + size;
* 3. if (p < end) {
* 4. p += 1;
* 5. }
* 6. if (p < end) {
* 7. int val = *p; // GOOD
* 8. }
* ```
* this is safe because `p` is guarded to be strictly less than `end` on line 6 before the dereference on line 7. However, if we
* run the query on the above without further modifications we would see an alert on line 7. This is because range analysis infers
* that `p <= end` after the increment on line 4, and thus the result of `p += 1` is seen as a valid dereference source. This
* node then flows to `p` on line 6 (which is a valid dereference sink since it non-strictly upper bounds an address operand), and
* range analysis then infers that the address operand of `*p` (i.e., `p`) is non-strictly upper bounded by `p`, and thus reports
* an alert on line 7.
*
* In order to handle the above false positive, we define a barrier that identifies guards such as `p < end` that ensures that a value
* is less than the pointer-arithmetic instruction that computed the invalid pointer. This is done in the `InvalidPointerToDerefBarrier`
* module. Since the node we are tracking is not necessarily _equal_ to the pointer-arithmetic instruction, but rather satisfies
* `node.asInstruction() <= pai + deltaDerefSourceAndPai`, we need to account for the delta when checking if a guard is sufficiently
* strong to infer that a future dereference is safe. To do this, we check that the guard guarantees that a node `n` satisfies
* `n < node + k` where `node` is a node we know is equal to the value of the dereference source (i.e., it satisfies
* `node.asInstruction() <= pai + deltaDerefSourceAndPai`) and `k <= deltaDerefSourceAndPai`. Combining this we have
* `n < node + k <= node + deltaDerefSourceAndPai <= pai + 2*deltaDerefSourceAndPai` (TODO: Oops. This math doesn't quite work out.
* I think this is because we need to redefine the `BarrierConfig` to start flow at the pointer-arithmetic instruction instead of
* at the dereference source. When combined with TODO above it's easy to show that this guard ensures that the dereference is safe).
*/
private import cpp
@@ -19,10 +88,10 @@ private module InvalidPointerToDerefBarrier {
}
additional predicate isSink(
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int state, boolean testIsTrue
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int k, boolean testIsTrue
) {
// The sink is any "large" side of a relational comparison.
g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue)
g.comparesLt(left.asOperand(), right.asOperand(), k, true, testIsTrue)
}
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
@@ -40,12 +109,12 @@ private module InvalidPointerToDerefBarrier {
private predicate operandGuardChecks(
IRGuardCondition g, Operand left, Operand right, int state, boolean edge
) {
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int state0 |
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int k |
nRight.asOperand() = right and
nLeft.asOperand() = left and
BarrierConfig::isSink(nLeft, nRight, g, state0, edge) and
BarrierConfig::isSink(nLeft, nRight, g, k, edge) and
state = getInvalidPointerToDerefSourceDelta(nRight) and
state0 <= state
k <= state
)
}
@@ -85,47 +154,48 @@ private module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
private import DataFlow::Global<InvalidPointerToDerefConfig>
/**
* Holds if `source1` is dataflow node that represents an allocation that flows to the
* left-hand side of the pointer-arithmetic `pai`, and `derefSource` is a dataflow node with
* a pointer-value that is non-strictly upper bounded by `pai + delta`.
* Holds if `allocSource` is dataflow node that represents an allocation that flows to the
* left-hand side of the pointer-arithmetic `pai`, and `derefSource <= pai + derefSourcePaiDelta`.
*
* For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
* as `(p + size) + 1` and `derefSource` is the node representing `(p + size) + 1`. In this
* case `delta` is 1.
* case `derefSourcePaiDelta` is 1.
*/
private predicate invalidPointerToDerefSource(
DataFlow::Node source1, PointerArithmeticInstruction pai, DataFlow::Node derefSource, int delta
DataFlow::Node allocSource, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
int deltaDerefSourceAndPai
) {
exists(int delta0 |
// Note that `delta` is not necessarily equal to `delta0`:
// `delta0` is the constant offset added to the size of the allocation, and
// delta is the constant difference between the pointer-arithmetic instruction
exists(int rhsSizeDelta |
// Note that `deltaDerefSourceAndPai` is not necessarily equal to `rhsSizeDelta`:
// `rhsSizeDelta` is the constant offset added to the size of the allocation, and
// `deltaDerefSourceAndPai` is the constant difference between the pointer-arithmetic instruction
// and the instruction computing the address for which we will search for a dereference.
AllocToInvalidPointer::pointerAddInstructionHasBounds(source1, pai, _, delta0) and
bounded2(derefSource.asInstruction(), pai, delta) and
delta >= 0 and
// TODO: This condition will go away once #13725 is merged, and then we can make `Barrier2`
AllocToInvalidPointer::pointerAddInstructionHasBounds(allocSource, pai, _, rhsSizeDelta) and
bounded2(derefSource.asInstruction(), pai, deltaDerefSourceAndPai) and
deltaDerefSourceAndPai >= 0 and
// TODO: This condition will go away once #13725 is merged, and then we can make `SizeBarrier`
// private to `AllocationToInvalidPointer.qll`.
not derefSource.getBasicBlock() = AllocToInvalidPointer::Barrier2::getABarrierBlock(delta0)
not derefSource.getBasicBlock() =
AllocToInvalidPointer::SizeBarrier::getABarrierBlock(rhsSizeDelta)
)
}
/**
* Holds if `sink` is a sink for `InvalidPointerToDerefConfig` and `i` is a `StoreInstruction` that
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
* reads from an address that non-strictly upper-bounds `sink`.
* writes to an address `addr` such that `addr <= sink`, or `i` is a `LoadInstruction` that
* reads from an address `addr` such that `addr <= sink`.
*/
pragma[inline]
private predicate isInvalidPointerDerefSink(
DataFlow::Node sink, Instruction i, string operation, int delta
DataFlow::Node sink, Instruction i, string operation, int deltaDerefSinkAndDerefAddress
) {
exists(AddressOperand addr, Instruction s, IRBlock b |
s = sink.asInstruction() and
bounded(addr.getDef(), s, delta) and
delta >= 0 and
bounded(addr.getDef(), s, deltaDerefSinkAndDerefAddress) and
deltaDerefSinkAndDerefAddress >= 0 and
i.getAnOperand() = addr and
b = i.getBlock() and
not b = InvalidPointerToDerefBarrier::getABarrierBlock(delta)
not b = InvalidPointerToDerefBarrier::getABarrierBlock(deltaDerefSinkAndDerefAddress)
|
i instanceof StoreInstruction and
operation = "write"
@@ -165,13 +235,13 @@ private predicate paiForDereferenceSink(PointerArithmeticInstruction pai, DataFl
*/
private predicate derefSinkToOperation(
DataFlow::Node derefSink, PointerArithmeticInstruction pai, DataFlow::Node operation,
string description, int delta
string description, int deltaDerefSinkAndDerefAddress
) {
exists(Instruction i |
exists(Instruction operationInstr |
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink)) and
isInvalidPointerDerefSink(derefSink, i, description, delta) and
i = getASuccessor(derefSink.asInstruction()) and
operation.asInstruction() = i
isInvalidPointerDerefSink(derefSink, operationInstr, description, deltaDerefSinkAndDerefAddress) and
operationInstr = getASuccessor(derefSink.asInstruction()) and
operation.asInstruction() = operationInstr
)
}

View File

@@ -608,7 +608,7 @@ case @builtintype.kind of
| 47 = @std_float64 // _Float64
| 48 = @float64x // _Float64x
| 49 = @std_float128 // _Float128
| 50 = @float128x // _Float128x
// ... 50 _Float128x
| 51 = @char8_t
| 52 = @float16 // _Float16
| 53 = @complex_float16 // _Complex _Float16

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
class BuiltinType extends @builtintype {
string toString() { none() }
}
predicate isFloat128xBuiltinType(BuiltinType type) {
exists(int kind | builtintypes(type, _, kind, _, _, _) | kind = 50)
}
from BuiltinType type, string name, int kind, int kind_new, int size, int sign, int alignment
where
builtintypes(type, name, kind, size, sign, alignment) and
if isFloat128xBuiltinType(type) then kind_new = 1 else kind_new = kind
select type, name, kind_new, size, sign, alignment

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Remove _Float128 type
compatibility: partial
builtintypes.rel: run builtintypes.qlo

View File

@@ -1,3 +1,7 @@
## 0.7.2
No user-facing changes.
## 0.7.1
### Minor Analysis Improvements

View File

@@ -1,9 +1,10 @@
int f() {
void f() {
char* buf = new char[SIZE];
....
...
if (error) {
free(buf); //error handling has freed the buffer
delete buf; //error handling has freed the buffer
}
...
log_contents(buf); //but it is still used here for logging
...
}

View File

@@ -0,0 +1,3 @@
## 0.7.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.7.1
lastReleaseVersion: 0.7.2

View File

@@ -15,6 +15,51 @@
* external/cwe/cwe-787
*/
/*
* High-level description of the query:
*
* The goal of this query is to identify issues such as:
* ```cpp
* 1. int* base = new int[size];
* 2. int* end = base + size;
* 3. for(int* p = base; p <= end; ++p) {
* 4. *p = 0; // BUG: Should have been bounded by `p < end`.
* 5. }
* ```
* In order to do this, we split the problem into three subtasks:
* 1. First, we find flow from `new int[size]` to `base + size`.
* 2. Then, we find flow from `base + size` to `end` (on line 3).
* 3. Finally, we use range-analysis to find a write to (or read from) a pointer that may be greater than or equal to `end`.
*
* Step 1 is implemented in `AllocationToInvalidPointer.qll`, and step 2 is implemented by
* `InvalidPointerToDereference.qll`. See those files for the description of these.
*
* This file imports both libraries and defines a final dataflow configuration that constructs the full path from
* the allocation to the dereference of the out-of-bounds pointer. This is done for several reasons:
* 1. It means the user is able to inspect the entire path from the allocation to the dereference, which can be useful
* to understand the problem highlighted.
* 2. It ensures that the call-contexts line up correctly when we transition from step 1 to step 2. See the
* `test_missing_call_context_1` and `test_missing_call_context_2` tests for how this may flag false positives
* without this final configuration.
*
* The source of the final path is an allocation that is:
* 1. identified as flowing to an invalid pointer (by `AllocationToInvalidPointer`), and
* 2. for which the invalid pointer flows to a dereference (as identified by `InvalidPointerToDereference`).
*
* The path can be described in 3 "chunks":
* 1. One path from the allocation to the construction of the invalid pointer
* 2. Another path from the construction of the invalid pointer to the final pointer that is about to be dereferenced.
* 3. Finally, a single step from the dataflow node that represents the final pointer to the dereference.
*
* Step 1 happens when the flow state is `TInitial`, and step 2 and 3 happen when the flow state is `TPointerArith(pai)`
* where the pointer-arithmetic instruction `pai` tracks the instruction that generated the out-of-bounds pointer. This
* instruction is used in the construction of the alert message.
*
* The set of pointer-arithmetic instructions that define the `TPointerArith` flow state is restricted to be the pointer-
* arithmetic instructions that both receive flow from the allocation (as identified by `AllocationToInvalidPointer.qll`),
* and further flow to a dereference (as identified by `InvalidPointerToDereference.qll`).
*/
import cpp
import semmle.code.cpp.dataflow.new.DataFlow
import semmle.code.cpp.ir.IR

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.7.1
version: 0.7.2
groups:
- cpp
- queries

View File

@@ -1308,6 +1308,11 @@ union_etc.cpp:
# 6| Type = [IntType] int
# 6| ValueCategory = prvalue(load)
# 6| getStmt(1): [ReturnStmt] return ...
# 7| [GlobalVariable] S s
# 7| getInitializer(): [Initializer] initializer for s
# 7| getExpr(): [ConstructorCall] call to S
# 7| Type = [VoidType] void
# 7| ValueCategory = prvalue
# 9| [CopyAssignmentOperator] C& C::operator=(C const&)
# 9| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -1332,6 +1337,7 @@ union_etc.cpp:
# 12| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] U &&
# 14| [GlobalVariable] C c
# 16| [CopyAssignmentOperator] U& U::operator=(U const&)
# 16| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -1356,6 +1362,7 @@ union_etc.cpp:
# 18| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] C &&
# 20| [GlobalVariable] U u
# 22| [TopLevelFunction] int foo()
# 22| <params>:
# 22| getEntryPoint(): [BlockStmt] { ... }

View File

@@ -221,6 +221,13 @@ edges
| test.cpp:656:3:656:6 | ... ++ | test.cpp:662:3:662:11 | ... = ... |
| test.cpp:656:3:656:6 | ... ++ | test.cpp:662:3:662:11 | ... = ... |
| test.cpp:667:14:667:31 | new[] | test.cpp:675:7:675:23 | ... = ... |
| test.cpp:695:13:695:26 | new[] | test.cpp:698:5:698:10 | ... += ... |
| test.cpp:698:5:698:10 | ... += ... | test.cpp:701:15:701:16 | * ... |
| test.cpp:705:18:705:18 | q | test.cpp:705:18:705:18 | q |
| test.cpp:705:18:705:18 | q | test.cpp:706:12:706:13 | * ... |
| test.cpp:705:18:705:18 | q | test.cpp:706:12:706:13 | * ... |
| test.cpp:711:13:711:26 | new[] | test.cpp:714:11:714:11 | q |
| test.cpp:714:11:714:11 | q | test.cpp:705:18:705:18 | q |
nodes
| test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc |
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
@@ -370,6 +377,14 @@ nodes
| test.cpp:662:3:662:11 | ... = ... | semmle.label | ... = ... |
| test.cpp:667:14:667:31 | new[] | semmle.label | new[] |
| test.cpp:675:7:675:23 | ... = ... | semmle.label | ... = ... |
| test.cpp:695:13:695:26 | new[] | semmle.label | new[] |
| test.cpp:698:5:698:10 | ... += ... | semmle.label | ... += ... |
| test.cpp:701:15:701:16 | * ... | semmle.label | * ... |
| test.cpp:705:18:705:18 | q | semmle.label | q |
| test.cpp:705:18:705:18 | q | semmle.label | q |
| test.cpp:706:12:706:13 | * ... | semmle.label | * ... |
| test.cpp:711:13:711:26 | new[] | semmle.label | new[] |
| test.cpp:714:11:714:11 | q | semmle.label | q |
subpaths
#select
| test.cpp:6:14:6:15 | * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
@@ -405,3 +420,5 @@ subpaths
| test.cpp:647:5:647:19 | ... = ... | test.cpp:642:14:642:31 | new[] | test.cpp:647:5:647:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:642:14:642:31 | new[] | new[] | test.cpp:647:8:647:14 | src_pos | src_pos |
| test.cpp:662:3:662:11 | ... = ... | test.cpp:652:14:652:27 | new[] | test.cpp:662:3:662:11 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:652:14:652:27 | new[] | new[] | test.cpp:653:19:653:22 | size | size |
| test.cpp:675:7:675:23 | ... = ... | test.cpp:667:14:667:31 | new[] | test.cpp:675:7:675:23 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:667:14:667:31 | new[] | new[] | test.cpp:675:10:675:18 | ... ++ | ... ++ |
| test.cpp:701:15:701:16 | * ... | test.cpp:695:13:695:26 | new[] | test.cpp:701:15:701:16 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:695:13:695:26 | new[] | new[] | test.cpp:696:19:696:22 | size | size |
| test.cpp:706:12:706:13 | * ... | test.cpp:711:13:711:26 | new[] | test.cpp:706:12:706:13 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:711:13:711:26 | new[] | new[] | test.cpp:712:19:712:22 | size | size |

View File

@@ -689,4 +689,28 @@ void test_missing_call_context_2(unsigned size) {
int* p = new int[size];
int* end_minus_one = pointer_arithmetic(p, size - 1);
*end_minus_one = '0'; // $ deref=L680->L690->L691 // GOOD
}
}
void test34(unsigned size) {
char *p = new char[size];
char *end = p + size + 1; // $ alloc=L695
if (p + 1 < end) {
p += 1;
}
if (p + 1 < end) {
int val = *p; // $ deref=L698->L700->L701 // GOOD [FALSE POSITIVE]
}
}
void deref(char* q) {
char x = *q; // $ deref=L714->L705->L706 // BAD
}
void test35(unsigned long size, char* q)
{
char* p = new char[size];
char* end = p + size; // $ alloc=L711
if(q <= end) {
deref(q);
}
}

View File

@@ -16,3 +16,5 @@ class AddressOfGetter {
&field;
}
};
__declspec("SAL_volatile") char* pBuf;

View File

@@ -4,6 +4,7 @@
| ms_var_attributes.cpp:8:15:8:20 | myInt4 | ms_var_attributes.cpp:8:1:8:9 | dllexport |
| ms_var_attributes.cpp:9:5:9:10 | myInt5 | ms_var_attributes.h:7:1:7:9 | dllexport |
| ms_var_attributes.cpp:12:42:12:46 | field | ms_var_attributes.cpp:12:14:12:21 | property |
| ms_var_attributes.cpp:20:34:20:37 | pBuf | ms_var_attributes.cpp:20:12:20:12 | SAL_volatile |
| ms_var_attributes.h:5:22:5:27 | myInt3 | ms_var_attributes.h:5:1:5:9 | dllexport |
| var_attributes.c:1:12:1:19 | weak_var | var_attributes.c:1:36:1:39 | weak |
| var_attributes.c:2:12:2:22 | weakref_var | var_attributes.c:2:39:2:45 | weakref |

View File

@@ -1728,6 +1728,76 @@ complex.c:
# 144| Type = [LongDoubleType] long double
# 144| ValueCategory = prvalue
# 145| getStmt(72): [ReturnStmt] return ...
ir.c:
# 5| [TopLevelFunction] int getX(MyCoords*)
# 5| <params>:
# 5| getParameter(0): [Parameter] coords
# 5| Type = [PointerType] MyCoords *
# 7| [TopLevelFunction] void MyCoordsTest(int)
# 7| <params>:
# 7| getParameter(0): [Parameter] pos
# 7| Type = [IntType] int
# 7| getEntryPoint(): [BlockStmt] { ... }
# 8| getStmt(0): [DeclStmt] declaration
# 8| getDeclarationEntry(0): [VariableDeclarationEntry] definition of coords
# 8| Type = [CTypedefType] MyCoords
# 8| getVariable().getInitializer(): [Initializer] initializer for coords
# 8| getExpr(): [ClassAggregateLiteral] {...}
# 8| Type = [Struct] (unnamed class/struct/union)
# 8| ValueCategory = prvalue
# 8| getAFieldExpr(x): [Literal] 0
# 8| Type = [IntType] int
# 8| Value = [Literal] 0
# 8| ValueCategory = prvalue
# 9| getStmt(1): [ExprStmt] ExprStmt
# 9| getExpr(): [AssignExpr] ... = ...
# 9| Type = [IntType] int
# 9| ValueCategory = prvalue
# 9| getLValue(): [ValueFieldAccess] x
# 9| Type = [IntType] int
# 9| ValueCategory = lvalue
# 9| getQualifier(): [VariableAccess] coords
# 9| Type = [CTypedefType] MyCoords
# 9| ValueCategory = lvalue
# 9| getRValue(): [AssignExpr] ... = ...
# 9| Type = [IntType] int
# 9| ValueCategory = prvalue
# 9| getLValue(): [ValueFieldAccess] y
# 9| Type = [IntType] int
# 9| ValueCategory = lvalue
# 9| getQualifier(): [VariableAccess] coords
# 9| Type = [CTypedefType] MyCoords
# 9| ValueCategory = lvalue
# 9| getRValue(): [AddExpr] ... + ...
# 9| Type = [IntType] int
# 9| ValueCategory = prvalue
# 9| getLeftOperand(): [VariableAccess] pos
# 9| Type = [IntType] int
# 9| ValueCategory = prvalue(load)
# 9| getRightOperand(): [Literal] 1
# 9| Type = [IntType] int
# 9| Value = [Literal] 1
# 9| ValueCategory = prvalue
# 10| getStmt(2): [ExprStmt] ExprStmt
# 10| getExpr(): [AssignExpr] ... = ...
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue
# 10| getLValue(): [ValueFieldAccess] x
# 10| Type = [IntType] int
# 10| ValueCategory = lvalue
# 10| getQualifier(): [VariableAccess] coords
# 10| Type = [CTypedefType] MyCoords
# 10| ValueCategory = lvalue
# 10| getRValue(): [FunctionCall] call to getX
# 10| Type = [IntType] int
# 10| ValueCategory = prvalue
# 10| getArgument(0): [AddressOfExpr] & ...
# 10| Type = [PointerType] MyCoords *
# 10| ValueCategory = prvalue
# 10| getOperand(): [VariableAccess] coords
# 10| Type = [CTypedefType] MyCoords
# 10| ValueCategory = lvalue
# 11| getStmt(3): [ReturnStmt] return ...
ir.cpp:
# 1| [TopLevelFunction] void Constants()
# 1| <params>:
@@ -8529,6 +8599,11 @@ ir.cpp:
# 1035| Type = [Struct] EmptyStruct
# 1035| ValueCategory = prvalue
# 1036| getStmt(1): [ReturnStmt] return ...
# 1038| [GlobalVariable] (lambda [] type at line 1038, col. 12) lam
# 1038| getInitializer(): [Initializer] initializer for lam
# 1038| getExpr(): [LambdaExpression] [...](...){...}
# 1038| Type = [Closure] decltype([...](...){...})
# 1038| ValueCategory = prvalue
# 1038| [CopyAssignmentOperator] (lambda [] type at line 1038, col. 12)& (lambda [] type at line 1038, col. 12)::operator=((lambda [] type at line 1038, col. 12) const&)
# 1038| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -13976,6 +14051,54 @@ ir.cpp:
# 1815| Type = [IntType] int
# 1815| ValueCategory = prvalue(load)
# 1817| getStmt(8): [ReturnStmt] return ...
# 1821| [GlobalVariable] int global_2
# 1821| getInitializer(): [Initializer] initializer for global_2
# 1821| getExpr(): [Literal] 1
# 1821| Type = [IntType] int
# 1821| Value = [Literal] 1
# 1821| ValueCategory = prvalue
# 1823| [GlobalVariable] int const global_3
# 1823| getInitializer(): [Initializer] initializer for global_3
# 1823| getExpr(): [Literal] 2
# 1823| Type = [IntType] int
# 1823| Value = [Literal] 2
# 1823| ValueCategory = prvalue
# 1825| [GlobalVariable] constructor_only global_4
# 1825| getInitializer(): [Initializer] initializer for global_4
# 1825| getExpr(): [ConstructorCall] call to constructor_only
# 1825| Type = [VoidType] void
# 1825| ValueCategory = prvalue
# 1825| getArgument(0): [Literal] 1
# 1825| Type = [IntType] int
# 1825| Value = [Literal] 1
# 1825| ValueCategory = prvalue
# 1827| [GlobalVariable] constructor_only global_5
# 1827| getInitializer(): [Initializer] initializer for global_5
# 1827| getExpr(): [ConstructorCall] call to constructor_only
# 1827| Type = [VoidType] void
# 1827| ValueCategory = prvalue
# 1827| getArgument(0): [Literal] 2
# 1827| Type = [IntType] int
# 1827| Value = [Literal] 2
# 1827| ValueCategory = prvalue
# 1829| [GlobalVariable] char* global_string
# 1829| getInitializer(): [Initializer] initializer for global_string
# 1829| getExpr(): global string
# 1829| Type = [ArrayType] const char[14]
# 1829| Value = [StringLiteral] "global string"
# 1829| ValueCategory = lvalue
# 1829| getExpr().getFullyConverted(): [CStyleCast] (char *)...
# 1829| Conversion = [PointerConversion] pointer conversion
# 1829| Type = [CharPointerType] char *
# 1829| ValueCategory = prvalue
# 1829| getExpr(): [ArrayToPointerConversion] array to pointer conversion
# 1829| Type = [PointerType] const char *
# 1829| ValueCategory = prvalue
# 1831| [GlobalVariable] int global_6
# 1831| getInitializer(): [Initializer] initializer for global_6
# 1831| getExpr(): [VariableAccess] global_2
# 1831| Type = [IntType] int
# 1831| ValueCategory = prvalue(load)
# 1834| [CopyAssignmentOperator] block_assignment::A& block_assignment::A::operator=(block_assignment::A const&)
# 1834| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -14377,6 +14500,23 @@ ir.cpp:
# 1885| Type = [ClassTemplateInstantiation,Struct] Bar2<int>
# 1885| ValueCategory = lvalue
# 1886| getStmt(2): [ReturnStmt] return ...
# 1889| [GlobalVariable] char global_template<char>
# 1889| getInitializer(): [Initializer] initializer for global_template
# 1889| getExpr(): [Literal] 42
# 1889| Type = [IntType] int
# 1889| Value = [Literal] 42
# 1889| ValueCategory = prvalue
# 1889| getExpr().getFullyConverted(): [CStyleCast] (char)...
# 1889| Conversion = [IntegralConversion] integral conversion
# 1889| Type = [PlainCharType] char
# 1889| Value = [CStyleCast] 42
# 1889| ValueCategory = prvalue
# 1889| [GlobalVariable] int global_template<int>
# 1889| getInitializer(): [Initializer] initializer for global_template
# 1889| getExpr(): [Literal] 42
# 1889| Type = [IntType] int
# 1889| Value = [Literal] 42
# 1889| ValueCategory = prvalue
# 1891| [TopLevelFunction] int test_global_template_int()
# 1891| <params>:
# 1891| getEntryPoint(): [BlockStmt] { ... }
@@ -14888,6 +15028,514 @@ ir.cpp:
# 1993| Type = [Class] C
# 1993| ValueCategory = lvalue
# 1994| getStmt(3): [ReturnStmt] return ...
# 1996| [TopLevelFunction] void TernaryTestInt(bool, int, int, int)
# 1996| <params>:
# 1996| getParameter(0): [Parameter] a
# 1996| Type = [BoolType] bool
# 1996| getParameter(1): [Parameter] x
# 1996| Type = [IntType] int
# 1996| getParameter(2): [Parameter] y
# 1996| Type = [IntType] int
# 1996| getParameter(3): [Parameter] z
# 1996| Type = [IntType] int
# 1996| getEntryPoint(): [BlockStmt] { ... }
# 1997| getStmt(0): [ExprStmt] ExprStmt
# 1997| getExpr(): [AssignExpr] ... = ...
# 1997| Type = [IntType] int
# 1997| ValueCategory = lvalue
# 1997| getLValue(): [VariableAccess] z
# 1997| Type = [IntType] int
# 1997| ValueCategory = lvalue
# 1997| getRValue(): [ConditionalExpr] ... ? ... : ...
# 1997| Type = [IntType] int
# 1997| ValueCategory = prvalue
# 1997| getCondition(): [VariableAccess] a
# 1997| Type = [BoolType] bool
# 1997| ValueCategory = prvalue(load)
# 1997| getThen(): [VariableAccess] x
# 1997| Type = [IntType] int
# 1997| ValueCategory = prvalue(load)
# 1997| getElse(): [VariableAccess] y
# 1997| Type = [IntType] int
# 1997| ValueCategory = prvalue(load)
# 1998| getStmt(1): [ExprStmt] ExprStmt
# 1998| getExpr(): [AssignExpr] ... = ...
# 1998| Type = [IntType] int
# 1998| ValueCategory = lvalue
# 1998| getLValue(): [VariableAccess] z
# 1998| Type = [IntType] int
# 1998| ValueCategory = lvalue
# 1998| getRValue(): [ConditionalExpr] ... ? ... : ...
# 1998| Type = [IntType] int
# 1998| ValueCategory = prvalue
# 1998| getCondition(): [VariableAccess] a
# 1998| Type = [BoolType] bool
# 1998| ValueCategory = prvalue(load)
# 1998| getThen(): [VariableAccess] x
# 1998| Type = [IntType] int
# 1998| ValueCategory = prvalue(load)
# 1998| getElse(): [Literal] 5
# 1998| Type = [IntType] int
# 1998| Value = [Literal] 5
# 1998| ValueCategory = prvalue
# 1999| getStmt(2): [ExprStmt] ExprStmt
# 1999| getExpr(): [AssignExpr] ... = ...
# 1999| Type = [IntType] int
# 1999| ValueCategory = lvalue
# 1999| getLValue(): [VariableAccess] z
# 1999| Type = [IntType] int
# 1999| ValueCategory = lvalue
# 1999| getRValue(): [ConditionalExpr] ... ? ... : ...
# 1999| Type = [IntType] int
# 1999| ValueCategory = prvalue
# 1999| getCondition(): [VariableAccess] a
# 1999| Type = [BoolType] bool
# 1999| ValueCategory = prvalue(load)
# 1999| getThen(): [Literal] 3
# 1999| Type = [IntType] int
# 1999| Value = [Literal] 3
# 1999| ValueCategory = prvalue
# 1999| getElse(): [Literal] 5
# 1999| Type = [IntType] int
# 1999| Value = [Literal] 5
# 1999| ValueCategory = prvalue
# 2000| getStmt(3): [ExprStmt] ExprStmt
# 2000| getExpr(): [AssignExpr] ... = ...
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2000| getLValue(): [ConditionalExpr] ... ? ... : ...
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2000| getCondition(): [VariableAccess] a
# 2000| Type = [BoolType] bool
# 2000| ValueCategory = prvalue(load)
# 2000| getThen(): [VariableAccess] x
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2000| getElse(): [VariableAccess] y
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2000| getRValue(): [Literal] 7
# 2000| Type = [IntType] int
# 2000| Value = [Literal] 7
# 2000| ValueCategory = prvalue
# 2000| getLValue().getFullyConverted(): [ParenthesisExpr] (...)
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
# 2001| getStmt(4): [ReturnStmt] return ...
# 2003| [CopyAssignmentOperator] TernaryPodObj& TernaryPodObj::operator=(TernaryPodObj const&)
# 2003| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const TernaryPodObj &
# 2003| [MoveAssignmentOperator] TernaryPodObj& TernaryPodObj::operator=(TernaryPodObj&&)
# 2003| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] TernaryPodObj &&
# 2006| [TopLevelFunction] void TernaryTestPodObj(bool, TernaryPodObj, TernaryPodObj, TernaryPodObj)
# 2006| <params>:
# 2006| getParameter(0): [Parameter] a
# 2006| Type = [BoolType] bool
# 2006| getParameter(1): [Parameter] x
# 2006| Type = [Struct] TernaryPodObj
# 2006| getParameter(2): [Parameter] y
# 2006| Type = [Struct] TernaryPodObj
# 2006| getParameter(3): [Parameter] z
# 2006| Type = [Struct] TernaryPodObj
# 2006| getEntryPoint(): [BlockStmt] { ... }
# 2007| getStmt(0): [ExprStmt] ExprStmt
# 2007| getExpr(): [AssignExpr] ... = ...
# 2007| Type = [Struct] TernaryPodObj
# 2007| ValueCategory = lvalue
# 2007| getLValue(): [VariableAccess] z
# 2007| Type = [Struct] TernaryPodObj
# 2007| ValueCategory = lvalue
# 2007| getRValue(): [ConditionalExpr] ... ? ... : ...
# 2007| Type = [Struct] TernaryPodObj
# 2007| ValueCategory = prvalue
# 2007| getCondition(): [VariableAccess] a
# 2007| Type = [BoolType] bool
# 2007| ValueCategory = prvalue(load)
# 2007| getThen(): [VariableAccess] x
# 2007| Type = [Struct] TernaryPodObj
# 2007| ValueCategory = prvalue(load)
# 2007| getElse(): [VariableAccess] y
# 2007| Type = [Struct] TernaryPodObj
# 2007| ValueCategory = prvalue(load)
# 2008| getStmt(1): [ExprStmt] ExprStmt
# 2008| getExpr(): [AssignExpr] ... = ...
# 2008| Type = [Struct] TernaryPodObj
# 2008| ValueCategory = lvalue
# 2008| getLValue(): [VariableAccess] z
# 2008| Type = [Struct] TernaryPodObj
# 2008| ValueCategory = lvalue
# 2008| getRValue(): [ConditionalExpr] ... ? ... : ...
# 2008| Type = [Struct] TernaryPodObj
# 2008| ValueCategory = prvalue
# 2008| getCondition(): [VariableAccess] a
# 2008| Type = [BoolType] bool
# 2008| ValueCategory = prvalue(load)
# 2008| getThen(): [VariableAccess] x
# 2008| Type = [Struct] TernaryPodObj
# 2008| ValueCategory = prvalue(load)
# 2008| getElse(): [Literal] 0
# 2008| Type = [Struct] TernaryPodObj
# 2008| Value = [Literal] 0
# 2008| ValueCategory = prvalue
# 2008| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2008| Type = [Struct] TernaryPodObj
# 2008| ValueCategory = prvalue(load)
# 2008| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2008| Type = [Struct] TernaryPodObj
# 2008| ValueCategory = prvalue(load)
# 2008| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2008| Type = [Struct] TernaryPodObj
# 2008| ValueCategory = prvalue(load)
# 2009| getStmt(2): [ExprStmt] ExprStmt
# 2009| getExpr(): [AssignExpr] ... = ...
# 2009| Type = [Struct] TernaryPodObj
# 2009| ValueCategory = lvalue
# 2009| getLValue(): [VariableAccess] z
# 2009| Type = [Struct] TernaryPodObj
# 2009| ValueCategory = lvalue
# 2009| getRValue(): [ConditionalExpr] ... ? ... : ...
# 2009| Type = [Struct] TernaryPodObj
# 2009| ValueCategory = prvalue
# 2009| getCondition(): [VariableAccess] a
# 2009| Type = [BoolType] bool
# 2009| ValueCategory = prvalue(load)
# 2009| getThen(): [Literal] 0
# 2009| Type = [Struct] TernaryPodObj
# 2009| Value = [Literal] 0
# 2009| ValueCategory = prvalue
# 2009| getElse(): [Literal] 0
# 2009| Type = [Struct] TernaryPodObj
# 2009| Value = [Literal] 0
# 2009| ValueCategory = prvalue
# 2009| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2009| Type = [Struct] TernaryPodObj
# 2009| ValueCategory = prvalue(load)
# 2009| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2009| Type = [Struct] TernaryPodObj
# 2009| ValueCategory = prvalue(load)
# 2009| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2009| Type = [Struct] TernaryPodObj
# 2009| ValueCategory = prvalue(load)
# 2010| getStmt(3): [ExprStmt] ExprStmt
# 2010| getExpr(): [AssignExpr] ... = ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
# 2010| getLValue(): [AssignExpr] ... = ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
# 2010| getLValue(): [VariableAccess] z
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
# 2010| getRValue(): [ConditionalExpr] ... ? ... : ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue
# 2010| getCondition(): [VariableAccess] a
# 2010| Type = [BoolType] bool
# 2010| ValueCategory = prvalue(load)
# 2010| getThen(): [VariableAccess] x
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue(load)
# 2010| getElse(): [VariableAccess] y
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue(load)
# 2010| getRValue(): [Literal] 0
# 2010| Type = [Struct] TernaryPodObj
# 2010| Value = [Literal] 0
# 2010| ValueCategory = prvalue
# 2010| getLValue().getFullyConverted(): [ParenthesisExpr] (...)
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
# 2010| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue(load)
# 2011| getStmt(4): [ReturnStmt] return ...
# 2013| [CopyAssignmentOperator] TernaryNonPodObj& TernaryNonPodObj::operator=(TernaryNonPodObj const&)
# 2013| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const TernaryNonPodObj &
#-----| getEntryPoint(): [BlockStmt] { ... }
#-----| getStmt(0): [ReturnStmt] return ...
#-----| getExpr(): [PointerDereferenceExpr] * ...
#-----| Type = [Struct] TernaryNonPodObj
#-----| ValueCategory = lvalue
#-----| getOperand(): [ThisExpr] this
#-----| Type = [PointerType] TernaryNonPodObj *
#-----| ValueCategory = prvalue(load)
#-----| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
#-----| Type = [LValueReferenceType] TernaryNonPodObj &
#-----| ValueCategory = prvalue
# 2013| [Constructor] void TernaryNonPodObj::TernaryNonPodObj()
# 2013| <params>:
# 2013| <initializations>:
# 2013| getEntryPoint(): [BlockStmt] { ... }
# 2013| getStmt(0): [ReturnStmt] return ...
# 2013| [CopyConstructor] void TernaryNonPodObj::TernaryNonPodObj(TernaryNonPodObj const&)
# 2013| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const TernaryNonPodObj &
# 2013| <initializations>:
# 2013| getEntryPoint(): [BlockStmt] { ... }
# 2013| getStmt(0): [ReturnStmt] return ...
# 2014| [Destructor,VirtualFunction] void TernaryNonPodObj::~TernaryNonPodObj()
# 2014| <params>:
# 2014| getEntryPoint(): [BlockStmt] { ... }
# 2014| getStmt(0): [ReturnStmt] return ...
# 2014| <destructions>:
# 2017| [TopLevelFunction] void TernaryTestNonPodObj(bool, TernaryNonPodObj, TernaryNonPodObj, TernaryNonPodObj)
# 2017| <params>:
# 2017| getParameter(0): [Parameter] a
# 2017| Type = [BoolType] bool
# 2017| getParameter(1): [Parameter] x
# 2017| Type = [Struct] TernaryNonPodObj
# 2017| getParameter(2): [Parameter] y
# 2017| Type = [Struct] TernaryNonPodObj
# 2017| getParameter(3): [Parameter] z
# 2017| Type = [Struct] TernaryNonPodObj
# 2017| getEntryPoint(): [BlockStmt] { ... }
# 2018| getStmt(0): [ExprStmt] ExprStmt
# 2018| getExpr(): [FunctionCall] call to operator=
# 2018| Type = [LValueReferenceType] TernaryNonPodObj &
# 2018| ValueCategory = prvalue
# 2018| getQualifier(): [VariableAccess] z
# 2018| Type = [Struct] TernaryNonPodObj
# 2018| ValueCategory = lvalue
# 2018| getArgument(0): [ConditionalExpr] ... ? ... : ...
# 2018| Type = [Struct] TernaryNonPodObj
# 2018| ValueCategory = lvalue
# 2018| getCondition(): [VariableAccess] a
# 2018| Type = [BoolType] bool
# 2018| ValueCategory = prvalue(load)
# 2018| getThen(): [VariableAccess] x
# 2018| Type = [Struct] TernaryNonPodObj
# 2018| ValueCategory = lvalue
# 2018| getElse(): [VariableAccess] y
# 2018| Type = [Struct] TernaryNonPodObj
# 2018| ValueCategory = lvalue
# 2018| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
# 2018| Type = [LValueReferenceType] const TernaryNonPodObj &
# 2018| ValueCategory = prvalue
# 2018| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
# 2018| Conversion = [GlvalueConversion] glvalue conversion
# 2018| Type = [SpecifiedType] const TernaryNonPodObj
# 2018| ValueCategory = lvalue
# 2018| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2018| Type = [Struct] TernaryNonPodObj
# 2018| ValueCategory = lvalue
# 2019| getStmt(1): [ExprStmt] ExprStmt
# 2019| getExpr(): [FunctionCall] call to operator=
# 2019| Type = [LValueReferenceType] TernaryNonPodObj &
# 2019| ValueCategory = prvalue
# 2019| getQualifier(): [VariableAccess] z
# 2019| Type = [Struct] TernaryNonPodObj
# 2019| ValueCategory = lvalue
# 2019| getArgument(0): [ConditionalExpr] ... ? ... : ...
# 2019| Type = [Struct] TernaryNonPodObj
# 2019| ValueCategory = prvalue
# 2019| getCondition(): [VariableAccess] a
# 2019| Type = [BoolType] bool
# 2019| ValueCategory = prvalue(load)
# 2019| getThen(): [ConstructorCall] call to TernaryNonPodObj
# 2019| Type = [VoidType] void
# 2019| ValueCategory = prvalue
# 2019| getArgument(0): [VariableAccess] x
# 2019| Type = [Struct] TernaryNonPodObj
# 2019| ValueCategory = lvalue
# 2019| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
# 2019| Type = [LValueReferenceType] const TernaryNonPodObj &
# 2019| ValueCategory = prvalue
# 2019| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
# 2019| Conversion = [GlvalueConversion] glvalue conversion
# 2019| Type = [SpecifiedType] const TernaryNonPodObj
# 2019| ValueCategory = lvalue
# 2019| getElse(): [ConstructorCall] call to TernaryNonPodObj
# 2019| Type = [VoidType] void
# 2019| ValueCategory = prvalue
# 2019| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2019| Type = [Struct] TernaryNonPodObj
# 2019| ValueCategory = prvalue(load)
# 2019| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2019| Type = [Struct] TernaryNonPodObj
# 2019| ValueCategory = prvalue(load)
# 2019| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
# 2019| Type = [LValueReferenceType] const TernaryNonPodObj &
# 2019| ValueCategory = prvalue
# 2019| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
# 2019| Conversion = [GlvalueConversion] glvalue conversion
# 2019| Type = [SpecifiedType] const TernaryNonPodObj
# 2019| ValueCategory = lvalue
# 2019| getExpr(): [TemporaryObjectExpr] temporary object
# 2019| Type = [Struct] TernaryNonPodObj
# 2019| ValueCategory = lvalue
# 2019| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2019| Type = [Struct] TernaryNonPodObj
# 2019| ValueCategory = lvalue
# 2020| getStmt(2): [ExprStmt] ExprStmt
# 2020| getExpr(): [FunctionCall] call to operator=
# 2020| Type = [LValueReferenceType] TernaryNonPodObj &
# 2020| ValueCategory = prvalue
# 2020| getQualifier(): [VariableAccess] z
# 2020| Type = [Struct] TernaryNonPodObj
# 2020| ValueCategory = lvalue
# 2020| getArgument(0): [ConditionalExpr] ... ? ... : ...
# 2020| Type = [Struct] TernaryNonPodObj
# 2020| ValueCategory = prvalue
# 2020| getCondition(): [VariableAccess] a
# 2020| Type = [BoolType] bool
# 2020| ValueCategory = prvalue(load)
# 2020| getThen(): [ConstructorCall] call to TernaryNonPodObj
# 2020| Type = [VoidType] void
# 2020| ValueCategory = prvalue
# 2020| getElse(): [ConstructorCall] call to TernaryNonPodObj
# 2020| Type = [VoidType] void
# 2020| ValueCategory = prvalue
# 2020| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2020| Type = [Struct] TernaryNonPodObj
# 2020| ValueCategory = prvalue(load)
# 2020| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 2020| Type = [Struct] TernaryNonPodObj
# 2020| ValueCategory = prvalue(load)
# 2020| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
# 2020| Type = [LValueReferenceType] const TernaryNonPodObj &
# 2020| ValueCategory = prvalue
# 2020| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
# 2020| Conversion = [GlvalueConversion] glvalue conversion
# 2020| Type = [SpecifiedType] const TernaryNonPodObj
# 2020| ValueCategory = lvalue
# 2020| getExpr(): [TemporaryObjectExpr] temporary object
# 2020| Type = [Struct] TernaryNonPodObj
# 2020| ValueCategory = lvalue
# 2020| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2020| Type = [Struct] TernaryNonPodObj
# 2020| ValueCategory = lvalue
# 2021| getStmt(3): [ExprStmt] ExprStmt
# 2021| getExpr(): [FunctionCall] call to operator=
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
# 2021| ValueCategory = prvalue
# 2021| getQualifier(): [FunctionCall] call to operator=
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
# 2021| ValueCategory = prvalue
# 2021| getQualifier(): [VariableAccess] z
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0): [ConditionalExpr] ... ? ... : ...
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getCondition(): [VariableAccess] a
# 2021| Type = [BoolType] bool
# 2021| ValueCategory = prvalue(load)
# 2021| getThen(): [VariableAccess] x
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getElse(): [VariableAccess] y
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
# 2021| Type = [LValueReferenceType] const TernaryNonPodObj &
# 2021| ValueCategory = prvalue
# 2021| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
# 2021| Conversion = [GlvalueConversion] glvalue conversion
# 2021| Type = [SpecifiedType] const TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0): [ConstructorCall] call to TernaryNonPodObj
# 2021| Type = [VoidType] void
# 2021| ValueCategory = prvalue
# 2021| getQualifier().getFullyConverted(): [ParenthesisExpr] (...)
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
# 2021| Type = [LValueReferenceType] const TernaryNonPodObj &
# 2021| ValueCategory = prvalue
# 2021| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
# 2021| Conversion = [GlvalueConversion] glvalue conversion
# 2021| Type = [SpecifiedType] const TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getExpr(): [TemporaryObjectExpr] temporary object
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2022| getStmt(4): [ReturnStmt] return ...
# 2024| [TopLevelFunction] void CommaTestHelper(unsigned int)
# 2024| <params>:
# 2024| getParameter(0): [Parameter] (unnamed parameter 0)
# 2024| Type = [IntType] unsigned int
# 2026| [TopLevelFunction] unsigned int CommaTest(unsigned int)
# 2026| <params>:
# 2026| getParameter(0): [Parameter] x
# 2026| Type = [IntType] unsigned int
# 2026| getEntryPoint(): [BlockStmt] { ... }
# 2027| getStmt(0): [DeclStmt] declaration
# 2027| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
# 2027| Type = [IntType] unsigned int
# 2028| getStmt(1): [ExprStmt] ExprStmt
# 2028| getExpr(): [AssignExpr] ... = ...
# 2028| Type = [IntType] unsigned int
# 2028| ValueCategory = lvalue
# 2028| getLValue(): [VariableAccess] y
# 2028| Type = [IntType] unsigned int
# 2028| ValueCategory = lvalue
# 2028| getRValue(): [ConditionalExpr] ... ? ... : ...
# 2028| Type = [IntType] unsigned int
# 2028| ValueCategory = prvalue
# 2028| getCondition(): [LTExpr] ... < ...
# 2028| Type = [BoolType] bool
# 2028| ValueCategory = prvalue
# 2028| getLesserOperand(): [VariableAccess] x
# 2028| Type = [IntType] unsigned int
# 2028| ValueCategory = prvalue(load)
# 2028| getGreaterOperand(): [Literal] 100
# 2028| Type = [IntType] int
# 2028| Value = [Literal] 100
# 2028| ValueCategory = prvalue
# 2028| getGreaterOperand().getFullyConverted(): [CStyleCast] (unsigned int)...
# 2028| Conversion = [IntegralConversion] integral conversion
# 2028| Type = [IntType] unsigned int
# 2028| Value = [CStyleCast] 100
# 2028| ValueCategory = prvalue
# 2029| getThen(): [CommaExpr] ... , ...
# 2029| Type = [IntType] unsigned int
# 2029| ValueCategory = prvalue
# 2029| getLeftOperand(): [FunctionCall] call to CommaTestHelper
# 2029| Type = [VoidType] void
# 2029| ValueCategory = prvalue
# 2029| getArgument(0): [VariableAccess] x
# 2029| Type = [IntType] unsigned int
# 2029| ValueCategory = prvalue(load)
# 2029| getRightOperand(): [VariableAccess] x
# 2029| Type = [IntType] unsigned int
# 2029| ValueCategory = prvalue(load)
# 2030| getElse(): [CommaExpr] ... , ...
# 2030| Type = [IntType] int
# 2030| ValueCategory = prvalue
# 2030| getLeftOperand(): [FunctionCall] call to CommaTestHelper
# 2030| Type = [VoidType] void
# 2030| ValueCategory = prvalue
# 2030| getArgument(0): [VariableAccess] x
# 2030| Type = [IntType] unsigned int
# 2030| ValueCategory = prvalue(load)
# 2030| getRightOperand(): [Literal] 10
# 2030| Type = [IntType] int
# 2030| Value = [Literal] 10
# 2030| ValueCategory = prvalue
# 2029| getThen().getFullyConverted(): [ParenthesisExpr] (...)
# 2029| Type = [IntType] unsigned int
# 2029| ValueCategory = prvalue
# 2030| getElse().getFullyConverted(): [CStyleCast] (unsigned int)...
# 2030| Conversion = [IntegralConversion] integral conversion
# 2030| Type = [IntType] unsigned int
# 2030| ValueCategory = prvalue
# 2030| getExpr(): [ParenthesisExpr] (...)
# 2030| Type = [IntType] int
# 2030| ValueCategory = prvalue
# 2031| getStmt(2): [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:
@@ -15170,6 +15818,40 @@ struct_init.cpp:
# 4| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] Info &&
# 9| [GlobalVariable] Info infos_in_file[]
# 9| getInitializer(): [Initializer] initializer for infos_in_file
# 9| getExpr(): [ArrayAggregateLiteral] {...}
# 9| Type = [ArrayType] Info[2]
# 9| ValueCategory = prvalue
# 10| getAnElementExpr(0): [ClassAggregateLiteral] {...}
# 10| Type = [Struct] Info
# 10| ValueCategory = prvalue
# 10| getAFieldExpr(name): 1
# 10| Type = [ArrayType] const char[2]
# 10| Value = [StringLiteral] "1"
# 10| ValueCategory = lvalue
# 10| getAFieldExpr(handler): [FunctionAccess] handler1
# 10| Type = [FunctionPointerType] ..(*)(..)
# 10| ValueCategory = prvalue(load)
# 10| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 10| Type = [PointerType] const char *
# 10| ValueCategory = prvalue
# 11| getAnElementExpr(1): [ClassAggregateLiteral] {...}
# 11| Type = [Struct] Info
# 11| ValueCategory = prvalue
# 11| getAFieldExpr(name): 3
# 11| Type = [ArrayType] const char[2]
# 11| Value = [StringLiteral] "3"
# 11| ValueCategory = lvalue
# 11| getAFieldExpr(handler): [AddressOfExpr] & ...
# 11| Type = [FunctionPointerType] ..(*)(..)
# 11| ValueCategory = prvalue
# 11| getOperand(): [FunctionAccess] handler2
# 11| Type = [RoutineType] ..()(..)
# 11| ValueCategory = lvalue
# 11| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 11| Type = [PointerType] const char *
# 11| ValueCategory = prvalue
# 16| [TopLevelFunction] void let_info_escape(Info*)
# 16| <params>:
# 16| getParameter(0): [Parameter] info

View File

@@ -7,5 +7,5 @@ private import semmle.code.cpp.PrintAST
private import PrintConfig
private class PrintConfig extends PrintAstConfiguration {
override predicate shouldPrintFunction(Function func) { shouldDumpFunction(func) }
override predicate shouldPrintDeclaration(Declaration decl) { shouldDumpDeclaration(decl) }
}

View File

@@ -8,11 +8,11 @@ predicate locationIsInStandardHeaders(Location loc) {
}
/**
* Holds if the AST or IR for the specified function should be printed in the test output.
* Holds if the AST or IR for the specified declaration should be printed in the test output.
*
* This predicate excludes functions defined in standard headers.
* This predicate excludes declarations defined in standard headers.
*/
predicate shouldDumpFunction(Declaration decl) {
predicate shouldDumpDeclaration(Declaration decl) {
not locationIsInStandardHeaders(decl.getLocation()) and
(
decl instanceof Function

View File

@@ -0,0 +1,11 @@
typedef struct {
int x, y;
} MyCoords;
int getX(MyCoords *coords);
void MyCoordsTest(int pos) {
MyCoords coords = {0};
coords.x = coords.y = pos + 1;
coords.x = getX(&coords);
}

View File

@@ -1993,4 +1993,41 @@ void SetStaticFuncPtr() {
pfn = c.StaticMemberFunction;
}
void TernaryTestInt(bool a, int x, int y, int z) {
z = a ? x : y;
z = a ? x : 5;
z = a ? 3 : 5;
(a ? x : y) = 7;
}
struct TernaryPodObj {
};
void TernaryTestPodObj(bool a, TernaryPodObj x, TernaryPodObj y, TernaryPodObj z) {
z = a ? x : y;
z = a ? x : TernaryPodObj();
z = a ? TernaryPodObj() : TernaryPodObj();
(z = a ? x : y) = TernaryPodObj();
}
struct TernaryNonPodObj {
virtual ~TernaryNonPodObj() {}
};
void TernaryTestNonPodObj(bool a, TernaryNonPodObj x, TernaryNonPodObj y, TernaryNonPodObj z) {
z = a ? x : y;
z = a ? x : TernaryNonPodObj();
z = a ? TernaryNonPodObj() : TernaryNonPodObj();
(z = a ? x : y) = TernaryNonPodObj();
}
void CommaTestHelper(unsigned int);
unsigned int CommaTest(unsigned int x) {
unsigned int y;
y = x < 100 ?
(CommaTestHelper(x), x) :
(CommaTestHelper(x), 10);
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -680,6 +680,10 @@
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_2 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
@@ -704,6 +708,10 @@
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_4 |
| file://:0:0:0:0 | Address | &:r0_4 |
| file://:0:0:0:0 | Address | &:r0_5 |
@@ -715,6 +723,8 @@
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_6 |
| file://:0:0:0:0 | Address | &:r0_6 |
| file://:0:0:0:0 | Address | &:r0_7 |
| file://:0:0:0:0 | Address | &:r0_7 |
@@ -799,6 +809,8 @@
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_5 |
| file://:0:0:0:0 | Load | m0_8 |
| file://:0:0:0:0 | Load | m0_11 |
@@ -814,6 +826,7 @@
| file://:0:0:0:0 | Load | m1834_6 |
| file://:0:0:0:0 | Load | m1834_6 |
| file://:0:0:0:0 | Load | m1839_6 |
| file://:0:0:0:0 | Load | m2013_6 |
| file://:0:0:0:0 | Load | ~m0_4 |
| file://:0:0:0:0 | Load | ~m1444_6 |
| file://:0:0:0:0 | Load | ~m1712_10 |
@@ -832,6 +845,8 @@
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_14 |
| file://:0:0:0:0 | SideEffect | m1078_23 |
| file://:0:0:0:0 | SideEffect | m1078_23 |
@@ -869,6 +884,7 @@
| file://:0:0:0:0 | StoreValue | r0_7 |
| file://:0:0:0:0 | StoreValue | r0_9 |
| file://:0:0:0:0 | StoreValue | r0_9 |
| file://:0:0:0:0 | StoreValue | r0_9 |
| file://:0:0:0:0 | StoreValue | r0_12 |
| file://:0:0:0:0 | StoreValue | r0_12 |
| file://:0:0:0:0 | StoreValue | r0_13 |
@@ -895,6 +911,8 @@
| file://:0:0:0:0 | Unary | r0_7 |
| file://:0:0:0:0 | Unary | r0_7 |
| file://:0:0:0:0 | Unary | r0_7 |
| file://:0:0:0:0 | Unary | r0_7 |
| file://:0:0:0:0 | Unary | r0_8 |
| file://:0:0:0:0 | Unary | r0_8 |
| file://:0:0:0:0 | Unary | r0_9 |
| file://:0:0:0:0 | Unary | r0_9 |
@@ -914,6 +932,52 @@
| file://:0:0:0:0 | Unary | r0_20 |
| file://:0:0:0:0 | Unary | r0_21 |
| file://:0:0:0:0 | Unary | r0_21 |
| ir.c:7:6:7:17 | ChiPartial | partial:m7_3 |
| ir.c:7:6:7:17 | ChiTotal | total:m7_2 |
| ir.c:7:6:7:17 | SideEffect | ~m10_6 |
| ir.c:7:23:7:25 | Address | &:r7_5 |
| ir.c:8:12:8:17 | Address | &:r8_1 |
| ir.c:8:12:8:17 | Unary | r8_1 |
| ir.c:8:12:8:17 | Unary | r8_1 |
| ir.c:8:20:8:23 | Address | &:r8_3 |
| ir.c:8:20:8:23 | Address | &:r8_7 |
| ir.c:8:20:8:23 | ChiPartial | partial:m8_9 |
| ir.c:8:20:8:23 | ChiTotal | total:m8_6 |
| ir.c:8:20:8:23 | StoreValue | r8_8 |
| ir.c:8:22:8:22 | ChiPartial | partial:m8_5 |
| ir.c:8:22:8:22 | ChiTotal | total:m8_2 |
| ir.c:8:22:8:22 | StoreValue | r8_4 |
| ir.c:9:3:9:8 | Unary | r9_10 |
| ir.c:9:3:9:31 | ChiPartial | partial:m9_12 |
| ir.c:9:3:9:31 | ChiTotal | total:m9_8 |
| ir.c:9:10:9:10 | Address | &:r9_11 |
| ir.c:9:14:9:19 | Unary | r9_5 |
| ir.c:9:14:9:31 | ChiPartial | partial:m9_7 |
| ir.c:9:14:9:31 | ChiTotal | total:m8_10 |
| ir.c:9:14:9:31 | StoreValue | r9_9 |
| ir.c:9:21:9:21 | Address | &:r9_6 |
| ir.c:9:25:9:27 | Address | &:r9_1 |
| ir.c:9:25:9:27 | Left | r9_2 |
| ir.c:9:25:9:27 | Load | m7_6 |
| ir.c:9:25:9:31 | StoreValue | r9_4 |
| ir.c:9:25:9:31 | Unary | r9_4 |
| ir.c:9:31:9:31 | Right | r9_3 |
| ir.c:10:3:10:8 | Unary | r10_10 |
| ir.c:10:3:10:26 | ChiPartial | partial:m10_12 |
| ir.c:10:3:10:26 | ChiTotal | total:m10_9 |
| ir.c:10:10:10:10 | Address | &:r10_11 |
| ir.c:10:14:10:17 | CallTarget | func:r10_1 |
| ir.c:10:14:10:17 | ChiPartial | partial:m10_5 |
| ir.c:10:14:10:17 | ChiTotal | total:m7_4 |
| ir.c:10:14:10:17 | SideEffect | ~m7_4 |
| ir.c:10:14:10:17 | StoreValue | r10_4 |
| ir.c:10:19:10:25 | Address | &:r10_3 |
| ir.c:10:19:10:25 | Address | &:r10_3 |
| ir.c:10:19:10:25 | Arg(0) | 0:r10_3 |
| ir.c:10:19:10:25 | ChiPartial | partial:m10_8 |
| ir.c:10:19:10:25 | ChiTotal | total:m9_13 |
| ir.c:10:19:10:25 | SideEffect | ~m9_13 |
| ir.c:10:20:10:25 | Unary | r10_2 |
| ir.cpp:1:6:1:14 | ChiPartial | partial:m1_3 |
| ir.cpp:1:6:1:14 | ChiTotal | total:m1_2 |
| ir.cpp:1:6:1:14 | SideEffect | m1_3 |
@@ -9058,6 +9122,446 @@
| ir.cpp:1992:23:1992:45 | StoreValue | r1992_2 |
| ir.cpp:1993:5:1993:7 | Address | &:r1993_3 |
| ir.cpp:1993:13:1993:32 | StoreValue | r1993_2 |
| ir.cpp:1996:6:1996:19 | ChiPartial | partial:m1996_3 |
| ir.cpp:1996:6:1996:19 | ChiTotal | total:m1996_2 |
| ir.cpp:1996:6:1996:19 | SideEffect | ~m2000_9 |
| ir.cpp:1996:26:1996:26 | Address | &:r1996_5 |
| ir.cpp:1996:33:1996:33 | Address | &:r1996_7 |
| ir.cpp:1996:40:1996:40 | Address | &:r1996_9 |
| ir.cpp:1996:47:1996:47 | Address | &:r1996_11 |
| ir.cpp:1997:5:1997:5 | Address | &:r1997_7 |
| ir.cpp:1997:9:1997:9 | Address | &:r1997_1 |
| ir.cpp:1997:9:1997:9 | Condition | r1997_2 |
| ir.cpp:1997:9:1997:9 | Load | m1996_6 |
| ir.cpp:1997:9:1997:17 | Address | &:r1997_5 |
| ir.cpp:1997:9:1997:17 | Address | &:r1997_11 |
| ir.cpp:1997:9:1997:17 | Address | &:r1997_15 |
| ir.cpp:1997:9:1997:17 | Load | m1997_4 |
| ir.cpp:1997:9:1997:17 | Phi | from 2:m1997_12 |
| ir.cpp:1997:9:1997:17 | Phi | from 3:m1997_16 |
| ir.cpp:1997:9:1997:17 | StoreValue | r1997_6 |
| ir.cpp:1997:13:1997:13 | Address | &:r1997_9 |
| ir.cpp:1997:13:1997:13 | Load | m1996_8 |
| ir.cpp:1997:13:1997:13 | StoreValue | r1997_10 |
| ir.cpp:1997:17:1997:17 | Address | &:r1997_13 |
| ir.cpp:1997:17:1997:17 | Load | m1996_10 |
| ir.cpp:1997:17:1997:17 | StoreValue | r1997_14 |
| ir.cpp:1998:5:1998:5 | Address | &:r1998_7 |
| ir.cpp:1998:9:1998:9 | Address | &:r1998_1 |
| ir.cpp:1998:9:1998:9 | Condition | r1998_2 |
| ir.cpp:1998:9:1998:9 | Load | m1996_6 |
| ir.cpp:1998:9:1998:17 | Address | &:r1998_5 |
| ir.cpp:1998:9:1998:17 | Address | &:r1998_11 |
| ir.cpp:1998:9:1998:17 | Address | &:r1998_14 |
| ir.cpp:1998:9:1998:17 | Load | m1998_4 |
| ir.cpp:1998:9:1998:17 | Phi | from 5:m1998_12 |
| ir.cpp:1998:9:1998:17 | Phi | from 6:m1998_15 |
| ir.cpp:1998:9:1998:17 | StoreValue | r1998_6 |
| ir.cpp:1998:13:1998:13 | Address | &:r1998_9 |
| ir.cpp:1998:13:1998:13 | Load | m1996_8 |
| ir.cpp:1998:13:1998:13 | StoreValue | r1998_10 |
| ir.cpp:1998:17:1998:17 | StoreValue | r1998_13 |
| ir.cpp:1999:5:1999:5 | Address | &:r1999_7 |
| ir.cpp:1999:9:1999:9 | Address | &:r1999_1 |
| ir.cpp:1999:9:1999:9 | Condition | r1999_2 |
| ir.cpp:1999:9:1999:9 | Load | m1996_6 |
| ir.cpp:1999:9:1999:17 | Address | &:r1999_5 |
| ir.cpp:1999:9:1999:17 | Address | &:r1999_10 |
| ir.cpp:1999:9:1999:17 | Address | &:r1999_13 |
| ir.cpp:1999:9:1999:17 | Load | m1999_4 |
| ir.cpp:1999:9:1999:17 | Phi | from 8:m1999_11 |
| ir.cpp:1999:9:1999:17 | Phi | from 9:m1999_14 |
| ir.cpp:1999:9:1999:17 | StoreValue | r1999_6 |
| ir.cpp:1999:13:1999:13 | StoreValue | r1999_9 |
| ir.cpp:1999:17:1999:17 | StoreValue | r1999_12 |
| ir.cpp:2000:5:2000:19 | ChiPartial | partial:m2000_8 |
| ir.cpp:2000:5:2000:19 | ChiTotal | total:m1996_4 |
| ir.cpp:2000:6:2000:6 | Address | &:r2000_2 |
| ir.cpp:2000:6:2000:6 | Condition | r2000_3 |
| ir.cpp:2000:6:2000:6 | Load | m1996_6 |
| ir.cpp:2000:6:2000:14 | Address | &:r2000_6 |
| ir.cpp:2000:6:2000:14 | Address | &:r2000_7 |
| ir.cpp:2000:6:2000:14 | Address | &:r2000_11 |
| ir.cpp:2000:6:2000:14 | Address | &:r2000_14 |
| ir.cpp:2000:6:2000:14 | Load | m2000_5 |
| ir.cpp:2000:6:2000:14 | Phi | from 11:m2000_12 |
| ir.cpp:2000:6:2000:14 | Phi | from 12:m2000_15 |
| ir.cpp:2000:10:2000:10 | StoreValue | r2000_10 |
| ir.cpp:2000:14:2000:14 | StoreValue | r2000_13 |
| ir.cpp:2000:19:2000:19 | StoreValue | r2000_1 |
| ir.cpp:2006:6:2006:22 | ChiPartial | partial:m2006_3 |
| ir.cpp:2006:6:2006:22 | ChiTotal | total:m2006_2 |
| ir.cpp:2006:6:2006:22 | SideEffect | m2006_3 |
| ir.cpp:2006:29:2006:29 | Address | &:r2006_5 |
| ir.cpp:2006:46:2006:46 | Address | &:r2006_7 |
| ir.cpp:2006:63:2006:63 | Address | &:r2006_9 |
| ir.cpp:2006:80:2006:80 | Address | &:r2006_11 |
| ir.cpp:2007:5:2007:5 | Address | &:r2007_7 |
| ir.cpp:2007:9:2007:9 | Address | &:r2007_1 |
| ir.cpp:2007:9:2007:9 | Condition | r2007_2 |
| ir.cpp:2007:9:2007:9 | Load | m2006_6 |
| ir.cpp:2007:9:2007:17 | Address | &:r2007_5 |
| ir.cpp:2007:9:2007:17 | Address | &:r2007_11 |
| ir.cpp:2007:9:2007:17 | Address | &:r2007_15 |
| ir.cpp:2007:9:2007:17 | Load | m2007_4 |
| ir.cpp:2007:9:2007:17 | Phi | from 2:m2007_12 |
| ir.cpp:2007:9:2007:17 | Phi | from 3:m2007_16 |
| ir.cpp:2007:9:2007:17 | StoreValue | r2007_6 |
| ir.cpp:2007:13:2007:13 | Address | &:r2007_9 |
| ir.cpp:2007:13:2007:13 | Load | m2006_8 |
| ir.cpp:2007:13:2007:13 | StoreValue | r2007_10 |
| ir.cpp:2007:17:2007:17 | Address | &:r2007_13 |
| ir.cpp:2007:17:2007:17 | Load | m2006_10 |
| ir.cpp:2007:17:2007:17 | StoreValue | r2007_14 |
| ir.cpp:2008:5:2008:5 | Address | &:r2008_10 |
| ir.cpp:2008:9:2008:9 | Address | &:r2008_2 |
| ir.cpp:2008:9:2008:9 | Address | &:r2008_6 |
| ir.cpp:2008:9:2008:9 | Address | &:r2008_17 |
| ir.cpp:2008:9:2008:9 | Address | &:r2008_23 |
| ir.cpp:2008:9:2008:9 | Condition | r2008_3 |
| ir.cpp:2008:9:2008:9 | Load | m2006_6 |
| ir.cpp:2008:9:2008:9 | Load | m2008_5 |
| ir.cpp:2008:9:2008:9 | Phi | from 5:m2008_18 |
| ir.cpp:2008:9:2008:9 | Phi | from 6:m2008_24 |
| ir.cpp:2008:9:2008:9 | StoreValue | r2008_7 |
| ir.cpp:2008:9:2008:31 | Address | &:r2008_1 |
| ir.cpp:2008:9:2008:31 | Address | &:r2008_1 |
| ir.cpp:2008:9:2008:31 | Load | m2008_8 |
| ir.cpp:2008:9:2008:31 | StoreValue | r2008_9 |
| ir.cpp:2008:13:2008:13 | Address | &:r2008_12 |
| ir.cpp:2008:13:2008:13 | Address | &:r2008_12 |
| ir.cpp:2008:13:2008:13 | Address | &:r2008_13 |
| ir.cpp:2008:13:2008:13 | Load | m2006_8 |
| ir.cpp:2008:13:2008:13 | Load | m2008_15 |
| ir.cpp:2008:13:2008:13 | StoreValue | r2008_14 |
| ir.cpp:2008:13:2008:13 | StoreValue | r2008_16 |
| ir.cpp:2008:17:2008:31 | Address | &:r2008_19 |
| ir.cpp:2008:17:2008:31 | Address | &:r2008_19 |
| ir.cpp:2008:17:2008:31 | Load | m2008_21 |
| ir.cpp:2008:17:2008:31 | StoreValue | r2008_20 |
| ir.cpp:2008:17:2008:31 | StoreValue | r2008_22 |
| ir.cpp:2009:5:2009:5 | Address | &:r2009_10 |
| ir.cpp:2009:9:2009:9 | Address | &:r2009_2 |
| ir.cpp:2009:9:2009:9 | Address | &:r2009_6 |
| ir.cpp:2009:9:2009:9 | Address | &:r2009_16 |
| ir.cpp:2009:9:2009:9 | Address | &:r2009_22 |
| ir.cpp:2009:9:2009:9 | Condition | r2009_3 |
| ir.cpp:2009:9:2009:9 | Load | m2006_6 |
| ir.cpp:2009:9:2009:9 | Load | m2009_5 |
| ir.cpp:2009:9:2009:9 | Phi | from 8:m2009_17 |
| ir.cpp:2009:9:2009:9 | Phi | from 9:m2009_23 |
| ir.cpp:2009:9:2009:9 | StoreValue | r2009_7 |
| ir.cpp:2009:9:2009:45 | Address | &:r2009_1 |
| ir.cpp:2009:9:2009:45 | Address | &:r2009_1 |
| ir.cpp:2009:9:2009:45 | Load | m2009_8 |
| ir.cpp:2009:9:2009:45 | StoreValue | r2009_9 |
| ir.cpp:2009:13:2009:27 | Address | &:r2009_12 |
| ir.cpp:2009:13:2009:27 | Address | &:r2009_12 |
| ir.cpp:2009:13:2009:27 | Load | m2009_14 |
| ir.cpp:2009:13:2009:27 | StoreValue | r2009_13 |
| ir.cpp:2009:13:2009:27 | StoreValue | r2009_15 |
| ir.cpp:2009:31:2009:45 | Address | &:r2009_18 |
| ir.cpp:2009:31:2009:45 | Address | &:r2009_18 |
| ir.cpp:2009:31:2009:45 | Load | m2009_20 |
| ir.cpp:2009:31:2009:45 | StoreValue | r2009_19 |
| ir.cpp:2009:31:2009:45 | StoreValue | r2009_21 |
| ir.cpp:2010:6:2010:6 | Address | &:r2010_11 |
| ir.cpp:2010:6:2010:6 | Unary | r2010_11 |
| ir.cpp:2010:6:2010:18 | Address | &:r2010_13 |
| ir.cpp:2010:10:2010:10 | Address | &:r2010_5 |
| ir.cpp:2010:10:2010:10 | Condition | r2010_6 |
| ir.cpp:2010:10:2010:10 | Load | m2006_6 |
| ir.cpp:2010:10:2010:18 | Address | &:r2010_9 |
| ir.cpp:2010:10:2010:18 | Address | &:r2010_17 |
| ir.cpp:2010:10:2010:18 | Address | &:r2010_21 |
| ir.cpp:2010:10:2010:18 | Load | m2010_8 |
| ir.cpp:2010:10:2010:18 | Phi | from 11:m2010_18 |
| ir.cpp:2010:10:2010:18 | Phi | from 12:m2010_22 |
| ir.cpp:2010:10:2010:18 | StoreValue | r2010_10 |
| ir.cpp:2010:14:2010:14 | Address | &:r2010_15 |
| ir.cpp:2010:14:2010:14 | Load | m2006_8 |
| ir.cpp:2010:14:2010:14 | StoreValue | r2010_16 |
| ir.cpp:2010:18:2010:18 | Address | &:r2010_19 |
| ir.cpp:2010:18:2010:18 | Load | m2006_10 |
| ir.cpp:2010:18:2010:18 | StoreValue | r2010_20 |
| ir.cpp:2010:23:2010:37 | Address | &:r2010_1 |
| ir.cpp:2010:23:2010:37 | Address | &:r2010_1 |
| ir.cpp:2010:23:2010:37 | Load | m2010_3 |
| ir.cpp:2010:23:2010:37 | StoreValue | r2010_2 |
| ir.cpp:2010:23:2010:37 | StoreValue | r2010_4 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_10 |
| ir.cpp:2013:8:2013:8 | ChiPartial | partial:m2013_3 |
| ir.cpp:2013:8:2013:8 | ChiPartial | partial:m2013_3 |
| ir.cpp:2013:8:2013:8 | ChiPartial | partial:m2013_3 |
| ir.cpp:2013:8:2013:8 | ChiTotal | total:m2013_2 |
| ir.cpp:2013:8:2013:8 | ChiTotal | total:m2013_2 |
| ir.cpp:2013:8:2013:8 | ChiTotal | total:m2013_2 |
| ir.cpp:2013:8:2013:8 | Load | m0_10 |
| ir.cpp:2013:8:2013:8 | Load | m2013_6 |
| ir.cpp:2013:8:2013:8 | Load | m2013_6 |
| ir.cpp:2013:8:2013:8 | Load | m2013_6 |
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_3 |
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_3 |
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_3 |
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_8 |
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_8 |
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_8 |
| ir.cpp:2014:13:2014:29 | Address | &:r2014_5 |
| ir.cpp:2014:13:2014:29 | Address | &:r2014_5 |
| ir.cpp:2014:13:2014:29 | Address | &:r2014_7 |
| ir.cpp:2014:13:2014:29 | Address | &:r2014_7 |
| ir.cpp:2014:13:2014:29 | ChiPartial | partial:m2014_3 |
| ir.cpp:2014:13:2014:29 | ChiTotal | total:m2014_2 |
| ir.cpp:2014:13:2014:29 | Load | m2014_6 |
| ir.cpp:2014:13:2014:29 | SideEffect | m2014_3 |
| ir.cpp:2014:13:2014:29 | SideEffect | m2014_8 |
| ir.cpp:2017:6:2017:25 | ChiPartial | partial:m2017_3 |
| ir.cpp:2017:6:2017:25 | ChiTotal | total:m2017_2 |
| ir.cpp:2017:6:2017:25 | SideEffect | ~m2021_32 |
| ir.cpp:2017:32:2017:32 | Address | &:r2017_5 |
| ir.cpp:2017:52:2017:52 | Address | &:r2017_7 |
| ir.cpp:2017:72:2017:72 | Address | &:r2017_9 |
| ir.cpp:2017:92:2017:92 | Address | &:r2017_11 |
| ir.cpp:2018:5:2018:5 | Address | &:r2018_1 |
| ir.cpp:2018:5:2018:5 | Address | &:r2018_1 |
| ir.cpp:2018:5:2018:5 | Arg(this) | this:r2018_1 |
| ir.cpp:2018:5:2018:5 | ChiPartial | partial:m2018_16 |
| ir.cpp:2018:5:2018:5 | ChiTotal | total:m2017_12 |
| ir.cpp:2018:5:2018:5 | SideEffect | m2017_12 |
| ir.cpp:2018:7:2018:7 | CallTarget | func:r2018_2 |
| ir.cpp:2018:7:2018:7 | ChiPartial | partial:m2018_12 |
| ir.cpp:2018:7:2018:7 | ChiTotal | total:m2017_4 |
| ir.cpp:2018:7:2018:7 | SideEffect | ~m2017_4 |
| ir.cpp:2018:7:2018:7 | Unary | r2018_11 |
| ir.cpp:2018:9:2018:9 | Address | &:r2018_3 |
| ir.cpp:2018:9:2018:9 | Condition | r2018_4 |
| ir.cpp:2018:9:2018:9 | Load | m2017_6 |
| ir.cpp:2018:9:2018:17 | Address | &:r2018_7 |
| ir.cpp:2018:9:2018:17 | Address | &:r2018_10 |
| ir.cpp:2018:9:2018:17 | Address | &:r2018_20 |
| ir.cpp:2018:9:2018:17 | Address | &:r2018_23 |
| ir.cpp:2018:9:2018:17 | Arg(0) | 0:r2018_10 |
| ir.cpp:2018:9:2018:17 | Load | m2018_6 |
| ir.cpp:2018:9:2018:17 | Phi | from 2:m2018_21 |
| ir.cpp:2018:9:2018:17 | Phi | from 3:m2018_24 |
| ir.cpp:2018:9:2018:17 | SideEffect | ~m2018_13 |
| ir.cpp:2018:9:2018:17 | Unary | r2018_8 |
| ir.cpp:2018:9:2018:17 | Unary | r2018_9 |
| ir.cpp:2018:13:2018:13 | StoreValue | r2018_19 |
| ir.cpp:2018:17:2018:17 | StoreValue | r2018_22 |
| ir.cpp:2019:5:2019:5 | Address | &:r2019_1 |
| ir.cpp:2019:5:2019:5 | Address | &:r2019_1 |
| ir.cpp:2019:5:2019:5 | Arg(this) | this:r2019_1 |
| ir.cpp:2019:5:2019:5 | ChiPartial | partial:m2019_19 |
| ir.cpp:2019:5:2019:5 | ChiTotal | total:m2018_17 |
| ir.cpp:2019:5:2019:5 | SideEffect | m2018_17 |
| ir.cpp:2019:7:2019:7 | CallTarget | func:r2019_2 |
| ir.cpp:2019:7:2019:7 | ChiPartial | partial:m2019_15 |
| ir.cpp:2019:7:2019:7 | ChiTotal | total:m2019_7 |
| ir.cpp:2019:7:2019:7 | SideEffect | ~m2019_7 |
| ir.cpp:2019:7:2019:7 | Unary | r2019_14 |
| ir.cpp:2019:9:2019:9 | Address | &:r2019_4 |
| ir.cpp:2019:9:2019:9 | Address | &:r2019_9 |
| ir.cpp:2019:9:2019:9 | Address | &:r2019_35 |
| ir.cpp:2019:9:2019:9 | Address | &:r2019_46 |
| ir.cpp:2019:9:2019:9 | Condition | r2019_5 |
| ir.cpp:2019:9:2019:9 | Load | m2017_6 |
| ir.cpp:2019:9:2019:9 | Load | m2019_8 |
| ir.cpp:2019:9:2019:9 | Phi | from 5:m2019_36 |
| ir.cpp:2019:9:2019:9 | Phi | from 5:~m2019_30 |
| ir.cpp:2019:9:2019:9 | Phi | from 6:m2019_47 |
| ir.cpp:2019:9:2019:9 | Phi | from 6:~m2019_42 |
| ir.cpp:2019:9:2019:9 | StoreValue | r2019_10 |
| ir.cpp:2019:9:2019:34 | Address | &:r2019_3 |
| ir.cpp:2019:9:2019:34 | Address | &:r2019_13 |
| ir.cpp:2019:9:2019:34 | Arg(0) | 0:r2019_13 |
| ir.cpp:2019:9:2019:34 | SideEffect | ~m2019_11 |
| ir.cpp:2019:9:2019:34 | Unary | r2019_3 |
| ir.cpp:2019:9:2019:34 | Unary | r2019_12 |
| ir.cpp:2019:13:2019:13 | Address | &:r2019_22 |
| ir.cpp:2019:13:2019:13 | Address | &:r2019_22 |
| ir.cpp:2019:13:2019:13 | Address | &:r2019_22 |
| ir.cpp:2019:13:2019:13 | Address | &:r2019_27 |
| ir.cpp:2019:13:2019:13 | Arg(0) | 0:r2019_27 |
| ir.cpp:2019:13:2019:13 | Arg(this) | this:r2019_22 |
| ir.cpp:2019:13:2019:13 | CallTarget | func:r2019_24 |
| ir.cpp:2019:13:2019:13 | ChiPartial | partial:m2019_29 |
| ir.cpp:2019:13:2019:13 | ChiPartial | partial:m2019_32 |
| ir.cpp:2019:13:2019:13 | ChiTotal | total:m2018_13 |
| ir.cpp:2019:13:2019:13 | ChiTotal | total:m2019_23 |
| ir.cpp:2019:13:2019:13 | Load | m2019_33 |
| ir.cpp:2019:13:2019:13 | SideEffect | ~m2017_8 |
| ir.cpp:2019:13:2019:13 | SideEffect | ~m2018_13 |
| ir.cpp:2019:13:2019:13 | StoreValue | r2019_34 |
| ir.cpp:2019:13:2019:13 | Unary | r2019_25 |
| ir.cpp:2019:13:2019:13 | Unary | r2019_26 |
| ir.cpp:2019:17:2019:34 | Address | &:r2019_37 |
| ir.cpp:2019:17:2019:34 | Address | &:r2019_37 |
| ir.cpp:2019:17:2019:34 | Address | &:r2019_37 |
| ir.cpp:2019:17:2019:34 | Arg(this) | this:r2019_37 |
| ir.cpp:2019:17:2019:34 | CallTarget | func:r2019_39 |
| ir.cpp:2019:17:2019:34 | ChiPartial | partial:m2019_41 |
| ir.cpp:2019:17:2019:34 | ChiPartial | partial:m2019_43 |
| ir.cpp:2019:17:2019:34 | ChiTotal | total:m2018_13 |
| ir.cpp:2019:17:2019:34 | ChiTotal | total:m2019_38 |
| ir.cpp:2019:17:2019:34 | Load | m2019_44 |
| ir.cpp:2019:17:2019:34 | SideEffect | ~m2018_13 |
| ir.cpp:2019:17:2019:34 | StoreValue | r2019_45 |
| ir.cpp:2020:5:2020:5 | Address | &:r2020_1 |
| ir.cpp:2020:5:2020:5 | Address | &:r2020_1 |
| ir.cpp:2020:5:2020:5 | Arg(this) | this:r2020_1 |
| ir.cpp:2020:5:2020:5 | ChiPartial | partial:m2020_19 |
| ir.cpp:2020:5:2020:5 | ChiTotal | total:m2019_20 |
| ir.cpp:2020:5:2020:5 | SideEffect | m2019_20 |
| ir.cpp:2020:7:2020:7 | CallTarget | func:r2020_2 |
| ir.cpp:2020:7:2020:7 | ChiPartial | partial:m2020_15 |
| ir.cpp:2020:7:2020:7 | ChiTotal | total:m2020_7 |
| ir.cpp:2020:7:2020:7 | SideEffect | ~m2020_7 |
| ir.cpp:2020:7:2020:7 | Unary | r2020_14 |
| ir.cpp:2020:9:2020:9 | Address | &:r2020_4 |
| ir.cpp:2020:9:2020:9 | Address | &:r2020_9 |
| ir.cpp:2020:9:2020:9 | Address | &:r2020_31 |
| ir.cpp:2020:9:2020:9 | Address | &:r2020_42 |
| ir.cpp:2020:9:2020:9 | Condition | r2020_5 |
| ir.cpp:2020:9:2020:9 | Load | m2017_6 |
| ir.cpp:2020:9:2020:9 | Load | m2020_8 |
| ir.cpp:2020:9:2020:9 | Phi | from 8:m2020_32 |
| ir.cpp:2020:9:2020:9 | Phi | from 8:~m2020_27 |
| ir.cpp:2020:9:2020:9 | Phi | from 9:m2020_43 |
| ir.cpp:2020:9:2020:9 | Phi | from 9:~m2020_38 |
| ir.cpp:2020:9:2020:9 | StoreValue | r2020_10 |
| ir.cpp:2020:9:2020:51 | Address | &:r2020_3 |
| ir.cpp:2020:9:2020:51 | Address | &:r2020_13 |
| ir.cpp:2020:9:2020:51 | Arg(0) | 0:r2020_13 |
| ir.cpp:2020:9:2020:51 | SideEffect | ~m2020_11 |
| ir.cpp:2020:9:2020:51 | Unary | r2020_3 |
| ir.cpp:2020:9:2020:51 | Unary | r2020_12 |
| ir.cpp:2020:13:2020:30 | Address | &:r2020_22 |
| ir.cpp:2020:13:2020:30 | Address | &:r2020_22 |
| ir.cpp:2020:13:2020:30 | Address | &:r2020_22 |
| ir.cpp:2020:13:2020:30 | Arg(this) | this:r2020_22 |
| ir.cpp:2020:13:2020:30 | CallTarget | func:r2020_24 |
| ir.cpp:2020:13:2020:30 | ChiPartial | partial:m2020_26 |
| ir.cpp:2020:13:2020:30 | ChiPartial | partial:m2020_28 |
| ir.cpp:2020:13:2020:30 | ChiTotal | total:m2019_16 |
| ir.cpp:2020:13:2020:30 | ChiTotal | total:m2020_23 |
| ir.cpp:2020:13:2020:30 | Load | m2020_29 |
| ir.cpp:2020:13:2020:30 | SideEffect | ~m2019_16 |
| ir.cpp:2020:13:2020:30 | StoreValue | r2020_30 |
| ir.cpp:2020:34:2020:51 | Address | &:r2020_33 |
| ir.cpp:2020:34:2020:51 | Address | &:r2020_33 |
| ir.cpp:2020:34:2020:51 | Address | &:r2020_33 |
| ir.cpp:2020:34:2020:51 | Arg(this) | this:r2020_33 |
| ir.cpp:2020:34:2020:51 | CallTarget | func:r2020_35 |
| ir.cpp:2020:34:2020:51 | ChiPartial | partial:m2020_37 |
| ir.cpp:2020:34:2020:51 | ChiPartial | partial:m2020_39 |
| ir.cpp:2020:34:2020:51 | ChiTotal | total:m2019_16 |
| ir.cpp:2020:34:2020:51 | ChiTotal | total:m2020_34 |
| ir.cpp:2020:34:2020:51 | Load | m2020_40 |
| ir.cpp:2020:34:2020:51 | SideEffect | ~m2019_16 |
| ir.cpp:2020:34:2020:51 | StoreValue | r2020_41 |
| ir.cpp:2021:5:2021:19 | ChiPartial | partial:m2021_35 |
| ir.cpp:2021:5:2021:19 | ChiTotal | total:m2021_17 |
| ir.cpp:2021:5:2021:19 | SideEffect | m2021_17 |
| ir.cpp:2021:6:2021:6 | Address | &:r2021_1 |
| ir.cpp:2021:6:2021:6 | Address | &:r2021_1 |
| ir.cpp:2021:6:2021:6 | Arg(this) | this:r2021_1 |
| ir.cpp:2021:6:2021:6 | ChiPartial | partial:m2021_16 |
| ir.cpp:2021:6:2021:6 | ChiTotal | total:m2020_20 |
| ir.cpp:2021:6:2021:6 | SideEffect | m2020_20 |
| ir.cpp:2021:8:2021:8 | CallTarget | func:r2021_2 |
| ir.cpp:2021:8:2021:8 | ChiPartial | partial:m2021_12 |
| ir.cpp:2021:8:2021:8 | ChiTotal | total:m2020_16 |
| ir.cpp:2021:8:2021:8 | SideEffect | ~m2020_16 |
| ir.cpp:2021:8:2021:8 | Unary | r2021_11 |
| ir.cpp:2021:8:2021:19 | Address | &:r2021_18 |
| ir.cpp:2021:8:2021:19 | Address | &:r2021_18 |
| ir.cpp:2021:8:2021:19 | Arg(this) | this:r2021_18 |
| ir.cpp:2021:10:2021:10 | Address | &:r2021_3 |
| ir.cpp:2021:10:2021:10 | Condition | r2021_4 |
| ir.cpp:2021:10:2021:10 | Load | m2017_6 |
| ir.cpp:2021:10:2021:18 | Address | &:r2021_7 |
| ir.cpp:2021:10:2021:18 | Address | &:r2021_10 |
| ir.cpp:2021:10:2021:18 | Address | &:r2021_39 |
| ir.cpp:2021:10:2021:18 | Address | &:r2021_42 |
| ir.cpp:2021:10:2021:18 | Arg(0) | 0:r2021_10 |
| ir.cpp:2021:10:2021:18 | Load | m2021_6 |
| ir.cpp:2021:10:2021:18 | Phi | from 11:m2021_40 |
| ir.cpp:2021:10:2021:18 | Phi | from 12:m2021_43 |
| ir.cpp:2021:10:2021:18 | SideEffect | ~m2021_13 |
| ir.cpp:2021:10:2021:18 | Unary | r2021_8 |
| ir.cpp:2021:10:2021:18 | Unary | r2021_9 |
| ir.cpp:2021:14:2021:14 | StoreValue | r2021_38 |
| ir.cpp:2021:18:2021:18 | StoreValue | r2021_41 |
| ir.cpp:2021:21:2021:21 | CallTarget | func:r2021_19 |
| ir.cpp:2021:21:2021:21 | ChiPartial | partial:m2021_31 |
| ir.cpp:2021:21:2021:21 | ChiTotal | total:m2021_25 |
| ir.cpp:2021:21:2021:21 | SideEffect | ~m2021_25 |
| ir.cpp:2021:21:2021:21 | Unary | r2021_30 |
| ir.cpp:2021:23:2021:40 | Address | &:r2021_20 |
| ir.cpp:2021:23:2021:40 | Address | &:r2021_20 |
| ir.cpp:2021:23:2021:40 | Address | &:r2021_29 |
| ir.cpp:2021:23:2021:40 | Arg(0) | 0:r2021_29 |
| ir.cpp:2021:23:2021:40 | Arg(this) | this:r2021_20 |
| ir.cpp:2021:23:2021:40 | CallTarget | func:r2021_22 |
| ir.cpp:2021:23:2021:40 | ChiPartial | partial:m2021_24 |
| ir.cpp:2021:23:2021:40 | ChiPartial | partial:m2021_26 |
| ir.cpp:2021:23:2021:40 | ChiTotal | total:m2021_13 |
| ir.cpp:2021:23:2021:40 | ChiTotal | total:m2021_21 |
| ir.cpp:2021:23:2021:40 | SideEffect | ~m2021_13 |
| ir.cpp:2021:23:2021:40 | SideEffect | ~m2021_27 |
| ir.cpp:2021:23:2021:40 | Unary | r2021_20 |
| ir.cpp:2021:23:2021:40 | Unary | r2021_28 |
| ir.cpp:2026:14:2026:22 | ChiPartial | partial:m2026_3 |
| ir.cpp:2026:14:2026:22 | ChiTotal | total:m2026_2 |
| ir.cpp:2026:37:2026:37 | Address | &:r2026_5 |
| ir.cpp:2027:16:2027:16 | Address | &:r2027_1 |
| ir.cpp:2028:3:2028:3 | Address | &:r2028_9 |
| ir.cpp:2028:7:2028:7 | Address | &:r2028_1 |
| ir.cpp:2028:7:2028:7 | Left | r2028_2 |
| ir.cpp:2028:7:2028:7 | Load | m2026_6 |
| ir.cpp:2028:7:2028:13 | Condition | r2028_4 |
| ir.cpp:2028:7:2030:28 | Address | &:r2028_7 |
| ir.cpp:2028:7:2030:28 | Address | &:r2028_11 |
| ir.cpp:2028:7:2030:28 | Address | &:r2028_13 |
| ir.cpp:2028:7:2030:28 | Load | m2028_6 |
| ir.cpp:2028:7:2030:28 | Phi | from 2:m2028_12 |
| ir.cpp:2028:7:2030:28 | Phi | from 3:m2028_14 |
| ir.cpp:2028:7:2030:28 | StoreValue | r2028_8 |
| ir.cpp:2028:11:2028:13 | Right | r2028_3 |
| ir.cpp:2029:6:2029:20 | CallTarget | func:r2029_1 |
| ir.cpp:2029:6:2029:20 | ChiPartial | partial:m2029_5 |
| ir.cpp:2029:6:2029:20 | ChiTotal | total:m2026_4 |
| ir.cpp:2029:6:2029:20 | SideEffect | ~m2026_4 |
| ir.cpp:2029:6:2029:26 | StoreValue | r2029_9 |
| ir.cpp:2029:22:2029:22 | Address | &:r2029_2 |
| ir.cpp:2029:22:2029:22 | Arg(0) | 0:r2029_3 |
| ir.cpp:2029:22:2029:22 | Load | m2026_6 |
| ir.cpp:2029:26:2029:26 | Address | &:r2029_7 |
| ir.cpp:2029:26:2029:26 | Load | m2026_6 |
| ir.cpp:2029:26:2029:26 | Unary | r2029_8 |
| ir.cpp:2030:5:2030:28 | StoreValue | r2030_9 |
| ir.cpp:2030:6:2030:20 | CallTarget | func:r2030_1 |
| ir.cpp:2030:6:2030:20 | ChiPartial | partial:m2030_5 |
| ir.cpp:2030:6:2030:20 | ChiTotal | total:m2026_4 |
| ir.cpp:2030:6:2030:20 | SideEffect | ~m2026_4 |
| ir.cpp:2030:6:2030:27 | Unary | r2030_8 |
| ir.cpp:2030:22:2030:22 | Address | &:r2030_2 |
| ir.cpp:2030:22:2030:22 | Arg(0) | 0:r2030_3 |
| ir.cpp:2030:22:2030:22 | Load | m2026_6 |
| ir.cpp:2030:26:2030:27 | Unary | r2030_7 |
| 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 |

View File

@@ -724,6 +724,48 @@ complex.c:
# 58| v58_5(void) = AliasedUse : ~m?
# 58| v58_6(void) = ExitFunction :
ir.c:
# 7| void MyCoordsTest(int)
# 7| Block 0
# 7| v7_1(void) = EnterFunction :
# 7| mu7_2(unknown) = AliasedDefinition :
# 7| mu7_3(unknown) = InitializeNonLocal :
# 7| r7_4(glval<int>) = VariableAddress[pos] :
# 7| mu7_5(int) = InitializeParameter[pos] : &:r7_4
# 8| r8_1(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
# 8| mu8_2((unnamed class/struct/union)) = Uninitialized[coords] : &:r8_1
# 8| r8_3(glval<int>) = FieldAddress[x] : r8_1
# 8| r8_4(int) = Constant[0] :
# 8| mu8_5(int) = Store[?] : &:r8_3, r8_4
# 8| r8_6(glval<int>) = FieldAddress[y] : r8_1
# 8| r8_7(int) = Constant[0] :
# 8| mu8_8(int) = Store[?] : &:r8_6, r8_7
# 9| r9_1(glval<int>) = VariableAddress[pos] :
# 9| r9_2(int) = Load[pos] : &:r9_1, ~m?
# 9| r9_3(int) = Constant[1] :
# 9| r9_4(int) = Add : r9_2, r9_3
# 9| r9_5(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
# 9| r9_6(glval<int>) = FieldAddress[y] : r9_5
# 9| mu9_7(int) = Store[?] : &:r9_6, r9_4
# 9| r9_8(int) = CopyValue : r9_4
# 9| r9_9(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
# 9| r9_10(glval<int>) = FieldAddress[x] : r9_9
# 9| mu9_11(int) = Store[?] : &:r9_10, r9_8
# 10| r10_1(glval<unknown>) = FunctionAddress[getX] :
# 10| r10_2(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
# 10| r10_3(struct <unnamed> *) = CopyValue : r10_2
# 10| r10_4(int) = Call[getX] : func:r10_1, 0:r10_3
# 10| mu10_5(unknown) = ^CallSideEffect : ~m?
# 10| v10_6(void) = ^BufferReadSideEffect[0] : &:r10_3, ~m?
# 10| mu10_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_3
# 10| r10_8(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
# 10| r10_9(glval<int>) = FieldAddress[x] : r10_8
# 10| mu10_10(int) = Store[?] : &:r10_9, r10_4
# 11| v11_1(void) = NoOp :
# 7| v7_6(void) = ReturnVoid :
# 7| v7_7(void) = AliasedUse : ~m?
# 7| v7_8(void) = ExitFunction :
ir.cpp:
# 1| void Constants()
# 1| Block 0
@@ -10456,6 +10498,579 @@ ir.cpp:
# 1990| v1990_5(void) = AliasedUse : ~m?
# 1990| v1990_6(void) = ExitFunction :
# 1996| void TernaryTestInt(bool, int, int, int)
# 1996| Block 0
# 1996| v1996_1(void) = EnterFunction :
# 1996| mu1996_2(unknown) = AliasedDefinition :
# 1996| mu1996_3(unknown) = InitializeNonLocal :
# 1996| r1996_4(glval<bool>) = VariableAddress[a] :
# 1996| mu1996_5(bool) = InitializeParameter[a] : &:r1996_4
# 1996| r1996_6(glval<int>) = VariableAddress[x] :
# 1996| mu1996_7(int) = InitializeParameter[x] : &:r1996_6
# 1996| r1996_8(glval<int>) = VariableAddress[y] :
# 1996| mu1996_9(int) = InitializeParameter[y] : &:r1996_8
# 1996| r1996_10(glval<int>) = VariableAddress[z] :
# 1996| mu1996_11(int) = InitializeParameter[z] : &:r1996_10
# 1997| r1997_1(glval<bool>) = VariableAddress[a] :
# 1997| r1997_2(bool) = Load[a] : &:r1997_1, ~m?
# 1997| v1997_3(void) = ConditionalBranch : r1997_2
#-----| False -> Block 3
#-----| True -> Block 2
# 1997| Block 1
# 1997| r1997_4(glval<int>) = VariableAddress[#temp1997:9] :
# 1997| r1997_5(int) = Load[#temp1997:9] : &:r1997_4, ~m?
# 1997| r1997_6(glval<int>) = VariableAddress[z] :
# 1997| mu1997_7(int) = Store[z] : &:r1997_6, r1997_5
# 1998| r1998_1(glval<bool>) = VariableAddress[a] :
# 1998| r1998_2(bool) = Load[a] : &:r1998_1, ~m?
# 1998| v1998_3(void) = ConditionalBranch : r1998_2
#-----| False -> Block 6
#-----| True -> Block 5
# 1997| Block 2
# 1997| r1997_8(glval<int>) = VariableAddress[x] :
# 1997| r1997_9(int) = Load[x] : &:r1997_8, ~m?
# 1997| r1997_10(glval<int>) = VariableAddress[#temp1997:9] :
# 1997| mu1997_11(int) = Store[#temp1997:9] : &:r1997_10, r1997_9
#-----| Goto -> Block 1
# 1997| Block 3
# 1997| r1997_12(glval<int>) = VariableAddress[y] :
# 1997| r1997_13(int) = Load[y] : &:r1997_12, ~m?
# 1997| r1997_14(glval<int>) = VariableAddress[#temp1997:9] :
# 1997| mu1997_15(int) = Store[#temp1997:9] : &:r1997_14, r1997_13
#-----| Goto -> Block 1
# 1998| Block 4
# 1998| r1998_4(glval<int>) = VariableAddress[#temp1998:9] :
# 1998| r1998_5(int) = Load[#temp1998:9] : &:r1998_4, ~m?
# 1998| r1998_6(glval<int>) = VariableAddress[z] :
# 1998| mu1998_7(int) = Store[z] : &:r1998_6, r1998_5
# 1999| r1999_1(glval<bool>) = VariableAddress[a] :
# 1999| r1999_2(bool) = Load[a] : &:r1999_1, ~m?
# 1999| v1999_3(void) = ConditionalBranch : r1999_2
#-----| False -> Block 9
#-----| True -> Block 8
# 1998| Block 5
# 1998| r1998_8(glval<int>) = VariableAddress[x] :
# 1998| r1998_9(int) = Load[x] : &:r1998_8, ~m?
# 1998| r1998_10(glval<int>) = VariableAddress[#temp1998:9] :
# 1998| mu1998_11(int) = Store[#temp1998:9] : &:r1998_10, r1998_9
#-----| Goto -> Block 4
# 1998| Block 6
# 1998| r1998_12(int) = Constant[5] :
# 1998| r1998_13(glval<int>) = VariableAddress[#temp1998:9] :
# 1998| mu1998_14(int) = Store[#temp1998:9] : &:r1998_13, r1998_12
#-----| Goto -> Block 4
# 1999| Block 7
# 1999| r1999_4(glval<int>) = VariableAddress[#temp1999:9] :
# 1999| r1999_5(int) = Load[#temp1999:9] : &:r1999_4, ~m?
# 1999| r1999_6(glval<int>) = VariableAddress[z] :
# 1999| mu1999_7(int) = Store[z] : &:r1999_6, r1999_5
# 2000| r2000_1(int) = Constant[7] :
# 2000| r2000_2(glval<bool>) = VariableAddress[a] :
# 2000| r2000_3(bool) = Load[a] : &:r2000_2, ~m?
# 2000| v2000_4(void) = ConditionalBranch : r2000_3
#-----| False -> Block 12
#-----| True -> Block 11
# 1999| Block 8
# 1999| r1999_8(int) = Constant[3] :
# 1999| r1999_9(glval<int>) = VariableAddress[#temp1999:9] :
# 1999| mu1999_10(int) = Store[#temp1999:9] : &:r1999_9, r1999_8
#-----| Goto -> Block 7
# 1999| Block 9
# 1999| r1999_11(int) = Constant[5] :
# 1999| r1999_12(glval<int>) = VariableAddress[#temp1999:9] :
# 1999| mu1999_13(int) = Store[#temp1999:9] : &:r1999_12, r1999_11
#-----| Goto -> Block 7
# 2000| Block 10
# 2000| r2000_5(glval<unknown>) = VariableAddress[#temp2000:6] :
# 2000| r2000_6(glval<int>) = Load[#temp2000:6] : &:r2000_5, ~m?
# 2000| mu2000_7(int) = Store[?] : &:r2000_6, r2000_1
# 2001| v2001_1(void) = NoOp :
# 1996| v1996_12(void) = ReturnVoid :
# 1996| v1996_13(void) = AliasedUse : ~m?
# 1996| v1996_14(void) = ExitFunction :
# 2000| Block 11
# 2000| r2000_8(glval<int>) = VariableAddress[x] :
# 2000| r2000_9(glval<unknown>) = VariableAddress[#temp2000:6] :
# 2000| mu2000_10(glval<int>) = Store[#temp2000:6] : &:r2000_9, r2000_8
#-----| Goto -> Block 10
# 2000| Block 12
# 2000| r2000_11(glval<int>) = VariableAddress[y] :
# 2000| r2000_12(glval<unknown>) = VariableAddress[#temp2000:6] :
# 2000| mu2000_13(glval<int>) = Store[#temp2000:6] : &:r2000_12, r2000_11
#-----| Goto -> Block 10
# 2006| void TernaryTestPodObj(bool, TernaryPodObj, TernaryPodObj, TernaryPodObj)
# 2006| Block 0
# 2006| v2006_1(void) = EnterFunction :
# 2006| mu2006_2(unknown) = AliasedDefinition :
# 2006| mu2006_3(unknown) = InitializeNonLocal :
# 2006| r2006_4(glval<bool>) = VariableAddress[a] :
# 2006| mu2006_5(bool) = InitializeParameter[a] : &:r2006_4
# 2006| r2006_6(glval<TernaryPodObj>) = VariableAddress[x] :
# 2006| mu2006_7(TernaryPodObj) = InitializeParameter[x] : &:r2006_6
# 2006| r2006_8(glval<TernaryPodObj>) = VariableAddress[y] :
# 2006| mu2006_9(TernaryPodObj) = InitializeParameter[y] : &:r2006_8
# 2006| r2006_10(glval<TernaryPodObj>) = VariableAddress[z] :
# 2006| mu2006_11(TernaryPodObj) = InitializeParameter[z] : &:r2006_10
# 2007| r2007_1(glval<bool>) = VariableAddress[a] :
# 2007| r2007_2(bool) = Load[a] : &:r2007_1, ~m?
# 2007| v2007_3(void) = ConditionalBranch : r2007_2
#-----| False -> Block 3
#-----| True -> Block 2
# 2007| Block 1
# 2007| r2007_4(glval<TernaryPodObj>) = VariableAddress[#temp2007:9] :
# 2007| r2007_5(TernaryPodObj) = Load[#temp2007:9] : &:r2007_4, ~m?
# 2007| r2007_6(glval<TernaryPodObj>) = VariableAddress[z] :
# 2007| mu2007_7(TernaryPodObj) = Store[z] : &:r2007_6, r2007_5
# 2008| r2008_1(glval<TernaryPodObj>) = VariableAddress[#temp2008:9] :
# 2008| r2008_2(glval<bool>) = VariableAddress[a] :
# 2008| r2008_3(bool) = Load[a] : &:r2008_2, ~m?
# 2008| v2008_4(void) = ConditionalBranch : r2008_3
#-----| False -> Block 6
#-----| True -> Block 5
# 2007| Block 2
# 2007| r2007_8(glval<TernaryPodObj>) = VariableAddress[x] :
# 2007| r2007_9(TernaryPodObj) = Load[x] : &:r2007_8, ~m?
# 2007| r2007_10(glval<TernaryPodObj>) = VariableAddress[#temp2007:9] :
# 2007| mu2007_11(TernaryPodObj) = Store[#temp2007:9] : &:r2007_10, r2007_9
#-----| Goto -> Block 1
# 2007| Block 3
# 2007| r2007_12(glval<TernaryPodObj>) = VariableAddress[y] :
# 2007| r2007_13(TernaryPodObj) = Load[y] : &:r2007_12, ~m?
# 2007| r2007_14(glval<TernaryPodObj>) = VariableAddress[#temp2007:9] :
# 2007| mu2007_15(TernaryPodObj) = Store[#temp2007:9] : &:r2007_14, r2007_13
#-----| Goto -> Block 1
# 2008| Block 4
# 2008| r2008_5(glval<TernaryPodObj>) = VariableAddress[#temp2008:9] :
# 2008| r2008_6(TernaryPodObj) = Load[#temp2008:9] : &:r2008_5, ~m?
# 2008| mu2008_7(TernaryPodObj) = Store[#temp2008:9] : &:r2008_1, r2008_6
# 2008| r2008_8(TernaryPodObj) = Load[#temp2008:9] : &:r2008_1, ~m?
# 2008| r2008_9(glval<TernaryPodObj>) = VariableAddress[z] :
# 2008| mu2008_10(TernaryPodObj) = Store[z] : &:r2008_9, r2008_8
# 2009| r2009_1(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
# 2009| r2009_2(glval<bool>) = VariableAddress[a] :
# 2009| r2009_3(bool) = Load[a] : &:r2009_2, ~m?
# 2009| v2009_4(void) = ConditionalBranch : r2009_3
#-----| False -> Block 9
#-----| True -> Block 8
# 2008| Block 5
# 2008| r2008_11(glval<TernaryPodObj>) = VariableAddress[#temp2008:13] :
# 2008| r2008_12(glval<TernaryPodObj>) = VariableAddress[x] :
# 2008| r2008_13(TernaryPodObj) = Load[x] : &:r2008_12, ~m?
# 2008| mu2008_14(TernaryPodObj) = Store[#temp2008:13] : &:r2008_11, r2008_13
# 2008| r2008_15(TernaryPodObj) = Load[#temp2008:13] : &:r2008_11, ~m?
# 2008| r2008_16(glval<TernaryPodObj>) = VariableAddress[#temp2008:9] :
# 2008| mu2008_17(TernaryPodObj) = Store[#temp2008:9] : &:r2008_16, r2008_15
#-----| Goto -> Block 4
# 2008| Block 6
# 2008| r2008_18(glval<TernaryPodObj>) = VariableAddress[#temp2008:17] :
# 2008| r2008_19(TernaryPodObj) = Constant[0] :
# 2008| mu2008_20(TernaryPodObj) = Store[#temp2008:17] : &:r2008_18, r2008_19
# 2008| r2008_21(TernaryPodObj) = Load[#temp2008:17] : &:r2008_18, ~m?
# 2008| r2008_22(glval<TernaryPodObj>) = VariableAddress[#temp2008:9] :
# 2008| mu2008_23(TernaryPodObj) = Store[#temp2008:9] : &:r2008_22, r2008_21
#-----| Goto -> Block 4
# 2009| Block 7
# 2009| r2009_5(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
# 2009| r2009_6(TernaryPodObj) = Load[#temp2009:9] : &:r2009_5, ~m?
# 2009| mu2009_7(TernaryPodObj) = Store[#temp2009:9] : &:r2009_1, r2009_6
# 2009| r2009_8(TernaryPodObj) = Load[#temp2009:9] : &:r2009_1, ~m?
# 2009| r2009_9(glval<TernaryPodObj>) = VariableAddress[z] :
# 2009| mu2009_10(TernaryPodObj) = Store[z] : &:r2009_9, r2009_8
# 2010| r2010_1(glval<TernaryPodObj>) = VariableAddress[#temp2010:23] :
# 2010| r2010_2(TernaryPodObj) = Constant[0] :
# 2010| mu2010_3(TernaryPodObj) = Store[#temp2010:23] : &:r2010_1, r2010_2
# 2010| r2010_4(TernaryPodObj) = Load[#temp2010:23] : &:r2010_1, ~m?
# 2010| r2010_5(glval<bool>) = VariableAddress[a] :
# 2010| r2010_6(bool) = Load[a] : &:r2010_5, ~m?
# 2010| v2010_7(void) = ConditionalBranch : r2010_6
#-----| False -> Block 12
#-----| True -> Block 11
# 2009| Block 8
# 2009| r2009_11(glval<TernaryPodObj>) = VariableAddress[#temp2009:13] :
# 2009| r2009_12(TernaryPodObj) = Constant[0] :
# 2009| mu2009_13(TernaryPodObj) = Store[#temp2009:13] : &:r2009_11, r2009_12
# 2009| r2009_14(TernaryPodObj) = Load[#temp2009:13] : &:r2009_11, ~m?
# 2009| r2009_15(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
# 2009| mu2009_16(TernaryPodObj) = Store[#temp2009:9] : &:r2009_15, r2009_14
#-----| Goto -> Block 7
# 2009| Block 9
# 2009| r2009_17(glval<TernaryPodObj>) = VariableAddress[#temp2009:31] :
# 2009| r2009_18(TernaryPodObj) = Constant[0] :
# 2009| mu2009_19(TernaryPodObj) = Store[#temp2009:31] : &:r2009_17, r2009_18
# 2009| r2009_20(TernaryPodObj) = Load[#temp2009:31] : &:r2009_17, ~m?
# 2009| r2009_21(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
# 2009| mu2009_22(TernaryPodObj) = Store[#temp2009:9] : &:r2009_21, r2009_20
#-----| Goto -> Block 7
# 2010| Block 10
# 2010| r2010_8(glval<TernaryPodObj>) = VariableAddress[#temp2010:10] :
# 2010| r2010_9(TernaryPodObj) = Load[#temp2010:10] : &:r2010_8, ~m?
# 2010| r2010_10(glval<TernaryPodObj>) = VariableAddress[z] :
# 2010| mu2010_11(TernaryPodObj) = Store[z] : &:r2010_10, r2010_9
# 2010| r2010_12(glval<TernaryPodObj>) = CopyValue : r2010_10
# 2010| mu2010_13(TernaryPodObj) = Store[?] : &:r2010_12, r2010_4
# 2011| v2011_1(void) = NoOp :
# 2006| v2006_12(void) = ReturnVoid :
# 2006| v2006_13(void) = AliasedUse : ~m?
# 2006| v2006_14(void) = ExitFunction :
# 2010| Block 11
# 2010| r2010_14(glval<TernaryPodObj>) = VariableAddress[x] :
# 2010| r2010_15(TernaryPodObj) = Load[x] : &:r2010_14, ~m?
# 2010| r2010_16(glval<TernaryPodObj>) = VariableAddress[#temp2010:10] :
# 2010| mu2010_17(TernaryPodObj) = Store[#temp2010:10] : &:r2010_16, r2010_15
#-----| Goto -> Block 10
# 2010| Block 12
# 2010| r2010_18(glval<TernaryPodObj>) = VariableAddress[y] :
# 2010| r2010_19(TernaryPodObj) = Load[y] : &:r2010_18, ~m?
# 2010| r2010_20(glval<TernaryPodObj>) = VariableAddress[#temp2010:10] :
# 2010| mu2010_21(TernaryPodObj) = Store[#temp2010:10] : &:r2010_20, r2010_19
#-----| Goto -> Block 10
# 2013| TernaryNonPodObj& TernaryNonPodObj::operator=(TernaryNonPodObj const&)
# 2013| Block 0
# 2013| v2013_1(void) = EnterFunction :
# 2013| mu2013_2(unknown) = AliasedDefinition :
# 2013| mu2013_3(unknown) = InitializeNonLocal :
# 2013| r2013_4(glval<unknown>) = VariableAddress[#this] :
# 2013| mu2013_5(glval<TernaryNonPodObj>) = InitializeParameter[#this] : &:r2013_4
# 2013| r2013_6(glval<TernaryNonPodObj>) = Load[#this] : &:r2013_4, ~m?
# 2013| mu2013_7(TernaryNonPodObj) = InitializeIndirection[#this] : &:r2013_6
#-----| r0_1(glval<TernaryNonPodObj &>) = VariableAddress[(unnamed parameter 0)] :
#-----| mu0_2(TernaryNonPodObj &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
#-----| r0_3(TernaryNonPodObj &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
#-----| r0_5(glval<TernaryNonPodObj &>) = VariableAddress[#return] :
#-----| r0_6(glval<unknown>) = VariableAddress[#this] :
#-----| r0_7(TernaryNonPodObj *) = Load[#this] : &:r0_6, ~m?
#-----| r0_8(glval<TernaryNonPodObj>) = CopyValue : r0_7
#-----| r0_9(TernaryNonPodObj &) = CopyValue : r0_8
#-----| mu0_10(TernaryNonPodObj &) = Store[#return] : &:r0_5, r0_9
# 2013| v2013_8(void) = ReturnIndirection[#this] : &:r2013_6, ~m?
#-----| v0_11(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
# 2013| r2013_9(glval<TernaryNonPodObj &>) = VariableAddress[#return] :
# 2013| v2013_10(void) = ReturnValue : &:r2013_9, ~m?
# 2013| v2013_11(void) = AliasedUse : ~m?
# 2013| v2013_12(void) = ExitFunction :
# 2013| void TernaryNonPodObj::TernaryNonPodObj()
# 2013| Block 0
# 2013| v2013_1(void) = EnterFunction :
# 2013| mu2013_2(unknown) = AliasedDefinition :
# 2013| mu2013_3(unknown) = InitializeNonLocal :
# 2013| r2013_4(glval<unknown>) = VariableAddress[#this] :
# 2013| mu2013_5(glval<TernaryNonPodObj>) = InitializeParameter[#this] : &:r2013_4
# 2013| r2013_6(glval<TernaryNonPodObj>) = Load[#this] : &:r2013_4, ~m?
# 2013| mu2013_7(TernaryNonPodObj) = InitializeIndirection[#this] : &:r2013_6
# 2013| v2013_8(void) = NoOp :
# 2013| v2013_9(void) = ReturnIndirection[#this] : &:r2013_6, ~m?
# 2013| v2013_10(void) = ReturnVoid :
# 2013| v2013_11(void) = AliasedUse : ~m?
# 2013| v2013_12(void) = ExitFunction :
# 2013| void TernaryNonPodObj::TernaryNonPodObj(TernaryNonPodObj const&)
# 2013| Block 0
# 2013| v2013_1(void) = EnterFunction :
# 2013| mu2013_2(unknown) = AliasedDefinition :
# 2013| mu2013_3(unknown) = InitializeNonLocal :
# 2013| r2013_4(glval<unknown>) = VariableAddress[#this] :
# 2013| mu2013_5(glval<TernaryNonPodObj>) = InitializeParameter[#this] : &:r2013_4
# 2013| r2013_6(glval<TernaryNonPodObj>) = Load[#this] : &:r2013_4, ~m?
# 2013| mu2013_7(TernaryNonPodObj) = InitializeIndirection[#this] : &:r2013_6
#-----| r0_1(glval<TernaryNonPodObj &>) = VariableAddress[(unnamed parameter 0)] :
#-----| mu0_2(TernaryNonPodObj &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
#-----| r0_3(TernaryNonPodObj &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
# 2013| v2013_8(void) = NoOp :
# 2013| v2013_9(void) = ReturnIndirection[#this] : &:r2013_6, ~m?
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
# 2013| v2013_10(void) = ReturnVoid :
# 2013| v2013_11(void) = AliasedUse : ~m?
# 2013| v2013_12(void) = ExitFunction :
# 2014| void TernaryNonPodObj::~TernaryNonPodObj()
# 2014| Block 0
# 2014| v2014_1(void) = EnterFunction :
# 2014| mu2014_2(unknown) = AliasedDefinition :
# 2014| mu2014_3(unknown) = InitializeNonLocal :
# 2014| r2014_4(glval<unknown>) = VariableAddress[#this] :
# 2014| mu2014_5(glval<TernaryNonPodObj>) = InitializeParameter[#this] : &:r2014_4
# 2014| r2014_6(glval<TernaryNonPodObj>) = Load[#this] : &:r2014_4, ~m?
# 2014| mu2014_7(TernaryNonPodObj) = InitializeIndirection[#this] : &:r2014_6
# 2014| v2014_8(void) = NoOp :
# 2014| v2014_9(void) = ReturnIndirection[#this] : &:r2014_6, ~m?
# 2014| v2014_10(void) = ReturnVoid :
# 2014| v2014_11(void) = AliasedUse : ~m?
# 2014| v2014_12(void) = ExitFunction :
# 2017| void TernaryTestNonPodObj(bool, TernaryNonPodObj, TernaryNonPodObj, TernaryNonPodObj)
# 2017| Block 0
# 2017| v2017_1(void) = EnterFunction :
# 2017| mu2017_2(unknown) = AliasedDefinition :
# 2017| mu2017_3(unknown) = InitializeNonLocal :
# 2017| r2017_4(glval<bool>) = VariableAddress[a] :
# 2017| mu2017_5(bool) = InitializeParameter[a] : &:r2017_4
# 2017| r2017_6(glval<TernaryNonPodObj>) = VariableAddress[x] :
# 2017| mu2017_7(TernaryNonPodObj) = InitializeParameter[x] : &:r2017_6
# 2017| r2017_8(glval<TernaryNonPodObj>) = VariableAddress[y] :
# 2017| mu2017_9(TernaryNonPodObj) = InitializeParameter[y] : &:r2017_8
# 2017| r2017_10(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2017| mu2017_11(TernaryNonPodObj) = InitializeParameter[z] : &:r2017_10
# 2018| r2018_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2018| r2018_2(glval<unknown>) = FunctionAddress[operator=] :
# 2018| r2018_3(glval<bool>) = VariableAddress[a] :
# 2018| r2018_4(bool) = Load[a] : &:r2018_3, ~m?
# 2018| v2018_5(void) = ConditionalBranch : r2018_4
#-----| False -> Block 3
#-----| True -> Block 2
# 2018| Block 1
# 2018| r2018_6(glval<unknown>) = VariableAddress[#temp2018:9] :
# 2018| r2018_7(glval<TernaryNonPodObj>) = Load[#temp2018:9] : &:r2018_6, ~m?
# 2018| r2018_8(glval<TernaryNonPodObj>) = Convert : r2018_7
# 2018| r2018_9(TernaryNonPodObj &) = CopyValue : r2018_8
# 2018| r2018_10(TernaryNonPodObj &) = Call[operator=] : func:r2018_2, this:r2018_1, 0:r2018_9
# 2018| mu2018_11(unknown) = ^CallSideEffect : ~m?
# 2018| v2018_12(void) = ^IndirectReadSideEffect[-1] : &:r2018_1, ~m?
# 2018| v2018_13(void) = ^BufferReadSideEffect[0] : &:r2018_9, ~m?
# 2018| mu2018_14(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2018_1
# 2018| r2018_15(glval<TernaryNonPodObj>) = CopyValue : r2018_10
# 2019| r2019_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2019| r2019_2(glval<unknown>) = FunctionAddress[operator=] :
# 2019| r2019_3(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:9] :
# 2019| r2019_4(glval<bool>) = VariableAddress[a] :
# 2019| r2019_5(bool) = Load[a] : &:r2019_4, ~m?
# 2019| v2019_6(void) = ConditionalBranch : r2019_5
#-----| False -> Block 6
#-----| True -> Block 5
# 2018| Block 2
# 2018| r2018_16(glval<TernaryNonPodObj>) = VariableAddress[x] :
# 2018| r2018_17(glval<unknown>) = VariableAddress[#temp2018:9] :
# 2018| mu2018_18(glval<TernaryNonPodObj>) = Store[#temp2018:9] : &:r2018_17, r2018_16
#-----| Goto -> Block 1
# 2018| Block 3
# 2018| r2018_19(glval<TernaryNonPodObj>) = VariableAddress[y] :
# 2018| r2018_20(glval<unknown>) = VariableAddress[#temp2018:9] :
# 2018| mu2018_21(glval<TernaryNonPodObj>) = Store[#temp2018:9] : &:r2018_20, r2018_19
#-----| Goto -> Block 1
# 2019| Block 4
# 2019| r2019_7(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:9] :
# 2019| r2019_8(TernaryNonPodObj) = Load[#temp2019:9] : &:r2019_7, ~m?
# 2019| mu2019_9(TernaryNonPodObj) = Store[#temp2019:9] : &:r2019_3, r2019_8
# 2019| r2019_10(glval<TernaryNonPodObj>) = Convert : r2019_3
# 2019| r2019_11(TernaryNonPodObj &) = CopyValue : r2019_10
# 2019| r2019_12(TernaryNonPodObj &) = Call[operator=] : func:r2019_2, this:r2019_1, 0:r2019_11
# 2019| mu2019_13(unknown) = ^CallSideEffect : ~m?
# 2019| v2019_14(void) = ^IndirectReadSideEffect[-1] : &:r2019_1, ~m?
# 2019| v2019_15(void) = ^BufferReadSideEffect[0] : &:r2019_11, ~m?
# 2019| mu2019_16(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2019_1
# 2019| r2019_17(glval<TernaryNonPodObj>) = CopyValue : r2019_12
# 2020| r2020_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2020| r2020_2(glval<unknown>) = FunctionAddress[operator=] :
# 2020| r2020_3(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:9] :
# 2020| r2020_4(glval<bool>) = VariableAddress[a] :
# 2020| r2020_5(bool) = Load[a] : &:r2020_4, ~m?
# 2020| v2020_6(void) = ConditionalBranch : r2020_5
#-----| False -> Block 9
#-----| True -> Block 8
# 2019| Block 5
# 2019| r2019_18(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:13] :
# 2019| mu2019_19(TernaryNonPodObj) = Uninitialized[#temp2019:13] : &:r2019_18
# 2019| r2019_20(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
# 2019| r2019_21(glval<TernaryNonPodObj>) = VariableAddress[x] :
# 2019| r2019_22(glval<TernaryNonPodObj>) = Convert : r2019_21
# 2019| r2019_23(TernaryNonPodObj &) = CopyValue : r2019_22
# 2019| v2019_24(void) = Call[TernaryNonPodObj] : func:r2019_20, this:r2019_18, 0:r2019_23
# 2019| mu2019_25(unknown) = ^CallSideEffect : ~m?
# 2019| v2019_26(void) = ^BufferReadSideEffect[0] : &:r2019_23, ~m?
# 2019| mu2019_27(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2019_18
# 2019| r2019_28(TernaryNonPodObj) = Load[#temp2019:13] : &:r2019_18, ~m?
# 2019| r2019_29(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:9] :
# 2019| mu2019_30(TernaryNonPodObj) = Store[#temp2019:9] : &:r2019_29, r2019_28
#-----| Goto -> Block 4
# 2019| Block 6
# 2019| r2019_31(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:17] :
# 2019| mu2019_32(TernaryNonPodObj) = Uninitialized[#temp2019:17] : &:r2019_31
# 2019| r2019_33(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
# 2019| v2019_34(void) = Call[TernaryNonPodObj] : func:r2019_33, this:r2019_31
# 2019| mu2019_35(unknown) = ^CallSideEffect : ~m?
# 2019| mu2019_36(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2019_31
# 2019| r2019_37(TernaryNonPodObj) = Load[#temp2019:17] : &:r2019_31, ~m?
# 2019| r2019_38(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:9] :
# 2019| mu2019_39(TernaryNonPodObj) = Store[#temp2019:9] : &:r2019_38, r2019_37
#-----| Goto -> Block 4
# 2020| Block 7
# 2020| r2020_7(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:9] :
# 2020| r2020_8(TernaryNonPodObj) = Load[#temp2020:9] : &:r2020_7, ~m?
# 2020| mu2020_9(TernaryNonPodObj) = Store[#temp2020:9] : &:r2020_3, r2020_8
# 2020| r2020_10(glval<TernaryNonPodObj>) = Convert : r2020_3
# 2020| r2020_11(TernaryNonPodObj &) = CopyValue : r2020_10
# 2020| r2020_12(TernaryNonPodObj &) = Call[operator=] : func:r2020_2, this:r2020_1, 0:r2020_11
# 2020| mu2020_13(unknown) = ^CallSideEffect : ~m?
# 2020| v2020_14(void) = ^IndirectReadSideEffect[-1] : &:r2020_1, ~m?
# 2020| v2020_15(void) = ^BufferReadSideEffect[0] : &:r2020_11, ~m?
# 2020| mu2020_16(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2020_1
# 2020| r2020_17(glval<TernaryNonPodObj>) = CopyValue : r2020_12
# 2021| r2021_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
# 2021| r2021_2(glval<unknown>) = FunctionAddress[operator=] :
# 2021| r2021_3(glval<bool>) = VariableAddress[a] :
# 2021| r2021_4(bool) = Load[a] : &:r2021_3, ~m?
# 2021| v2021_5(void) = ConditionalBranch : r2021_4
#-----| False -> Block 12
#-----| True -> Block 11
# 2020| Block 8
# 2020| r2020_18(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:13] :
# 2020| mu2020_19(TernaryNonPodObj) = Uninitialized[#temp2020:13] : &:r2020_18
# 2020| r2020_20(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
# 2020| v2020_21(void) = Call[TernaryNonPodObj] : func:r2020_20, this:r2020_18
# 2020| mu2020_22(unknown) = ^CallSideEffect : ~m?
# 2020| mu2020_23(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2020_18
# 2020| r2020_24(TernaryNonPodObj) = Load[#temp2020:13] : &:r2020_18, ~m?
# 2020| r2020_25(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:9] :
# 2020| mu2020_26(TernaryNonPodObj) = Store[#temp2020:9] : &:r2020_25, r2020_24
#-----| Goto -> Block 7
# 2020| Block 9
# 2020| r2020_27(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:34] :
# 2020| mu2020_28(TernaryNonPodObj) = Uninitialized[#temp2020:34] : &:r2020_27
# 2020| r2020_29(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
# 2020| v2020_30(void) = Call[TernaryNonPodObj] : func:r2020_29, this:r2020_27
# 2020| mu2020_31(unknown) = ^CallSideEffect : ~m?
# 2020| mu2020_32(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2020_27
# 2020| r2020_33(TernaryNonPodObj) = Load[#temp2020:34] : &:r2020_27, ~m?
# 2020| r2020_34(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:9] :
# 2020| mu2020_35(TernaryNonPodObj) = Store[#temp2020:9] : &:r2020_34, r2020_33
#-----| Goto -> Block 7
# 2021| Block 10
# 2021| r2021_6(glval<unknown>) = VariableAddress[#temp2021:10] :
# 2021| r2021_7(glval<TernaryNonPodObj>) = Load[#temp2021:10] : &:r2021_6, ~m?
# 2021| r2021_8(glval<TernaryNonPodObj>) = Convert : r2021_7
# 2021| r2021_9(TernaryNonPodObj &) = CopyValue : r2021_8
# 2021| r2021_10(TernaryNonPodObj &) = Call[operator=] : func:r2021_2, this:r2021_1, 0:r2021_9
# 2021| mu2021_11(unknown) = ^CallSideEffect : ~m?
# 2021| v2021_12(void) = ^IndirectReadSideEffect[-1] : &:r2021_1, ~m?
# 2021| v2021_13(void) = ^BufferReadSideEffect[0] : &:r2021_9, ~m?
# 2021| mu2021_14(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_1
# 2021| r2021_15(glval<TernaryNonPodObj>) = CopyValue : r2021_10
# 2021| r2021_16(glval<unknown>) = FunctionAddress[operator=] :
# 2021| r2021_17(glval<TernaryNonPodObj>) = VariableAddress[#temp2021:23] :
# 2021| mu2021_18(TernaryNonPodObj) = Uninitialized[#temp2021:23] : &:r2021_17
# 2021| r2021_19(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
# 2021| v2021_20(void) = Call[TernaryNonPodObj] : func:r2021_19, this:r2021_17
# 2021| mu2021_21(unknown) = ^CallSideEffect : ~m?
# 2021| mu2021_22(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_17
# 2021| r2021_23(glval<TernaryNonPodObj>) = Convert : r2021_17
# 2021| r2021_24(TernaryNonPodObj &) = CopyValue : r2021_23
# 2021| r2021_25(TernaryNonPodObj &) = Call[operator=] : func:r2021_16, this:r2021_15, 0:r2021_24
# 2021| mu2021_26(unknown) = ^CallSideEffect : ~m?
# 2021| v2021_27(void) = ^IndirectReadSideEffect[-1] : &:r2021_15, ~m?
# 2021| v2021_28(void) = ^BufferReadSideEffect[0] : &:r2021_24, ~m?
# 2021| mu2021_29(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_15
# 2021| r2021_30(glval<TernaryNonPodObj>) = CopyValue : r2021_25
# 2022| v2022_1(void) = NoOp :
# 2017| v2017_12(void) = ReturnVoid :
# 2017| v2017_13(void) = AliasedUse : ~m?
# 2017| v2017_14(void) = ExitFunction :
# 2021| Block 11
# 2021| r2021_31(glval<TernaryNonPodObj>) = VariableAddress[x] :
# 2021| r2021_32(glval<unknown>) = VariableAddress[#temp2021:10] :
# 2021| mu2021_33(glval<TernaryNonPodObj>) = Store[#temp2021:10] : &:r2021_32, r2021_31
#-----| Goto -> Block 10
# 2021| Block 12
# 2021| r2021_34(glval<TernaryNonPodObj>) = VariableAddress[y] :
# 2021| r2021_35(glval<unknown>) = VariableAddress[#temp2021:10] :
# 2021| mu2021_36(glval<TernaryNonPodObj>) = Store[#temp2021:10] : &:r2021_35, r2021_34
#-----| Goto -> Block 10
# 2026| unsigned int CommaTest(unsigned int)
# 2026| Block 0
# 2026| v2026_1(void) = EnterFunction :
# 2026| mu2026_2(unknown) = AliasedDefinition :
# 2026| mu2026_3(unknown) = InitializeNonLocal :
# 2026| r2026_4(glval<unsigned int>) = VariableAddress[x] :
# 2026| mu2026_5(unsigned int) = InitializeParameter[x] : &:r2026_4
# 2027| r2027_1(glval<unsigned int>) = VariableAddress[y] :
# 2027| mu2027_2(unsigned int) = Uninitialized[y] : &:r2027_1
# 2028| r2028_1(glval<unsigned int>) = VariableAddress[x] :
# 2028| r2028_2(unsigned int) = Load[x] : &:r2028_1, ~m?
# 2028| r2028_3(unsigned int) = Constant[100] :
# 2028| r2028_4(bool) = CompareLT : r2028_2, r2028_3
# 2028| v2028_5(void) = ConditionalBranch : r2028_4
#-----| False -> Block 4
#-----| True -> Block 3
# 2026| Block 1
# 2026| r2026_6(glval<unsigned int>) = VariableAddress[#return] :
# 2026| v2026_7(void) = ReturnValue : &:r2026_6, ~m?
# 2026| v2026_8(void) = AliasedUse : ~m?
# 2026| v2026_9(void) = ExitFunction :
# 2028| Block 2
# 2028| r2028_6(glval<unsigned int>) = VariableAddress[#temp2028:7] :
# 2028| r2028_7(unsigned int) = Load[#temp2028:7] : &:r2028_6, ~m?
# 2028| r2028_8(glval<unsigned int>) = VariableAddress[y] :
# 2028| mu2028_9(unsigned int) = Store[y] : &:r2028_8, r2028_7
# 2031| v2031_1(void) = Unreached :
# 2029| Block 3
# 2029| r2029_1(glval<unknown>) = FunctionAddress[CommaTestHelper] :
# 2029| r2029_2(glval<unsigned int>) = VariableAddress[x] :
# 2029| r2029_3(unsigned int) = Load[x] : &:r2029_2, ~m?
# 2029| v2029_4(void) = Call[CommaTestHelper] : func:r2029_1, 0:r2029_3
# 2029| mu2029_5(unknown) = ^CallSideEffect : ~m?
# 2029| r2029_6(glval<unsigned int>) = VariableAddress[x] :
# 2029| r2029_7(unsigned int) = Load[x] : &:r2029_6, ~m?
# 2029| r2029_8(unsigned int) = CopyValue : r2029_7
# 2028| r2028_10(glval<unsigned int>) = VariableAddress[#temp2028:7] :
# 2028| mu2028_11(unsigned int) = Store[#temp2028:7] : &:r2028_10, r2029_8
#-----| Goto -> Block 2
# 2030| Block 4
# 2030| r2030_1(glval<unknown>) = FunctionAddress[CommaTestHelper] :
# 2030| r2030_2(glval<unsigned int>) = VariableAddress[x] :
# 2030| r2030_3(unsigned int) = Load[x] : &:r2030_2, ~m?
# 2030| v2030_4(void) = Call[CommaTestHelper] : func:r2030_1, 0:r2030_3
# 2030| mu2030_5(unknown) = ^CallSideEffect : ~m?
# 2030| r2030_6(int) = Constant[10] :
# 2030| r2030_7(int) = CopyValue : r2030_6
# 2030| r2030_8(unsigned int) = Convert : r2030_7
# 2028| r2028_12(glval<unsigned int>) = VariableAddress[#temp2028:7] :
# 2028| mu2028_13(unsigned int) = Store[#temp2028:7] : &:r2028_12, r2030_8
#-----| Goto -> Block 2
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

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(Declaration decl) { shouldDumpFunction(decl) }
override predicate shouldPrintDeclaration(Declaration decl) { shouldDumpDeclaration(decl) }
}

View File

@@ -2157,3 +2157,46 @@ ssa.cpp:
# 431| v431_9(void) = ReturnValue : &:r431_8, m435_4
# 431| v431_10(void) = AliasedUse : m431_3
# 431| v431_11(void) = ExitFunction :
# 438| void Conditional(bool, int, int)
# 438| Block 0
# 438| v438_1(void) = EnterFunction :
# 438| m438_2(unknown) = AliasedDefinition :
# 438| m438_3(unknown) = InitializeNonLocal :
# 438| m438_4(unknown) = Chi : total:m438_2, partial:m438_3
# 438| r438_5(glval<bool>) = VariableAddress[a] :
# 438| m438_6(bool) = InitializeParameter[a] : &:r438_5
# 438| r438_7(glval<int>) = VariableAddress[x] :
# 438| m438_8(int) = InitializeParameter[x] : &:r438_7
# 438| r438_9(glval<int>) = VariableAddress[y] :
# 438| m438_10(int) = InitializeParameter[y] : &:r438_9
# 439| r439_1(glval<int>) = VariableAddress[z] :
# 439| r439_2(glval<bool>) = VariableAddress[a] :
# 439| r439_3(bool) = Load[a] : &:r439_2, m438_6
# 439| v439_4(void) = ConditionalBranch : r439_3
#-----| False -> Block 3
#-----| True -> Block 2
# 439| Block 1
# 439| m439_5(int) = Phi : from 2:m439_12, from 3:m439_16
# 439| r439_6(glval<int>) = VariableAddress[#temp439:13] :
# 439| r439_7(int) = Load[#temp439:13] : &:r439_6, m439_5
# 439| m439_8(int) = Store[z] : &:r439_1, r439_7
# 440| v440_1(void) = NoOp :
# 438| v438_11(void) = ReturnVoid :
# 438| v438_12(void) = AliasedUse : m438_3
# 438| v438_13(void) = ExitFunction :
# 439| Block 2
# 439| r439_9(glval<int>) = VariableAddress[x] :
# 439| r439_10(int) = Load[x] : &:r439_9, m438_8
# 439| r439_11(glval<int>) = VariableAddress[#temp439:13] :
# 439| m439_12(int) = Store[#temp439:13] : &:r439_11, r439_10
#-----| Goto -> Block 1
# 439| Block 3
# 439| r439_13(glval<int>) = VariableAddress[y] :
# 439| r439_14(int) = Load[y] : &:r439_13, m438_10
# 439| r439_15(glval<int>) = VariableAddress[#temp439:13] :
# 439| m439_16(int) = Store[#temp439:13] : &:r439_15, r439_14
#-----| Goto -> Block 1

View File

@@ -2146,3 +2146,46 @@ ssa.cpp:
# 431| v431_9(void) = ReturnValue : &:r431_8, m435_4
# 431| v431_10(void) = AliasedUse : m431_3
# 431| v431_11(void) = ExitFunction :
# 438| void Conditional(bool, int, int)
# 438| Block 0
# 438| v438_1(void) = EnterFunction :
# 438| m438_2(unknown) = AliasedDefinition :
# 438| m438_3(unknown) = InitializeNonLocal :
# 438| m438_4(unknown) = Chi : total:m438_2, partial:m438_3
# 438| r438_5(glval<bool>) = VariableAddress[a] :
# 438| m438_6(bool) = InitializeParameter[a] : &:r438_5
# 438| r438_7(glval<int>) = VariableAddress[x] :
# 438| m438_8(int) = InitializeParameter[x] : &:r438_7
# 438| r438_9(glval<int>) = VariableAddress[y] :
# 438| m438_10(int) = InitializeParameter[y] : &:r438_9
# 439| r439_1(glval<int>) = VariableAddress[z] :
# 439| r439_2(glval<bool>) = VariableAddress[a] :
# 439| r439_3(bool) = Load[a] : &:r439_2, m438_6
# 439| v439_4(void) = ConditionalBranch : r439_3
#-----| False -> Block 3
#-----| True -> Block 2
# 439| Block 1
# 439| m439_5(int) = Phi : from 2:m439_12, from 3:m439_16
# 439| r439_6(glval<int>) = VariableAddress[#temp439:13] :
# 439| r439_7(int) = Load[#temp439:13] : &:r439_6, m439_5
# 439| m439_8(int) = Store[z] : &:r439_1, r439_7
# 440| v440_1(void) = NoOp :
# 438| v438_11(void) = ReturnVoid :
# 438| v438_12(void) = AliasedUse : m438_3
# 438| v438_13(void) = ExitFunction :
# 439| Block 2
# 439| r439_9(glval<int>) = VariableAddress[x] :
# 439| r439_10(int) = Load[x] : &:r439_9, m438_8
# 439| r439_11(glval<int>) = VariableAddress[#temp439:13] :
# 439| m439_12(int) = Store[#temp439:13] : &:r439_11, r439_10
#-----| Goto -> Block 1
# 439| Block 3
# 439| r439_13(glval<int>) = VariableAddress[y] :
# 439| r439_14(int) = Load[y] : &:r439_13, m438_10
# 439| r439_15(glval<int>) = VariableAddress[#temp439:13] :
# 439| m439_16(int) = Store[#temp439:13] : &:r439_15, r439_14
#-----| Goto -> Block 1

View File

@@ -434,3 +434,7 @@ int noreturnTest2(int x) {
}
return x;
}
void Conditional(bool a, int x, int y) {
int z = a ? x : y;
}

View File

@@ -2002,3 +2002,45 @@ ssa.cpp:
# 431| v431_8(void) = ReturnValue : &:r431_7, m435_4
# 431| v431_9(void) = AliasedUse : ~m?
# 431| v431_10(void) = ExitFunction :
# 438| void Conditional(bool, int, int)
# 438| Block 0
# 438| v438_1(void) = EnterFunction :
# 438| mu438_2(unknown) = AliasedDefinition :
# 438| mu438_3(unknown) = InitializeNonLocal :
# 438| r438_4(glval<bool>) = VariableAddress[a] :
# 438| m438_5(bool) = InitializeParameter[a] : &:r438_4
# 438| r438_6(glval<int>) = VariableAddress[x] :
# 438| m438_7(int) = InitializeParameter[x] : &:r438_6
# 438| r438_8(glval<int>) = VariableAddress[y] :
# 438| m438_9(int) = InitializeParameter[y] : &:r438_8
# 439| r439_1(glval<int>) = VariableAddress[z] :
# 439| r439_2(glval<bool>) = VariableAddress[a] :
# 439| r439_3(bool) = Load[a] : &:r439_2, m438_5
# 439| v439_4(void) = ConditionalBranch : r439_3
#-----| False -> Block 3
#-----| True -> Block 2
# 439| Block 1
# 439| m439_5(int) = Phi : from 2:m439_12, from 3:m439_16
# 439| r439_6(glval<int>) = VariableAddress[#temp439:13] :
# 439| r439_7(int) = Load[#temp439:13] : &:r439_6, m439_5
# 439| m439_8(int) = Store[z] : &:r439_1, r439_7
# 440| v440_1(void) = NoOp :
# 438| v438_10(void) = ReturnVoid :
# 438| v438_11(void) = AliasedUse : ~m?
# 438| v438_12(void) = ExitFunction :
# 439| Block 2
# 439| r439_9(glval<int>) = VariableAddress[x] :
# 439| r439_10(int) = Load[x] : &:r439_9, m438_7
# 439| r439_11(glval<int>) = VariableAddress[#temp439:13] :
# 439| m439_12(int) = Store[#temp439:13] : &:r439_11, r439_10
#-----| Goto -> Block 1
# 439| Block 3
# 439| r439_13(glval<int>) = VariableAddress[y] :
# 439| r439_14(int) = Load[y] : &:r439_13, m438_9
# 439| r439_15(glval<int>) = VariableAddress[#temp439:13] :
# 439| m439_16(int) = Store[#temp439:13] : &:r439_15, r439_14
#-----| Goto -> Block 1

View File

@@ -2002,3 +2002,45 @@ ssa.cpp:
# 431| v431_8(void) = ReturnValue : &:r431_7, m435_4
# 431| v431_9(void) = AliasedUse : ~m?
# 431| v431_10(void) = ExitFunction :
# 438| void Conditional(bool, int, int)
# 438| Block 0
# 438| v438_1(void) = EnterFunction :
# 438| mu438_2(unknown) = AliasedDefinition :
# 438| mu438_3(unknown) = InitializeNonLocal :
# 438| r438_4(glval<bool>) = VariableAddress[a] :
# 438| m438_5(bool) = InitializeParameter[a] : &:r438_4
# 438| r438_6(glval<int>) = VariableAddress[x] :
# 438| m438_7(int) = InitializeParameter[x] : &:r438_6
# 438| r438_8(glval<int>) = VariableAddress[y] :
# 438| m438_9(int) = InitializeParameter[y] : &:r438_8
# 439| r439_1(glval<int>) = VariableAddress[z] :
# 439| r439_2(glval<bool>) = VariableAddress[a] :
# 439| r439_3(bool) = Load[a] : &:r439_2, m438_5
# 439| v439_4(void) = ConditionalBranch : r439_3
#-----| False -> Block 3
#-----| True -> Block 2
# 439| Block 1
# 439| m439_5(int) = Phi : from 2:m439_12, from 3:m439_16
# 439| r439_6(glval<int>) = VariableAddress[#temp439:13] :
# 439| r439_7(int) = Load[#temp439:13] : &:r439_6, m439_5
# 439| m439_8(int) = Store[z] : &:r439_1, r439_7
# 440| v440_1(void) = NoOp :
# 438| v438_10(void) = ReturnVoid :
# 438| v438_11(void) = AliasedUse : ~m?
# 438| v438_12(void) = ExitFunction :
# 439| Block 2
# 439| r439_9(glval<int>) = VariableAddress[x] :
# 439| r439_10(int) = Load[x] : &:r439_9, m438_7
# 439| r439_11(glval<int>) = VariableAddress[#temp439:13] :
# 439| m439_12(int) = Store[#temp439:13] : &:r439_11, r439_10
#-----| Goto -> Block 1
# 439| Block 3
# 439| r439_13(glval<int>) = VariableAddress[y] :
# 439| r439_14(int) = Load[y] : &:r439_13, m438_9
# 439| r439_15(glval<int>) = VariableAddress[#temp439:13] :
# 439| m439_16(int) = Store[#temp439:13] : &:r439_15, r439_14
#-----| Goto -> Block 1

View File

@@ -13,7 +13,6 @@
| file://:0:0:0:0 | _Float64 |
| file://:0:0:0:0 | _Float64x |
| file://:0:0:0:0 | _Float128 |
| file://:0:0:0:0 | _Float128x |
| file://:0:0:0:0 | _Imaginary double |
| file://:0:0:0:0 | _Imaginary float |
| file://:0:0:0:0 | _Imaginary long double |

View File

@@ -33,7 +33,6 @@
| file://:0:0:0:0 | _Float64 | 8 |
| file://:0:0:0:0 | _Float64x | 16 |
| file://:0:0:0:0 | _Float128 | 16 |
| file://:0:0:0:0 | _Float128x | 32 |
| file://:0:0:0:0 | _Imaginary double | 8 |
| file://:0:0:0:0 | _Imaginary float | 4 |
| file://:0:0:0:0 | _Imaginary long double | 16 |

View File

@@ -15,7 +15,6 @@
| file://:0:0:0:0 | _Float64 | _Float64 |
| file://:0:0:0:0 | _Float64x | _Float64x |
| file://:0:0:0:0 | _Float128 | _Float128 |
| file://:0:0:0:0 | _Float128x | _Float128x |
| file://:0:0:0:0 | _Imaginary double | _Imaginary double |
| file://:0:0:0:0 | _Imaginary float | _Imaginary float |
| file://:0:0:0:0 | _Imaginary long double | _Imaginary long double |

View File

@@ -14,7 +14,6 @@
| _Float64 | BinaryFloatingPointType, RealNumberType | | | | |
| _Float64x | BinaryFloatingPointType, RealNumberType | | | | |
| _Float128 | BinaryFloatingPointType, RealNumberType | | | | |
| _Float128x | BinaryFloatingPointType, RealNumberType | | | | |
| _Imaginary double | BinaryFloatingPointType, ImaginaryNumberType | | | | |
| _Imaginary float | BinaryFloatingPointType, ImaginaryNumberType | | | | |
| _Imaginary long double | BinaryFloatingPointType, ImaginaryNumberType | | | | |