Merge rc/1.19 into next.

This commit is contained in:
Aditya Sharad
2018-12-13 12:23:59 +00:00
77 changed files with 9632 additions and 987 deletions

View File

@@ -26,6 +26,11 @@ to run queries and explore the data flow in results.
## Changes to QL libraries
* The class `ControlFlowNode` (and by extension `BasicBlock`) has until now
been directly equatable to `Expr` and `Stmt`. Exploiting these equalities,
for example by using casts, is now deprecated, and the conversions
`Expr.getControlFlowNode()` and `Stmt.getControlFlowNode()` should be used
instead.
* The default set of taint sources in the `FlowSources` library is extended to
cover parameters annotated with Spring framework annotations indicating
remote user input from servlets. This affects all security queries, which

View File

@@ -1,55 +1,98 @@
{
"C++ IR Instruction": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll"
],
"C++ IR IRBlock": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll"
],
"C++ IR IRVariable": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll"
],
"C++ IR FunctionIR": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/FunctionIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/FunctionIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/FunctionIR.qll"
],
"C++ IR Operand": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll"
],
"C++ IR IRImpl": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll"
],
"C++ IR IRSanityImpl": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll"
],
"C++ IR PrintIRImpl": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll"
],
"C++ SSA AliasAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll"
],
"C++ SSA SSAConstruction": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll"
],
"C++ IR ValueNumber": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll"
]
"DataFlow Java/C++": [
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll",
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll",
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll",
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll",
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplDepr.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll"
],
"DataFlow Java/C++ Common": [
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll"
],
"C++ IR Instruction": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll"
],
"C++ IR IRBlock": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll"
],
"C++ IR IRVariable": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll"
],
"C++ IR FunctionIR": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/FunctionIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/FunctionIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/FunctionIR.qll"
],
"C++ IR Operand": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll"
],
"C++ IR IRImpl": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll"
],
"C++ IR IRSanityImpl": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll"
],
"C++ IR PrintIRImpl": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll"
],
"C++ SSA AliasAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll"
],
"C++ SSA SSAConstruction": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll"
],
"C++ IR ValueNumber": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll"
],
"C++ IR ConstantAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/ConstantAnalysis.qll"
],
"C++ IR PrintConstantAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/PrintConstantAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/PrintConstantAnalysis.qll"
],
"C++ IR ReachableBlock": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll"
],
"C++ IR PrintReachableBlock": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll"
],
"C++ IR Dominance": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/Dominance.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll"
]
}

View File

@@ -9,11 +9,21 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.dataflow.DataFlow2
import semmle.code.cpp.dataflow.DataFlow3
import semmle.code.cpp.dataflow.DataFlow4
import semmle.code.cpp.dataflow.TaintTracking
module ASTDataFlow {
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.dataflow.DataFlow2
import semmle.code.cpp.dataflow.DataFlow3
import semmle.code.cpp.dataflow.DataFlow4
import semmle.code.cpp.dataflow.TaintTracking
}
module IRDataFlow {
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.dataflow.DataFlow2
import semmle.code.cpp.ir.dataflow.DataFlow3
import semmle.code.cpp.ir.dataflow.DataFlow4
}
import semmle.code.cpp.valuenumbering.HashCons
from File f, string tag

View File

@@ -0,0 +1,23 @@
/**
* Provides a library for local (intra-procedural) and global (inter-procedural)
* data flow analysis: deciding whether data can flow from a _source_ to a
* _sink_. This library differs from the one in `semmle.code.cpp.dataflow` in that
* this library uses the IR (Intermediate Representation) library, which provides
* a more precise semantic representation of the program, whereas the other dataflow
* library uses the more syntax-oriented ASTs. This library should provide more accurate
* results than the AST-based library in most scenarios.
*
* Unless configured otherwise, _flow_ means that the exact value of
* the source may reach the sink. We do not track flow across pointer
* dereferences or array indexing.
*
* To use global (interprocedural) data flow, extend the class
* `DataFlow::Configuration` as documented on that class. To use local
* (intraprocedural) data flow, invoke `DataFlow::localFlow` or
* `DataFlow::LocalFlowStep` with arguments of type `DataFlow::Node`.
*/
import cpp
module DataFlow {
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl
}

View File

@@ -0,0 +1,38 @@
/**
* Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use
* this class when data-flow configurations must depend on each other. Two
* classes extending `DataFlow::Configuration` should never depend on each
* other, but one of them should instead depend on a
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
* `DataFlow4::Configuration`.
*
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
*/
import cpp
module DataFlow2 {
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl2
/**
* This class exists to prevent mutual recursion between the user-overridden
* member predicates of `Configuration` and the rest of the data-flow library.
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
* Four copies are available: `DataFlow` through `DataFlow4`.
*/
private abstract
class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
override predicate hasFlow(Node source, Node sink) {
strictcount(Node n | this.isSource(n)) < 0
or
strictcount(Node n | this.isSink(n)) < 0
or
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
or
super.hasFlow(source, sink)
}
}
}

View File

@@ -0,0 +1,38 @@
/**
* Provides a `DataFlow3` module, which is a copy of the `DataFlow` module. Use
* this class when data-flow configurations must depend on each other. Two
* classes extending `DataFlow::Configuration` should never depend on each
* other, but one of them should instead depend on a
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
* `DataFlow4::Configuration`.
*
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
*/
import cpp
module DataFlow3 {
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl3
/**
* This class exists to prevent mutual recursion between the user-overridden
* member predicates of `Configuration` and the rest of the data-flow library.
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
* Four copies are available: `DataFlow` through `DataFlow4`.
*/
private abstract
class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
override predicate hasFlow(Node source, Node sink) {
strictcount(Node n | this.isSource(n)) < 0
or
strictcount(Node n | this.isSink(n)) < 0
or
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
or
super.hasFlow(source, sink)
}
}
}

View File

@@ -0,0 +1,38 @@
/**
* Provides a `DataFlow4` module, which is a copy of the `DataFlow` module. Use
* this class when data-flow configurations must depend on each other. Two
* classes extending `DataFlow::Configuration` should never depend on each
* other, but one of them should instead depend on a
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
* `DataFlow4::Configuration`.
*
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
*/
import cpp
module DataFlow4 {
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl4
/**
* This class exists to prevent mutual recursion between the user-overridden
* member predicates of `Configuration` and the rest of the data-flow library.
* Good performance cannot be guaranteed in the presence of such recursion, so
* it should be replaced by using more than one copy of the data flow library.
* Four copies are available: `DataFlow` through `DataFlow4`.
*/
private abstract
class ConfigurationRecursionPrevention extends Configuration {
bindingset[this]
ConfigurationRecursionPrevention() { any() }
override predicate hasFlow(Node source, Node sink) {
strictcount(Node n | this.isSource(n)) < 0
or
strictcount(Node n | this.isSink(n)) < 0
or
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
or
super.hasFlow(source, sink)
}
}
}

View File

@@ -0,0 +1,73 @@
private import cpp
private import DataFlowPrivate
Function viableImpl(MethodAccess ma) {
result = ma.getTarget()
}
Function viableCallable(Call call) {
result = call.getTarget()
}
/**
* Holds if the call context `ctx` reduces the set of viable dispatch
* targets of `ma` in `c`.
*/
predicate reducedViableImplInCallContext(MethodAccess ma, Callable c, Call ctx) {
none()
}
/**
* Gets a viable dispatch target of `ma` in the context `ctx`. This is
* restricted to those `ma`s for which a context might make a difference.
*/
private Method viableImplInCallContext(MethodAccess ma, Call ctx) {
// stub implementation
result = viableImpl(ma) and
viableCallable(ctx) = ma.getEnclosingFunction()
}
/**
* Gets a viable dispatch target of `ma` in the context `ctx`. This is
* restricted to those `ma`s for which the context makes a difference.
*/
Method prunedViableImplInCallContext(MethodAccess ma, Call ctx) {
result = viableImplInCallContext(ma, ctx) and
reducedViableImplInCallContext(ma, _, ctx)
}
/**
* Holds if data might flow from `ma` to a return statement in some
* configuration.
*/
private predicate maybeChainedReturn(MethodAccess ma) {
exists(ReturnStmt ret |
exists(ret.getExpr()) and
ret.getEnclosingFunction() = ma.getEnclosingFunction() and
not ma.getParent() instanceof ExprStmt
)
}
/**
* Holds if flow returning from `m` to `ma` might return further and if
* this path restricts the set of call sites that can be returned to.
*/
predicate reducedViableImplInReturn(Method m, MethodAccess ma) {
exists(int tgts, int ctxtgts |
m = viableImpl(ma) and
ctxtgts = count(Call ctx | m = viableImplInCallContext(ma, ctx)) and
tgts = strictcount(Call ctx | viableCallable(ctx) = ma.getEnclosingFunction()) and
ctxtgts < tgts
) and
maybeChainedReturn(ma)
}
/**
* Gets a viable dispatch target of `ma` in the context `ctx`. This is
* restricted to those `ma`s and results for which the return flow from the
* result to `ma` restricts the possible context `ctx`.
*/
Method prunedViableImplInCallContextReverse(MethodAccess ma, Call ctx) {
result = viableImplInCallContext(ma, ctx) and
reducedViableImplInReturn(result, ma)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,284 @@
import DataFlowUtil
private import DataFlowPrivate
private import DataFlowDispatch
cached
private module ImplCommon {
/**
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
* The instance parameter is considered to have index `-1`.
*/
pragma[nomagic]
private predicate viableParam(Call call, int i, ParameterNode p) {
exists(Callable callable |
callable = viableCallable(call) and
p.isParameterOf(callable, i)
)
}
/**
* Holds if `arg` is a possible argument to `p` taking virtual dispatch into account.
*/
cached
predicate viableParamArg(ParameterNode p, ArgumentNode arg) {
exists(int i, Call call |
viableParam(call, i, p) and
arg.argumentOf(call, i)
)
}
/**
* Holds if `p` can flow to `node` in the same callable using only
* value-preserving steps.
*/
private predicate parameterValueFlow(ParameterNode p, Node node) {
p = node
or
exists(Node mid |
parameterValueFlow(p, mid) and
localFlowStep(mid, node) and
compatibleTypes(p.getType(), node.getType())
)
or
// flow through a callable
exists(Node arg |
parameterValueFlow(p, arg) and
argumentValueFlowsThrough(arg, node) and
compatibleTypes(p.getType(), node.getType())
)
}
/**
* Holds if `p` can flow to a `ReturnNode` in the same callable using only
* value-preserving steps.
*/
cached
predicate parameterValueFlowsThrough(ParameterNode p) {
exists(ReturnNode ret | parameterValueFlow(p, ret))
}
/**
* Holds if `arg` flows through `call` using only value-preserving steps.
*/
cached
predicate argumentValueFlowsThrough(ArgumentNode arg, ExprNode call) {
exists(ParameterNode param |
viableParamArg(param, arg) and
parameterValueFlowsThrough(param) and
arg.argumentOf(call.getExpr(), _) and
compatibleTypes(arg.getType(), call.getType())
)
}
/**
* Holds if `p` can flow to the pre-update node of `n` in the same callable
* using only value-preserving steps.
*/
cached
predicate parameterValueFlowsToUpdate(ParameterNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode())
}
/**
* Holds if data can flow from `node1` to `node2` in one local step or a step
* through a value-preserving method.
*/
private predicate localValueStep(Node node1, Node node2) {
localFlowStep(node1, node2) or
argumentValueFlowsThrough(node1, node2)
}
/*
* Calculation of `predicate store(Node node1, Content f, Node node2)`:
* There are three cases:
* - The base case: A direct local assignment given by `storeStep`.
* - A call to a method or constructor with two arguments, `arg1` and `arg2`,
* such the call has the side-effect `arg2.f = arg1`.
* - A call to a method that returns an object in which an argument has been
* stored.
* `storeViaSideEffect` covers the first two cases, and `storeReturn` covers
* the third case.
*/
/**
* Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f` or via a call that acts as a setter.
*/
cached
predicate store(Node node1, Content f, Node node2) {
storeViaSideEffect(node1, f, node2) or
storeReturn(node1, f, node2)
}
private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) {
storeStep(node1, f, node2) and readStep(_, f, _)
or
exists(Call call, int i1, int i2 |
setterCall(call, i1, i2, f) and
node1.(ArgumentNode).argumentOf(call, i1) and
node2.getPreUpdateNode().(ArgumentNode).argumentOf(call, i2) and
compatibleTypes(node1.getTypeBound(), f.getType()) and
compatibleTypes(node2.getTypeBound(), f.getContainerType())
)
}
pragma[nomagic]
private predicate setterInParam(ParameterNode p1, Content f, ParameterNode p2) {
exists(Node n1, PostUpdateNode n2 |
parameterValueFlow(p1, n1) and
storeViaSideEffect(n1, f, n2) and
parameterValueFlow(p2, n2.getPreUpdateNode()) and
p1 != p2
)
}
pragma[nomagic]
private predicate setterCall(Call call, int i1, int i2, Content f) {
exists(Callable callable, ParameterNode p1, ParameterNode p2 |
setterInParam(p1, f, p2) and
callable = viableCallable(call) and
p1.isParameterOf(callable, i1) and
p2.isParameterOf(callable, i2)
)
}
private predicate storeReturn(Node node1, Content f, Node node2) {
exists(ParameterNode p, ArgumentNode arg |
arg = node1 and
viableParamArg(p, arg) and
setterReturn(p, f) and
arg.argumentOf(node2.asExpr(), _) and
compatibleTypes(node1.getTypeBound(), f.getType()) and
compatibleTypes(node2.getTypeBound(), f.getContainerType())
)
}
private predicate setterReturn(ParameterNode p, Content f) {
exists(Node n1, Node n2, ReturnNode ret |
parameterValueFlow(p, n1) and
store(n1, f, n2) and
localValueStep*(n2, ret)
)
}
/**
* Holds if data can flow from `node1` to `node2` via a direct read of `f` or
* via a getter.
*/
cached
predicate read(Node node1, Content f, Node node2) {
readStep(node1, f, node2) and storeStep(_, f, _)
or
exists(ParameterNode p, ArgumentNode arg |
arg = node1 and
viableParamArg(p, arg) and
getter(p, f) and
arg.argumentOf(node2.asExpr(), _) and
compatibleTypes(node1.getTypeBound(), f.getContainerType()) and
compatibleTypes(node2.getTypeBound(), f.getType())
)
}
private predicate getter(ParameterNode p, Content f) {
exists(Node n1, Node n2, ReturnNode ret |
parameterValueFlow(p, n1) and
read(n1, f, n2) and
localValueStep*(n2, ret)
)
}
cached
predicate localStoreReadStep(Node node1, Node node2) {
exists(Node mid1, Node mid2, Content f |
store(node1, f, mid1) and
localValueStep*(mid1, mid2) and
read(mid2, f, node2)
)
}
/**
* Holds if `call` passes an implicit or explicit instance argument, i.e., an
* expression that reaches a `this` parameter.
*/
private predicate callHasInstanceArgument(Call call) {
exists(ArgumentNode arg | arg.argumentOf(call, -1))
}
cached
newtype TCallContext =
TAnyCallContext() or
TSpecificCall(Call call, int i, boolean emptyAp) {
reducedViableImplInCallContext(_, _, call) and
(emptyAp = true or emptyAp = false) and
(
exists(call.getArgument(i))
or
i = -1 and callHasInstanceArgument(call)
)
} or
TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or
TReturn(Method m, MethodAccess ma) { reducedViableImplInReturn(m, ma) }
}
import ImplCommon
/**
* A call context to restrict the targets of virtual dispatch and match the
* call sites of flow into a method with flow out of a method.
*
* There are four cases:
* - `TAnyCallContext()` : No restrictions on method flow.
* - `TSpecificCall(Call call, int i)` : Flow entered through the `i`th
* parameter at the given `call`. This call improves the set of viable
* dispatch targets for at least one method call in the current callable.
* - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The
* originating call does not improve the set of dispatch targets for any
* method call in the current callable and was therefore not recorded.
* - `TReturn(Method m, MethodAccess ma)` : Flow reached `ma` from `m` and
* this dispatch target of `ma` implies a reduced set of dispatch origins
* to which data may flow if it should reach a `return` statement.
*/
abstract class CallContext extends TCallContext { abstract string toString(); }
class CallContextAny extends CallContext, TAnyCallContext {
override string toString() { result = "CcAny" }
}
abstract class CallContextCall extends CallContext { }
class CallContextSpecificCall extends CallContextCall, TSpecificCall {
override string toString() { result = "CcCall" }
}
class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" }
}
class CallContextReturn extends CallContext, TReturn {
override string toString() { result = "CcReturn" }
}
bindingset[cc, callable]
predicate resolveReturn(CallContext cc, Callable callable, Call call) {
cc instanceof CallContextAny and callable = viableCallable(call)
or
exists(Method m0, MethodAccess ma0 |
ma0.getEnclosingCallable() = callable and
cc = TReturn(m0, ma0) and
m0 = prunedViableImplInCallContextReverse(ma0, call)
)
}
bindingset[call, cc]
Callable resolveCall(Call call, CallContext cc) {
exists(Call ctx | cc = TSpecificCall(ctx, _, _) |
if reducedViableImplInCallContext(call, _, ctx)
then result = prunedViableImplInCallContext(call, ctx)
else result = viableCallable(call)
)
or
result = viableCallable(call) and cc instanceof CallContextSomeCall
or
result = viableCallable(call) and cc instanceof CallContextAny
or
result = viableCallable(call) and cc instanceof CallContextReturn
}

View File

@@ -0,0 +1,187 @@
private import cpp
private import DataFlowUtil
/**
* A data flow node that occurs as the argument of a call and is passed as-is
* to the callable. Instance arguments (`this` pointer) are also included.
*/
class ArgumentNode extends Node {
ArgumentNode() {
exists(CallInstruction call |
this = call.getAnArgument()
)
}
/**
* Holds if this argument occurs at the given position in the given call.
* The instance argument is considered to have index `-1`.
*/
predicate argumentOf(Call call, int pos) {
exists (CallInstruction callInstr |
callInstr.getAST() = call and
(
this = callInstr.getPositionalArgument(pos) or
this = callInstr.getThisArgument() and pos = -1
)
)
}
}
/** A data flow node that occurs as the result of a `ReturnStmt`. */
class ReturnNode extends Node {
ReturnNode() {
exists(ReturnValueInstruction ret | this = ret.getReturnValue() )
}
}
/**
* Holds if data can flow from `node1` to `node2` in a way that loses the
* calling context. For example, this would happen with flow through a
* global or static variable.
*/
predicate jumpStep(Node n1, Node n2) {
none()
}
/**
* Holds if `call` does not pass an implicit or explicit qualifier, i.e., a
* `this` parameter.
*/
predicate callHasQualifier(Call call) {
call.hasQualifier()
or
call.getTarget() instanceof Destructor
}
private newtype TContent = TFieldContent(Field f) or TCollectionContent() or TArrayContent()
/**
* A reference contained in an object. Examples include instance fields, the
* contents of a collection object, or the contents of an array.
*/
class Content extends TContent {
/** Gets a textual representation of this element. */
abstract string toString();
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
}
/** Gets the type of the object containing this content. */
abstract RefType getContainerType();
/** Gets the type of this content. */
abstract Type getType();
}
private class FieldContent extends Content, TFieldContent {
Field f;
FieldContent() { this = TFieldContent(f) }
Field getField() { result = f }
override string toString() { result = f.toString() }
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
}
override RefType getContainerType() { result = f.getDeclaringType() }
override Type getType() { result = f.getType() }
}
private class CollectionContent extends Content, TCollectionContent {
override string toString() { result = "collection" }
override RefType getContainerType() { none() }
override Type getType() { none() }
}
private class ArrayContent extends Content, TArrayContent {
override string toString() { result = "array" }
override RefType getContainerType() { none() }
override Type getType() { none() }
}
/**
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
* Thus, `node2` references an object with a field `f` that contains the
* value of `node1`.
*/
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
none() // stub implementation
}
/**
* Holds if data can flow from `node1` to `node2` via a read of `f`.
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
predicate readStep(Node node1, Content f, Node node2) {
none() // stub implementation
}
/**
* Gets a representative (boxed) type for `t` for the purpose of pruning
* possible flow. A single type is used for all numeric types to account for
* numeric conversions, and otherwise the erasure is used.
*/
RefType getErasedRepr(Type t) {
suppressUnusedType(t) and
result instanceof VoidType // stub implementation
}
/** Gets a string representation of a type returned by `getErasedRepr`. */
string ppReprType(Type t) {
result = t.toString()
}
/**
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
* a node of type `t1` to a node of type `t2`.
*/
pragma[inline]
predicate compatibleTypes(Type t1, Type t2) {
any() // stub implementation
}
private predicate suppressUnusedType(Type t) { any() }
//////////////////////////////////////////////////////////////////////////////
// Java QL library compatibility wrappers
//////////////////////////////////////////////////////////////////////////////
class RefType extends Type {
}
class CastExpr extends Expr {
CastExpr() { none() } // stub implementation
}
/** An argument to a call. */
class Argument extends Expr {
Call call;
int pos;
Argument() {
call.getArgument(pos) = this
}
/** Gets the call that has this argument. */
Call getCall() { result = call }
/** Gets the position of this argument. */
int getPosition() {
result = pos
}
}
class Callable extends Function { }
/**
* An alias for `Function` in the C++ library. In the Java library, a `Method`
* is any callable except a constructor.
*/
class Method extends Function { }
/**
* An alias for `FunctionCall` in the C++ library. In the Java library, a
* `MethodAccess` is any `Call` that does not call a constructor.
*/
class MethodAccess extends FunctionCall {
/**
* INTERNAL: Do not use. Alternative name for `getEnclosingFunction`.
*/
Callable getEnclosingCallable() {
result = this.getEnclosingFunction()
}
}

View File

@@ -0,0 +1,135 @@
/**
* Provides C++-specific definitions for use in the data flow library.
*/
import cpp
import semmle.code.cpp.ir.IR
/**
* A node in a data flow graph.
*
* A node can be either an expression, a parameter, or an uninitialized local
* variable. Such nodes are created with `DataFlow::exprNode`,
* `DataFlow::parameterNode`, and `DataFlow::uninitializedNode` respectively.
*/
class Node extends Instruction {
/**
* INTERNAL: Do not use. Alternative name for `getFunction`.
*/
Function getEnclosingCallable() {
result = this.getFunction()
}
/** Gets the type of this node. */
Type getType() {
result = this.getResultType()
}
/** Gets the expression corresponding to this node, if any. */
Expr asExpr() { result = this.getConvertedResultExpression() }
/** Gets the parameter corresponding to this node, if any. */
Parameter asParameter() { result = this.(InitializeParameterInstruction).getParameter() }
/**
* Gets the uninitialized local variable corresponding to this node, if
* any.
*/
LocalVariable asUninitialized() {
result = this.(UninitializedInstruction).getLocalVariable()
}
/**
* Gets an upper bound on the type of this node.
*/
Type getTypeBound() { result = getType() }
}
/**
* An expression, viewed as a node in a data flow graph.
*/
class ExprNode extends Node {
Expr expr;
ExprNode() { expr = this.asExpr() }
Expr getExpr() { result = expr }
}
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParameterNode extends Node, InitializeParameterInstruction {
/**
* Holds if this node is the parameter of `c` at the specified (zero-based)
* position. The implicit `this` parameter is considered to have index `-1`.
*/
predicate isParameterOf(Function f, int i) {
f.getParameter(i) = getParameter()
}
}
/**
* The value of an uninitialized local variable, viewed as a node in a data
* flow graph.
*/
class UninitializedNode extends Node, UninitializedInstruction {
}
/**
* A node associated with an object after an operation that might have
* changed its state.
*
* This can be either the argument to a callable after the callable returns
* (which might have mutated the argument), or the qualifier of a field after
* an update to the field.
*
* Nodes corresponding to AST elements, for example `ExprNode`, usually refer
* to the value before the update with the exception of `ClassInstanceExpr`,
* which represents the value after the constructor has run.
*
* This class exists to match the interface used by Java. There are currently no non-abstract
* classes that extend it. When we implement field flow, we can revisit this.
*/
abstract class PostUpdateNode extends Node {
/**
* Gets the node before the state update.
*/
abstract Node getPreUpdateNode();
}
/**
* Gets the `Node` corresponding to `e`.
*/
ExprNode exprNode(Expr e) { result.getExpr() = e }
/**
* Gets the `Node` corresponding to the value of `p` at function entry.
*/
ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
/**
* Gets the `Node` corresponding to the value of an uninitialized local
* variable `v`.
*/
UninitializedNode uninitializedNode(LocalVariable v) {
result.getLocalVariable() = v
}
/**
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step.
*/
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
nodeTo.(CopyInstruction).getSourceValue() = nodeFrom or
nodeTo.(PhiInstruction).getAnOperand().getDefinitionInstruction() = nodeFrom or
// Treat all conversions as flow, even conversions between different numeric types.
nodeTo.(ConvertInstruction).getOperand() = nodeFrom
}
/**
* Holds if data flows from `source` to `sink` in zero or more local
* (intra-procedural) steps.
*/
predicate localFlow(Node source, Node sink) {
localFlowStep*(source, sink)
}

View File

@@ -68,7 +68,8 @@ private newtype TOpcode =
TBufferReadSideEffect() or
TBufferWriteSideEffect() or
TBufferMayWriteSideEffect() or
TChi()
TChi() or
TUnreached()
class Opcode extends TOpcode {
string toString() {
@@ -195,5 +196,6 @@ module Opcode {
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferAccessOpcode, TBufferReadSideEffect { override final string toString() { result = "BufferReadSideEffect" } }
class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode, TBufferWriteSideEffect { override final string toString() { result = "BufferWriteSideEffect" } }
class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode, TBufferMayWriteSideEffect { override final string toString() { result = "BufferMayWriteSideEffect" } }
class Chi extends Opcode, TChi {override final string toString() { result = "Chi" } }
class Chi extends Opcode, TChi { override final string toString() { result = "Chi" } }
class Unreached extends Opcode, TUnreached { override final string toString() { result = "Unreached" } }
}

View File

@@ -1,7 +1,7 @@
private import internal.IRInternal
import Instruction
import semmle.code.cpp.ir.implementation.EdgeKind
import Cached
private import Cached
class IRBlock extends TIRBlock {
final string toString() {

View File

@@ -102,7 +102,8 @@ module InstructionSanity {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
@@ -451,8 +452,7 @@ class Instruction extends Construction::TInstruction {
final predicate isResultModeled() {
// Register results are always in SSA form.
not hasMemoryResult() or
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
not (getAUse() instanceof UnmodeledUseOperand)
Construction::hasModeledMemoryResult(this)
}
/**
@@ -595,7 +595,7 @@ class FieldAddressInstruction extends FieldInstruction {
}
}
class UninitializedInstruction extends Instruction {
class UninitializedInstruction extends VariableInstruction {
UninitializedInstruction() {
opcode instanceof Opcode::Uninitialized
}
@@ -603,6 +603,13 @@ class UninitializedInstruction extends Instruction {
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof IndirectMemoryAccess
}
/**
* Gets the `LocalVariable` that is uninitialized.
*/
final LocalVariable getLocalVariable() {
result = var.(IRUserVariable).getVariable()
}
}
class NoOpInstruction extends Instruction {
@@ -1106,9 +1113,39 @@ class CallInstruction extends Instruction {
opcode instanceof Opcode::Call
}
/**
* Gets the `Instruction` that computes the target function of the call. This is usually a
* `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a
* function pointer.
*/
final Instruction getCallTarget() {
result = getAnOperand().(CallTargetOperand).getDefinitionInstruction()
}
/**
* Gets all of the arguments of the call, including the `this` pointer, if any.
*/
final Instruction getAnArgument() {
result = getAnOperand().(ArgumentOperand).getDefinitionInstruction()
}
/**
* Gets the `this` pointer argument of the call, if any.
*/
final Instruction getThisArgument() {
result = getAnOperand().(ThisArgumentOperand).getDefinitionInstruction()
}
/**
* Gets the argument at the specified index.
*/
final Instruction getPositionalArgument(int index) {
exists(PositionalArgumentOperand operand |
operand = getAnOperand() and
operand.getIndex() = index and
result = operand.getDefinitionInstruction()
)
}
}
/**
@@ -1432,6 +1469,17 @@ class ChiInstruction extends Instruction {
}
}
/**
* An instruction representing unreachable code. Inserted in place of the original target
* instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is
* infeasible.
*/
class UnreachedInstruction extends Instruction {
UnreachedInstruction() {
opcode instanceof Opcode::Unreached
}
}
/**
* An instruction representing a built-in operation. This is used to represent
* operations such as access to variable argument lists.

View File

@@ -304,6 +304,13 @@ class PositionalArgumentOperand extends ArgumentOperand {
override string toString() {
result = "Arg(" + argIndex + ")"
}
/**
* Gets the zero-based index of the argument.
*/
final int getIndex() {
result = argIndex
}
}
class SideEffectOperand extends NonPhiOperand {

View File

@@ -0,0 +1,38 @@
private import internal.ConstantAnalysisInternal
import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right) or
binInstr instanceof CompareEQInstruction and result = compareEQ(left, right) or
binInstr instanceof CompareNEInstruction and result = compareNE(left, right) or
binInstr instanceof CompareLTInstruction and result = compareLT(left, right) or
binInstr instanceof CompareGTInstruction and result = compareGT(left, right) or
binInstr instanceof CompareLEInstruction and result = compareLE(left, right) or
binInstr instanceof CompareGEInstruction and result = compareGE(left, right)
)
) or
exists(UnaryInstruction unaryInstr, IntValue src |
unaryInstr = instr and
src = getConstantValue(unaryInstr.getOperand()) and
(
unaryInstr instanceof NegateInstruction and result = neg(src)
)
) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
)
}

View File

@@ -0,0 +1,11 @@
private import internal.ConstantAnalysisInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import ConstantAnalysis
import IR
private class ConstantAnalysisPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instr, string key) {
key = "ConstantValue" and
result = getValue(getConstantValue(instr)).toString()
}
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as IR

View File

@@ -19,6 +19,10 @@ private VirtualIRVariable getVirtualVariable(IRVariable var) {
result.getIRVariable() = var
}
private UnknownVirtualVariable getUnknownVirtualVariable(FunctionIR f) {
result.getFunctionIR() = f
}
class VirtualVariable extends TVirtualVariable {
string toString() {
none()
@@ -83,10 +87,10 @@ class UnknownVirtualVariable extends VirtualVariable, TUnknownVirtualVariable {
}
private newtype TMemoryAccess =
TVariableMemoryAccess(VirtualIRVariable vvar, IntValue offset, IntValue size) {
TVariableMemoryAccess(IRVariable var, IntValue offset, IntValue size) {
exists(Instruction instr |
exists(MemoryAccessKind mak | instr.getResultMemoryAccess() = mak and not mak instanceof PhiMemoryAccess) and
resultPointsTo(instr.getAnOperand().(AddressOperand).getDefinitionInstruction(), vvar.getIRVariable(), offset) and
resultPointsTo(instr.getAnOperand().(AddressOperand).getDefinitionInstruction(), var, offset) and
if exists(instr.getResultSize())
then instr.getResultSize() = size
else size = Ints::unknown()
@@ -97,7 +101,7 @@ private newtype TMemoryAccess =
TTotalUnknownMemoryAccess(UnknownVirtualVariable uvv)
private VariableMemoryAccess getVariableMemoryAccess(IRVariable var, IntValue offset, IntValue size) {
result.getVirtualVariable() = getVirtualVariable(var) and
result.getVariable() = var and
result.getOffset() = offset and
result.getSize() = size
}
@@ -117,20 +121,21 @@ class MemoryAccess extends TMemoryAccess {
}
class VariableMemoryAccess extends TVariableMemoryAccess, MemoryAccess {
VirtualIRVariable vvar;
IRVariable var;
IntValue offset;
IntValue size;
VariableMemoryAccess() {
this = TVariableMemoryAccess(vvar, offset, size)
this = TVariableMemoryAccess(var, offset, size)
}
override final string toString() {
result = vvar.toString()
result = var.toString() + "[" + offset.toString() + ".." + (offset + size - 1).toString() + "]"
}
final override VirtualVariable getVirtualVariable() {
result = vvar
result = getVirtualVariable(var) or
not exists(getVirtualVariable(var)) and result = getUnknownVirtualVariable(var.getFunctionIR())
}
IntValue getOffset() {
@@ -141,10 +146,15 @@ class VariableMemoryAccess extends TVariableMemoryAccess, MemoryAccess {
result = size
}
final IRVariable getVariable() {
result = var
}
final override predicate isPartialMemoryAccess() {
not exists(getVirtualVariable(var)) or
getOffset() != 0
or
getSize() != vvar.getType().getSize()
getSize() != var.getType().getSize()
}
}
@@ -166,6 +176,7 @@ class UnknownMemoryAccess extends TUnknownMemoryAccess, MemoryAccess {
final override predicate isPartialMemoryAccess() {
any()
}
Type getType() {
result instanceof UnknownType
}
@@ -257,9 +268,10 @@ MemoryAccess getOperandMemoryAccess(Operand operand) {
if exists(IRVariable var, IntValue i |
resultPointsTo(operand.getAddressOperand().getDefinitionInstruction(), var, i)
)
then exists(IRVariable var, IntValue i |
then exists(IRVariable var, IntValue i, int size |
resultPointsTo(operand.getAddressOperand().getDefinitionInstruction(), var, i) and
result = getVariableMemoryAccess(var, i, operand.getDefinitionInstruction().getResultSize())
result = getVariableMemoryAccess(var, i, size) and
size = operand.getDefinitionInstruction().getResultSize()
)
else (
result = TUnknownMemoryAccess(TUnknownVirtualVariable(operand.getInstruction().getFunctionIR())) and

View File

@@ -0,0 +1,12 @@
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
private import AliasedSSA
/**
* Property provide that dumps the memory access of each result. Useful for debugging SSA
* construction.
*/
class PropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instruction, string key) {
key = "ResultMemoryAccess" and result = getResultMemoryAccess(instruction).toString()
}
}

View File

@@ -4,23 +4,35 @@ private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached private module Cached {
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached newtype TInstructionTag =
WrappedInstructionTag(OldIR::Instruction oldInstruction) {
WrappedInstructionTag(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction
} or
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
PhiTag(Alias::VirtualVariable vvar, OldBlock block) {
hasPhiNode(vvar, block)
} or
ChiTag(OldIR::Instruction oldInstruction) {
ChiTag(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction and
hasChiNode(_, oldInstruction)
} or
UnreachedTag(OldInstruction oldInstruction, EdgeKind kind) {
// We need an `Unreached` instruction for the destination of any edge whose predecessor
// instruction is reachable, but whose successor block is not. This should occur only for
// infeasible edges.
exists(OldIR::Instruction succInstruction |
succInstruction = oldInstruction.getSuccessor(kind) and
not succInstruction instanceof OldInstruction
)
}
cached class InstructionTagType extends TInstructionTag {
@@ -35,11 +47,11 @@ cached private module Cached {
)
}
cached OldIR::Instruction getOldInstruction(Instruction instr) {
cached OldInstruction getOldInstruction(Instruction instr) {
instr.getTag() = WrappedInstructionTag(result)
}
private Instruction getNewInstruction(OldIR::Instruction instr) {
private Instruction getNewInstruction(OldInstruction instr) {
getOldInstruction(result) = instr
}
@@ -47,21 +59,21 @@ cached private module Cached {
* Gets the chi node corresponding to `instr` if one is present, or the new `Instruction`
* corresponding to `instr` if there is no `Chi` node.
*/
private Instruction getNewFinalInstruction(OldIR::Instruction instr) {
private Instruction getNewFinalInstruction(OldInstruction instr) {
result = getChiInstruction(instr)
or
not exists(getChiInstruction(instr)) and
result = getNewInstruction(instr)
}
private PhiInstruction getPhiInstruction(Function func, OldIR::IRBlock oldBlock,
private PhiInstruction getPhiInstruction(Function func, OldBlock oldBlock,
Alias::VirtualVariable vvar) {
result.getFunction() = func and
result.getAST() = oldBlock.getFirstInstruction().getAST() and
result.getTag() = PhiTag(vvar, oldBlock)
}
private ChiInstruction getChiInstruction (OldIR::Instruction instr) {
private ChiInstruction getChiInstruction (OldInstruction instr) {
hasChiNode(_, instr) and
result.getTag() = ChiTag(instr)
}
@@ -91,8 +103,8 @@ cached private module Cached {
}
private predicate hasInstruction(Function func, Opcode opcode, Locatable ast,
InstructionTag tag, Type resultType, boolean isGLValue) {
exists(OldIR::Instruction instr |
InstructionTag tag, Type resultType, boolean isGLValue) {
exists(OldInstruction instr |
instr.getFunction() = func and
instr.getOpcode() = opcode and
instr.getAST() = ast and
@@ -103,7 +115,7 @@ cached private module Cached {
else
isGLValue = false
) or
exists(OldIR::IRBlock block, Alias::VirtualVariable vvar |
exists(OldBlock block, Alias::VirtualVariable vvar |
hasPhiNode(vvar, block) and
block.getFunction() = func and
opcode instanceof Opcode::Phi and
@@ -112,7 +124,7 @@ cached private module Cached {
resultType = vvar.getType() and
isGLValue = false
) or
exists(OldIR::Instruction instr, Alias::VirtualVariable vvar |
exists(OldInstruction instr, Alias::VirtualVariable vvar |
hasChiNode(vvar, instr) and
instr.getFunction() = func and
opcode instanceof Opcode::Chi and
@@ -120,11 +132,19 @@ cached private module Cached {
tag = ChiTag(instr) and
resultType = vvar.getType() and
isGLValue = false
) or
exists(OldInstruction oldInstruction, EdgeKind kind |
oldInstruction.getFunction() = func and
tag = UnreachedTag(oldInstruction, kind) and
opcode instanceof Opcode::Unreached and
ast = oldInstruction.getSuccessor(kind).getAST() and
resultType instanceof VoidType and
isGLValue = false
)
}
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
Type type) {
Type type) {
exists(OldIR::IRTempVariable var |
var.getFunction() = func and
var.getAST() = ast and
@@ -135,19 +155,20 @@ cached private module Cached {
cached predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryAccess(getOldInstruction(instruction))) or
instruction instanceof PhiInstruction // Phis always have modeled results
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand |
exists(OldInstruction oldInstruction, OldIR::NonPhiOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
if oldOperand instanceof OldIR::MemoryOperand then (
(
if exists(Alias::getOperandMemoryAccess(oldOperand)) then (
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, int defIndex |
exists(OldBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldBlock defBlock, int defRank, int defIndex |
vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and
@@ -164,7 +185,7 @@ cached private module Cached {
) or
// Connect any definitions that are not being modeled in SSA to the
// `UnmodeledUse` instruction.
exists(OldIR::Instruction oldDefinition |
exists(OldInstruction oldDefinition |
instruction instanceof UnmodeledUseInstruction and
tag instanceof UnmodeledUseOperandTag and
oldDefinition = oldOperand.getDefinitionInstruction() and
@@ -189,8 +210,8 @@ cached private module Cached {
cached Instruction getPhiInstructionOperandDefinition(PhiInstruction instr,
IRBlock newPredecessorBlock) {
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
exists(Alias::VirtualVariable vvar, OldBlock phiBlock,
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
hasPhiNode(vvar, phiBlock) and
predBlock = phiBlock.getAPredecessor() and
instr.getTag() = PhiTag(vvar, phiBlock) and
@@ -205,8 +226,8 @@ cached private module Cached {
}
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(Alias::VirtualVariable vvar, OldIR::Instruction oldInstr, OldIR::IRBlock defBlock,
int defRank, int defIndex, OldIR::IRBlock useBlock, int useRank |
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
int defRank, int defIndex, OldBlock useBlock, int useRank |
ChiTag(oldInstr) = chiInstr.getTag() and
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
@@ -220,7 +241,7 @@ cached private module Cached {
}
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldIR::IRBlock oldBlock |
exists(OldBlock oldBlock |
instr.getTag() = PhiTag(_, oldBlock) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
@@ -247,10 +268,11 @@ cached private module Cached {
else (
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
or
exists(OldIR::Instruction oldInstruction |
exists(OldInstruction oldInstruction |
instruction = getChiInstruction(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
) or
result.getTag() = UnreachedTag(getOldInstruction(instruction), kind)
)
}
@@ -310,29 +332,29 @@ cached private module Cached {
}
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
OldInstruction instr, OldBlock block, int index) {
block.getInstruction(index) = instr and
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
}
private predicate hasDefinition(Alias::VirtualVariable vvar, OldIR::IRBlock block, int index) {
private predicate hasDefinition(Alias::VirtualVariable vvar, OldBlock block, int index) {
(
hasPhiNode(vvar, block) and
index = -1
) or
exists(Alias::MemoryAccess access, OldIR::Instruction def |
exists(Alias::MemoryAccess access, OldInstruction def |
access = Alias::getResultMemoryAccess(def) and
block.getInstruction(index) = def and
vvar = access.getVirtualVariable()
)
}
private predicate defUseRank(Alias::VirtualVariable vvar, OldIR::IRBlock block, int rankIndex, int index) {
private predicate defUseRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex, int index) {
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
}
private predicate hasUse(Alias::VirtualVariable vvar,
OldIR::Instruction use, OldIR::IRBlock block, int index) {
private predicate hasUse(Alias::VirtualVariable vvar, OldInstruction use, OldBlock block,
int index) {
exists(Alias::MemoryAccess access |
(
access = Alias::getOperandMemoryAccess(use.getAnOperand())
@@ -349,7 +371,7 @@ cached private module Cached {
)
}
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
exists (int index | hasUse(vvar, _, block, index) |
not exists (int j | ssa_variableUpdate(vvar, _, block, j) | j < index)
) or
@@ -357,7 +379,7 @@ cached private module Cached {
}
pragma[noinline]
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldBlock block) {
variableLiveOnEntryToBlock(vvar, block.getASuccessor())
}
@@ -367,18 +389,18 @@ cached private module Cached {
* end of the block, even if the definition is the last instruction in the
* block.
*/
private int exitRank(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private int exitRank(Alias::VirtualVariable vvar, OldBlock block) {
result = max(int rankIndex | defUseRank(vvar, block, rankIndex, _)) + 1
}
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar,
OldIR::IRBlock block, int rankIndex, int instructionIndex) {
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
int instructionIndex) {
hasDefinition(vvar, block, instructionIndex) and
defUseRank(vvar, block, rankIndex, instructionIndex)
}
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldIR::IRBlock block,
int rankIndex, OldIR::Instruction use) {
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
OldInstruction use) {
exists(int index |
hasUse(vvar, use, block, index) and
defUseRank(vvar, block, rankIndex, index)
@@ -389,8 +411,8 @@ cached private module Cached {
* Holds if the definition of `vvar` at `(block, defRank)` reaches the rank
* index `reachesRank` in block `block`.
*/
private predicate definitionReachesRank(Alias::VirtualVariable vvar,
OldIR::IRBlock block, int defRank, int reachesRank) {
private predicate definitionReachesRank(Alias::VirtualVariable vvar, OldBlock block, int defRank,
int reachesRank) {
hasDefinitionAtRank(vvar, block, defRank, _) and
reachesRank <= exitRank(vvar, block) and // Without this, the predicate would be infinite.
(
@@ -410,8 +432,8 @@ cached private module Cached {
* Holds if the definition of `vvar` at `(defBlock, defRank)` reaches the end of
* block `block`.
*/
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock block) {
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock block) {
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
(
(
@@ -421,7 +443,7 @@ cached private module Cached {
variableLiveOnExitFromBlock(vvar, defBlock) and
definitionReachesRank(vvar, defBlock, defRank, exitRank(vvar, defBlock))
) or
exists(OldIR::IRBlock idom |
exists(OldBlock idom |
definitionReachesEndOfBlock(vvar, defBlock, defRank, idom) and
noDefinitionsSinceIDominator(vvar, idom, block)
)
@@ -429,24 +451,23 @@ cached private module Cached {
}
pragma[noinline]
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar,
OldIR::IRBlock idom, OldIR::IRBlock block) {
idom.immediatelyDominates(block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar, OldBlock idom,
OldBlock block) {
Dominance::blockImmediatelyDominates(idom, block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
variableLiveOnExitFromBlock(vvar, block) and
not hasDefinition(vvar, block, _)
}
private predicate definitionReachesUseWithinBlock(
Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank,
OldIR::IRBlock useBlock, int useRank) {
private predicate definitionReachesUseWithinBlock(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
defBlock = useBlock and
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
hasUseAtRank(vvar, useBlock, useRank, _) and
definitionReachesRank(vvar, defBlock, defRank, useRank)
}
private predicate definitionReachesUse(Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock useBlock, int useRank) {
private predicate definitionReachesUse(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
hasUseAtRank(vvar, useBlock, useRank, _) and
(
definitionReachesUseWithinBlock(vvar, defBlock, defRank, useBlock,
@@ -459,24 +480,21 @@ cached private module Cached {
)
}
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar,
OldIR::IRBlock phiBlock) {
exists(OldIR::IRBlock defBlock |
phiBlock = defBlock.dominanceFrontier() and
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar, OldBlock phiBlock) {
exists(OldBlock defBlock |
phiBlock = Dominance::getDominanceFrontier(defBlock) and
hasDefinition(vvar, defBlock, _) and
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
variableLiveOnEntryToBlock(vvar, phiBlock)
)
}
private predicate hasPhiNode(Alias::VirtualVariable vvar,
OldIR::IRBlock phiBlock) {
private predicate hasPhiNode(Alias::VirtualVariable vvar, OldBlock phiBlock) {
hasFrontierPhiNode(vvar, phiBlock)
//or ssa_sanitized_custom_phi_node(vvar, block)
}
private predicate hasChiNode(Alias::VirtualVariable vvar,
OldIR::Instruction def) {
private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
exists(Alias::MemoryAccess ma |
ma = Alias::getResultMemoryAccess(def) and
ma.isPartialMemoryAccess() and
@@ -492,13 +510,17 @@ cached private module CachedForDebugging {
}
cached string getInstructionUniqueId(Instruction instr) {
exists(OldIR::Instruction oldInstr |
exists(OldInstruction oldInstr |
oldInstr = getOldInstruction(instr) and
result = "NonSSA: " + oldInstr.getUniqueId()
) or
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock |
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
instr.getTag() = PhiTag(vvar, phiBlock) and
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
) or
exists(OldInstruction oldInstr, EdgeKind kind |
instr.getTag() = UnreachedTag(oldInstr, kind) and
result = "Unreached(" + oldInstr.getUniqueId() + ":" + kind.toString() + ")"
)
}

View File

@@ -1,3 +1,5 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
import AliasedSSA as Alias

View File

@@ -1,7 +1,7 @@
private import internal.IRInternal
import Instruction
import semmle.code.cpp.ir.implementation.EdgeKind
import Cached
private import Cached
class IRBlock extends TIRBlock {
final string toString() {

View File

@@ -102,7 +102,8 @@ module InstructionSanity {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
@@ -451,8 +452,7 @@ class Instruction extends Construction::TInstruction {
final predicate isResultModeled() {
// Register results are always in SSA form.
not hasMemoryResult() or
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
not (getAUse() instanceof UnmodeledUseOperand)
Construction::hasModeledMemoryResult(this)
}
/**
@@ -595,7 +595,7 @@ class FieldAddressInstruction extends FieldInstruction {
}
}
class UninitializedInstruction extends Instruction {
class UninitializedInstruction extends VariableInstruction {
UninitializedInstruction() {
opcode instanceof Opcode::Uninitialized
}
@@ -603,6 +603,13 @@ class UninitializedInstruction extends Instruction {
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof IndirectMemoryAccess
}
/**
* Gets the `LocalVariable` that is uninitialized.
*/
final LocalVariable getLocalVariable() {
result = var.(IRUserVariable).getVariable()
}
}
class NoOpInstruction extends Instruction {
@@ -1106,9 +1113,39 @@ class CallInstruction extends Instruction {
opcode instanceof Opcode::Call
}
/**
* Gets the `Instruction` that computes the target function of the call. This is usually a
* `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a
* function pointer.
*/
final Instruction getCallTarget() {
result = getAnOperand().(CallTargetOperand).getDefinitionInstruction()
}
/**
* Gets all of the arguments of the call, including the `this` pointer, if any.
*/
final Instruction getAnArgument() {
result = getAnOperand().(ArgumentOperand).getDefinitionInstruction()
}
/**
* Gets the `this` pointer argument of the call, if any.
*/
final Instruction getThisArgument() {
result = getAnOperand().(ThisArgumentOperand).getDefinitionInstruction()
}
/**
* Gets the argument at the specified index.
*/
final Instruction getPositionalArgument(int index) {
exists(PositionalArgumentOperand operand |
operand = getAnOperand() and
operand.getIndex() = index and
result = operand.getDefinitionInstruction()
)
}
}
/**
@@ -1432,6 +1469,17 @@ class ChiInstruction extends Instruction {
}
}
/**
* An instruction representing unreachable code. Inserted in place of the original target
* instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is
* infeasible.
*/
class UnreachedInstruction extends Instruction {
UnreachedInstruction() {
opcode instanceof Opcode::Unreached
}
}
/**
* An instruction representing a built-in operation. This is used to represent
* operations such as access to variable argument lists.

View File

@@ -304,6 +304,13 @@ class PositionalArgumentOperand extends ArgumentOperand {
override string toString() {
result = "Arg(" + argIndex + ")"
}
/**
* Gets the zero-based index of the argument.
*/
final int getIndex() {
result = argIndex
}
}
class SideEffectOperand extends NonPhiOperand {

View File

@@ -0,0 +1,38 @@
private import internal.ConstantAnalysisInternal
import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right) or
binInstr instanceof CompareEQInstruction and result = compareEQ(left, right) or
binInstr instanceof CompareNEInstruction and result = compareNE(left, right) or
binInstr instanceof CompareLTInstruction and result = compareLT(left, right) or
binInstr instanceof CompareGTInstruction and result = compareGT(left, right) or
binInstr instanceof CompareLEInstruction and result = compareLE(left, right) or
binInstr instanceof CompareGEInstruction and result = compareGE(left, right)
)
) or
exists(UnaryInstruction unaryInstr, IntValue src |
unaryInstr = instr and
src = getConstantValue(unaryInstr.getOperand()) and
(
unaryInstr instanceof NegateInstruction and result = neg(src)
)
) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
)
}

View File

@@ -0,0 +1,11 @@
private import internal.ConstantAnalysisInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import ConstantAnalysis
import IR
private class ConstantAnalysisPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instr, string key) {
key = "ConstantValue" and
result = getValue(getConstantValue(instr)).toString()
}
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.raw.IR as IR

View File

@@ -1,6 +1,7 @@
import cpp
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import semmle.code.cpp.models.interfaces.SideEffect
private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
@@ -37,9 +38,18 @@ abstract class TranslatedCall extends TranslatedExpr {
isGLValue = false
) or
(
hasSideEffect() and
tag = CallSideEffectTag() and
opcode instanceof Opcode::CallSideEffect and
resultType instanceof UnknownType and
(
if hasWriteSideEffect() then (
opcode instanceof Opcode::CallSideEffect and
resultType instanceof UnknownType
)
else (
opcode instanceof Opcode::CallReadSideEffect and
resultType instanceof VoidType
)
) and
isGLValue = false
)
}
@@ -68,9 +78,13 @@ abstract class TranslatedCall extends TranslatedExpr {
(
(
tag = CallTag() and
result = getInstruction(CallSideEffectTag())
if hasSideEffect() then
result = getInstruction(CallSideEffectTag())
else
result = getParent().getChildSuccessor(this)
) or
(
hasSideEffect() and
tag = CallSideEffectTag() and
result = getParent().getChildSuccessor(this)
)
@@ -183,6 +197,18 @@ abstract class TranslatedCall extends TranslatedExpr {
* Holds if the call has any arguments, not counting the `this` argument.
*/
abstract predicate hasArguments();
predicate hasReadSideEffect() {
any()
}
predicate hasWriteSideEffect() {
any()
}
private predicate hasSideEffect() {
hasReadSideEffect() or hasWriteSideEffect()
}
}
/**
@@ -280,6 +306,14 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
override Function getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = funcCall.getTarget()
}
override predicate hasReadSideEffect() {
not funcCall.getTarget().(SideEffectFunction).neverReadsMemory()
}
override predicate hasWriteSideEffect() {
not funcCall.getTarget().(SideEffectFunction).neverWritesMemory()
}
}
/**
@@ -302,4 +336,3 @@ class TranslatedStructorCall extends TranslatedFunctionCall {
any()
}
}

View File

@@ -142,7 +142,10 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
}
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = InitializerVariableAddressTag() and
(
tag = InitializerVariableAddressTag() or
hasUninitializedInstruction() and tag = InitializerStoreTag()
) and
result = getIRUserVariable(getFunction(), getVariable())
}

View File

@@ -0,0 +1,21 @@
private import DominanceInternal
predicate blockImmediatelyDominates(Graph::Block dominator, Graph::Block block) =
idominance(Graph::isEntryBlock/1, Graph::blockSuccessor/2)(_, dominator, block)
predicate blockStrictlyDominates(Graph::Block dominator, Graph::Block block) {
blockImmediatelyDominates+(dominator, block)
}
predicate blockDominates(Graph::Block dominator, Graph::Block block) {
blockStrictlyDominates(dominator, block) or dominator = block
}
pragma[noinline]
Graph::Block getDominanceFrontier(Graph::Block dominator) {
exists(Graph::Block pred |
Graph::blockSuccessor(pred, result) and
blockDominates(dominator, pred) and
not blockStrictlyDominates(dominator, result)
)
}

View File

@@ -0,0 +1,7 @@
private import ReachableBlock as Reachability
private module ReachabilityGraph = Reachability::Graph;
module Graph {
import Reachability::Graph
class Block = Reachability::ReachableBlock;
}

View File

@@ -0,0 +1,20 @@
private import ReachableBlockInternal
private import ReachableBlock
import IR
private class ReachableBlockPropertyProvider extends IRPropertyProvider {
override string getBlockProperty(IRBlock block, string key) {
(
not block instanceof ReachableBlock and
key = "Unreachable" and
result = "true"
) or
(
exists(EdgeKind kind |
isInfeasibleEdge(block, kind) and
key = "Infeasible(" + kind.toString() + ")" and
result = "true"
)
)
}
}

View File

@@ -0,0 +1,56 @@
private import ReachableBlockInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
private import ConstantAnalysis
predicate isInfeasibleEdge(IRBlock block, EdgeKind kind) {
exists(ConditionalBranchInstruction instr, int conditionValue |
instr = block.getLastInstruction() and
conditionValue = getValue(getConstantValue(instr.getCondition())) and
if conditionValue = 0 then
kind instanceof TrueEdge
else
kind instanceof FalseEdge
)
}
IRBlock getAFeasiblePredecessor(IRBlock successor) {
exists(EdgeKind kind |
result.getSuccessor(kind) = successor and
not isInfeasibleEdge(result, kind)
)
}
predicate isBlockReachable(IRBlock block) {
exists(FunctionIR f |
getAFeasiblePredecessor*(block) = f.getEntryBlock()
)
}
predicate isInstructionReachable(Instruction instr) {
isBlockReachable(instr.getBlock())
}
class ReachableBlock extends IRBlock {
ReachableBlock() {
isBlockReachable(this)
}
}
class ReachableInstruction extends Instruction {
ReachableInstruction() {
this.getBlock() instanceof ReachableBlock
}
}
module Graph {
predicate isEntryBlock(ReachableBlock block) {
exists(FunctionIR f |
block = f.getEntryBlock()
)
}
predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) {
succ = pred.getASuccessor()
}
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.raw.IR as IR
import semmle.code.cpp.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis

View File

@@ -1,7 +1,7 @@
private import internal.IRInternal
import Instruction
import semmle.code.cpp.ir.implementation.EdgeKind
import Cached
private import Cached
class IRBlock extends TIRBlock {
final string toString() {

View File

@@ -102,7 +102,8 @@ module InstructionSanity {
not exists(instr.getASuccessor()) and
not instr instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not instr instanceof PhiInstruction
not instr instanceof PhiInstruction and
not instr instanceof UnreachedInstruction
}
/**
@@ -451,8 +452,7 @@ class Instruction extends Construction::TInstruction {
final predicate isResultModeled() {
// Register results are always in SSA form.
not hasMemoryResult() or
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
not (getAUse() instanceof UnmodeledUseOperand)
Construction::hasModeledMemoryResult(this)
}
/**
@@ -595,7 +595,7 @@ class FieldAddressInstruction extends FieldInstruction {
}
}
class UninitializedInstruction extends Instruction {
class UninitializedInstruction extends VariableInstruction {
UninitializedInstruction() {
opcode instanceof Opcode::Uninitialized
}
@@ -603,6 +603,13 @@ class UninitializedInstruction extends Instruction {
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof IndirectMemoryAccess
}
/**
* Gets the `LocalVariable` that is uninitialized.
*/
final LocalVariable getLocalVariable() {
result = var.(IRUserVariable).getVariable()
}
}
class NoOpInstruction extends Instruction {
@@ -1106,9 +1113,39 @@ class CallInstruction extends Instruction {
opcode instanceof Opcode::Call
}
/**
* Gets the `Instruction` that computes the target function of the call. This is usually a
* `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a
* function pointer.
*/
final Instruction getCallTarget() {
result = getAnOperand().(CallTargetOperand).getDefinitionInstruction()
}
/**
* Gets all of the arguments of the call, including the `this` pointer, if any.
*/
final Instruction getAnArgument() {
result = getAnOperand().(ArgumentOperand).getDefinitionInstruction()
}
/**
* Gets the `this` pointer argument of the call, if any.
*/
final Instruction getThisArgument() {
result = getAnOperand().(ThisArgumentOperand).getDefinitionInstruction()
}
/**
* Gets the argument at the specified index.
*/
final Instruction getPositionalArgument(int index) {
exists(PositionalArgumentOperand operand |
operand = getAnOperand() and
operand.getIndex() = index and
result = operand.getDefinitionInstruction()
)
}
}
/**
@@ -1432,6 +1469,17 @@ class ChiInstruction extends Instruction {
}
}
/**
* An instruction representing unreachable code. Inserted in place of the original target
* instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is
* infeasible.
*/
class UnreachedInstruction extends Instruction {
UnreachedInstruction() {
opcode instanceof Opcode::Unreached
}
}
/**
* An instruction representing a built-in operation. This is used to represent
* operations such as access to variable argument lists.

View File

@@ -304,6 +304,13 @@ class PositionalArgumentOperand extends ArgumentOperand {
override string toString() {
result = "Arg(" + argIndex + ")"
}
/**
* Gets the zero-based index of the argument.
*/
final int getIndex() {
result = argIndex
}
}
class SideEffectOperand extends NonPhiOperand {

View File

@@ -0,0 +1,38 @@
private import internal.ConstantAnalysisInternal
import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right) or
binInstr instanceof CompareEQInstruction and result = compareEQ(left, right) or
binInstr instanceof CompareNEInstruction and result = compareNE(left, right) or
binInstr instanceof CompareLTInstruction and result = compareLT(left, right) or
binInstr instanceof CompareGTInstruction and result = compareGT(left, right) or
binInstr instanceof CompareLEInstruction and result = compareLE(left, right) or
binInstr instanceof CompareGEInstruction and result = compareGE(left, right)
)
) or
exists(UnaryInstruction unaryInstr, IntValue src |
unaryInstr = instr and
src = getConstantValue(unaryInstr.getOperand()) and
(
unaryInstr instanceof NegateInstruction and result = neg(src)
)
) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
)
}

View File

@@ -0,0 +1,11 @@
private import internal.ConstantAnalysisInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import ConstantAnalysis
import IR
private class ConstantAnalysisPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instr, string key) {
key = "ConstantValue" and
result = getValue(getConstantValue(instr)).toString()
}
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR

View File

@@ -4,23 +4,35 @@ private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.OperandTag
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached private module Cached {
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached newtype TInstructionTag =
WrappedInstructionTag(OldIR::Instruction oldInstruction) {
WrappedInstructionTag(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction
} or
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
PhiTag(Alias::VirtualVariable vvar, OldBlock block) {
hasPhiNode(vvar, block)
} or
ChiTag(OldIR::Instruction oldInstruction) {
ChiTag(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction and
hasChiNode(_, oldInstruction)
} or
UnreachedTag(OldInstruction oldInstruction, EdgeKind kind) {
// We need an `Unreached` instruction for the destination of any edge whose predecessor
// instruction is reachable, but whose successor block is not. This should occur only for
// infeasible edges.
exists(OldIR::Instruction succInstruction |
succInstruction = oldInstruction.getSuccessor(kind) and
not succInstruction instanceof OldInstruction
)
}
cached class InstructionTagType extends TInstructionTag {
@@ -35,11 +47,11 @@ cached private module Cached {
)
}
cached OldIR::Instruction getOldInstruction(Instruction instr) {
cached OldInstruction getOldInstruction(Instruction instr) {
instr.getTag() = WrappedInstructionTag(result)
}
private Instruction getNewInstruction(OldIR::Instruction instr) {
private Instruction getNewInstruction(OldInstruction instr) {
getOldInstruction(result) = instr
}
@@ -47,21 +59,21 @@ cached private module Cached {
* Gets the chi node corresponding to `instr` if one is present, or the new `Instruction`
* corresponding to `instr` if there is no `Chi` node.
*/
private Instruction getNewFinalInstruction(OldIR::Instruction instr) {
private Instruction getNewFinalInstruction(OldInstruction instr) {
result = getChiInstruction(instr)
or
not exists(getChiInstruction(instr)) and
result = getNewInstruction(instr)
}
private PhiInstruction getPhiInstruction(Function func, OldIR::IRBlock oldBlock,
private PhiInstruction getPhiInstruction(Function func, OldBlock oldBlock,
Alias::VirtualVariable vvar) {
result.getFunction() = func and
result.getAST() = oldBlock.getFirstInstruction().getAST() and
result.getTag() = PhiTag(vvar, oldBlock)
}
private ChiInstruction getChiInstruction (OldIR::Instruction instr) {
private ChiInstruction getChiInstruction (OldInstruction instr) {
hasChiNode(_, instr) and
result.getTag() = ChiTag(instr)
}
@@ -91,8 +103,8 @@ cached private module Cached {
}
private predicate hasInstruction(Function func, Opcode opcode, Locatable ast,
InstructionTag tag, Type resultType, boolean isGLValue) {
exists(OldIR::Instruction instr |
InstructionTag tag, Type resultType, boolean isGLValue) {
exists(OldInstruction instr |
instr.getFunction() = func and
instr.getOpcode() = opcode and
instr.getAST() = ast and
@@ -103,7 +115,7 @@ cached private module Cached {
else
isGLValue = false
) or
exists(OldIR::IRBlock block, Alias::VirtualVariable vvar |
exists(OldBlock block, Alias::VirtualVariable vvar |
hasPhiNode(vvar, block) and
block.getFunction() = func and
opcode instanceof Opcode::Phi and
@@ -112,7 +124,7 @@ cached private module Cached {
resultType = vvar.getType() and
isGLValue = false
) or
exists(OldIR::Instruction instr, Alias::VirtualVariable vvar |
exists(OldInstruction instr, Alias::VirtualVariable vvar |
hasChiNode(vvar, instr) and
instr.getFunction() = func and
opcode instanceof Opcode::Chi and
@@ -120,11 +132,19 @@ cached private module Cached {
tag = ChiTag(instr) and
resultType = vvar.getType() and
isGLValue = false
) or
exists(OldInstruction oldInstruction, EdgeKind kind |
oldInstruction.getFunction() = func and
tag = UnreachedTag(oldInstruction, kind) and
opcode instanceof Opcode::Unreached and
ast = oldInstruction.getSuccessor(kind).getAST() and
resultType instanceof VoidType and
isGLValue = false
)
}
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
Type type) {
Type type) {
exists(OldIR::IRTempVariable var |
var.getFunction() = func and
var.getAST() = ast and
@@ -135,19 +155,20 @@ cached private module Cached {
cached predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryAccess(getOldInstruction(instruction))) or
instruction instanceof PhiInstruction // Phis always have modeled results
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand |
exists(OldInstruction oldInstruction, OldIR::NonPhiOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
if oldOperand instanceof OldIR::MemoryOperand then (
(
if exists(Alias::getOperandMemoryAccess(oldOperand)) then (
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, int defIndex |
exists(OldBlock useBlock, int useRank, Alias::VirtualVariable vvar,
OldBlock defBlock, int defRank, int defIndex |
vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and
@@ -164,7 +185,7 @@ cached private module Cached {
) or
// Connect any definitions that are not being modeled in SSA to the
// `UnmodeledUse` instruction.
exists(OldIR::Instruction oldDefinition |
exists(OldInstruction oldDefinition |
instruction instanceof UnmodeledUseInstruction and
tag instanceof UnmodeledUseOperandTag and
oldDefinition = oldOperand.getDefinitionInstruction() and
@@ -189,8 +210,8 @@ cached private module Cached {
cached Instruction getPhiInstructionOperandDefinition(PhiInstruction instr,
IRBlock newPredecessorBlock) {
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
exists(Alias::VirtualVariable vvar, OldBlock phiBlock,
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
hasPhiNode(vvar, phiBlock) and
predBlock = phiBlock.getAPredecessor() and
instr.getTag() = PhiTag(vvar, phiBlock) and
@@ -205,8 +226,8 @@ cached private module Cached {
}
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(Alias::VirtualVariable vvar, OldIR::Instruction oldInstr, OldIR::IRBlock defBlock,
int defRank, int defIndex, OldIR::IRBlock useBlock, int useRank |
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
int defRank, int defIndex, OldBlock useBlock, int useRank |
ChiTag(oldInstr) = chiInstr.getTag() and
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
@@ -220,7 +241,7 @@ cached private module Cached {
}
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldIR::IRBlock oldBlock |
exists(OldBlock oldBlock |
instr.getTag() = PhiTag(_, oldBlock) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
@@ -247,10 +268,11 @@ cached private module Cached {
else (
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
or
exists(OldIR::Instruction oldInstruction |
exists(OldInstruction oldInstruction |
instruction = getChiInstruction(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
) or
result.getTag() = UnreachedTag(getOldInstruction(instruction), kind)
)
}
@@ -310,29 +332,29 @@ cached private module Cached {
}
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
OldInstruction instr, OldBlock block, int index) {
block.getInstruction(index) = instr and
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
}
private predicate hasDefinition(Alias::VirtualVariable vvar, OldIR::IRBlock block, int index) {
private predicate hasDefinition(Alias::VirtualVariable vvar, OldBlock block, int index) {
(
hasPhiNode(vvar, block) and
index = -1
) or
exists(Alias::MemoryAccess access, OldIR::Instruction def |
exists(Alias::MemoryAccess access, OldInstruction def |
access = Alias::getResultMemoryAccess(def) and
block.getInstruction(index) = def and
vvar = access.getVirtualVariable()
)
}
private predicate defUseRank(Alias::VirtualVariable vvar, OldIR::IRBlock block, int rankIndex, int index) {
private predicate defUseRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex, int index) {
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
}
private predicate hasUse(Alias::VirtualVariable vvar,
OldIR::Instruction use, OldIR::IRBlock block, int index) {
private predicate hasUse(Alias::VirtualVariable vvar, OldInstruction use, OldBlock block,
int index) {
exists(Alias::MemoryAccess access |
(
access = Alias::getOperandMemoryAccess(use.getAnOperand())
@@ -349,7 +371,7 @@ cached private module Cached {
)
}
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
exists (int index | hasUse(vvar, _, block, index) |
not exists (int j | ssa_variableUpdate(vvar, _, block, j) | j < index)
) or
@@ -357,7 +379,7 @@ cached private module Cached {
}
pragma[noinline]
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldBlock block) {
variableLiveOnEntryToBlock(vvar, block.getASuccessor())
}
@@ -367,18 +389,18 @@ cached private module Cached {
* end of the block, even if the definition is the last instruction in the
* block.
*/
private int exitRank(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
private int exitRank(Alias::VirtualVariable vvar, OldBlock block) {
result = max(int rankIndex | defUseRank(vvar, block, rankIndex, _)) + 1
}
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar,
OldIR::IRBlock block, int rankIndex, int instructionIndex) {
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
int instructionIndex) {
hasDefinition(vvar, block, instructionIndex) and
defUseRank(vvar, block, rankIndex, instructionIndex)
}
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldIR::IRBlock block,
int rankIndex, OldIR::Instruction use) {
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
OldInstruction use) {
exists(int index |
hasUse(vvar, use, block, index) and
defUseRank(vvar, block, rankIndex, index)
@@ -389,8 +411,8 @@ cached private module Cached {
* Holds if the definition of `vvar` at `(block, defRank)` reaches the rank
* index `reachesRank` in block `block`.
*/
private predicate definitionReachesRank(Alias::VirtualVariable vvar,
OldIR::IRBlock block, int defRank, int reachesRank) {
private predicate definitionReachesRank(Alias::VirtualVariable vvar, OldBlock block, int defRank,
int reachesRank) {
hasDefinitionAtRank(vvar, block, defRank, _) and
reachesRank <= exitRank(vvar, block) and // Without this, the predicate would be infinite.
(
@@ -410,8 +432,8 @@ cached private module Cached {
* Holds if the definition of `vvar` at `(defBlock, defRank)` reaches the end of
* block `block`.
*/
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock block) {
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock block) {
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
(
(
@@ -421,7 +443,7 @@ cached private module Cached {
variableLiveOnExitFromBlock(vvar, defBlock) and
definitionReachesRank(vvar, defBlock, defRank, exitRank(vvar, defBlock))
) or
exists(OldIR::IRBlock idom |
exists(OldBlock idom |
definitionReachesEndOfBlock(vvar, defBlock, defRank, idom) and
noDefinitionsSinceIDominator(vvar, idom, block)
)
@@ -429,24 +451,23 @@ cached private module Cached {
}
pragma[noinline]
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar,
OldIR::IRBlock idom, OldIR::IRBlock block) {
idom.immediatelyDominates(block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar, OldBlock idom,
OldBlock block) {
Dominance::blockImmediatelyDominates(idom, block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
variableLiveOnExitFromBlock(vvar, block) and
not hasDefinition(vvar, block, _)
}
private predicate definitionReachesUseWithinBlock(
Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank,
OldIR::IRBlock useBlock, int useRank) {
private predicate definitionReachesUseWithinBlock(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
defBlock = useBlock and
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
hasUseAtRank(vvar, useBlock, useRank, _) and
definitionReachesRank(vvar, defBlock, defRank, useRank)
}
private predicate definitionReachesUse(Alias::VirtualVariable vvar,
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock useBlock, int useRank) {
private predicate definitionReachesUse(Alias::VirtualVariable vvar, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
hasUseAtRank(vvar, useBlock, useRank, _) and
(
definitionReachesUseWithinBlock(vvar, defBlock, defRank, useBlock,
@@ -459,24 +480,21 @@ cached private module Cached {
)
}
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar,
OldIR::IRBlock phiBlock) {
exists(OldIR::IRBlock defBlock |
phiBlock = defBlock.dominanceFrontier() and
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar, OldBlock phiBlock) {
exists(OldBlock defBlock |
phiBlock = Dominance::getDominanceFrontier(defBlock) and
hasDefinition(vvar, defBlock, _) and
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
variableLiveOnEntryToBlock(vvar, phiBlock)
)
}
private predicate hasPhiNode(Alias::VirtualVariable vvar,
OldIR::IRBlock phiBlock) {
private predicate hasPhiNode(Alias::VirtualVariable vvar, OldBlock phiBlock) {
hasFrontierPhiNode(vvar, phiBlock)
//or ssa_sanitized_custom_phi_node(vvar, block)
}
private predicate hasChiNode(Alias::VirtualVariable vvar,
OldIR::Instruction def) {
private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
exists(Alias::MemoryAccess ma |
ma = Alias::getResultMemoryAccess(def) and
ma.isPartialMemoryAccess() and
@@ -492,13 +510,17 @@ cached private module CachedForDebugging {
}
cached string getInstructionUniqueId(Instruction instr) {
exists(OldIR::Instruction oldInstr |
exists(OldInstruction oldInstr |
oldInstr = getOldInstruction(instr) and
result = "NonSSA: " + oldInstr.getUniqueId()
) or
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock |
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
instr.getTag() = PhiTag(vvar, phiBlock) and
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
) or
exists(OldInstruction oldInstr, EdgeKind kind |
instr.getTag() = UnreachedTag(oldInstr, kind) and
result = "Unreached(" + oldInstr.getUniqueId() + ":" + kind.toString() + ")"
)
}

View File

@@ -1,3 +1,5 @@
import semmle.code.cpp.ir.implementation.raw.IR as OldIR
import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
import SimpleSSA as Alias

View File

@@ -0,0 +1,21 @@
private import DominanceInternal
predicate blockImmediatelyDominates(Graph::Block dominator, Graph::Block block) =
idominance(Graph::isEntryBlock/1, Graph::blockSuccessor/2)(_, dominator, block)
predicate blockStrictlyDominates(Graph::Block dominator, Graph::Block block) {
blockImmediatelyDominates+(dominator, block)
}
predicate blockDominates(Graph::Block dominator, Graph::Block block) {
blockStrictlyDominates(dominator, block) or dominator = block
}
pragma[noinline]
Graph::Block getDominanceFrontier(Graph::Block dominator) {
exists(Graph::Block pred |
Graph::blockSuccessor(pred, result) and
blockDominates(dominator, pred) and
not blockStrictlyDominates(dominator, result)
)
}

View File

@@ -0,0 +1,7 @@
private import ReachableBlock as Reachability
private module ReachabilityGraph = Reachability::Graph;
module Graph {
import Reachability::Graph
class Block = Reachability::ReachableBlock;
}

View File

@@ -0,0 +1,20 @@
private import ReachableBlockInternal
private import ReachableBlock
import IR
private class ReachableBlockPropertyProvider extends IRPropertyProvider {
override string getBlockProperty(IRBlock block, string key) {
(
not block instanceof ReachableBlock and
key = "Unreachable" and
result = "true"
) or
(
exists(EdgeKind kind |
isInfeasibleEdge(block, kind) and
key = "Infeasible(" + kind.toString() + ")" and
result = "true"
)
)
}
}

View File

@@ -0,0 +1,56 @@
private import ReachableBlockInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
private import ConstantAnalysis
predicate isInfeasibleEdge(IRBlock block, EdgeKind kind) {
exists(ConditionalBranchInstruction instr, int conditionValue |
instr = block.getLastInstruction() and
conditionValue = getValue(getConstantValue(instr.getCondition())) and
if conditionValue = 0 then
kind instanceof TrueEdge
else
kind instanceof FalseEdge
)
}
IRBlock getAFeasiblePredecessor(IRBlock successor) {
exists(EdgeKind kind |
result.getSuccessor(kind) = successor and
not isInfeasibleEdge(result, kind)
)
}
predicate isBlockReachable(IRBlock block) {
exists(FunctionIR f |
getAFeasiblePredecessor*(block) = f.getEntryBlock()
)
}
predicate isInstructionReachable(Instruction instr) {
isBlockReachable(instr.getBlock())
}
class ReachableBlock extends IRBlock {
ReachableBlock() {
isBlockReachable(this)
}
}
class ReachableInstruction extends Instruction {
ReachableInstruction() {
this.getBlock() instanceof ReachableBlock
}
}
module Graph {
predicate isEntryBlock(ReachableBlock block) {
exists(FunctionIR f |
block = f.getEntryBlock()
)
}
predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) {
succ = pred.getASuccessor()
}
}

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
import semmle.code.cpp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis

View File

@@ -102,6 +102,96 @@ IntValue div(IntValue a, IntValue b) {
result = unknown()
}
/**
* Returns `a == b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareEQ(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a = b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a != b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareNE(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a != b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a < b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareLT(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a < b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a > b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareGT(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a > b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a <= b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareLE(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a <= b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Returns `a >= b`. If either input is unknown, the result is unknown.
*/
bindingset[a, b]
IntValue compareGE(IntValue a, IntValue b) {
if hasValue(a) and hasValue(b) then (
if a >= b then
result = 1
else
result = 0
)
else
result = unknown()
}
/**
* Return `-a`. If `a` is unknown, the result is unknown.
*/

View File

@@ -1,3 +1,4 @@
private import implementations.IdentityFunction
private import implementations.Inet
private import implementations.Memcpy
private import implementations.Printf

View File

@@ -0,0 +1,45 @@
import semmle.code.cpp.Function
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.SideEffect
/**
* The standard function templates `std::move` and `std::identity`
*/
class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFunction {
IdentityFunction() {
this.getNamespace().getParentNamespace() instanceof GlobalNamespace and
this.getNamespace().getName() = "std" and
(
this.getName() = "move" or
this.getName() = "forward"
)
}
override predicate neverReadsMemory() {
any()
}
override predicate neverWritesMemory() {
any()
}
override predicate parameterNeverEscapes(int index) {
none()
}
override predicate parameterEscapesOnlyViaReturn(int index) {
// These functions simply return the argument value.
index = 0
}
override predicate parameterIsAlwaysReturned(int index) {
// These functions simply return the argument value.
index = 0
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
// These functions simply return the argument value.
input.isInParameter(0) and output.isOutReturnValue()
}
}

View File

@@ -0,0 +1,54 @@
/**
* Provides an abstract class for accurate alias modeling of library
* functions when source code is not available. To use this QL library,
* create a QL class extending `AliasFunction` with a characteristic
* predicate that selects the function or set of functions you are modeling.
* Within that class, override the predicates provided by `AliasFunction`
* to match the flow within that function.
*/
import semmle.code.cpp.Function
import semmle.code.cpp.models.Models
/**
* Models the aliasing behavior of a library function.
*/
abstract class AliasFunction extends Function {
/**
* Holds if the address passed to the parameter at the specified index is never retained after
* the function returns.
*
* Example:
* ```
* int* g;
* int* func(int* p, int* q, int* r, int* s, int n) {
* *s = 1; // `s` does not escape.
* g = p; // Stored in global. `p` escapes.
* if (rand()) {
* return q; // `q` escapes via the return value.
* }
* else {
* return r + n; // `r` escapes via the return value, even though an offset has been added.
* }
* }
* ```
*
* For the above function, the following terms hold:
* - `parameterEscapesOnlyViaReturn(1)`
* - `parameterEscapesOnlyViaReturn(2)`
* - `parameterNeverEscapes(3)`
*/
abstract predicate parameterNeverEscapes(int index);
/**
* Holds if the address passed to the parameter at the specified index escapes via the return
* value of the function, but does not otherwise escape. See the comment for
* `parameterNeverEscapes` for an example.
*/
abstract predicate parameterEscapesOnlyViaReturn(int index);
/**
* Holds if the function always returns the value of the parameter at the specified index.
*/
abstract predicate parameterIsAlwaysReturned(int index);
}

View File

@@ -1,5 +1,5 @@
/**
* Provides a set of QL clcasses for indicating dataflows through a particular
* Provides a set of QL classes for indicating dataflows through a particular
* parameter, return value, or qualifier, as well as flows at one level of
* pointer indirection.
*/

View File

@@ -0,0 +1,30 @@
/**
* Provides an abstract class for accurate dataflow modeling of library
* functions when source code is not available. To use this QL library,
* create a QL class extending `SideEffectFunction` with a characteristic
* predicate that selects the function or set of functions you are modeling.
* Within that class, override the predicates provided by `SideEffectFunction`
* to match the flow within that function.
*/
import semmle.code.cpp.Function
import semmle.code.cpp.models.Models
/**
* Models the side effects of a library function.
*/
abstract class SideEffectFunction extends Function {
/**
* Holds if the function never reads from memory that was defined before entry to the function.
* This memory could be from global variables, or from other memory that was reachable from a
* pointer that was passed into the function.
*/
abstract predicate neverReadsMemory();
/**
* Holds if the function never writes to memory that remains allocated after the function
* returns. This memory could be from global variables, or from other memory that was reachable
* from a pointer that was passed into the function.
*/
abstract predicate neverWritesMemory();
}

View File

@@ -25,7 +25,6 @@ astGuards
| test.c:126:12:126:26 | call to test3_condition |
| test.c:131:7:131:7 | b |
| test.c:137:7:137:7 | 0 |
| test.c:138:9:138:9 | i |
| test.c:146:7:146:8 | ! ... |
| test.c:146:8:146:8 | x |
| test.c:152:10:152:10 | x |
@@ -164,6 +163,7 @@ astGuardsControl
| test.c:42:16:42:21 | ... < ... | true | 45 | 47 |
| test.c:42:16:42:21 | ... < ... | true | 48 | 55 |
| test.c:42:16:42:21 | ... < ... | true | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | false | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | false | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | true | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | true | 45 | 47 |
@@ -203,9 +203,8 @@ astGuardsControl
| test.c:126:7:126:28 | ... && ... | true | 126 | 128 |
| test.c:126:12:126:26 | call to test3_condition | true | 126 | 128 |
| test.c:131:7:131:7 | b | true | 131 | 132 |
| test.c:137:7:137:7 | 0 | false | 142 | 136 |
| test.c:137:7:137:7 | 0 | true | 137 | 138 |
| test.c:137:7:137:7 | 0 | true | 138 | 139 |
| test.c:138:9:138:9 | i | true | 138 | 139 |
| test.c:146:7:146:8 | ! ... | true | 146 | 147 |
| test.c:146:8:146:8 | x | false | 146 | 147 |
| test.c:152:10:152:10 | x | true | 151 | 152 |
@@ -302,6 +301,7 @@ astGuardsEnsure
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 45 | 47 |
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 48 | 55 |
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | test.c:44:16:44:16 | 0 | 1 | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | test.c:44:16:44:16 | 0 | 1 | 51 | 53 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 45 | 47 |
@@ -309,6 +309,7 @@ astGuardsEnsure
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 45 | 45 |
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 45 | 47 |
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 48 | 55 |
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | >= | test.c:44:12:44:12 | z | 0 | 42 | 42 |
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | >= | test.c:44:12:44:12 | z | 0 | 51 | 53 |
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | < | test.c:45:20:45:20 | 0 | 1 | 48 | 55 |
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | >= | test.c:45:20:45:20 | 0 | 1 | 45 | 47 |
@@ -406,7 +407,6 @@ irGuards
| test.c:126:12:126:26 | Call: call to test3_condition |
| test.c:131:7:131:7 | Load: b |
| test.c:137:7:137:7 | Constant: 0 |
| test.c:138:9:138:9 | Load: i |
| test.c:146:8:146:8 | Load: x |
| test.c:152:10:152:10 | Load: x |
| test.c:152:15:152:15 | Load: y |
@@ -521,7 +521,6 @@ irGuardsControl
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 59 | 59 |
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 62 | 62 |
| test.c:34:16:34:21 | CompareLT: ... < ... | true | 35 | 35 |
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 42 | 42 |
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 43 | 43 |
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 45 | 45 |
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 46 | 46 |
@@ -563,9 +562,8 @@ irGuardsControl
| test.c:126:7:126:7 | Constant: 1 | true | 127 | 127 |
| test.c:126:12:126:26 | Call: call to test3_condition | true | 127 | 127 |
| test.c:131:7:131:7 | Load: b | true | 132 | 132 |
| test.c:137:7:137:7 | Constant: 0 | false | 142 | 142 |
| test.c:137:7:137:7 | Constant: 0 | true | 138 | 138 |
| test.c:137:7:137:7 | Constant: 0 | true | 139 | 139 |
| test.c:138:9:138:9 | Load: i | true | 139 | 139 |
| test.c:146:8:146:8 | Load: x | false | 147 | 147 |
| test.c:152:10:152:10 | Load: x | true | 152 | 152 |
| test.c:152:15:152:15 | Load: y | true | 152 | 152 |
@@ -644,13 +642,11 @@ irGuardsEnsure
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 59 | 59 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 62 | 62 |
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | >= | test.c:34:16:34:16 | Load: j | 1 | 35 | 35 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 42 | 42 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 43 | 43 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 45 | 45 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 46 | 46 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 49 | 49 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 52 | 52 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 42 | 42 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 43 | 43 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 45 | 45 |
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 46 | 46 |

View File

@@ -0,0 +1,29 @@
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
/** Common data flow configuration to be used by tests. */
class TestAllocationConfig extends DataFlow::Configuration {
TestAllocationConfig() {
this = "TestAllocationConfig"
}
override predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asParameter().getName().matches("source%")
or
// Track uninitialized variables
exists(source.asUninitialized())
}
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument().getFullyConverted()
)
}
override predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier")
}
}

View File

@@ -0,0 +1,13 @@
| test.cpp:66:30:66:36 | test.cpp:71:8:71:9 | AST only |
| test.cpp:89:28:89:34 | test.cpp:90:8:90:14 | AST only |
| test.cpp:100:13:100:18 | test.cpp:103:10:103:12 | AST only |
| test.cpp:120:9:120:20 | test.cpp:126:8:126:19 | AST only |
| test.cpp:122:18:122:30 | test.cpp:132:22:132:23 | IR only |
| test.cpp:122:18:122:30 | test.cpp:140:22:140:23 | IR only |
| test.cpp:136:27:136:32 | test.cpp:137:27:137:28 | AST only |
| test.cpp:136:27:136:32 | test.cpp:140:22:140:23 | AST only |
| test.cpp:395:17:395:22 | test.cpp:397:10:397:18 | AST only |
| test.cpp:421:13:421:18 | test.cpp:423:10:423:14 | AST only |
| true_upon_entry.cpp:9:11:9:16 | true_upon_entry.cpp:13:8:13:8 | IR only |
| true_upon_entry.cpp:62:11:62:16 | true_upon_entry.cpp:66:8:66:8 | IR only |
| true_upon_entry.cpp:98:11:98:16 | true_upon_entry.cpp:105:8:105:8 | IR only |

View File

@@ -0,0 +1,37 @@
import cpp
import DataflowTestCommon as ASTCommon
import IRDataflowTestCommon as IRCommon
import semmle.code.cpp.dataflow.DataFlow as ASTDataFlow
import semmle.code.cpp.ir.dataflow.DataFlow as IRDataFlow
predicate astFlow(Location sourceLocation, Location sinkLocation) {
exists(ASTDataFlow::DataFlow::Node source, ASTDataFlow::DataFlow::Node sink,
ASTCommon::TestAllocationConfig cfg |
cfg.hasFlow(source, sink) and
sourceLocation = source.getLocation() and
sinkLocation = sink.getLocation()
)
}
predicate irFlow(Location sourceLocation, Location sinkLocation) {
exists(IRDataFlow::DataFlow::Node source, IRDataFlow::DataFlow::Node sink,
IRCommon::TestAllocationConfig cfg |
cfg.hasFlow(source, sink) and
sourceLocation = source.getLocation() and
sinkLocation = sink.getLocation()
)
}
from Location sourceLocation, Location sinkLocation, string note
where
(
astFlow(sourceLocation, sinkLocation) and
not irFlow(sourceLocation, sinkLocation) and
note = "AST only"
) or
(
irFlow(sourceLocation, sinkLocation) and
not astFlow(sourceLocation, sinkLocation) and
note = "IR only"
)
select sourceLocation.toString(), sinkLocation.toString(), note

View File

@@ -0,0 +1,33 @@
| test.cpp:7:8:7:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:9:8:9:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:10:8:10:9 | Load: t2 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:15:8:15:9 | Load: t2 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:26:8:26:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source |
| test.cpp:30:8:30:8 | Load: t | test.cpp:35:10:35:15 | Call: call to source |
| test.cpp:31:8:31:8 | Load: c | test.cpp:36:13:36:18 | Call: call to source |
| test.cpp:58:10:58:10 | Load: t | test.cpp:50:14:50:19 | Call: call to source |
| test.cpp:76:8:76:9 | Load: u1 | test.cpp:75:7:75:8 | Uninitialized: definition of u1 |
| test.cpp:84:8:84:18 | Load: ... ? ... : ... | test.cpp:83:7:83:8 | Uninitialized: definition of u2 |
| test.cpp:86:8:86:9 | Load: i1 | test.cpp:83:7:83:8 | Uninitialized: definition of u2 |
| test.cpp:132:22:132:23 | Load: m1 | test.cpp:122:18:122:30 | InitializeParameter: sourceStruct1 |
| test.cpp:140:22:140:23 | Load: m1 | test.cpp:122:18:122:30 | InitializeParameter: sourceStruct1 |
| test.cpp:188:8:188:8 | Load: y | test.cpp:186:27:186:32 | Call: call to source |
| test.cpp:192:8:192:8 | Load: s | test.cpp:199:33:199:38 | Call: call to source |
| test.cpp:200:8:200:8 | Load: y | test.cpp:199:33:199:38 | Call: call to source |
| test.cpp:205:8:205:8 | Load: x | test.cpp:212:34:212:39 | Call: call to source |
| test.cpp:213:8:213:8 | Load: y | test.cpp:212:34:212:39 | Call: call to source |
| test.cpp:226:8:226:8 | Load: y | test.cpp:219:11:219:16 | Call: call to source |
| test.cpp:308:12:308:12 | Load: x | test.cpp:293:14:293:19 | Call: call to source |
| test.cpp:314:12:314:12 | Load: x | test.cpp:313:22:313:27 | Call: call to source |
| test.cpp:337:14:337:14 | Load: x | test.cpp:353:17:353:22 | Call: call to source |
| test.cpp:366:7:366:7 | Load: x | test.cpp:362:4:362:9 | Call: call to source |
| true_upon_entry.cpp:13:8:13:8 | Load: x | true_upon_entry.cpp:9:11:9:16 | Call: call to source |
| true_upon_entry.cpp:21:8:21:8 | Load: x | true_upon_entry.cpp:17:11:17:16 | Call: call to source |
| true_upon_entry.cpp:29:8:29:8 | Load: x | true_upon_entry.cpp:27:9:27:14 | Call: call to source |
| true_upon_entry.cpp:39:8:39:8 | Load: x | true_upon_entry.cpp:33:11:33:16 | Call: call to source |
| true_upon_entry.cpp:49:8:49:8 | Load: x | true_upon_entry.cpp:43:11:43:16 | Call: call to source |
| true_upon_entry.cpp:57:8:57:8 | Load: x | true_upon_entry.cpp:54:11:54:16 | Call: call to source |
| true_upon_entry.cpp:66:8:66:8 | Load: x | true_upon_entry.cpp:62:11:62:16 | Call: call to source |
| true_upon_entry.cpp:78:8:78:8 | Load: x | true_upon_entry.cpp:70:11:70:16 | Call: call to source |
| true_upon_entry.cpp:86:8:86:8 | Load: x | true_upon_entry.cpp:83:11:83:16 | Call: call to source |
| true_upon_entry.cpp:105:8:105:8 | Load: x | true_upon_entry.cpp:98:11:98:16 | Call: call to source |

View File

@@ -0,0 +1,5 @@
import IRDataflowTestCommon
from DataFlow::Node sink, DataFlow::Node source, TestAllocationConfig cfg
where cfg.hasFlow(source, sink)
select sink, source

View File

@@ -30,3 +30,31 @@ int ReturnConstantPhiLoop(int x) {
}
return y;
}
int UnreachableViaGoto() {
goto skip;
return 1;
skip:
return 0;
}
int UnreachableIf(bool b) {
int x = 5;
int y = 10;
if (b) {
if (x == y) {
return 1;
}
else {
return 0;
}
}
else {
if (x < y) {
return 0;
}
else {
return 1;
}
}
}

View File

@@ -1,3 +1,5 @@
| constant_func.cpp:1:5:1:18 | IR: ReturnConstant | 7 |
| constant_func.cpp:5:5:5:21 | IR: ReturnConstantPhi | 7 |
| constant_func.cpp:25:5:25:25 | IR: ReturnConstantPhiLoop | 7 |
| constant_func.cpp:34:5:34:22 | IR: UnreachableViaGoto | 0 |
| constant_func.cpp:41:5:41:17 | IR: UnreachableIf | 0 |

View File

@@ -1,29 +1,8 @@
import default
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.implementation.aliased_ssa.constant.ConstantAnalysis
import semmle.code.cpp.ir.internal.IntegerConstant
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right)
)
) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
)
}
from FunctionIR funcIR, int value
where
value = getValue(getConstantValue(funcIR.getReturnInstruction().(ReturnValueInstruction).getReturnValue()))

View File

@@ -21,15 +21,49 @@
| -1 * -INT_MAX | 2147483647 |
| -1 - -INT_MAX | 2147483646 |
| -1 - INT_MAX | unknown |
| -3 != 6 | 1 |
| -3 != -3 | 0 |
| -3 != unknown | unknown |
| -3 < 6 | 1 |
| -3 < -3 | 0 |
| -3 < -7 | 0 |
| -3 < unknown | unknown |
| -3 <= 6 | 1 |
| -3 <= -3 | 1 |
| -3 <= -7 | 0 |
| -3 <= unknown | unknown |
| -3 == 6 | 0 |
| -3 == -3 | 1 |
| -3 == unknown | unknown |
| -3 > 6 | 0 |
| -3 > -3 | 0 |
| -3 > -7 | 1 |
| -3 > unknown | unknown |
| -3 >= 6 | 0 |
| -3 >= -3 | 1 |
| -3 >= -7 | 1 |
| -3 >= unknown | unknown |
| -35 / 7 | -5 |
| -35 / 8 | -4 |
| -35 / -7 | 5 |
| -35 / -8 | 4 |
| INT_MAX * INT_MAX | unknown |
| INT_MAX / 0 | unknown |
| unknown != 6 | unknown |
| unknown != unknown | unknown |
| unknown + 5 | unknown |
| unknown + unknown | unknown |
| unknown - 5 | unknown |
| unknown - unknown | unknown |
| unknown / 3 | unknown |
| unknown / unknown | unknown |
| unknown < 6 | unknown |
| unknown < unknown | unknown |
| unknown <= 6 | unknown |
| unknown <= unknown | unknown |
| unknown == 6 | unknown |
| unknown == unknown | unknown |
| unknown > 6 | unknown |
| unknown > unknown | unknown |
| unknown >= 6 | unknown |
| unknown >= unknown | unknown |

View File

@@ -45,5 +45,39 @@ where
expr = "INT_MAX / 0" and res = Ints::div(Ints::maxValue(), 0) or
expr = "0 / unknown" and res = Ints::div(0, Ints::unknown()) or
expr = "unknown / 3" and res = Ints::div(Ints::unknown(), 3) or
expr = "unknown / unknown" and res = Ints::div(Ints::unknown(), Ints::unknown())
expr = "unknown / unknown" and res = Ints::div(Ints::unknown(), Ints::unknown()) or
expr = "-3 == -3" and res = Ints::compareEQ(-3, -3) or
expr = "-3 == 6" and res = Ints::compareEQ(-3, 6) or
expr = "-3 == unknown" and res = Ints::compareEQ(-3, Ints::unknown()) or
expr = "unknown == 6" and res = Ints::compareEQ(Ints::unknown(), 6) or
expr = "unknown == unknown" and res = Ints::compareEQ(Ints::unknown(), Ints::unknown()) or
expr = "-3 != -3" and res = Ints::compareNE(-3, -3) or
expr = "-3 != 6" and res = Ints::compareNE(-3, 6) or
expr = "-3 != unknown" and res = Ints::compareNE(-3, Ints::unknown()) or
expr = "unknown != 6" and res = Ints::compareNE(Ints::unknown(), 6) or
expr = "unknown != unknown" and res = Ints::compareNE(Ints::unknown(), Ints::unknown()) or
expr = "-3 < -3" and res = Ints::compareLT(-3, -3) or
expr = "-3 < 6" and res = Ints::compareLT(-3, 6) or
expr = "-3 < -7" and res = Ints::compareLT(-3, -7) or
expr = "-3 < unknown" and res = Ints::compareLT(-3, Ints::unknown()) or
expr = "unknown < 6" and res = Ints::compareLT(Ints::unknown(), 6) or
expr = "unknown < unknown" and res = Ints::compareLT(Ints::unknown(), Ints::unknown()) or
expr = "-3 > -3" and res = Ints::compareGT(-3, -3) or
expr = "-3 > 6" and res = Ints::compareGT(-3, 6) or
expr = "-3 > -7" and res = Ints::compareGT(-3, -7) or
expr = "-3 > unknown" and res = Ints::compareGT(-3, Ints::unknown()) or
expr = "unknown > 6" and res = Ints::compareGT(Ints::unknown(), 6) or
expr = "unknown > unknown" and res = Ints::compareGT(Ints::unknown(), Ints::unknown()) or
expr = "-3 <= -3" and res = Ints::compareLE(-3, -3) or
expr = "-3 <= 6" and res = Ints::compareLE(-3, 6) or
expr = "-3 <= -7" and res = Ints::compareLE(-3, -7) or
expr = "-3 <= unknown" and res = Ints::compareLE(-3, Ints::unknown()) or
expr = "unknown <= 6" and res = Ints::compareLE(Ints::unknown(), 6) or
expr = "unknown <= unknown" and res = Ints::compareLE(Ints::unknown(), Ints::unknown()) or
expr = "-3 >= -3" and res = Ints::compareGE(-3, -3) or
expr = "-3 >= 6" and res = Ints::compareGE(-3, 6) or
expr = "-3 >= -7" and res = Ints::compareGE(-3, -7) or
expr = "-3 >= unknown" and res = Ints::compareGE(-3, Ints::unknown()) or
expr = "unknown >= 6" and res = Ints::compareGE(Ints::unknown(), 6) or
expr = "unknown >= unknown" and res = Ints::compareGE(Ints::unknown(), Ints::unknown())
select expr, resultString(res)

View File

@@ -6668,3 +6668,89 @@ ir.cpp:
# 1018| -1: p
# 1018| Type = Point *
# 1018| ValueCategory = prvalue(load)
# 1021| UnreachableViaGoto() -> int
# 1021| params:
# 1021| body: { ... }
# 1022| 0: goto ...
# 1023| 1: return ...
# 1023| 0: 1
# 1023| Type = int
# 1023| Value = 1
# 1023| ValueCategory = prvalue
# 1024| 2: label ...:
# 1025| 3: return ...
# 1025| 0: 0
# 1025| Type = int
# 1025| Value = 0
# 1025| ValueCategory = prvalue
# 1028| UnreachableIf(bool) -> int
# 1028| params:
# 1028| 0: b
# 1028| Type = bool
# 1028| body: { ... }
# 1029| 0: declaration
# 1029| 0: definition of x
# 1029| Type = int
# 1029| init: initializer for x
# 1029| expr: 5
# 1029| Type = int
# 1029| Value = 5
# 1029| ValueCategory = prvalue
# 1030| 1: declaration
# 1030| 0: definition of y
# 1030| Type = int
# 1030| init: initializer for y
# 1030| expr: 10
# 1030| Type = int
# 1030| Value = 10
# 1030| ValueCategory = prvalue
# 1031| 2: if (...) ...
# 1031| 0: b
# 1031| Type = bool
# 1031| ValueCategory = prvalue(load)
# 1031| 1: { ... }
# 1032| 0: if (...) ...
# 1032| 0: ... == ...
# 1032| Type = bool
# 1032| ValueCategory = prvalue
# 1032| 0: x
# 1032| Type = int
# 1032| ValueCategory = prvalue(load)
# 1032| 1: y
# 1032| Type = int
# 1032| ValueCategory = prvalue(load)
# 1032| 1: { ... }
# 1033| 0: return ...
# 1033| 0: 1
# 1033| Type = int
# 1033| Value = 1
# 1033| ValueCategory = prvalue
# 1035| 2: { ... }
# 1036| 0: return ...
# 1036| 0: 0
# 1036| Type = int
# 1036| Value = 0
# 1036| ValueCategory = prvalue
# 1039| 2: { ... }
# 1040| 0: if (...) ...
# 1040| 0: ... < ...
# 1040| Type = bool
# 1040| ValueCategory = prvalue
# 1040| 0: x
# 1040| Type = int
# 1040| ValueCategory = prvalue(load)
# 1040| 1: y
# 1040| Type = int
# 1040| ValueCategory = prvalue(load)
# 1040| 1: { ... }
# 1041| 0: return ...
# 1041| 0: 0
# 1041| Type = int
# 1041| Value = 0
# 1041| ValueCategory = prvalue
# 1043| 2: { ... }
# 1044| 0: return ...
# 1044| 0: 1
# 1044| Type = int
# 1044| Value = 1
# 1044| ValueCategory = prvalue

File diff suppressed because it is too large Load Diff

View File

@@ -1018,4 +1018,32 @@ int ChiPhiNode(Point *p, bool which1, bool which2) {
return p->x + p->y;
}
int UnreachableViaGoto() {
goto skip;
return 1;
skip:
return 0;
}
int UnreachableIf(bool b) {
int x = 5;
int y = 10;
if (b) {
if (x == y) {
return 1;
}
else {
return 0;
}
}
else {
if (x < y) {
return 0;
}
else {
return 1;
}
}
}
// semmle-extractor-options: -std=c++17

View File

@@ -5,7 +5,7 @@ bad_asts.cpp:
# 14| mu0_1(unknown) = AliasedDefinition :
# 14| mu0_2(unknown) = UnmodeledDefinition :
# 15| r0_3(glval<S>) = VariableAddress[s] :
# 15| mu0_4(S) = Uninitialized : r0_3
# 15| mu0_4(S) = Uninitialized[s] : r0_3
# 15| r0_5(glval<int>) = FieldAddress[x] : r0_3
# 15| r0_6(int) = Constant[0] :
# 15| mu0_7(int) = Store : r0_5, r0_6
@@ -186,7 +186,7 @@ ir.cpp:
# 50| r0_5(glval<int>) = VariableAddress[y] :
# 50| mu0_6(int) = InitializeParameter[y] : r0_5
# 51| r0_7(glval<int>) = VariableAddress[z] :
# 51| mu0_8(int) = Uninitialized : r0_7
# 51| mu0_8(int) = Uninitialized[z] : r0_7
# 53| r0_9(glval<int>) = VariableAddress[x] :
# 53| r0_10(int) = Load : r0_9, mu0_2
# 53| r0_11(glval<int>) = VariableAddress[y] :
@@ -359,7 +359,7 @@ ir.cpp:
# 87| r0_5(glval<int>) = VariableAddress[y] :
# 87| mu0_6(int) = InitializeParameter[y] : r0_5
# 88| r0_7(glval<bool>) = VariableAddress[b] :
# 88| mu0_8(bool) = Uninitialized : r0_7
# 88| mu0_8(bool) = Uninitialized[b] : r0_7
# 90| r0_9(glval<int>) = VariableAddress[x] :
# 90| r0_10(int) = Load : r0_9, mu0_2
# 90| r0_11(glval<int>) = VariableAddress[y] :
@@ -415,7 +415,7 @@ ir.cpp:
# 98| r0_3(glval<int>) = VariableAddress[x] :
# 98| mu0_4(int) = InitializeParameter[x] : r0_3
# 99| r0_5(glval<int>) = VariableAddress[y] :
# 99| mu0_6(int) = Uninitialized : r0_5
# 99| mu0_6(int) = Uninitialized[y] : r0_5
# 101| r0_7(glval<int>) = VariableAddress[x] :
# 101| r0_8(int) = Load : r0_7, mu0_2
# 101| r0_9(int) = Constant[1] :
@@ -457,7 +457,7 @@ ir.cpp:
# 107| r0_3(glval<int>) = VariableAddress[x] :
# 107| mu0_4(int) = InitializeParameter[x] : r0_3
# 108| r0_5(glval<int *>) = VariableAddress[p] :
# 108| mu0_6(int *) = Uninitialized : r0_5
# 108| mu0_6(int *) = Uninitialized[p] : r0_5
# 110| r0_7(glval<int>) = VariableAddress[x] :
# 110| r0_8(int) = Load : r0_7, mu0_2
# 110| r0_9(int) = Constant[1] :
@@ -487,7 +487,7 @@ ir.cpp:
# 114| r0_5(glval<double>) = VariableAddress[y] :
# 114| mu0_6(double) = InitializeParameter[y] : r0_5
# 115| r0_7(glval<double>) = VariableAddress[z] :
# 115| mu0_8(double) = Uninitialized : r0_7
# 115| mu0_8(double) = Uninitialized[z] : r0_7
# 117| r0_9(glval<double>) = VariableAddress[x] :
# 117| r0_10(double) = Load : r0_9, mu0_2
# 117| r0_11(glval<double>) = VariableAddress[y] :
@@ -569,7 +569,7 @@ ir.cpp:
# 133| r0_5(glval<double>) = VariableAddress[y] :
# 133| mu0_6(double) = InitializeParameter[y] : r0_5
# 134| r0_7(glval<bool>) = VariableAddress[b] :
# 134| mu0_8(bool) = Uninitialized : r0_7
# 134| mu0_8(bool) = Uninitialized[b] : r0_7
# 136| r0_9(glval<double>) = VariableAddress[x] :
# 136| r0_10(double) = Load : r0_9, mu0_2
# 136| r0_11(glval<double>) = VariableAddress[y] :
@@ -625,7 +625,7 @@ ir.cpp:
# 144| r0_3(glval<float>) = VariableAddress[x] :
# 144| mu0_4(float) = InitializeParameter[x] : r0_3
# 145| r0_5(glval<float>) = VariableAddress[y] :
# 145| mu0_6(float) = Uninitialized : r0_5
# 145| mu0_6(float) = Uninitialized[y] : r0_5
# 147| r0_7(glval<float>) = VariableAddress[x] :
# 147| r0_8(float) = Load : r0_7, mu0_2
# 147| r0_9(float) = Constant[1.0] :
@@ -669,9 +669,9 @@ ir.cpp:
# 153| r0_5(glval<int>) = VariableAddress[i] :
# 153| mu0_6(int) = InitializeParameter[i] : r0_5
# 154| r0_7(glval<int *>) = VariableAddress[q] :
# 154| mu0_8(int *) = Uninitialized : r0_7
# 154| mu0_8(int *) = Uninitialized[q] : r0_7
# 155| r0_9(glval<bool>) = VariableAddress[b] :
# 155| mu0_10(bool) = Uninitialized : r0_9
# 155| mu0_10(bool) = Uninitialized[b] : r0_9
# 157| r0_11(glval<int *>) = VariableAddress[p] :
# 157| r0_12(int *) = Load : r0_11, mu0_2
# 157| r0_13(glval<int>) = VariableAddress[i] :
@@ -745,7 +745,7 @@ ir.cpp:
# 171| r0_5(glval<int>) = VariableAddress[i] :
# 171| mu0_6(int) = InitializeParameter[i] : r0_5
# 172| r0_7(glval<int>) = VariableAddress[x] :
# 172| mu0_8(int) = Uninitialized : r0_7
# 172| mu0_8(int) = Uninitialized[x] : r0_7
# 174| r0_9(glval<int *>) = VariableAddress[p] :
# 174| r0_10(int *) = Load : r0_9, mu0_2
# 174| r0_11(glval<int>) = VariableAddress[i] :
@@ -779,7 +779,7 @@ ir.cpp:
# 178| r0_39(int *) = PointerAdd[4] : r0_36, r0_38
# 178| mu0_40(int) = Store : r0_39, r0_34
# 180| r0_41(glval<int[10]>) = VariableAddress[a] :
# 180| mu0_42(int[10]) = Uninitialized : r0_41
# 180| mu0_42(int[10]) = Uninitialized[a] : r0_41
# 181| r0_43(glval<int[10]>) = VariableAddress[a] :
# 181| r0_44(int *) = Convert : r0_43
# 181| r0_45(glval<int>) = VariableAddress[i] :
@@ -860,7 +860,7 @@ ir.cpp:
# 193| r0_5(glval<int *>) = VariableAddress[q] :
# 193| mu0_6(int *) = InitializeParameter[q] : r0_5
# 194| r0_7(glval<bool>) = VariableAddress[b] :
# 194| mu0_8(bool) = Uninitialized : r0_7
# 194| mu0_8(bool) = Uninitialized[b] : r0_7
# 196| r0_9(glval<int *>) = VariableAddress[p] :
# 196| r0_10(int *) = Load : r0_9, mu0_2
# 196| r0_11(glval<int *>) = VariableAddress[q] :
@@ -916,7 +916,7 @@ ir.cpp:
# 204| r0_3(glval<int *>) = VariableAddress[p] :
# 204| mu0_4(int *) = InitializeParameter[p] : r0_3
# 205| r0_5(glval<int *>) = VariableAddress[q] :
# 205| mu0_6(int *) = Uninitialized : r0_5
# 205| mu0_6(int *) = Uninitialized[q] : r0_5
# 207| r0_7(glval<int *>) = VariableAddress[p] :
# 207| r0_8(int *) = Load : r0_7, mu0_2
# 207| r0_9(int) = Constant[1] :
@@ -1000,7 +1000,7 @@ ir.cpp:
# 230| mu0_1(unknown) = AliasedDefinition :
# 230| mu0_2(unknown) = UnmodeledDefinition :
# 231| r0_3(glval<int>) = VariableAddress[x] :
# 231| mu0_4(int) = Uninitialized : r0_3
# 231| mu0_4(int) = Uninitialized[x] : r0_3
# 232| r0_5(glval<int>) = VariableAddress[y] :
# 232| r0_6(glval<int>) = VariableAddress[x] :
# 232| r0_7(int) = Load : r0_6, mu0_2
@@ -1160,7 +1160,7 @@ ir.cpp:
# 265| mu0_1(unknown) = AliasedDefinition :
# 265| mu0_2(unknown) = UnmodeledDefinition :
# 266| r0_3(glval<int>) = VariableAddress[j] :
# 266| mu0_4(int) = Uninitialized : r0_3
# 266| mu0_4(int) = Uninitialized[j] : r0_3
#-----| Goto -> Block 2
# 265| Block 1
@@ -1697,7 +1697,7 @@ ir.cpp:
# 384| r0_3(glval<int>) = VariableAddress[x] :
# 384| mu0_4(int) = InitializeParameter[x] : r0_3
# 385| r0_5(glval<int>) = VariableAddress[y] :
# 385| mu0_6(int) = Uninitialized : r0_5
# 385| mu0_6(int) = Uninitialized[y] : r0_5
# 386| r0_7(glval<int>) = VariableAddress[x] :
# 386| r0_8(int) = Load : r0_7, mu0_2
# 386| v0_9(void) = Switch : r0_8
@@ -1792,7 +1792,7 @@ ir.cpp:
# 426| mu0_1(unknown) = AliasedDefinition :
# 426| mu0_2(unknown) = UnmodeledDefinition :
# 427| r0_3(glval<Point>) = VariableAddress[pt] :
# 427| mu0_4(Point) = Uninitialized : r0_3
# 427| mu0_4(Point) = Uninitialized[pt] : r0_3
# 428| r0_5(int) = Constant[5] :
# 428| r0_6(glval<Point>) = VariableAddress[pt] :
# 428| r0_7(glval<int>) = FieldAddress[x] : r0_6
@@ -1822,7 +1822,7 @@ ir.cpp:
# 433| r0_5(glval<bool>) = VariableAddress[b] :
# 433| mu0_6(bool) = InitializeParameter[b] : r0_5
# 434| r0_7(glval<int>) = VariableAddress[x] :
# 434| mu0_8(int) = Uninitialized : r0_7
# 434| mu0_8(int) = Uninitialized[x] : r0_7
# 435| r0_9(glval<bool>) = VariableAddress[a] :
# 435| r0_10(bool) = Load : r0_9, mu0_2
# 435| v0_11(void) = ConditionalBranch : r0_10
@@ -1884,7 +1884,7 @@ ir.cpp:
# 447| r0_5(glval<bool>) = VariableAddress[b] :
# 447| mu0_6(bool) = InitializeParameter[b] : r0_5
# 448| r0_7(glval<int>) = VariableAddress[x] :
# 448| mu0_8(int) = Uninitialized : r0_7
# 448| mu0_8(int) = Uninitialized[x] : r0_7
# 449| r0_9(glval<bool>) = VariableAddress[a] :
# 449| r0_10(bool) = Load : r0_9, mu0_2
# 449| v0_11(void) = ConditionalBranch : r0_10
@@ -1946,7 +1946,7 @@ ir.cpp:
# 461| r0_5(glval<bool>) = VariableAddress[b] :
# 461| mu0_6(bool) = InitializeParameter[b] : r0_5
# 462| r0_7(glval<int>) = VariableAddress[x] :
# 462| mu0_8(int) = Uninitialized : r0_7
# 462| mu0_8(int) = Uninitialized[x] : r0_7
# 463| r0_9(glval<bool>) = VariableAddress[a] :
# 463| r0_10(bool) = Load : r0_9, mu0_2
# 463| v0_11(void) = ConditionalBranch : r0_10
@@ -2001,7 +2001,7 @@ ir.cpp:
# 475| r0_5(glval<bool>) = VariableAddress[b] :
# 475| mu0_6(bool) = InitializeParameter[b] : r0_5
# 476| r0_7(glval<bool>) = VariableAddress[x] :
# 476| mu0_8(bool) = Uninitialized : r0_7
# 476| mu0_8(bool) = Uninitialized[x] : r0_7
# 477| r0_9(glval<bool>) = VariableAddress[a] :
# 477| r0_10(bool) = Load : r0_9, mu0_2
# 477| v0_11(void) = ConditionalBranch : r0_10
@@ -2147,9 +2147,9 @@ ir.cpp:
# 486| r0_3(glval<bool>) = VariableAddress[a] :
# 486| mu0_4(bool) = InitializeParameter[a] : r0_3
# 487| r0_5(glval<int>) = VariableAddress[x] :
# 487| mu0_6(int) = Uninitialized : r0_5
# 487| mu0_6(int) = Uninitialized[x] : r0_5
# 488| r0_7(glval<int>) = VariableAddress[y] :
# 488| mu0_8(int) = Uninitialized : r0_7
# 488| mu0_8(int) = Uninitialized[y] : r0_7
# 489| r0_9(int) = Constant[5] :
# 489| r0_10(glval<bool>) = VariableAddress[a] :
# 489| r0_11(bool) = Load : r0_10, mu0_2
@@ -2241,7 +2241,7 @@ ir.cpp:
# 503| r0_5(glval<float>) = VariableAddress[f] :
# 503| mu0_6(float) = InitializeParameter[f] : r0_5
# 504| r0_7(glval<Point>) = VariableAddress[pt1] :
# 504| mu0_8(Point) = Uninitialized : r0_7
# 504| mu0_8(Point) = Uninitialized[pt1] : r0_7
# 504| r0_9(glval<int>) = FieldAddress[x] : r0_7
# 504| r0_10(glval<int>) = VariableAddress[x] :
# 504| r0_11(int) = Load : r0_10, mu0_2
@@ -2252,7 +2252,7 @@ ir.cpp:
# 504| r0_16(int) = Convert : r0_15
# 504| mu0_17(int) = Store : r0_13, r0_16
# 505| r0_18(glval<Point>) = VariableAddress[pt2] :
# 505| mu0_19(Point) = Uninitialized : r0_18
# 505| mu0_19(Point) = Uninitialized[pt2] : r0_18
# 505| r0_20(glval<int>) = FieldAddress[x] : r0_18
# 505| r0_21(glval<int>) = VariableAddress[x] :
# 505| r0_22(int) = Load : r0_21, mu0_2
@@ -2261,7 +2261,7 @@ ir.cpp:
# 505| r0_25(int) = Constant[0] :
# 505| mu0_26(int) = Store : r0_24, r0_25
# 506| r0_27(glval<Point>) = VariableAddress[pt3] :
# 506| mu0_28(Point) = Uninitialized : r0_27
# 506| mu0_28(Point) = Uninitialized[pt3] : r0_27
# 506| r0_29(glval<int>) = FieldAddress[x] : r0_27
# 506| r0_30(int) = Constant[0] :
# 506| mu0_31(int) = Store : r0_29, r0_30
@@ -2289,7 +2289,7 @@ ir.cpp:
# 512| r0_5(glval<float>) = VariableAddress[f] :
# 512| mu0_6(float) = InitializeParameter[f] : r0_5
# 513| r0_7(glval<Rect>) = VariableAddress[r1] :
# 513| mu0_8(Rect) = Uninitialized : r0_7
# 513| mu0_8(Rect) = Uninitialized[r1] : r0_7
# 513| r0_9(glval<Point>) = FieldAddress[topLeft] : r0_7
# 513| r0_10(Point) = Constant[0] :
# 513| mu0_11(Point) = Store : r0_9, r0_10
@@ -2297,7 +2297,7 @@ ir.cpp:
# 513| r0_13(Point) = Constant[0] :
# 513| mu0_14(Point) = Store : r0_12, r0_13
# 514| r0_15(glval<Rect>) = VariableAddress[r2] :
# 514| mu0_16(Rect) = Uninitialized : r0_15
# 514| mu0_16(Rect) = Uninitialized[r2] : r0_15
# 514| r0_17(glval<Point>) = FieldAddress[topLeft] : r0_15
# 514| r0_18(glval<int>) = FieldAddress[x] : r0_17
# 514| r0_19(glval<int>) = VariableAddress[x] :
@@ -2312,7 +2312,7 @@ ir.cpp:
# 514| r0_28(Point) = Constant[0] :
# 514| mu0_29(Point) = Store : r0_27, r0_28
# 515| r0_30(glval<Rect>) = VariableAddress[r3] :
# 515| mu0_31(Rect) = Uninitialized : r0_30
# 515| mu0_31(Rect) = Uninitialized[r3] : r0_30
# 515| r0_32(glval<Point>) = FieldAddress[topLeft] : r0_30
# 515| r0_33(glval<int>) = FieldAddress[x] : r0_32
# 515| r0_34(glval<int>) = VariableAddress[x] :
@@ -2334,7 +2334,7 @@ ir.cpp:
# 515| r0_50(int) = Convert : r0_49
# 515| mu0_51(int) = Store : r0_47, r0_50
# 516| r0_52(glval<Rect>) = VariableAddress[r4] :
# 516| mu0_53(Rect) = Uninitialized : r0_52
# 516| mu0_53(Rect) = Uninitialized[r4] : r0_52
# 516| r0_54(glval<Point>) = FieldAddress[topLeft] : r0_52
# 516| r0_55(glval<int>) = FieldAddress[x] : r0_54
# 516| r0_56(glval<int>) = VariableAddress[x] :
@@ -2366,13 +2366,13 @@ ir.cpp:
# 519| r0_5(glval<float>) = VariableAddress[f] :
# 519| mu0_6(float) = InitializeParameter[f] : r0_5
# 520| r0_7(glval<int[3]>) = VariableAddress[a1] :
# 520| mu0_8(int[3]) = Uninitialized : r0_7
# 520| mu0_8(int[3]) = Uninitialized[a1] : r0_7
# 520| r0_9(int) = Constant[0] :
# 520| r0_10(glval<int>) = PointerAdd : r0_7, r0_9
# 520| r0_11(unknown[12]) = Constant[0] :
# 520| mu0_12(unknown[12]) = Store : r0_10, r0_11
# 521| r0_13(glval<int[3]>) = VariableAddress[a2] :
# 521| mu0_14(int[3]) = Uninitialized : r0_13
# 521| mu0_14(int[3]) = Uninitialized[a2] : r0_13
# 521| r0_15(int) = Constant[0] :
# 521| r0_16(glval<int>) = PointerAdd : r0_13, r0_15
# 521| r0_17(glval<int>) = VariableAddress[x] :
@@ -2389,7 +2389,7 @@ ir.cpp:
# 521| r0_28(int) = Constant[0] :
# 521| mu0_29(int) = Store : r0_27, r0_28
# 522| r0_30(glval<int[3]>) = VariableAddress[a3] :
# 522| mu0_31(int[3]) = Uninitialized : r0_30
# 522| mu0_31(int[3]) = Uninitialized[a3] : r0_30
# 522| r0_32(int) = Constant[0] :
# 522| r0_33(glval<int>) = PointerAdd : r0_30, r0_32
# 522| r0_34(glval<int>) = VariableAddress[x] :
@@ -2414,7 +2414,7 @@ ir.cpp:
# 530| r0_5(glval<float>) = VariableAddress[f] :
# 530| mu0_6(float) = InitializeParameter[f] : r0_5
# 531| r0_7(glval<U>) = VariableAddress[u1] :
# 531| mu0_8(U) = Uninitialized : r0_7
# 531| mu0_8(U) = Uninitialized[u1] : r0_7
# 531| r0_9(glval<double>) = FieldAddress[d] : r0_7
# 531| r0_10(glval<float>) = VariableAddress[f] :
# 531| r0_11(float) = Load : r0_10, mu0_2
@@ -2584,15 +2584,15 @@ ir.cpp:
# 574| r0_17(char[5]) = Load : r0_16, mu0_2
# 574| mu0_18(char[5]) = Store : r0_15, r0_17
# 575| r0_19(glval<char[2]>) = VariableAddress[b] :
# 575| mu0_20(char[2]) = Uninitialized : r0_19
# 575| mu0_20(char[2]) = Uninitialized[b] : r0_19
# 576| r0_21(glval<char[2]>) = VariableAddress[c] :
# 576| mu0_22(char[2]) = Uninitialized : r0_21
# 576| mu0_22(char[2]) = Uninitialized[c] : r0_21
# 576| r0_23(int) = Constant[0] :
# 576| r0_24(glval<char>) = PointerAdd : r0_21, r0_23
# 576| r0_25(unknown[2]) = Constant[0] :
# 576| mu0_26(unknown[2]) = Store : r0_24, r0_25
# 577| r0_27(glval<char[2]>) = VariableAddress[d] :
# 577| mu0_28(char[2]) = Uninitialized : r0_27
# 577| mu0_28(char[2]) = Uninitialized[d] : r0_27
# 577| r0_29(int) = Constant[0] :
# 577| r0_30(glval<char>) = PointerAdd : r0_27, r0_29
# 577| r0_31(char) = Constant[0] :
@@ -2602,7 +2602,7 @@ ir.cpp:
# 577| r0_35(char) = Constant[0] :
# 577| mu0_36(char) = Store : r0_34, r0_35
# 578| r0_37(glval<char[2]>) = VariableAddress[e] :
# 578| mu0_38(char[2]) = Uninitialized : r0_37
# 578| mu0_38(char[2]) = Uninitialized[e] : r0_37
# 578| r0_39(int) = Constant[0] :
# 578| r0_40(glval<char>) = PointerAdd : r0_37, r0_39
# 578| r0_41(char) = Constant[0] :
@@ -2612,7 +2612,7 @@ ir.cpp:
# 578| r0_45(char) = Constant[1] :
# 578| mu0_46(char) = Store : r0_44, r0_45
# 579| r0_47(glval<char[3]>) = VariableAddress[f] :
# 579| mu0_48(char[3]) = Uninitialized : r0_47
# 579| mu0_48(char[3]) = Uninitialized[f] : r0_47
# 579| r0_49(int) = Constant[0] :
# 579| r0_50(glval<char>) = PointerAdd : r0_47, r0_49
# 579| r0_51(char) = Constant[0] :
@@ -2799,7 +2799,7 @@ ir.cpp:
# 645| r0_14(glval<int>) = FieldAddress[m_a] : r0_13
# 645| mu0_15(int) = Store : r0_14, r0_12
# 646| r0_16(glval<int>) = VariableAddress[x] :
# 646| mu0_17(int) = Uninitialized : r0_16
# 646| mu0_17(int) = Uninitialized[x] : r0_16
# 647| r0_18(C *) = CopyValue : r0_3
# 647| r0_19(glval<int>) = FieldAddress[m_a] : r0_18
# 647| r0_20(int) = Load : r0_19, mu0_2
@@ -2937,7 +2937,7 @@ ir.cpp:
# 691| mu0_1(unknown) = AliasedDefinition :
# 691| mu0_2(unknown) = UnmodeledDefinition :
# 692| r0_3(glval<int[10]>) = VariableAddress[a] :
# 692| mu0_4(int[10]) = Uninitialized : r0_3
# 692| mu0_4(int[10]) = Uninitialized[a] : r0_3
# 693| r0_5(glval<int(&)[10]>) = VariableAddress[ra] :
# 693| r0_6(glval<int[10]>) = VariableAddress[a] :
# 693| mu0_7(int(&)[10]) = Store : r0_5, r0_6
@@ -3851,7 +3851,7 @@ ir.cpp:
# 871| mu0_1(unknown) = AliasedDefinition :
# 871| mu0_2(unknown) = UnmodeledDefinition :
# 872| r0_3(glval<char[5]>) = VariableAddress[a] :
# 872| mu0_4(char[5]) = Uninitialized : r0_3
# 872| mu0_4(char[5]) = Uninitialized[a] : r0_3
# 873| r0_5(glval<char *>) = VariableAddress[p] :
# 873| r0_6(glval<char[5]>) = VariableAddress[a] :
# 873| r0_7(char *) = Convert : r0_6
@@ -3924,13 +3924,13 @@ ir.cpp:
# 888| r0_3(glval<int>) = VariableAddress[x] :
# 888| mu0_4(int) = InitializeParameter[x] : r0_3
# 889| r0_5(glval<__va_list_tag[1]>) = VariableAddress[args] :
# 889| mu0_6(__va_list_tag[1]) = Uninitialized : r0_5
# 889| mu0_6(__va_list_tag[1]) = Uninitialized[args] : r0_5
# 891| r0_7(glval<__va_list_tag[1]>) = VariableAddress[args] :
# 891| r0_8(__va_list_tag *) = Convert : r0_7
# 891| r0_9(glval<int>) = VariableAddress[x] :
# 891| v0_10(void) = VarArgsStart : r0_8, r0_9
# 892| r0_11(glval<__va_list_tag[1]>) = VariableAddress[args2] :
# 892| mu0_12(__va_list_tag[1]) = Uninitialized : r0_11
# 892| mu0_12(__va_list_tag[1]) = Uninitialized[args2] : r0_11
# 893| r0_13(glval<__va_list_tag[1]>) = VariableAddress[args2] :
# 893| r0_14(__va_list_tag *) = Convert : r0_13
# 893| r0_15(glval<__va_list_tag[1]>) = VariableAddress[args] :
@@ -4161,7 +4161,7 @@ ir.cpp:
# 961| mu0_1(unknown) = AliasedDefinition :
# 961| mu0_2(unknown) = UnmodeledDefinition :
# 962| r0_3(glval<int[1000]>) = VariableAddress[a1] :
# 962| mu0_4(int[1000]) = Uninitialized : r0_3
# 962| mu0_4(int[1000]) = Uninitialized[a1] : r0_3
# 962| r0_5(int) = Constant[0] :
# 962| r0_6(glval<int>) = PointerAdd : r0_3, r0_5
# 962| r0_7(unknown[8]) = Constant[0] :
@@ -4420,3 +4420,96 @@ ir.cpp:
# 1005| v6_12(void) = ReturnValue : r6_11, mu0_2
# 1005| v6_13(void) = UnmodeledUse : mu*
# 1005| v6_14(void) = ExitFunction :
# 1021| UnreachableViaGoto() -> int
# 1021| Block 0
# 1021| v0_0(void) = EnterFunction :
# 1021| mu0_1(unknown) = AliasedDefinition :
# 1021| mu0_2(unknown) = UnmodeledDefinition :
# 1022| v0_3(void) = NoOp :
# 1024| v0_4(void) = NoOp :
# 1025| r0_5(glval<int>) = VariableAddress[#return] :
# 1025| r0_6(int) = Constant[0] :
# 1025| mu0_7(int) = Store : r0_5, r0_6
#-----| Goto -> Block 1
# 1021| Block 1
# 1021| r1_0(glval<int>) = VariableAddress[#return] :
# 1021| v1_1(void) = ReturnValue : r1_0, mu0_2
# 1021| v1_2(void) = UnmodeledUse : mu*
# 1021| v1_3(void) = ExitFunction :
# 1023| Block 2
# 1023| r2_0(glval<int>) = VariableAddress[#return] :
# 1023| r2_1(int) = Constant[1] :
# 1023| mu2_2(int) = Store : r2_0, r2_1
#-----| Goto -> Block 1
# 1028| UnreachableIf(bool) -> int
# 1028| Block 0
# 1028| v0_0(void) = EnterFunction :
# 1028| mu0_1(unknown) = AliasedDefinition :
# 1028| mu0_2(unknown) = UnmodeledDefinition :
# 1028| r0_3(glval<bool>) = VariableAddress[b] :
# 1028| mu0_4(bool) = InitializeParameter[b] : r0_3
# 1029| r0_5(glval<int>) = VariableAddress[x] :
# 1029| r0_6(int) = Constant[5] :
# 1029| mu0_7(int) = Store : r0_5, r0_6
# 1030| r0_8(glval<int>) = VariableAddress[y] :
# 1030| r0_9(int) = Constant[10] :
# 1030| mu0_10(int) = Store : r0_8, r0_9
# 1031| r0_11(glval<bool>) = VariableAddress[b] :
# 1031| r0_12(bool) = Load : r0_11, mu0_2
# 1031| v0_13(void) = ConditionalBranch : r0_12
#-----| False -> Block 5
#-----| True -> Block 2
# 1028| Block 1
# 1028| r1_0(glval<int>) = VariableAddress[#return] :
# 1028| v1_1(void) = ReturnValue : r1_0, mu0_2
# 1028| v1_2(void) = UnmodeledUse : mu*
# 1028| v1_3(void) = ExitFunction :
# 1032| Block 2
# 1032| r2_0(glval<int>) = VariableAddress[x] :
# 1032| r2_1(int) = Load : r2_0, mu0_2
# 1032| r2_2(glval<int>) = VariableAddress[y] :
# 1032| r2_3(int) = Load : r2_2, mu0_2
# 1032| r2_4(bool) = CompareEQ : r2_1, r2_3
# 1032| v2_5(void) = ConditionalBranch : r2_4
#-----| False -> Block 4
#-----| True -> Block 3
# 1033| Block 3
# 1033| r3_0(glval<int>) = VariableAddress[#return] :
# 1033| r3_1(int) = Constant[1] :
# 1033| mu3_2(int) = Store : r3_0, r3_1
#-----| Goto -> Block 1
# 1036| Block 4
# 1036| r4_0(glval<int>) = VariableAddress[#return] :
# 1036| r4_1(int) = Constant[0] :
# 1036| mu4_2(int) = Store : r4_0, r4_1
#-----| Goto -> Block 1
# 1040| Block 5
# 1040| r5_0(glval<int>) = VariableAddress[x] :
# 1040| r5_1(int) = Load : r5_0, mu0_2
# 1040| r5_2(glval<int>) = VariableAddress[y] :
# 1040| r5_3(int) = Load : r5_2, mu0_2
# 1040| r5_4(bool) = CompareLT : r5_1, r5_3
# 1040| v5_5(void) = ConditionalBranch : r5_4
#-----| False -> Block 7
#-----| True -> Block 6
# 1041| Block 6
# 1041| r6_0(glval<int>) = VariableAddress[#return] :
# 1041| r6_1(int) = Constant[0] :
# 1041| mu6_2(int) = Store : r6_0, r6_1
#-----| Goto -> Block 1
# 1044| Block 7
# 1044| r7_0(glval<int>) = VariableAddress[#return] :
# 1044| r7_1(int) = Constant[1] :
# 1044| mu7_2(int) = Store : r7_0, r7_1
#-----| Goto -> Block 1

View File

@@ -22,7 +22,7 @@
| IR: Conditional | 4 |
| IR: Conditional_LValue | 4 |
| IR: Conditional_Void | 4 |
| IR: ConstantConditions | 4 |
| IR: ConstantConditions | 3 |
| IR: Constants | 1 |
| IR: Continue | 6 |
| IR: DeclareObject | 1 |
@@ -45,12 +45,12 @@
| IR: For_ConditionUpdate | 4 |
| IR: For_Continue_NoUpdate | 6 |
| IR: For_Continue_Update | 6 |
| IR: For_Empty | 3 |
| IR: For_Init | 3 |
| IR: For_Empty | 2 |
| IR: For_Init | 2 |
| IR: For_InitCondition | 4 |
| IR: For_InitConditionUpdate | 4 |
| IR: For_InitUpdate | 3 |
| IR: For_Update | 3 |
| IR: For_InitUpdate | 2 |
| IR: For_Update | 2 |
| IR: Func | 1 |
| IR: FuncPtrConversions | 1 |
| IR: FunctionReferences | 1 |
@@ -88,11 +88,13 @@
| IR: StaticMemberFunction | 1 |
| IR: String | 1 |
| IR: StringLiteral | 1 |
| IR: Switch | 10 |
| IR: Switch | 8 |
| IR: TakeReference | 1 |
| IR: TryCatch | 15 |
| IR: TryCatch | 13 |
| IR: UninitializedVariables | 1 |
| IR: UnionInit | 1 |
| IR: UnreachableIf | 8 |
| IR: UnreachableViaGoto | 1 |
| IR: VarArgUsage | 1 |
| IR: VarArgs | 1 |
| IR: VirtualMemberFunction | 1 |

View File

@@ -5,7 +5,7 @@ bad_asts.cpp:
# 14| mu0_1(unknown) = AliasedDefinition :
# 14| mu0_2(unknown) = UnmodeledDefinition :
# 15| r0_3(glval<S>) = VariableAddress[s] :
# 15| mu0_4(S) = Uninitialized : r0_3
# 15| mu0_4(S) = Uninitialized[s] : r0_3
# 15| r0_5(glval<int>) = FieldAddress[x] : r0_3
# 15| r0_6(int) = Constant[0] :
# 15| mu0_7(int) = Store : r0_5, r0_6
@@ -186,7 +186,7 @@ ir.cpp:
# 50| r0_5(glval<int>) = VariableAddress[y] :
# 50| m0_6(int) = InitializeParameter[y] : r0_5
# 51| r0_7(glval<int>) = VariableAddress[z] :
# 51| m0_8(int) = Uninitialized : r0_7
# 51| m0_8(int) = Uninitialized[z] : r0_7
# 53| r0_9(glval<int>) = VariableAddress[x] :
# 53| r0_10(int) = Load : r0_9, m0_4
# 53| r0_11(glval<int>) = VariableAddress[y] :
@@ -359,7 +359,7 @@ ir.cpp:
# 87| r0_5(glval<int>) = VariableAddress[y] :
# 87| m0_6(int) = InitializeParameter[y] : r0_5
# 88| r0_7(glval<bool>) = VariableAddress[b] :
# 88| m0_8(bool) = Uninitialized : r0_7
# 88| m0_8(bool) = Uninitialized[b] : r0_7
# 90| r0_9(glval<int>) = VariableAddress[x] :
# 90| r0_10(int) = Load : r0_9, m0_4
# 90| r0_11(glval<int>) = VariableAddress[y] :
@@ -415,7 +415,7 @@ ir.cpp:
# 98| r0_3(glval<int>) = VariableAddress[x] :
# 98| m0_4(int) = InitializeParameter[x] : r0_3
# 99| r0_5(glval<int>) = VariableAddress[y] :
# 99| m0_6(int) = Uninitialized : r0_5
# 99| m0_6(int) = Uninitialized[y] : r0_5
# 101| r0_7(glval<int>) = VariableAddress[x] :
# 101| r0_8(int) = Load : r0_7, m0_4
# 101| r0_9(int) = Constant[1] :
@@ -457,7 +457,7 @@ ir.cpp:
# 107| r0_3(glval<int>) = VariableAddress[x] :
# 107| mu0_4(int) = InitializeParameter[x] : r0_3
# 108| r0_5(glval<int *>) = VariableAddress[p] :
# 108| m0_6(int *) = Uninitialized : r0_5
# 108| m0_6(int *) = Uninitialized[p] : r0_5
# 110| r0_7(glval<int>) = VariableAddress[x] :
# 110| r0_8(int) = Load : r0_7, mu0_2
# 110| r0_9(int) = Constant[1] :
@@ -487,7 +487,7 @@ ir.cpp:
# 114| r0_5(glval<double>) = VariableAddress[y] :
# 114| m0_6(double) = InitializeParameter[y] : r0_5
# 115| r0_7(glval<double>) = VariableAddress[z] :
# 115| m0_8(double) = Uninitialized : r0_7
# 115| m0_8(double) = Uninitialized[z] : r0_7
# 117| r0_9(glval<double>) = VariableAddress[x] :
# 117| r0_10(double) = Load : r0_9, m0_4
# 117| r0_11(glval<double>) = VariableAddress[y] :
@@ -569,7 +569,7 @@ ir.cpp:
# 133| r0_5(glval<double>) = VariableAddress[y] :
# 133| m0_6(double) = InitializeParameter[y] : r0_5
# 134| r0_7(glval<bool>) = VariableAddress[b] :
# 134| m0_8(bool) = Uninitialized : r0_7
# 134| m0_8(bool) = Uninitialized[b] : r0_7
# 136| r0_9(glval<double>) = VariableAddress[x] :
# 136| r0_10(double) = Load : r0_9, m0_4
# 136| r0_11(glval<double>) = VariableAddress[y] :
@@ -625,7 +625,7 @@ ir.cpp:
# 144| r0_3(glval<float>) = VariableAddress[x] :
# 144| m0_4(float) = InitializeParameter[x] : r0_3
# 145| r0_5(glval<float>) = VariableAddress[y] :
# 145| m0_6(float) = Uninitialized : r0_5
# 145| m0_6(float) = Uninitialized[y] : r0_5
# 147| r0_7(glval<float>) = VariableAddress[x] :
# 147| r0_8(float) = Load : r0_7, m0_4
# 147| r0_9(float) = Constant[1.0] :
@@ -669,9 +669,9 @@ ir.cpp:
# 153| r0_5(glval<int>) = VariableAddress[i] :
# 153| m0_6(int) = InitializeParameter[i] : r0_5
# 154| r0_7(glval<int *>) = VariableAddress[q] :
# 154| m0_8(int *) = Uninitialized : r0_7
# 154| m0_8(int *) = Uninitialized[q] : r0_7
# 155| r0_9(glval<bool>) = VariableAddress[b] :
# 155| m0_10(bool) = Uninitialized : r0_9
# 155| m0_10(bool) = Uninitialized[b] : r0_9
# 157| r0_11(glval<int *>) = VariableAddress[p] :
# 157| r0_12(int *) = Load : r0_11, m0_4
# 157| r0_13(glval<int>) = VariableAddress[i] :
@@ -745,7 +745,7 @@ ir.cpp:
# 171| r0_5(glval<int>) = VariableAddress[i] :
# 171| m0_6(int) = InitializeParameter[i] : r0_5
# 172| r0_7(glval<int>) = VariableAddress[x] :
# 172| m0_8(int) = Uninitialized : r0_7
# 172| m0_8(int) = Uninitialized[x] : r0_7
# 174| r0_9(glval<int *>) = VariableAddress[p] :
# 174| r0_10(int *) = Load : r0_9, m0_4
# 174| r0_11(glval<int>) = VariableAddress[i] :
@@ -779,7 +779,7 @@ ir.cpp:
# 178| r0_39(int *) = PointerAdd[4] : r0_36, r0_38
# 178| mu0_40(int) = Store : r0_39, r0_34
# 180| r0_41(glval<int[10]>) = VariableAddress[a] :
# 180| m0_42(int[10]) = Uninitialized : r0_41
# 180| m0_42(int[10]) = Uninitialized[a] : r0_41
# 181| r0_43(glval<int[10]>) = VariableAddress[a] :
# 181| r0_44(int *) = Convert : r0_43
# 181| r0_45(glval<int>) = VariableAddress[i] :
@@ -860,7 +860,7 @@ ir.cpp:
# 193| r0_5(glval<int *>) = VariableAddress[q] :
# 193| m0_6(int *) = InitializeParameter[q] : r0_5
# 194| r0_7(glval<bool>) = VariableAddress[b] :
# 194| m0_8(bool) = Uninitialized : r0_7
# 194| m0_8(bool) = Uninitialized[b] : r0_7
# 196| r0_9(glval<int *>) = VariableAddress[p] :
# 196| r0_10(int *) = Load : r0_9, m0_4
# 196| r0_11(glval<int *>) = VariableAddress[q] :
@@ -916,7 +916,7 @@ ir.cpp:
# 204| r0_3(glval<int *>) = VariableAddress[p] :
# 204| m0_4(int *) = InitializeParameter[p] : r0_3
# 205| r0_5(glval<int *>) = VariableAddress[q] :
# 205| m0_6(int *) = Uninitialized : r0_5
# 205| m0_6(int *) = Uninitialized[q] : r0_5
# 207| r0_7(glval<int *>) = VariableAddress[p] :
# 207| r0_8(int *) = Load : r0_7, m0_4
# 207| r0_9(int) = Constant[1] :
@@ -1000,7 +1000,7 @@ ir.cpp:
# 230| mu0_1(unknown) = AliasedDefinition :
# 230| mu0_2(unknown) = UnmodeledDefinition :
# 231| r0_3(glval<int>) = VariableAddress[x] :
# 231| m0_4(int) = Uninitialized : r0_3
# 231| m0_4(int) = Uninitialized[x] : r0_3
# 232| r0_5(glval<int>) = VariableAddress[y] :
# 232| r0_6(glval<int>) = VariableAddress[x] :
# 232| r0_7(int) = Load : r0_6, m0_4
@@ -1163,17 +1163,12 @@ ir.cpp:
# 265| mu0_1(unknown) = AliasedDefinition :
# 265| mu0_2(unknown) = UnmodeledDefinition :
# 266| r0_3(glval<int>) = VariableAddress[j] :
# 266| m0_4(int) = Uninitialized : r0_3
#-----| Goto -> Block 2
# 266| m0_4(int) = Uninitialized[j] : r0_3
#-----| Goto -> Block 1
# 265| Block 1
# 265| v1_0(void) = ReturnVoid :
# 265| v1_1(void) = UnmodeledUse : mu*
# 265| v1_2(void) = ExitFunction :
# 268| Block 2
# 268| v2_0(void) = NoOp :
#-----| Goto -> Block 2
# 268| Block 1
# 268| v1_0(void) = NoOp :
#-----| Goto -> Block 1
# 272| For_Init() -> void
# 272| Block 0
@@ -1183,16 +1178,11 @@ ir.cpp:
# 273| r0_3(glval<int>) = VariableAddress[i] :
# 273| r0_4(int) = Constant[0] :
# 273| m0_5(int) = Store : r0_3, r0_4
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 272| Block 1
# 272| v1_0(void) = ReturnVoid :
# 272| v1_1(void) = UnmodeledUse : mu*
# 272| v1_2(void) = ExitFunction :
# 274| Block 2
# 274| v2_0(void) = NoOp :
#-----| Goto -> Block 2
# 274| Block 1
# 274| v1_0(void) = NoOp :
#-----| Goto -> Block 1
# 278| For_Condition() -> void
# 278| Block 0
@@ -1231,22 +1221,17 @@ ir.cpp:
# 286| r0_3(glval<int>) = VariableAddress[i] :
# 286| r0_4(int) = Constant[0] :
# 286| m0_5(int) = Store : r0_3, r0_4
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 285| Block 1
# 285| v1_0(void) = ReturnVoid :
# 285| v1_1(void) = UnmodeledUse : mu*
# 285| v1_2(void) = ExitFunction :
# 288| Block 2
# 288| m2_0(int) = Phi : from 0:m0_5, from 2:m2_6
# 288| v2_1(void) = NoOp :
# 287| r2_2(int) = Constant[1] :
# 287| r2_3(glval<int>) = VariableAddress[i] :
# 287| r2_4(int) = Load : r2_3, m2_0
# 287| r2_5(int) = Add : r2_4, r2_2
# 287| m2_6(int) = Store : r2_3, r2_5
#-----| Goto -> Block 2
# 288| Block 1
# 288| m1_0(int) = Phi : from 0:m0_5, from 1:m1_6
# 288| v1_1(void) = NoOp :
# 287| r1_2(int) = Constant[1] :
# 287| r1_3(glval<int>) = VariableAddress[i] :
# 287| r1_4(int) = Load : r1_3, m1_0
# 287| r1_5(int) = Add : r1_4, r1_2
# 287| m1_6(int) = Store : r1_3, r1_5
#-----| Goto -> Block 1
# 292| For_InitCondition() -> void
# 292| Block 0
@@ -1285,22 +1270,17 @@ ir.cpp:
# 299| r0_3(glval<int>) = VariableAddress[i] :
# 299| r0_4(int) = Constant[0] :
# 299| m0_5(int) = Store : r0_3, r0_4
#-----| Goto -> Block 2
#-----| Goto -> Block 1
# 298| Block 1
# 298| v1_0(void) = ReturnVoid :
# 298| v1_1(void) = UnmodeledUse : mu*
# 298| v1_2(void) = ExitFunction :
# 300| Block 2
# 300| m2_0(int) = Phi : from 0:m0_5, from 2:m2_6
# 300| v2_1(void) = NoOp :
# 299| r2_2(int) = Constant[1] :
# 299| r2_3(glval<int>) = VariableAddress[i] :
# 299| r2_4(int) = Load : r2_3, m2_0
# 299| r2_5(int) = Add : r2_4, r2_2
# 299| m2_6(int) = Store : r2_3, r2_5
#-----| Goto -> Block 2
# 300| Block 1
# 300| m1_0(int) = Phi : from 0:m0_5, from 1:m1_6
# 300| v1_1(void) = NoOp :
# 299| r1_2(int) = Constant[1] :
# 299| r1_3(glval<int>) = VariableAddress[i] :
# 299| r1_4(int) = Load : r1_3, m1_0
# 299| r1_5(int) = Add : r1_4, r1_2
# 299| m1_6(int) = Store : r1_3, r1_5
#-----| Goto -> Block 1
# 304| For_ConditionUpdate() -> void
# 304| Block 0
@@ -1709,78 +1689,66 @@ ir.cpp:
# 384| r0_3(glval<int>) = VariableAddress[x] :
# 384| m0_4(int) = InitializeParameter[x] : r0_3
# 385| r0_5(glval<int>) = VariableAddress[y] :
# 385| m0_6(int) = Uninitialized : r0_5
# 385| m0_6(int) = Uninitialized[y] : r0_5
# 386| r0_7(glval<int>) = VariableAddress[x] :
# 386| r0_8(int) = Load : r0_7, m0_4
# 386| v0_9(void) = Switch : r0_8
#-----| Case[-1] -> Block 2
#-----| Case[1] -> Block 3
#-----| Case[2] -> Block 4
#-----| Case[3] -> Block 5
#-----| Case[4] -> Block 6
#-----| Default -> Block 7
#-----| Case[-1] -> Block 1
#-----| Case[1] -> Block 2
#-----| Case[2] -> Block 3
#-----| Case[3] -> Block 4
#-----| Case[4] -> Block 5
#-----| Default -> Block 6
# 387| Block 1
# 387| r1_0(int) = Constant[1234] :
# 387| r1_1(glval<int>) = VariableAddress[y] :
# 387| m1_2(int) = Store : r1_1, r1_0
#-----| Goto -> Block 2
# 389| Block 1
# 389| v1_0(void) = NoOp :
# 390| r1_1(int) = Constant[-1] :
# 390| r1_2(glval<int>) = VariableAddress[y] :
# 390| m1_3(int) = Store : r1_2, r1_1
# 391| v1_4(void) = NoOp :
#-----| Goto -> Block 7
# 389| Block 2
# 389| v2_0(void) = NoOp :
# 390| r2_1(int) = Constant[-1] :
# 390| r2_2(glval<int>) = VariableAddress[y] :
# 390| m2_3(int) = Store : r2_2, r2_1
# 391| v2_4(void) = NoOp :
#-----| Goto -> Block 9
# 393| Block 2
# 393| v2_0(void) = NoOp :
#-----| Goto -> Block 3
# 393| Block 3
# 393| v3_0(void) = NoOp :
#-----| Goto -> Block 4
# 394| Block 3
# 394| v3_0(void) = NoOp :
# 395| r3_1(int) = Constant[1] :
# 395| r3_2(glval<int>) = VariableAddress[y] :
# 395| m3_3(int) = Store : r3_2, r3_1
# 396| v3_4(void) = NoOp :
#-----| Goto -> Block 7
# 394| Block 4
# 394| v4_0(void) = NoOp :
# 395| r4_1(int) = Constant[1] :
# 395| r4_2(glval<int>) = VariableAddress[y] :
# 395| m4_3(int) = Store : r4_2, r4_1
# 396| v4_4(void) = NoOp :
#-----| Goto -> Block 9
# 398| Block 4
# 398| v4_0(void) = NoOp :
# 399| r4_1(int) = Constant[3] :
# 399| r4_2(glval<int>) = VariableAddress[y] :
# 399| m4_3(int) = Store : r4_2, r4_1
#-----| Goto -> Block 5
# 398| Block 5
# 398| v5_0(void) = NoOp :
# 399| r5_1(int) = Constant[3] :
# 399| r5_2(glval<int>) = VariableAddress[y] :
# 399| m5_3(int) = Store : r5_2, r5_1
#-----| Goto -> Block 6
# 400| Block 5
# 400| v5_0(void) = NoOp :
# 401| r5_1(int) = Constant[4] :
# 401| r5_2(glval<int>) = VariableAddress[y] :
# 401| m5_3(int) = Store : r5_2, r5_1
# 402| v5_4(void) = NoOp :
#-----| Goto -> Block 7
# 400| Block 6
# 400| v6_0(void) = NoOp :
# 401| r6_1(int) = Constant[4] :
# 401| r6_2(glval<int>) = VariableAddress[y] :
# 401| m6_3(int) = Store : r6_2, r6_1
# 402| v6_4(void) = NoOp :
#-----| Goto -> Block 9
# 404| Block 6
# 404| v6_0(void) = NoOp :
# 405| r6_1(int) = Constant[0] :
# 405| r6_2(glval<int>) = VariableAddress[y] :
# 405| m6_3(int) = Store : r6_2, r6_1
# 406| v6_4(void) = NoOp :
#-----| Goto -> Block 7
# 404| Block 7
# 404| v7_0(void) = NoOp :
# 405| r7_1(int) = Constant[0] :
# 405| r7_2(glval<int>) = VariableAddress[y] :
# 405| m7_3(int) = Store : r7_2, r7_1
# 406| v7_4(void) = NoOp :
#-----| Goto -> Block 9
# 408| Block 8
# 408| r8_0(int) = Constant[5678] :
# 408| r8_1(glval<int>) = VariableAddress[y] :
# 408| m8_2(int) = Store : r8_1, r8_0
#-----| Goto -> Block 9
# 409| Block 9
# 409| v9_0(void) = NoOp :
# 410| v9_1(void) = NoOp :
# 384| v9_2(void) = ReturnVoid :
# 384| v9_3(void) = UnmodeledUse : mu*
# 384| v9_4(void) = ExitFunction :
# 409| Block 7
# 409| v7_0(void) = NoOp :
# 410| v7_1(void) = NoOp :
# 384| v7_2(void) = ReturnVoid :
# 384| v7_3(void) = UnmodeledUse : mu*
# 384| v7_4(void) = ExitFunction :
# 422| ReturnStruct(Point) -> Point
# 422| Block 0
@@ -1804,7 +1772,7 @@ ir.cpp:
# 426| mu0_1(unknown) = AliasedDefinition :
# 426| mu0_2(unknown) = UnmodeledDefinition :
# 427| r0_3(glval<Point>) = VariableAddress[pt] :
# 427| mu0_4(Point) = Uninitialized : r0_3
# 427| mu0_4(Point) = Uninitialized[pt] : r0_3
# 428| r0_5(int) = Constant[5] :
# 428| r0_6(glval<Point>) = VariableAddress[pt] :
# 428| r0_7(glval<int>) = FieldAddress[x] : r0_6
@@ -1834,7 +1802,7 @@ ir.cpp:
# 433| r0_5(glval<bool>) = VariableAddress[b] :
# 433| m0_6(bool) = InitializeParameter[b] : r0_5
# 434| r0_7(glval<int>) = VariableAddress[x] :
# 434| m0_8(int) = Uninitialized : r0_7
# 434| m0_8(int) = Uninitialized[x] : r0_7
# 435| r0_9(glval<bool>) = VariableAddress[a] :
# 435| r0_10(bool) = Load : r0_9, m0_4
# 435| v0_11(void) = ConditionalBranch : r0_10
@@ -1896,7 +1864,7 @@ ir.cpp:
# 447| r0_5(glval<bool>) = VariableAddress[b] :
# 447| m0_6(bool) = InitializeParameter[b] : r0_5
# 448| r0_7(glval<int>) = VariableAddress[x] :
# 448| m0_8(int) = Uninitialized : r0_7
# 448| m0_8(int) = Uninitialized[x] : r0_7
# 449| r0_9(glval<bool>) = VariableAddress[a] :
# 449| r0_10(bool) = Load : r0_9, m0_4
# 449| v0_11(void) = ConditionalBranch : r0_10
@@ -1958,7 +1926,7 @@ ir.cpp:
# 461| r0_5(glval<bool>) = VariableAddress[b] :
# 461| m0_6(bool) = InitializeParameter[b] : r0_5
# 462| r0_7(glval<int>) = VariableAddress[x] :
# 462| m0_8(int) = Uninitialized : r0_7
# 462| m0_8(int) = Uninitialized[x] : r0_7
# 463| r0_9(glval<bool>) = VariableAddress[a] :
# 463| r0_10(bool) = Load : r0_9, m0_4
# 463| v0_11(void) = ConditionalBranch : r0_10
@@ -2013,7 +1981,7 @@ ir.cpp:
# 475| r0_5(glval<bool>) = VariableAddress[b] :
# 475| m0_6(bool) = InitializeParameter[b] : r0_5
# 476| r0_7(glval<bool>) = VariableAddress[x] :
# 476| m0_8(bool) = Uninitialized : r0_7
# 476| m0_8(bool) = Uninitialized[x] : r0_7
# 477| r0_9(glval<bool>) = VariableAddress[a] :
# 477| r0_10(bool) = Load : r0_9, m0_4
# 477| v0_11(void) = ConditionalBranch : r0_10
@@ -2163,9 +2131,9 @@ ir.cpp:
# 486| r0_3(glval<bool>) = VariableAddress[a] :
# 486| m0_4(bool) = InitializeParameter[a] : r0_3
# 487| r0_5(glval<int>) = VariableAddress[x] :
# 487| mu0_6(int) = Uninitialized : r0_5
# 487| mu0_6(int) = Uninitialized[x] : r0_5
# 488| r0_7(glval<int>) = VariableAddress[y] :
# 488| mu0_8(int) = Uninitialized : r0_7
# 488| mu0_8(int) = Uninitialized[y] : r0_7
# 489| r0_9(int) = Constant[5] :
# 489| r0_10(glval<bool>) = VariableAddress[a] :
# 489| r0_11(bool) = Load : r0_10, m0_4
@@ -2258,7 +2226,7 @@ ir.cpp:
# 503| r0_5(glval<float>) = VariableAddress[f] :
# 503| m0_6(float) = InitializeParameter[f] : r0_5
# 504| r0_7(glval<Point>) = VariableAddress[pt1] :
# 504| m0_8(Point) = Uninitialized : r0_7
# 504| m0_8(Point) = Uninitialized[pt1] : r0_7
# 504| r0_9(glval<int>) = FieldAddress[x] : r0_7
# 504| r0_10(glval<int>) = VariableAddress[x] :
# 504| r0_11(int) = Load : r0_10, m0_4
@@ -2269,7 +2237,7 @@ ir.cpp:
# 504| r0_16(int) = Convert : r0_15
# 504| mu0_17(int) = Store : r0_13, r0_16
# 505| r0_18(glval<Point>) = VariableAddress[pt2] :
# 505| m0_19(Point) = Uninitialized : r0_18
# 505| m0_19(Point) = Uninitialized[pt2] : r0_18
# 505| r0_20(glval<int>) = FieldAddress[x] : r0_18
# 505| r0_21(glval<int>) = VariableAddress[x] :
# 505| r0_22(int) = Load : r0_21, m0_4
@@ -2278,7 +2246,7 @@ ir.cpp:
# 505| r0_25(int) = Constant[0] :
# 505| mu0_26(int) = Store : r0_24, r0_25
# 506| r0_27(glval<Point>) = VariableAddress[pt3] :
# 506| m0_28(Point) = Uninitialized : r0_27
# 506| m0_28(Point) = Uninitialized[pt3] : r0_27
# 506| r0_29(glval<int>) = FieldAddress[x] : r0_27
# 506| r0_30(int) = Constant[0] :
# 506| m0_31(int) = Store : r0_29, r0_30
@@ -2306,7 +2274,7 @@ ir.cpp:
# 512| r0_5(glval<float>) = VariableAddress[f] :
# 512| m0_6(float) = InitializeParameter[f] : r0_5
# 513| r0_7(glval<Rect>) = VariableAddress[r1] :
# 513| m0_8(Rect) = Uninitialized : r0_7
# 513| m0_8(Rect) = Uninitialized[r1] : r0_7
# 513| r0_9(glval<Point>) = FieldAddress[topLeft] : r0_7
# 513| r0_10(Point) = Constant[0] :
# 513| m0_11(Point) = Store : r0_9, r0_10
@@ -2314,7 +2282,7 @@ ir.cpp:
# 513| r0_13(Point) = Constant[0] :
# 513| mu0_14(Point) = Store : r0_12, r0_13
# 514| r0_15(glval<Rect>) = VariableAddress[r2] :
# 514| m0_16(Rect) = Uninitialized : r0_15
# 514| m0_16(Rect) = Uninitialized[r2] : r0_15
# 514| r0_17(glval<Point>) = FieldAddress[topLeft] : r0_15
# 514| r0_18(glval<int>) = FieldAddress[x] : r0_17
# 514| r0_19(glval<int>) = VariableAddress[x] :
@@ -2329,7 +2297,7 @@ ir.cpp:
# 514| r0_28(Point) = Constant[0] :
# 514| mu0_29(Point) = Store : r0_27, r0_28
# 515| r0_30(glval<Rect>) = VariableAddress[r3] :
# 515| m0_31(Rect) = Uninitialized : r0_30
# 515| m0_31(Rect) = Uninitialized[r3] : r0_30
# 515| r0_32(glval<Point>) = FieldAddress[topLeft] : r0_30
# 515| r0_33(glval<int>) = FieldAddress[x] : r0_32
# 515| r0_34(glval<int>) = VariableAddress[x] :
@@ -2351,7 +2319,7 @@ ir.cpp:
# 515| r0_50(int) = Convert : r0_49
# 515| mu0_51(int) = Store : r0_47, r0_50
# 516| r0_52(glval<Rect>) = VariableAddress[r4] :
# 516| m0_53(Rect) = Uninitialized : r0_52
# 516| m0_53(Rect) = Uninitialized[r4] : r0_52
# 516| r0_54(glval<Point>) = FieldAddress[topLeft] : r0_52
# 516| r0_55(glval<int>) = FieldAddress[x] : r0_54
# 516| r0_56(glval<int>) = VariableAddress[x] :
@@ -2383,13 +2351,13 @@ ir.cpp:
# 519| r0_5(glval<float>) = VariableAddress[f] :
# 519| m0_6(float) = InitializeParameter[f] : r0_5
# 520| r0_7(glval<int[3]>) = VariableAddress[a1] :
# 520| mu0_8(int[3]) = Uninitialized : r0_7
# 520| mu0_8(int[3]) = Uninitialized[a1] : r0_7
# 520| r0_9(int) = Constant[0] :
# 520| r0_10(glval<int>) = PointerAdd : r0_7, r0_9
# 520| r0_11(unknown[12]) = Constant[0] :
# 520| mu0_12(unknown[12]) = Store : r0_10, r0_11
# 521| r0_13(glval<int[3]>) = VariableAddress[a2] :
# 521| mu0_14(int[3]) = Uninitialized : r0_13
# 521| mu0_14(int[3]) = Uninitialized[a2] : r0_13
# 521| r0_15(int) = Constant[0] :
# 521| r0_16(glval<int>) = PointerAdd : r0_13, r0_15
# 521| r0_17(glval<int>) = VariableAddress[x] :
@@ -2406,7 +2374,7 @@ ir.cpp:
# 521| r0_28(int) = Constant[0] :
# 521| mu0_29(int) = Store : r0_27, r0_28
# 522| r0_30(glval<int[3]>) = VariableAddress[a3] :
# 522| mu0_31(int[3]) = Uninitialized : r0_30
# 522| mu0_31(int[3]) = Uninitialized[a3] : r0_30
# 522| r0_32(int) = Constant[0] :
# 522| r0_33(glval<int>) = PointerAdd : r0_30, r0_32
# 522| r0_34(glval<int>) = VariableAddress[x] :
@@ -2431,7 +2399,7 @@ ir.cpp:
# 530| r0_5(glval<float>) = VariableAddress[f] :
# 530| m0_6(float) = InitializeParameter[f] : r0_5
# 531| r0_7(glval<U>) = VariableAddress[u1] :
# 531| m0_8(U) = Uninitialized : r0_7
# 531| m0_8(U) = Uninitialized[u1] : r0_7
# 531| r0_9(glval<double>) = FieldAddress[d] : r0_7
# 531| r0_10(glval<float>) = VariableAddress[f] :
# 531| r0_11(float) = Load : r0_10, m0_6
@@ -2603,15 +2571,15 @@ ir.cpp:
# 574| r0_17(char[5]) = Load : r0_16, mu0_2
# 574| m0_18(char[5]) = Store : r0_15, r0_17
# 575| r0_19(glval<char[2]>) = VariableAddress[b] :
# 575| m0_20(char[2]) = Uninitialized : r0_19
# 575| m0_20(char[2]) = Uninitialized[b] : r0_19
# 576| r0_21(glval<char[2]>) = VariableAddress[c] :
# 576| mu0_22(char[2]) = Uninitialized : r0_21
# 576| mu0_22(char[2]) = Uninitialized[c] : r0_21
# 576| r0_23(int) = Constant[0] :
# 576| r0_24(glval<char>) = PointerAdd : r0_21, r0_23
# 576| r0_25(unknown[2]) = Constant[0] :
# 576| mu0_26(unknown[2]) = Store : r0_24, r0_25
# 577| r0_27(glval<char[2]>) = VariableAddress[d] :
# 577| mu0_28(char[2]) = Uninitialized : r0_27
# 577| mu0_28(char[2]) = Uninitialized[d] : r0_27
# 577| r0_29(int) = Constant[0] :
# 577| r0_30(glval<char>) = PointerAdd : r0_27, r0_29
# 577| r0_31(char) = Constant[0] :
@@ -2621,7 +2589,7 @@ ir.cpp:
# 577| r0_35(char) = Constant[0] :
# 577| mu0_36(char) = Store : r0_34, r0_35
# 578| r0_37(glval<char[2]>) = VariableAddress[e] :
# 578| mu0_38(char[2]) = Uninitialized : r0_37
# 578| mu0_38(char[2]) = Uninitialized[e] : r0_37
# 578| r0_39(int) = Constant[0] :
# 578| r0_40(glval<char>) = PointerAdd : r0_37, r0_39
# 578| r0_41(char) = Constant[0] :
@@ -2631,7 +2599,7 @@ ir.cpp:
# 578| r0_45(char) = Constant[1] :
# 578| mu0_46(char) = Store : r0_44, r0_45
# 579| r0_47(glval<char[3]>) = VariableAddress[f] :
# 579| mu0_48(char[3]) = Uninitialized : r0_47
# 579| mu0_48(char[3]) = Uninitialized[f] : r0_47
# 579| r0_49(int) = Constant[0] :
# 579| r0_50(glval<char>) = PointerAdd : r0_47, r0_49
# 579| r0_51(char) = Constant[0] :
@@ -2818,7 +2786,7 @@ ir.cpp:
# 645| r0_14(glval<int>) = FieldAddress[m_a] : r0_13
# 645| mu0_15(int) = Store : r0_14, r0_12
# 646| r0_16(glval<int>) = VariableAddress[x] :
# 646| m0_17(int) = Uninitialized : r0_16
# 646| m0_17(int) = Uninitialized[x] : r0_16
# 647| r0_18(C *) = CopyValue : r0_3
# 647| r0_19(glval<int>) = FieldAddress[m_a] : r0_18
# 647| r0_20(int) = Load : r0_19, mu0_2
@@ -2956,7 +2924,7 @@ ir.cpp:
# 691| mu0_1(unknown) = AliasedDefinition :
# 691| mu0_2(unknown) = UnmodeledDefinition :
# 692| r0_3(glval<int[10]>) = VariableAddress[a] :
# 692| mu0_4(int[10]) = Uninitialized : r0_3
# 692| mu0_4(int[10]) = Uninitialized[a] : r0_3
# 693| r0_5(glval<int(&)[10]>) = VariableAddress[ra] :
# 693| r0_6(glval<int[10]>) = VariableAddress[a] :
# 693| m0_7(int(&)[10]) = Store : r0_5, r0_6
@@ -3871,7 +3839,7 @@ ir.cpp:
# 871| mu0_1(unknown) = AliasedDefinition :
# 871| mu0_2(unknown) = UnmodeledDefinition :
# 872| r0_3(glval<char[5]>) = VariableAddress[a] :
# 872| mu0_4(char[5]) = Uninitialized : r0_3
# 872| mu0_4(char[5]) = Uninitialized[a] : r0_3
# 873| r0_5(glval<char *>) = VariableAddress[p] :
# 873| r0_6(glval<char[5]>) = VariableAddress[a] :
# 873| r0_7(char *) = Convert : r0_6
@@ -3944,13 +3912,13 @@ ir.cpp:
# 888| r0_3(glval<int>) = VariableAddress[x] :
# 888| mu0_4(int) = InitializeParameter[x] : r0_3
# 889| r0_5(glval<__va_list_tag[1]>) = VariableAddress[args] :
# 889| mu0_6(__va_list_tag[1]) = Uninitialized : r0_5
# 889| mu0_6(__va_list_tag[1]) = Uninitialized[args] : r0_5
# 891| r0_7(glval<__va_list_tag[1]>) = VariableAddress[args] :
# 891| r0_8(__va_list_tag *) = Convert : r0_7
# 891| r0_9(glval<int>) = VariableAddress[x] :
# 891| v0_10(void) = VarArgsStart : r0_8, r0_9
# 892| r0_11(glval<__va_list_tag[1]>) = VariableAddress[args2] :
# 892| mu0_12(__va_list_tag[1]) = Uninitialized : r0_11
# 892| mu0_12(__va_list_tag[1]) = Uninitialized[args2] : r0_11
# 893| r0_13(glval<__va_list_tag[1]>) = VariableAddress[args2] :
# 893| r0_14(__va_list_tag *) = Convert : r0_13
# 893| r0_15(glval<__va_list_tag[1]>) = VariableAddress[args] :
@@ -4007,32 +3975,24 @@ ir.cpp:
# 906| r0_8(glval<int>) = VariableAddress[b] :
# 906| r0_9(bool) = Constant[1] :
# 906| v0_10(void) = ConditionalBranch : r0_9
#-----| False -> Block 3
#-----| True -> Block 2
#-----| False -> Block 2
#-----| True -> Block 1
# 906| Block 1
# 906| m1_0(int) = Phi : from 2:m2_3, from 3:m3_3
# 906| r1_1(glval<int>) = VariableAddress[#temp906:11] :
# 906| r1_2(int) = Load : r1_1, m1_0
# 906| m1_3(int) = Store : r0_8, r1_2
# 907| v1_4(void) = NoOp :
# 904| v1_5(void) = ReturnVoid :
# 904| v1_6(void) = UnmodeledUse : mu*
# 904| v1_7(void) = ExitFunction :
# 906| r1_0(glval<int>) = VariableAddress[x] :
# 906| r1_1(int) = Load : r1_0, m0_4
# 906| r1_2(glval<int>) = VariableAddress[#temp906:11] :
# 906| m1_3(int) = Store : r1_2, r1_1
# 906| r1_4(glval<int>) = VariableAddress[#temp906:11] :
# 906| r1_5(int) = Load : r1_4, m1_3
# 906| m1_6(int) = Store : r0_8, r1_5
# 907| v1_7(void) = NoOp :
# 904| v1_8(void) = ReturnVoid :
# 904| v1_9(void) = UnmodeledUse : mu*
# 904| v1_10(void) = ExitFunction :
# 906| Block 2
# 906| r2_0(glval<int>) = VariableAddress[x] :
# 906| r2_1(int) = Load : r2_0, m0_4
# 906| r2_2(glval<int>) = VariableAddress[#temp906:11] :
# 906| m2_3(int) = Store : r2_2, r2_1
#-----| Goto -> Block 1
# 906| Block 3
# 906| r3_0(glval<int>) = VariableAddress[x] :
# 906| r3_1(int) = Load : r3_0, m0_4
# 906| r3_2(glval<int>) = VariableAddress[#temp906:11] :
# 906| m3_3(int) = Store : r3_2, r3_1
#-----| Goto -> Block 1
# 906| v2_0(void) = Unreached :
# 940| OperatorNew() -> void
# 940| Block 0
@@ -4182,7 +4142,7 @@ ir.cpp:
# 961| mu0_1(unknown) = AliasedDefinition :
# 961| mu0_2(unknown) = UnmodeledDefinition :
# 962| r0_3(glval<int[1000]>) = VariableAddress[a1] :
# 962| mu0_4(int[1000]) = Uninitialized : r0_3
# 962| mu0_4(int[1000]) = Uninitialized[a1] : r0_3
# 962| r0_5(int) = Constant[0] :
# 962| r0_6(glval<int>) = PointerAdd : r0_3, r0_5
# 962| r0_7(unknown[8]) = Constant[0] :
@@ -4441,3 +4401,88 @@ ir.cpp:
# 1005| v6_12(void) = ReturnValue : r6_11, m6_10
# 1005| v6_13(void) = UnmodeledUse : mu*
# 1005| v6_14(void) = ExitFunction :
# 1021| UnreachableViaGoto() -> int
# 1021| Block 0
# 1021| v0_0(void) = EnterFunction :
# 1021| mu0_1(unknown) = AliasedDefinition :
# 1021| mu0_2(unknown) = UnmodeledDefinition :
# 1022| v0_3(void) = NoOp :
# 1024| v0_4(void) = NoOp :
# 1025| r0_5(glval<int>) = VariableAddress[#return] :
# 1025| r0_6(int) = Constant[0] :
# 1025| m0_7(int) = Store : r0_5, r0_6
# 1021| r0_8(glval<int>) = VariableAddress[#return] :
# 1021| v0_9(void) = ReturnValue : r0_8, m0_7
# 1021| v0_10(void) = UnmodeledUse : mu*
# 1021| v0_11(void) = ExitFunction :
# 1028| UnreachableIf(bool) -> int
# 1028| Block 0
# 1028| v0_0(void) = EnterFunction :
# 1028| mu0_1(unknown) = AliasedDefinition :
# 1028| mu0_2(unknown) = UnmodeledDefinition :
# 1028| r0_3(glval<bool>) = VariableAddress[b] :
# 1028| m0_4(bool) = InitializeParameter[b] : r0_3
# 1029| r0_5(glval<int>) = VariableAddress[x] :
# 1029| r0_6(int) = Constant[5] :
# 1029| m0_7(int) = Store : r0_5, r0_6
# 1030| r0_8(glval<int>) = VariableAddress[y] :
# 1030| r0_9(int) = Constant[10] :
# 1030| m0_10(int) = Store : r0_8, r0_9
# 1031| r0_11(glval<bool>) = VariableAddress[b] :
# 1031| r0_12(bool) = Load : r0_11, m0_4
# 1031| v0_13(void) = ConditionalBranch : r0_12
#-----| False -> Block 5
#-----| True -> Block 2
# 1028| Block 1
# 1028| m1_0(int) = Phi : from 3:m3_2, from 4:m4_2, from 6:m6_2, from 7:m7_2
# 1028| r1_1(glval<int>) = VariableAddress[#return] :
# 1028| v1_2(void) = ReturnValue : r1_1, m1_0
# 1028| v1_3(void) = UnmodeledUse : mu*
# 1028| v1_4(void) = ExitFunction :
# 1032| Block 2
# 1032| r2_0(glval<int>) = VariableAddress[x] :
# 1032| r2_1(int) = Load : r2_0, m0_7
# 1032| r2_2(glval<int>) = VariableAddress[y] :
# 1032| r2_3(int) = Load : r2_2, m0_10
# 1032| r2_4(bool) = CompareEQ : r2_1, r2_3
# 1032| v2_5(void) = ConditionalBranch : r2_4
#-----| False -> Block 4
#-----| True -> Block 3
# 1033| Block 3
# 1033| r3_0(glval<int>) = VariableAddress[#return] :
# 1033| r3_1(int) = Constant[1] :
# 1033| m3_2(int) = Store : r3_0, r3_1
#-----| Goto -> Block 1
# 1036| Block 4
# 1036| r4_0(glval<int>) = VariableAddress[#return] :
# 1036| r4_1(int) = Constant[0] :
# 1036| m4_2(int) = Store : r4_0, r4_1
#-----| Goto -> Block 1
# 1040| Block 5
# 1040| r5_0(glval<int>) = VariableAddress[x] :
# 1040| r5_1(int) = Load : r5_0, m0_7
# 1040| r5_2(glval<int>) = VariableAddress[y] :
# 1040| r5_3(int) = Load : r5_2, m0_10
# 1040| r5_4(bool) = CompareLT : r5_1, r5_3
# 1040| v5_5(void) = ConditionalBranch : r5_4
#-----| False -> Block 7
#-----| True -> Block 6
# 1041| Block 6
# 1041| r6_0(glval<int>) = VariableAddress[#return] :
# 1041| r6_1(int) = Constant[0] :
# 1041| m6_2(int) = Store : r6_0, r6_1
#-----| Goto -> Block 1
# 1044| Block 7
# 1044| r7_0(glval<int>) = VariableAddress[#return] :
# 1044| r7_1(int) = Constant[1] :
# 1044| m7_2(int) = Store : r7_0, r7_1
#-----| Goto -> Block 1

View File

@@ -499,7 +499,6 @@
| test.c:367:15:367:17 | Constant: (unsigned int)... | positive strictlyPositive |
| test.c:368:5:368:21 | Store: ... = ... | positive strictlyPositive |
| test.c:368:10:368:21 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:368:10:368:21 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:368:10:368:21 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:368:11:368:11 | Load: x | positive |
| test.c:368:11:368:13 | Add: ... + ... | positive strictlyPositive |
@@ -508,7 +507,6 @@
| test.c:369:5:369:36 | Store: ... = ... | positive strictlyPositive |
| test.c:369:10:369:36 | Convert: (unsigned int)... | positive strictlyPositive |
| test.c:369:10:369:36 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:369:10:369:36 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:369:10:369:36 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:369:11:369:30 | Convert: (unsigned char)... | positive |
| test.c:369:27:369:27 | Load: x | positive |
@@ -518,7 +516,6 @@
| test.c:370:5:370:38 | Store: ... = ... | positive strictlyPositive |
| test.c:370:10:370:38 | Convert: (unsigned int)... | positive strictlyPositive |
| test.c:370:10:370:38 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:370:10:370:38 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:370:10:370:38 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:370:11:370:30 | Convert: (unsigned char)... | positive |
| test.c:370:27:370:27 | Load: x | positive |
@@ -528,7 +525,6 @@
| test.c:371:5:371:39 | Store: ... = ... | positive strictlyPositive |
| test.c:371:10:371:39 | Convert: (unsigned int)... | positive strictlyPositive |
| test.c:371:10:371:39 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:371:10:371:39 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:371:10:371:39 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:371:11:371:31 | Convert: (unsigned short)... | positive |
| test.c:371:28:371:28 | Load: x | positive |
@@ -591,7 +587,6 @@
| test.c:384:12:384:14 | Constant: (unsigned int)... | positive strictlyPositive |
| test.c:385:5:385:21 | Store: ... = ... | positive strictlyPositive |
| test.c:385:10:385:21 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:385:10:385:21 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:385:10:385:21 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:385:11:385:11 | Load: x | positive strictlyPositive |
| test.c:385:11:385:15 | Sub: ... - ... | positive |
@@ -599,7 +594,6 @@
| test.c:385:21:385:21 | Constant: (unsigned int)... | positive strictlyPositive |
| test.c:386:5:386:21 | Store: ... = ... | positive strictlyPositive |
| test.c:386:10:386:21 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:386:10:386:21 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:386:10:386:21 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:386:11:386:11 | Load: x | positive strictlyPositive |
| test.c:386:11:386:15 | Sub: ... - ... | positive |
@@ -608,7 +602,6 @@
| test.c:387:5:387:38 | Store: ... = ... | positive strictlyPositive |
| test.c:387:10:387:38 | Convert: (unsigned int)... | positive strictlyPositive |
| test.c:387:10:387:38 | Load: ... ? ... : ... | positive strictlyPositive |
| test.c:387:10:387:38 | Phi: ... ? ... : ... | positive strictlyPositive |
| test.c:387:10:387:38 | Store: ... ? ... : ... | positive strictlyPositive |
| test.c:387:11:387:32 | Convert: (unsigned char)... | positive |
| test.c:387:27:387:27 | Load: x | positive strictlyPositive |

View File

@@ -16,15 +16,15 @@ test.cpp:
# 1| valnum = m0_6
# 2| r0_7(glval<int>) = VariableAddress[x] :
# 2| valnum = r0_7
# 2| m0_8(int) = Uninitialized : r0_7
# 2| m0_8(int) = Uninitialized[x] : r0_7
# 2| valnum = unique
# 2| r0_9(glval<int>) = VariableAddress[y] :
# 2| valnum = r0_9
# 2| m0_10(int) = Uninitialized : r0_9
# 2| m0_10(int) = Uninitialized[y] : r0_9
# 2| valnum = unique
# 3| r0_11(glval<unsigned char>) = VariableAddress[b] :
# 3| valnum = unique
# 3| m0_12(unsigned char) = Uninitialized : r0_11
# 3| m0_12(unsigned char) = Uninitialized[b] : r0_11
# 3| valnum = unique
# 5| r0_13(glval<int>) = VariableAddress[p0] :
# 5| valnum = r0_3
@@ -86,15 +86,15 @@ test.cpp:
# 12| valnum = m0_6
# 13| r0_7(glval<int>) = VariableAddress[x] :
# 13| valnum = r0_7
# 13| m0_8(int) = Uninitialized : r0_7
# 13| m0_8(int) = Uninitialized[x] : r0_7
# 13| valnum = unique
# 13| r0_9(glval<int>) = VariableAddress[y] :
# 13| valnum = r0_9
# 13| m0_10(int) = Uninitialized : r0_9
# 13| m0_10(int) = Uninitialized[y] : r0_9
# 13| valnum = unique
# 14| r0_11(glval<unsigned char>) = VariableAddress[b] :
# 14| valnum = unique
# 14| m0_12(unsigned char) = Uninitialized : r0_11
# 14| m0_12(unsigned char) = Uninitialized[b] : r0_11
# 14| valnum = unique
# 16| r0_13(glval<int>) = VariableAddress[p0] :
# 16| valnum = r0_3
@@ -168,15 +168,15 @@ test.cpp:
# 25| valnum = m0_6
# 26| r0_7(glval<int>) = VariableAddress[x] :
# 26| valnum = r0_7
# 26| m0_8(int) = Uninitialized : r0_7
# 26| m0_8(int) = Uninitialized[x] : r0_7
# 26| valnum = unique
# 26| r0_9(glval<int>) = VariableAddress[y] :
# 26| valnum = r0_9
# 26| m0_10(int) = Uninitialized : r0_9
# 26| m0_10(int) = Uninitialized[y] : r0_9
# 26| valnum = unique
# 27| r0_11(glval<unsigned char>) = VariableAddress[b] :
# 27| valnum = unique
# 27| m0_12(unsigned char) = Uninitialized : r0_11
# 27| m0_12(unsigned char) = Uninitialized[b] : r0_11
# 27| valnum = unique
# 29| r0_13(glval<int>) = VariableAddress[p0] :
# 29| valnum = r0_3
@@ -261,15 +261,15 @@ test.cpp:
# 39| valnum = m0_8
# 40| r0_9(glval<int>) = VariableAddress[x] :
# 40| valnum = r0_9
# 40| m0_10(int) = Uninitialized : r0_9
# 40| m0_10(int) = Uninitialized[x] : r0_9
# 40| valnum = unique
# 40| r0_11(glval<int>) = VariableAddress[y] :
# 40| valnum = r0_11
# 40| m0_12(int) = Uninitialized : r0_11
# 40| m0_12(int) = Uninitialized[y] : r0_11
# 40| valnum = unique
# 41| r0_13(glval<unsigned char>) = VariableAddress[b] :
# 41| valnum = unique
# 41| m0_14(unsigned char) = Uninitialized : r0_13
# 41| m0_14(unsigned char) = Uninitialized[b] : r0_13
# 41| valnum = unique
# 43| r0_15(glval<int>) = VariableAddress[p0] :
# 43| valnum = r0_3
@@ -353,7 +353,7 @@ test.cpp:
# 49| valnum = m0_6
# 50| r0_7(glval<char *>) = VariableAddress[ptr] :
# 50| valnum = r0_7
# 50| m0_8(char *) = Uninitialized : r0_7
# 50| m0_8(char *) = Uninitialized[ptr] : r0_7
# 50| valnum = unique
# 51| r0_9(glval<unsigned int>) = VariableAddress[result] :
# 51| valnum = r0_9
@@ -601,7 +601,7 @@ test.cpp:
# 84| valnum = m0_8
# 86| r0_9(glval<int>) = VariableAddress[v] :
# 86| valnum = r0_9
# 86| m0_10(int) = Uninitialized : r0_9
# 86| m0_10(int) = Uninitialized[v] : r0_9
# 86| valnum = unique
# 88| r0_11(glval<void *>) = VariableAddress[p] :
# 88| valnum = r0_7