mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge rc/1.19 into next.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
23
cpp/ql/src/semmle/code/cpp/ir/dataflow/DataFlow.qll
Normal file
23
cpp/ql/src/semmle/code/cpp/ir/dataflow/DataFlow.qll
Normal 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
|
||||
}
|
||||
38
cpp/ql/src/semmle/code/cpp/ir/dataflow/DataFlow2.qll
Normal file
38
cpp/ql/src/semmle/code/cpp/ir/dataflow/DataFlow2.qll
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
38
cpp/ql/src/semmle/code/cpp/ir/dataflow/DataFlow3.qll
Normal file
38
cpp/ql/src/semmle/code/cpp/ir/dataflow/DataFlow3.qll
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
38
cpp/ql/src/semmle/code/cpp/ir/dataflow/DataFlow4.qll
Normal file
38
cpp/ql/src/semmle/code/cpp/ir/dataflow/DataFlow4.qll
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
1614
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
Normal file
1614
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
Normal file
File diff suppressed because it is too large
Load Diff
1614
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
Normal file
1614
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
Normal file
File diff suppressed because it is too large
Load Diff
1614
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
Normal file
1614
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
Normal file
File diff suppressed because it is too large
Load Diff
1614
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
Normal file
1614
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
135
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Normal file
135
cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Normal 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)
|
||||
}
|
||||
@@ -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" } }
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()))
|
||||
)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as IR
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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() + ")"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()))
|
||||
)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.implementation.raw.IR as IR
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
private import ReachableBlock as Reachability
|
||||
private module ReachabilityGraph = Reachability::Graph;
|
||||
|
||||
module Graph {
|
||||
import Reachability::Graph
|
||||
class Block = Reachability::ReachableBlock;
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()))
|
||||
)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
|
||||
@@ -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() + ")"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
private import ReachableBlock as Reachability
|
||||
private module ReachabilityGraph = Reachability::Graph;
|
||||
|
||||
module Graph {
|
||||
import Reachability::Graph
|
||||
class Block = Reachability::ReachableBlock;
|
||||
}
|
||||
@@ -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"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
private import implementations.IdentityFunction
|
||||
private import implementations.Inet
|
||||
private import implementations.Memcpy
|
||||
private import implementations.Printf
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
54
cpp/ql/src/semmle/code/cpp/models/interfaces/Alias.qll
Normal file
54
cpp/ql/src/semmle/code/cpp/models/interfaces/Alias.qll
Normal 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);
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
30
cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll
Normal file
30
cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll
Normal 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();
|
||||
}
|
||||
@@ -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 |
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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 |
|
||||
@@ -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
|
||||
@@ -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 |
|
||||
@@ -0,0 +1,5 @@
|
||||
import IRDataflowTestCommon
|
||||
|
||||
from DataFlow::Node sink, DataFlow::Node source, TestAllocationConfig cfg
|
||||
where cfg.hasFlow(source, sink)
|
||||
select sink, source
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user