Merge branch 'master' into js/improve-getAResponseDataNode

This commit is contained in:
Esben Sparre Andreasen
2019-09-17 13:18:41 +02:00
committed by GitHub
220 changed files with 7667 additions and 2867 deletions

View File

@@ -36,5 +36,6 @@ The following changes in version 1.23 affect C# analysis in all applications.
picture of the partial flow paths from a given source. The feature is
disabled by default and can be enabled for individual configurations by
overriding `int explorationLimit()`.
* `foreach` statements where the body is guaranteed to be executed at least once, such as `foreach (var x in new string[]{ "a", "b", "c" }) { ... }`, are now recognized by all analyses based on the control flow graph (such as SSA, data flow and taint tracking).
## Changes to autobuilder

View File

@@ -13,16 +13,20 @@
| **Query** | **Tags** | **Purpose** |
|---------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Unused index variable (`js/unused-index-variable`) | correctness | Highlights loops that iterate over an array, but do not use the index variable to access array elements, indicating a possible typo or logic error. |
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
| Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false-positive results | This rule now recognizes additional ways delimiters can be stripped away. |
| Client-side cross-site scripting (`js/xss`) | More results | More potential vulnerabilities involving functions that manipulate DOM attributes are now recognized. |
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving functions that manipulate DOM event handler attributes are now recognized. |
| Hard-coded credentials (`js/hardcoded-credentials`) | Fewer false-positive results | This rule now flags fewer password examples. |
| Incorrect suffix check (`js/incorrect-suffix-check`) | Fewer false-positive results | The query recognizes valid checks in more cases.
| Network data written to file (`js/http-to-file-access`) | Fewer false-positive results | This query has been renamed to better match its intended purpose, and now only considers network data untrusted. |
| Password in configuration file (`js/password-in-configuration-file`) | Fewer false-positive results | This rule now flags fewer password examples. |
| Prototype pollution (`js/prototype-pollution`) | More results | The query now highlights vulnerable uses of jQuery and Angular, and the results are shown on LGTM by default. |
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now treats responses from servers as untrusted. |

View File

@@ -29,6 +29,8 @@
"TaintTracking::Configuration Java/C++/C#": [
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",

View File

@@ -4,7 +4,21 @@ import semmle.code.cpp.Initializer
private import semmle.code.cpp.internal.ResolveClass
/**
* A C/C++ variable.
* A C/C++ variable. For example, in the following code there are four
* variables, `a`, `b`, `c` and `d`:
* ```
* extern int a;
* int a;
*
* void myFunction(int b) {
* int c;
* }
*
* namespace N {
* extern int d;
* int d = 1;
* }
* ```
*
* For local variables, there is a one-to-one correspondence between
* `Variable` and `VariableDeclarationEntry`.
@@ -162,7 +176,22 @@ class Variable extends Declaration, @variable {
}
/**
* A particular declaration or definition of a C/C++ variable.
* A particular declaration or definition of a C/C++ variable. For example, in
* the following code there are six variable declaration entries - two each for
* `a` and `d`, and one each for `b` and `c`:
* ```
* extern int a;
* int a;
*
* void myFunction(int b) {
* int c;
* }
*
* namespace N {
* extern int d;
* int d = 1;
* }
* ```
*/
class VariableDeclarationEntry extends DeclarationEntry, @var_decl {
override Variable getDeclaration() { result = getVariable() }
@@ -183,13 +212,13 @@ class VariableDeclarationEntry extends DeclarationEntry, @var_decl {
* because the parameter may have a different name in the declaration
* than in the definition. For example:
*
* ```
* // Declaration. Parameter is named "x".
* int f(int x);
* ```
* // Declaration. Parameter is named "x".
* int f(int x);
*
* // Definition. Parameter is named "y".
* int f(int y) { return y; }
* ```
* // Definition. Parameter is named "y".
* int f(int y) { return y; }
* ```
*/
override string getName() { var_decls(underlyingElement(this), _, _, result, _) and result != "" }
@@ -215,7 +244,13 @@ class VariableDeclarationEntry extends DeclarationEntry, @var_decl {
/**
* A parameter as described within a particular declaration or definition
* of a C/C++ function.
* of a C/C++ function. For example the declaration of `a` in the following
* code:
* ```
* void myFunction(int a) {
* int b;
* }
* ```
*/
class ParameterDeclarationEntry extends VariableDeclarationEntry {
ParameterDeclarationEntry() { param_decl_bind(underlyingElement(this), _, _) }
@@ -272,8 +307,17 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry {
/**
* A C/C++ variable with block scope [N4140 3.3.3]. In other words, a local
* variable or a function parameter. Local variables can be static; use the
* `isStatic` member predicate to detect those.
* variable or a function parameter. For example, the variables `a`, `b` and
* `c` in the following code:
* ```
* void myFunction(int a) {
* int b;
* static int c;
* }
* ```
*
* Local variables can be static; use the `isStatic` member predicate to
* detect those.
*/
class LocalScopeVariable extends Variable, @localscopevariable {
/** Gets the function to which this variable belongs. */
@@ -292,6 +336,14 @@ deprecated class StackVariable extends Variable {
/**
* A C/C++ local variable. In other words, any variable that has block
* scope [N4140 3.3.3], but is not a parameter of a `Function` or `CatchBlock`.
* For example the variables `b` and `c` in the following code:
* ```
* void myFunction(int a) {
* int b;
* static int c;
* }
* ```
*
* Local variables can be static; use the `isStatic` member predicate to detect
* those.
*
@@ -310,7 +362,15 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
}
/**
* A C/C++ variable which has global scope or namespace scope.
* A C/C++ variable which has global scope or namespace scope. For example the
* variables `a` and `b` in the following code:
* ```
* int a;
*
* namespace N {
* int b;
* }
* ```
*/
class GlobalOrNamespaceVariable extends Variable, @globalvariable {
override string getName() { globalvariables(underlyingElement(this), _, result) }
@@ -321,7 +381,15 @@ class GlobalOrNamespaceVariable extends Variable, @globalvariable {
}
/**
* A C/C++ variable which has namespace scope.
* A C/C++ variable which has namespace scope. For example the variable `b`
* in the following code:
* ```
* int a;
*
* namespace N {
* int b;
* }
* ```
*/
class NamespaceVariable extends GlobalOrNamespaceVariable {
NamespaceVariable() {
@@ -330,7 +398,15 @@ class NamespaceVariable extends GlobalOrNamespaceVariable {
}
/**
* A C/C++ variable which has global scope.
* A C/C++ variable which has global scope. For example the variable `a`
* in the following code:
* ```
* int a;
*
* namespace N {
* int b;
* }
* ```
*
* Note that variables declared in anonymous namespaces have namespace scope,
* even though they are accessed in the same manner as variables declared in
@@ -341,7 +417,15 @@ class GlobalVariable extends GlobalOrNamespaceVariable {
}
/**
* A C structure member or C++ member variable.
* A C structure member or C++ member variable. For example the member
* variables `m` and `s` in the following code:
* ```
* class MyClass {
* public:
* int m;
* static int s;
* };
* ```
*
* This includes static member variables in C++. To exclude static member
* variables, use `Field` instead of `MemberVariable`.
@@ -395,7 +479,12 @@ deprecated class FunctionPointerMemberVariable extends MemberVariable {
}
/**
* A C++14 variable template.
* A C++14 variable template. For example, in the following code the variable
* template `v` defines a family of variables:
* ```
* template<class T>
* T v;
* ```
*/
class TemplateVariable extends Variable {
TemplateVariable() { is_variable_template(underlyingElement(this)) }
@@ -410,7 +499,24 @@ class TemplateVariable extends Variable {
* A non-static local variable or parameter that is not part of an
* uninstantiated template. Uninstantiated templates are purely syntax, and
* only on instantiation will they be complete with information about types,
* conversions, call targets, etc.
* conversions, call targets, etc. For example in the following code, the
* variables `a` in `myFunction` and `b` in the instantiation
* `myTemplateFunction<int>`, but not `b` in the template
* `myTemplateFunction<T>`:
* ```
* void myFunction() {
* T a;
* }
*
* template<type T>
* void myTemplateFunction() {
* T b;
* }
*
* ...
*
* myTemplateFunction<int>();
* ```
*/
class SemanticStackVariable extends LocalScopeVariable {
SemanticStackVariable() {

View File

@@ -166,3 +166,17 @@ class MicrosoftInt64Type extends IntegralType {
not isExplicitlySigned()
}
}
/**
* The `__builtin_va_list` type, used to provide variadic functionality.
*
* This is a complement to the `__builtin_va_start`, `__builtin_va_end`,
* `__builtin_va_copy` and `__builtin_va_arg` expressions.
*/
class BuiltInVarArgsList extends Type {
BuiltInVarArgsList() {
this.hasName("__builtin_va_list")
}
override string getCanonicalQLClass() { result = "BuiltInVarArgsList" }
}

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -226,6 +226,29 @@ class ImplicitThisFieldAccess extends FieldAccess {
ImplicitThisFieldAccess() { not exists(this.getQualifier()) }
}
/**
* A C++ _pointer to non-static data member_ literal. For example, `&C::x` is
* an expression that refers to field `x` of class `C`. If the type of that
* field is `int`, then `&C::x` ought to have type `int C::*`. It is currently
* modeled in QL as having type `int`.
*
* See [dcl.mptr] in the C++17 standard or see
* https://en.cppreference.com/w/cpp/language/pointer#Pointers_to_data_members.
*/
class PointerToFieldLiteral extends ImplicitThisFieldAccess {
PointerToFieldLiteral() {
// The extractor currently emits a pointer-to-field literal as a field
// access without a qualifier. The only other unqualified field accesses it
// emits are for compiler-generated constructors and destructors. When we
// filter those out, there are only pointer-to-field literals left.
not this.isCompilerGenerated()
}
override predicate isConstant() { any() }
override string getCanonicalQLClass() { result = "PointerToFieldLiteral" }
}
/**
* A C/C++ function access expression.
*/

View File

@@ -13,8 +13,10 @@
*
* 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`.
* (intraprocedural) data flow between expressions, call
* `DataFlow::localExprFlow`. For more general cases of local data flow, call
* `DataFlow::localFlow` or `DataFlow::localFlowStep` with arguments of type
* `DataFlow::Node`.
*/
import cpp

View File

@@ -6,7 +6,7 @@
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
* `DataFlow4::Configuration`.
*
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
*/
import cpp

View File

@@ -6,7 +6,7 @@
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
* `DataFlow4::Configuration`.
*
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
*/
import cpp

View File

@@ -6,7 +6,7 @@
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
* `DataFlow4::Configuration`.
*
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
*/
import cpp

View File

@@ -0,0 +1,159 @@
import cpp
import semmle.code.cpp.security.Security
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.IR
/**
* A predictable expression is one where an external user can predict
* the value. For example, a literal in the source code is considered
* predictable.
*/
// TODO: Change to use Instruction instead of Expr. Naive attempt breaks
// TaintedAllocationSize qltest.
private predicate predictable(Expr expr) {
expr instanceof Literal
or
exists(BinaryOperation binop | binop = expr |
predictable(binop.getLeftOperand()) and predictable(binop.getRightOperand())
)
or
exists(UnaryOperation unop | unop = expr | predictable(unop.getOperand()))
}
// TODO: remove when `predictable` has an `Instruction` parameter instead of `Expr`.
private predicate predictableInstruction(Instruction instr) {
predictable(DataFlow::instructionNode(instr).asExpr())
}
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) }
override predicate isSink(DataFlow::Node sink) { any() }
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
}
override predicate isBarrier(DataFlow::Node node) {
exists(Variable checkedVar |
accessesVariable(node.asInstruction(), checkedVar) and
hasUpperBoundsCheck(checkedVar)
)
}
}
private predicate accessesVariable(CopyInstruction copy, Variable var) {
exists(VariableAddressInstruction va | va.getVariable().getAST() = var |
copy.(StoreInstruction).getDestinationAddress() = va
or
copy.(LoadInstruction).getSourceAddress() = va
)
}
/**
* A variable that has any kind of upper-bound check anywhere in the program
*/
// TODO: This coarse overapproximation, ported from the old taint tracking
// library, could be replaced with an actual semantic check that a particular
// variable _access_ is guarded by an upper-bound check. We probably don't want
// to do this right away since it could expose a lot of FPs that were
// previously suppressed by this predicate by coincidence.
private predicate hasUpperBoundsCheck(Variable var) {
exists(RelationalOperation oper, VariableAccess access |
oper.getLeftOperand() = access and
access.getTarget() = var and
// Comparing to 0 is not an upper bound check
not oper.getRightOperand().getValue() = "0"
)
}
private predicate instructionTaintStep(Instruction i1, Instruction i2) {
// Expressions computed from tainted data are also tainted
i2 = any(CallInstruction call |
isPureFunction(call.getStaticCallTarget().getName()) and
call.getAnArgument() = i1 and
forall(Instruction arg | arg = call.getAnArgument() | arg = i1 or predictableInstruction(arg)) and
// flow through `strlen` tends to cause dubious results, if the length is
// bounded.
not call.getStaticCallTarget().getName() = "strlen"
)
or
// Flow through pointer dereference
i2.(LoadInstruction).getSourceAddress() = i1
or
i2.(UnaryInstruction).getUnary() = i1
or
exists(BinaryInstruction bin |
bin = i2 and
predictableInstruction(i2.getAnOperand().getDef()) and
i1 = i2.getAnOperand().getDef()
)
// TODO: Check that we have flow from `a` to `a[i]`. It may work for constant
// `i` because there is flow through `predictable` `BinaryInstruction` and
// through `LoadInstruction`.
//
// TODO: Flow from argument to return of known functions: Port missing parts
// of `returnArgument` to the `interfaces.Taint` and `interfaces.DataFlow`
// libraries.
//
// TODO: Flow from input argument to output argument of known functions: Port
// missing parts of `copyValueBetweenArguments` to the `interfaces.Taint` and
// `interfaces.DataFlow` libraries and implement call side-effect nodes. This
// will help with the test for `ExecTainted.ql`. The test for
// `TaintedPath.ql` is more tricky because the output arg is a pointer
// addition expression.
}
predicate tainted(Expr source, Element tainted) {
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
cfg.hasFlow(DataFlow::exprNode(source), sink)
|
// TODO: is it more appropriate to use asConvertedExpr here and avoid
// `getConversion*`? Or will that cause us to miss some cases where there's
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
// pretend there was flow to the converted `Expr` for the sake of
// compatibility.
sink.asExpr().getConversion*() = tainted
or
// For compatibility, send flow from arguments to parameters, even for
// functions with no body.
exists(FunctionCall call, int i |
sink.asExpr() = call.getArgument(i) and
tainted = resolveCall(call).getParameter(i)
)
or
// For compatibility, send flow into a `Variable` if there is flow to any
// Load or Store of that variable.
exists(CopyInstruction copy |
copy.getSourceValue() = sink.asInstruction() and
accessesVariable(copy, tainted) and
not hasUpperBoundsCheck(tainted)
)
or
// For compatibility, send flow into a `NotExpr` even if it's part of a
// short-circuiting condition and thus might get skipped.
tainted.(NotExpr).getOperand() = sink.asExpr()
)
}
predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) {
tainted(source, tainted) and
// TODO: Find a way to emulate how `security.TaintTracking` reports the last
// global variable that taint has passed through. Also make sure we emulate
// its behavior for interprocedural flow through globals.
globalVar = ""
}
GlobalOrNamespaceVariable globalVarFromId(string id) {
// TODO: Implement this when `taintedIncludingGlobalVars` has support for
// global variables.
none()
}
Function resolveCall(Call call) {
// TODO: improve virtual dispatch. This will help in the test for
// `UncontrolledProcessOperation.ql`.
result = call.getTarget()
}

View File

@@ -6,166 +6,24 @@
* the information from the source is preserved at the sink. For example, taint
* propagates from `x` to `x + 100`, but it does not propagate from `x` to `x >
* 100` since we consider a single bit of information to be too little.
*
* To use global (interprocedural) taint tracking, extend the class
* `TaintTracking::Configuration` as documented on that class. To use local
* (intraprocedural) taint tracking between expressions, call
* `TaintTracking::localExprTaint`. For more general cases of local taint
* tracking, call `TaintTracking::localTaint` or
* `TaintTracking::localTaintStep` with arguments of type `DataFlow::Node`.
*/
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.dataflow.DataFlow2
private import semmle.code.cpp.ir.IR
module TaintTracking {
/**
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
* this abstract class.
*
* A taint-tracking configuration is a special data flow configuration
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
* necessarily preserve values but are still relevant from a taint-tracking
* perspective. (For example, string concatenation, where one of the operands
* is tainted.)
*
* To create a configuration, extend this class with a subclass whose
* characteristic predicate is a unique singleton string. For example, write
*
* ```
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
* // Override `isSource` and `isSink`.
* // Optionally override `isSanitizer`.
* // Optionally override `isAdditionalTaintStep`.
* }
* ```
*
* Then, to query whether there is flow between some `source` and `sink`,
* write
*
* ```
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
* ```
*
* Multiple configurations can coexist, but it is unsupported to depend on a
* `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
* overridden predicates that define sources, sinks, or additional steps.
* Instead, the dependency should go to a `TaintTracking::Configuration2` or
* a `DataFlow{2,3,4}::Configuration`.
*/
abstract class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }
/** Holds if `source` is a taint source. */
// overridden to provide taint-tracking specific qldoc
abstract override predicate isSource(DataFlow::Node source);
/** Holds if `sink` is a taint sink. */
// overridden to provide taint-tracking specific qldoc
abstract override predicate isSink(DataFlow::Node sink);
/**
* Holds if taint should not flow into `node`.
*/
predicate isSanitizer(DataFlow::Node node) { none() }
/**
* Holds if the additional taint propagation step
* from `source` to `target` must be taken into account in the analysis.
* This step will only be followed if `target` is not in the `isSanitizer`
* predicate.
*/
predicate isAdditionalTaintStep(DataFlow::Node source, DataFlow::Node target) { none() }
final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) }
final override predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node target) {
this.isAdditionalTaintStep(source, target)
or
localTaintStep(source, target)
}
}
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
private import semmle.code.cpp.ir.dataflow.TaintTracking2
/**
* A taint-tracking configuration that is backed by the `DataFlow2` library
* instead of `DataFlow`. Use this class when taint-tracking configurations
* or data-flow configurations must depend on each other.
*
* See `TaintTracking::Configuration` for the full documentation.
* DEPRECATED: Use TaintTracking2::Configuration instead.
*/
abstract class Configuration2 extends DataFlow2::Configuration {
bindingset[this]
Configuration2() { any() }
/** Holds if `source` is a taint source. */
// overridden to provide taint-tracking specific qldoc
abstract override predicate isSource(DataFlow::Node source);
/** Holds if `sink` is a taint sink. */
// overridden to provide taint-tracking specific qldoc
abstract override predicate isSink(DataFlow::Node sink);
/**
* Holds if taint should not flow into `node`.
*/
predicate isSanitizer(DataFlow::Node node) { none() }
/**
* Holds if the additional taint propagation step
* from `source` to `target` must be taken into account in the analysis.
* This step will only be followed if `target` is not in the `isSanitizer`
* predicate.
*/
predicate isAdditionalTaintStep(DataFlow::Node source, DataFlow::Node target) { none() }
final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) }
final override predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node target) {
this.isAdditionalTaintStep(source, target)
or
localTaintStep(source, target)
}
}
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step.
*/
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// Taint can flow into using ordinary data flow.
DataFlow::localFlowStep(nodeFrom, nodeTo)
or
localInstructionTaintStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
}
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step.
*/
private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction nodeTo) {
// Taint can flow through expressions that alter the value but preserve
// more than one bit of it _or_ expressions that follow data through
// pointer indirections.
nodeTo.getAnOperand().getAnyDef() = nodeFrom and
(
nodeTo instanceof ArithmeticInstruction
or
nodeTo instanceof BitwiseInstruction
or
nodeTo instanceof PointerArithmeticInstruction
or
nodeTo instanceof FieldAddressInstruction
or
// The `CopyInstruction` case is also present in non-taint data flow, but
// that uses `getDef` rather than `getAnyDef`. For taint, we want flow
// from a definition of `myStruct` to a `myStruct.myField` expression.
nodeTo instanceof CopyInstruction
)
or
nodeTo.(LoadInstruction).getSourceAddress() = nodeFrom
}
/**
* Holds if taint may propagate from `source` to `sink` in zero or more local
* (intra-procedural) steps.
*/
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) }
deprecated class Configuration2 = TaintTracking2::Configuration;
}

View File

@@ -0,0 +1,15 @@
/**
* Provides a `TaintTracking2` module, which is a copy of the `TaintTracking`
* module. Use this class when data-flow configurations or taint-tracking
* 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`. The
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
*
* See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation.
*/
module TaintTracking2 {
import semmle.code.cpp.ir.dataflow.internal.tainttracking2.TaintTrackingImpl
}

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -156,6 +156,11 @@ abstract class PostUpdateNode extends Node {
abstract Node getPreUpdateNode();
}
/**
* Gets the node corresponding to `instr`.
*/
Node instructionNode(Instruction instr) { result.asInstruction() = instr }
/**
* Gets a `Node` corresponding to `e` or any of its conversions. There is no
* result if `e` is a `Conversion`.

View File

@@ -0,0 +1,76 @@
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step.
*/
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
DataFlow::localFlowStep(nodeFrom, nodeTo)
or
localAdditionalTaintStep(nodeFrom, nodeTo)
}
/**
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
* different objects.
*/
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
localInstructionTaintStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
}
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step.
*/
private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction nodeTo) {
// Taint can flow through expressions that alter the value but preserve
// more than one bit of it _or_ expressions that follow data through
// pointer indirections.
nodeTo.getAnOperand().getAnyDef() = nodeFrom and
(
nodeTo instanceof ArithmeticInstruction
or
nodeTo instanceof BitwiseInstruction
or
nodeTo instanceof PointerArithmeticInstruction
or
nodeTo instanceof FieldAddressInstruction
or
// The `CopyInstruction` case is also present in non-taint data flow, but
// that uses `getDef` rather than `getAnyDef`. For taint, we want flow
// from a definition of `myStruct` to a `myStruct.myField` expression.
nodeTo instanceof CopyInstruction
)
or
nodeTo.(LoadInstruction).getSourceAddress() = nodeFrom
}
/**
* Holds if taint may propagate from `source` to `sink` in zero or more local
* (intra-procedural) steps.
*/
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) }
/**
* Holds if taint can flow from `e1` to `e2` in zero or more
* local (intra-procedural) steps.
*/
predicate localExprTaint(Expr e1, Expr e2) {
localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2))
}
/**
* Holds if the additional step from `src` to `sink` should be included in all
* global taint flow configurations.
*/
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink)
}
/**
* Holds if `node` should be a barrier in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintBarrier(DataFlow::Node node) { none() }

View File

@@ -0,0 +1,112 @@
import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
* this abstract class.
*
* A taint-tracking configuration is a special data flow configuration
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
* necessarily preserve values but are still relevant from a taint tracking
* perspective. (For example, string concatenation, where one of the operands
* is tainted.)
*
* To create a configuration, extend this class with a subclass whose
* characteristic predicate is a unique singleton string. For example, write
*
* ```
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
* // Override `isSource` and `isSink`.
* // Optionally override `isSanitizer`.
* // Optionally override `isSanitizerIn`.
* // Optionally override `isSanitizerOut`.
* // Optionally override `isSanitizerGuard`.
* // Optionally override `isAdditionalTaintStep`.
* }
* ```
*
* Then, to query whether there is flow between some `source` and `sink`,
* write
*
* ```
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
* ```
*
* Multiple configurations can coexist, but it is unsupported to depend on
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
* overridden predicates that define sources, sinks, or additional steps.
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }
/**
* Holds if `source` is a relevant taint source.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
abstract override predicate isSource(DataFlow::Node source);
/**
* Holds if `sink` is a relevant taint sink.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
abstract override predicate isSink(DataFlow::Node sink);
/** Holds if the node `node` is a taint sanitizer. */
predicate isSanitizer(DataFlow::Node node) { none() }
final override predicate isBarrier(DataFlow::Node node) {
isSanitizer(node) or
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
/** Holds if data flow out of `node` is prohibited. */
predicate isSanitizerOut(DataFlow::Node node) { none() }
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.
*/
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
}
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
// overridden to provide taint-tracking specific qldoc
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
super.hasFlow(source, sink)
}
}

View File

@@ -0,0 +1,5 @@
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
module Private {
import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as DataFlow
}

View File

@@ -0,0 +1,112 @@
import TaintTrackingParameter::Public
private import TaintTrackingParameter::Private
/**
* A configuration of interprocedural taint tracking analysis. This defines
* sources, sinks, and any other configurable aspect of the analysis. Each
* use of the taint tracking library must define its own unique extension of
* this abstract class.
*
* A taint-tracking configuration is a special data flow configuration
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
* necessarily preserve values but are still relevant from a taint tracking
* perspective. (For example, string concatenation, where one of the operands
* is tainted.)
*
* To create a configuration, extend this class with a subclass whose
* characteristic predicate is a unique singleton string. For example, write
*
* ```
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
* // Override `isSource` and `isSink`.
* // Optionally override `isSanitizer`.
* // Optionally override `isSanitizerIn`.
* // Optionally override `isSanitizerOut`.
* // Optionally override `isSanitizerGuard`.
* // Optionally override `isAdditionalTaintStep`.
* }
* ```
*
* Then, to query whether there is flow between some `source` and `sink`,
* write
*
* ```
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
* ```
*
* Multiple configurations can coexist, but it is unsupported to depend on
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
* overridden predicates that define sources, sinks, or additional steps.
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
*/
abstract class Configuration extends DataFlow::Configuration {
bindingset[this]
Configuration() { any() }
/**
* Holds if `source` is a relevant taint source.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
abstract override predicate isSource(DataFlow::Node source);
/**
* Holds if `sink` is a relevant taint sink.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
abstract override predicate isSink(DataFlow::Node sink);
/** Holds if the node `node` is a taint sanitizer. */
predicate isSanitizer(DataFlow::Node node) { none() }
final override predicate isBarrier(DataFlow::Node node) {
isSanitizer(node) or
defaultTaintBarrier(node)
}
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
isSanitizerEdge(node1, node2)
}
/** Holds if data flow into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
/** Holds if data flow out of `node` is prohibited. */
predicate isSanitizerOut(DataFlow::Node node) { none() }
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.
*/
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
}
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/
// overridden to provide taint-tracking specific qldoc
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
super.hasFlow(source, sink)
}
}

View File

@@ -0,0 +1,5 @@
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
module Private {
import semmle.code.cpp.ir.dataflow.DataFlow2::DataFlow2 as DataFlow
}

View File

@@ -9,32 +9,31 @@ private import semmle.code.cpp.ir.implementation.internal.OperandTag
private class IntValue = Ints::IntValue;
private predicate hasResultMemoryAccess(Instruction instr, IRVariable var, Type type, IntValue startBitOffset,
IntValue endBitOffset) {
private predicate hasResultMemoryAccess(
Instruction instr, IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset
) {
resultPointsTo(instr.getResultAddress(), var, startBitOffset) and
type = instr.getResultType() and
if exists(instr.getResultSize()) then
endBitOffset = Ints::add(startBitOffset, Ints::mul(instr.getResultSize(), 8))
else
endBitOffset = Ints::unknown()
if exists(instr.getResultSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(instr.getResultSize(), 8))
else endBitOffset = Ints::unknown()
}
private predicate hasOperandMemoryAccess(MemoryOperand operand, IRVariable var, Type type, IntValue startBitOffset,
IntValue endBitOffset) {
private predicate hasOperandMemoryAccess(
MemoryOperand operand, IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset
) {
resultPointsTo(operand.getAddressOperand().getAnyDef(), var, startBitOffset) and
type = operand.getType() and
if exists(operand.getSize()) then
endBitOffset = Ints::add(startBitOffset, Ints::mul(operand.getSize(), 8))
else
endBitOffset = Ints::unknown()
if exists(operand.getSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(operand.getSize(), 8))
else endBitOffset = Ints::unknown()
}
private newtype TMemoryLocation =
TVariableMemoryLocation(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset) {
hasResultMemoryAccess(_, var, type, startBitOffset, endBitOffset) or
hasOperandMemoryAccess(_, var, type, startBitOffset, endBitOffset)
}
or
} or
TUnknownMemoryLocation(IRFunction irFunc) or
TUnknownVirtualVariable(IRFunction irFunc)
@@ -47,7 +46,7 @@ private newtype TMemoryLocation =
*/
abstract class MemoryLocation extends TMemoryLocation {
abstract string toString();
abstract VirtualVariable getVirtualVariable();
abstract Type getType();
@@ -55,8 +54,7 @@ abstract class MemoryLocation extends TMemoryLocation {
abstract string getUniqueId();
}
abstract class VirtualVariable extends MemoryLocation {
}
abstract class VirtualVariable extends MemoryLocation { }
/**
* An access to memory within a single known `IRVariable`. The variable may be either an unescaped variable
@@ -72,36 +70,28 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
this = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset)
}
override final string toString() {
result = var.toString() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" + type.toString() + ">"
final override string toString() {
result = var.toString() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" +
type.toString() + ">"
}
override final Type getType() {
result = type
}
final override Type getType() { result = type }
final IntValue getStartBitOffset() {
result = startBitOffset
}
final IntValue getEndBitOffset() {
result = endBitOffset
}
final IRVariable getVariable() {
result = var
}
final IntValue getStartBitOffset() { result = startBitOffset }
override final string getUniqueId() {
final IntValue getEndBitOffset() { result = endBitOffset }
final IRVariable getVariable() { result = var }
final override string getUniqueId() {
result = var.getUniqueId() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" +
getTypeIdentityString(type) + ">"
getTypeIdentityString(type) + ">"
}
override final VirtualVariable getVirtualVariable() {
if variableAddressEscapes(var) then
result = TUnknownVirtualVariable(var.getEnclosingIRFunction())
else
result = TVariableMemoryLocation(var, var.getType(), 0, var.getType().getSize() * 8)
final override VirtualVariable getVirtualVariable() {
if variableAddressEscapes(var)
then result = TUnknownVirtualVariable(var.getEnclosingIRFunction())
else result = TVariableMemoryLocation(var, var.getType(), 0, var.getType().getSize() * 8)
}
/**
@@ -132,25 +122,15 @@ class VariableVirtualVariable extends VariableMemoryLocation, VirtualVariable {
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
IRFunction irFunc;
UnknownMemoryLocation() {
this = TUnknownMemoryLocation(irFunc)
}
override final string toString() {
result = "{Unknown}"
}
override final VirtualVariable getVirtualVariable() {
result = TUnknownVirtualVariable(irFunc)
}
UnknownMemoryLocation() { this = TUnknownMemoryLocation(irFunc) }
override final Type getType() {
result instanceof UnknownType
}
final override string toString() { result = "{Unknown}" }
override final string getUniqueId() {
result = "{Unknown}"
}
final override VirtualVariable getVirtualVariable() { result = TUnknownVirtualVariable(irFunc) }
final override Type getType() { result instanceof UnknownType }
final override string getUniqueId() { result = "{Unknown}" }
}
/**
@@ -159,25 +139,15 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
class UnknownVirtualVariable extends TUnknownVirtualVariable, VirtualVariable {
IRFunction irFunc;
UnknownVirtualVariable() {
this = TUnknownVirtualVariable(irFunc)
}
override final string toString() {
result = "{AllAliased}"
}
UnknownVirtualVariable() { this = TUnknownVirtualVariable(irFunc) }
override final Type getType() {
result instanceof UnknownType
}
final override string toString() { result = "{AllAliased}" }
override final string getUniqueId() {
result = " " + toString()
}
final override Type getType() { result instanceof UnknownType }
override final VirtualVariable getVirtualVariable() {
result = this
}
final override string getUniqueId() { result = " " + toString() }
final override VirtualVariable getVirtualVariable() { result = this }
}
Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
@@ -185,44 +155,44 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
(
// An UnknownVirtualVariable must totally overlap any location within the same virtual variable.
def.getVirtualVariable() = use.getVirtualVariable() and
def instanceof UnknownVirtualVariable and result instanceof MustTotallyOverlap
def instanceof UnknownVirtualVariable and
result instanceof MustTotallyOverlap
or
// An UnknownMemoryLocation may partially overlap any Location within the same virtual variable.
def.getVirtualVariable() = use.getVirtualVariable() and
def instanceof UnknownMemoryLocation and result instanceof MayPartiallyOverlap
def instanceof UnknownMemoryLocation and
result instanceof MayPartiallyOverlap
or
exists(VariableMemoryLocation defVariableLocation |
defVariableLocation = def and
(
(
// A VariableMemoryLocation may partially overlap an unknown location within the same virtual variable.
def.getVirtualVariable() = use.getVirtualVariable() and
((use instanceof UnknownMemoryLocation) or (use instanceof UnknownVirtualVariable)) and
result instanceof MayPartiallyOverlap
) or
// A VariableMemoryLocation may partially overlap an unknown location within the same virtual variable.
def.getVirtualVariable() = use.getVirtualVariable() and
(use instanceof UnknownMemoryLocation or use instanceof UnknownVirtualVariable) and
result instanceof MayPartiallyOverlap
or
// A VariableMemoryLocation overlaps another location within the same variable based on the relationship
// of the two offset intervals.
exists(Overlap intervalOverlap |
intervalOverlap = getVariableMemoryLocationOverlap(def, use) and
if intervalOverlap instanceof MustExactlyOverlap then (
if def.getType() = use.getType() then (
if intervalOverlap instanceof MustExactlyOverlap
then
if def.getType() = use.getType()
then
// The def and use types match, so it's an exact overlap.
result instanceof MustExactlyOverlap
)
else (
else
// The def and use types are not the same, so it's just a total overlap.
result instanceof MustTotallyOverlap
)
)
else if defVariableLocation.coversEntireVariable() then (
// The definition covers the entire variable, so assume that it totally overlaps the use, even if the
// interval for the use is unknown or outside the bounds of the variable.
result instanceof MustTotallyOverlap
)
else (
// Just use the overlap relation of the interval.
result = intervalOverlap
)
else
if defVariableLocation.coversEntireVariable()
then
// The definition covers the entire variable, so assume that it totally overlaps the use, even if the
// interval for the use is unknown or outside the bounds of the variable.
result instanceof MustTotallyOverlap
else
// Just use the overlap relation of the interval.
result = intervalOverlap
)
)
)
@@ -245,10 +215,9 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
* 5. In `getVariableMemoryLocationOverlap`, compute the precise overlap relation for each
* overlapping pair of VMLs (linear in the size of the overlap set)
*/
private predicate isRelevantOffset(VirtualVariable vv, IntValue offset) {
exists(VariableMemoryLocation ml |
ml.getVirtualVariable() = vv
|
exists(VariableMemoryLocation ml | ml.getVirtualVariable() = vv |
ml.getStartBitOffset() = offset
or
ml.getEndBitOffset() = offset
@@ -278,50 +247,55 @@ private predicate hasUnknownOffset(VariableMemoryLocation vml, VirtualVariable v
)
}
private predicate overlappingVariableMemoryLocations(VariableMemoryLocation def, VariableMemoryLocation use) {
exists(VirtualVariable vv, int offsetRank | isCoveredOffset(def, vv, offsetRank) and isCoveredOffset(use, vv, offsetRank))
or
hasUnknownOffset(def, use.getVirtualVariable())
or
hasUnknownOffset(use, def.getVirtualVariable())
private predicate overlappingVariableMemoryLocations(
VariableMemoryLocation def, VariableMemoryLocation use
) {
exists(VirtualVariable vv, int offsetRank |
isCoveredOffset(def, vv, offsetRank) and isCoveredOffset(use, vv, offsetRank)
)
or
hasUnknownOffset(def, use.getVirtualVariable())
or
hasUnknownOffset(use, def.getVirtualVariable())
}
pragma[noopt] // Internal ticket: QL-937
private predicate overlappingIRVariableMemoryLocations(VariableMemoryLocation def, VariableMemoryLocation use) {
// Internal ticket: QL-937
pragma[noopt]
private predicate overlappingIRVariableMemoryLocations(
VariableMemoryLocation def, VariableMemoryLocation use
) {
overlappingVariableMemoryLocations(def, use) and
def.getVariable() = use.getVariable()
}
private Overlap getVariableMemoryLocationOverlap(VariableMemoryLocation def, VariableMemoryLocation use) {
private Overlap getVariableMemoryLocationOverlap(
VariableMemoryLocation def, VariableMemoryLocation use
) {
overlappingIRVariableMemoryLocations(def, use) and
result = Interval::getOverlap(def.getStartBitOffset(), def.getEndBitOffset(), use.getStartBitOffset(), use.getEndBitOffset())
result = Interval::getOverlap(def.getStartBitOffset(), def.getEndBitOffset(),
use.getStartBitOffset(), use.getEndBitOffset())
}
MemoryLocation getResultMemoryLocation(Instruction instr) {
exists(MemoryAccessKind kind |
kind = instr.getResultMemoryAccess() and
(
(
kind.usesAddressOperand() and
if hasResultMemoryAccess(instr, _, _, _, _) then (
if hasResultMemoryAccess(instr, _, _, _, _)
then
exists(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset |
hasResultMemoryAccess(instr, var, type, startBitOffset, endBitOffset) and
result = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset)
)
)
else (
result = TUnknownMemoryLocation(instr.getEnclosingIRFunction())
)
) or
(
kind instanceof EscapedMemoryAccess and
result = TUnknownVirtualVariable(instr.getEnclosingIRFunction())
) or
(
kind instanceof EscapedMayMemoryAccess and
result = TUnknownMemoryLocation(instr.getEnclosingIRFunction())
else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction())
)
or
kind instanceof EscapedMemoryAccess and
result = TUnknownVirtualVariable(instr.getEnclosingIRFunction())
or
kind instanceof EscapedMayMemoryAccess and
result = TUnknownMemoryLocation(instr.getEnclosingIRFunction())
)
)
}
@@ -332,24 +306,20 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
(
(
kind.usesAddressOperand() and
if hasOperandMemoryAccess(operand, _, _, _, _) then (
if hasOperandMemoryAccess(operand, _, _, _, _)
then
exists(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset |
hasOperandMemoryAccess(operand, var, type, startBitOffset, endBitOffset) and
result = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset)
)
)
else (
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction())
)
) or
(
kind instanceof EscapedMemoryAccess and
result = TUnknownVirtualVariable(operand.getEnclosingIRFunction())
) or
(
kind instanceof EscapedMayMemoryAccess and
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction())
else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction())
)
or
kind instanceof EscapedMemoryAccess and
result = TUnknownVirtualVariable(operand.getEnclosingIRFunction())
or
kind instanceof EscapedMayMemoryAccess and
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction())
)
)
}

View File

@@ -13,7 +13,8 @@ class PropertyProvider extends IRPropertyProvider {
exists(MemoryLocation location |
location = getResultMemoryLocation(instruction) and
(
key = "ResultMemoryLocation" and result = location.toString() or
key = "ResultMemoryLocation" and result = location.toString()
or
key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString()
)
)
@@ -21,33 +22,40 @@ class PropertyProvider extends IRPropertyProvider {
exists(MemoryLocation location |
location = getOperandMemoryLocation(instruction.getAnOperand()) and
(
key = "OperandMemoryAccess" and result = location.toString() or
key = "OperandMemoryAccess" and result = location.toString()
or
key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString()
)
) or
)
or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex |
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and
defBlock.getInstruction(defIndex) = instruction and
key = "DefinitionRank[" + useLocation.toString() + "]" and
result = defRank.toString()
) or
)
or
exists(MemoryLocation useLocation, IRBlock useBlock, int useRank |
hasUseAtRank(useLocation, useBlock, useRank, instruction) and
key = "UseRank[" + useLocation.toString() + "]" and
result = useRank.toString()
) or
)
or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex |
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and
defBlock.getInstruction(defIndex) = instruction and
key = "DefinitionReachesUse[" + useLocation.toString() + "]" and
result = strictconcat(IRBlock useBlock, int useRank, int useIndex |
exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
useBlock.getInstruction(useIndex) = useInstruction and
definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank)
) |
useBlock.getDisplayIndex().toString() + "_" + useIndex, ", " order by useBlock.getDisplayIndex(), useIndex
)
exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
useBlock.getInstruction(useIndex) = useInstruction and
definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank)
)
|
useBlock.getDisplayIndex().toString() + "_" + useIndex, ", "
order by
useBlock.getDisplayIndex(), useIndex
)
)
}
@@ -57,53 +65,62 @@ class PropertyProvider extends IRPropertyProvider {
defIndex = -1 and
key = "DefinitionRank(Phi)[" + useLocation.toString() + "]" and
result = defRank.toString()
) or
)
or
exists(MemoryLocation useLocation, MemoryLocation defLocation, int defRank, int defIndex |
hasDefinitionAtRank(useLocation, defLocation, block, defRank, defIndex) and
defIndex = -1 and
key = "DefinitionReachesUse(Phi)[" + useLocation.toString() + "]" and
result = strictconcat(IRBlock useBlock, int useRank, int useIndex |
exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
useBlock.getInstruction(useIndex) = useInstruction and
definitionReachesUse(useLocation, block, defRank, useBlock, useRank) and
exists(getOverlap(defLocation, useLocation))
) |
useBlock.getDisplayIndex().toString() + "_" + useIndex, ", " order by useBlock.getDisplayIndex(), useIndex
)
) or
exists(MemoryLocation useLocation, IRBlock predBlock, IRBlock defBlock, int defIndex, Overlap overlap |
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex, overlap) and
key = "PhiUse[" + useLocation.toString() + " from " + predBlock.getDisplayIndex().toString() + "]" and
result = defBlock.getDisplayIndex().toString() + "_" + defIndex + " (" + overlap.toString() + ")"
) or
(
key = "LiveOnEntry" and
result = strictconcat(MemoryLocation useLocation |
locationLiveOnEntryToBlock(useLocation, block) |
useLocation.toString(), ", " order by useLocation.toString()
)
) or
(
key = "LiveOnExit" and
result = strictconcat(MemoryLocation useLocation |
locationLiveOnExitFromBlock(useLocation, block) |
useLocation.toString(), ", " order by useLocation.toString()
)
) or
(
key = "DefsLiveOnEntry" and
result = strictconcat(MemoryLocation defLocation |
definitionLiveOnEntryToBlock(defLocation, block) |
defLocation.toString(), ", " order by defLocation.toString()
)
) or
(
key = "DefsLiveOnExit" and
result = strictconcat(MemoryLocation defLocation |
definitionLiveOnExitFromBlock(defLocation, block) |
defLocation.toString(), ", " order by defLocation.toString()
)
exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
useBlock.getInstruction(useIndex) = useInstruction and
definitionReachesUse(useLocation, block, defRank, useBlock, useRank) and
exists(getOverlap(defLocation, useLocation))
)
|
useBlock.getDisplayIndex().toString() + "_" + useIndex, ", "
order by
useBlock.getDisplayIndex(), useIndex
)
)
or
exists(
MemoryLocation useLocation, IRBlock predBlock, IRBlock defBlock, int defIndex, Overlap overlap
|
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex, overlap) and
key = "PhiUse[" + useLocation.toString() + " from " + predBlock.getDisplayIndex().toString() +
"]" and
result = defBlock.getDisplayIndex().toString() + "_" + defIndex + " (" + overlap.toString() +
")"
)
or
key = "LiveOnEntry" and
result = strictconcat(MemoryLocation useLocation |
locationLiveOnEntryToBlock(useLocation, block)
|
useLocation.toString(), ", " order by useLocation.toString()
)
or
key = "LiveOnExit" and
result = strictconcat(MemoryLocation useLocation |
locationLiveOnExitFromBlock(useLocation, block)
|
useLocation.toString(), ", " order by useLocation.toString()
)
or
key = "DefsLiveOnEntry" and
result = strictconcat(MemoryLocation defLocation |
definitionLiveOnEntryToBlock(defLocation, block)
|
defLocation.toString(), ", " order by defLocation.toString()
)
or
key = "DefsLiveOnExit" and
result = strictconcat(MemoryLocation defLocation |
definitionLiveOnExitFromBlock(defLocation, block)
|
defLocation.toString(), ", " order by defLocation.toString()
)
}
}

View File

@@ -6,31 +6,32 @@ private import semmle.code.cpp.ir.internal.Overlap
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached private module Cached {
cached
private module Cached {
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached predicate functionHasIR(Function func) {
exists(OldIR::IRFunction irFunc |
irFunc.getFunction() = func
)
cached
predicate functionHasIR(Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
}
cached OldInstruction getOldInstruction(Instruction instr) {
instr = WrappedInstruction(result)
}
cached
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
// This is just a type cast. Both classes derive from the same newtype.
result = var
}
cached newtype TInstruction =
cached
newtype TInstruction =
WrappedInstruction(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction
} or
@@ -48,8 +49,8 @@ cached private module Cached {
)
}
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
Type type) {
cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) {
exists(OldIR::IRTempVariable var |
var.getEnclosingFunction() = func and
var.getAST() = ast and
@@ -58,13 +59,15 @@ cached private module Cached {
)
}
cached predicate hasModeledMemoryResult(Instruction instruction) {
cached
predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
@@ -73,16 +76,22 @@ cached private module Cached {
)
}
cached Instruction getMemoryOperandDefinition(Instruction instruction, MemoryOperandTag tag, Overlap overlap) {
cached
Instruction getMemoryOperandDefinition(
Instruction instruction, MemoryOperandTag tag, Overlap overlap
) {
exists(OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
(
(
if exists(Alias::getOperandMemoryLocation(oldOperand)) then (
exists(OldBlock useBlock, int useRank, Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset |
if exists(Alias::getOperandMemoryLocation(oldOperand))
then
exists(
OldBlock useBlock, int useRank, Alias::MemoryLocation useLocation,
Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset
|
useLocation = Alias::getOperandMemoryLocation(oldOperand) and
hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and
hasUseAtRank(useLocation, useBlock, useRank, oldInstruction) and
@@ -90,12 +99,12 @@ cached private module Cached {
overlap = Alias::getOverlap(defLocation, useLocation) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation)
)
)
else (
result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and
overlap instanceof MustTotallyOverlap
)
) or
)
or
// Connect any definitions that are not being modeled in SSA to the
// `UnmodeledUse` instruction.
exists(OldInstruction oldDefinition |
@@ -107,7 +116,8 @@ cached private module Cached {
overlap instanceof MustTotallyOverlap
)
)
) or
)
or
instruction = Chi(getOldInstruction(result)) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
@@ -124,7 +134,8 @@ cached private module Cached {
overlap instanceof MustExactlyOverlap
}
cached Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
cached
Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |
oldInstruction = getOldInstruction(instr) and
oldOperand = oldInstruction.getAnOperand() and
@@ -133,7 +144,8 @@ cached private module Cached {
)
}
cached int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) {
cached
int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand |
oldInstruction = getOldInstruction(instr) and
oldOperand = oldInstruction.getAnOperand() and
@@ -144,20 +156,28 @@ cached private module Cached {
)
}
cached Instruction getPhiOperandDefinition(PhiInstruction instr,
IRBlock newPredecessorBlock, Overlap overlap) {
exists(Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock,
OldBlock defBlock, int defOffset |
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset, overlap) and
cached
Instruction getPhiOperandDefinition(
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
) {
exists(
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
OldBlock predBlock, OldBlock defBlock, int defOffset
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset,
overlap) and
instr = Phi(phiBlock, useLocation) and
newPredecessorBlock = getNewBlock(predBlock) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation)
)
}
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock,
int defRank, int defOffset, OldBlock useBlock, int useRank |
cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
chiInstr = Chi(oldInstr) and
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
@@ -167,28 +187,32 @@ cached private module Cached {
)
}
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
cached
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldBlock oldBlock |
instr = Phi(oldBlock, _) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
}
cached Expr getInstructionConvertedResultExpression(Instruction instruction) {
cached
Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression()
}
cached Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
cached
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression()
}
/*
/**
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction
*/
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if(hasChiNode(_, getOldInstruction(instruction)))
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = Chi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
@@ -196,14 +220,12 @@ cached private module Cached {
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) then (
result = Unreached(instruction.getEnclosingFunction())
)
else (
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = Unreached(instruction.getEnclosingFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
) or
)
or
exists(OldInstruction oldInstruction |
instruction = Chi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
@@ -211,7 +233,8 @@ cached private module Cached {
)
}
cached Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(OldInstruction oldInstruction |
not Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) and
// There is only one case for the translation into `result` because the
@@ -228,7 +251,8 @@ cached private module Cached {
)
}
cached Locatable getInstructionAST(Instruction instruction) {
cached
Locatable getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
@@ -245,13 +269,12 @@ cached private module Cached {
instruction = Unreached(result)
}
cached predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
cached
predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
type = oldInstruction.getResultType() and
if oldInstruction.isGLValue()
then isGLValue = true
else isGLValue = false
if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false
)
or
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
@@ -272,7 +295,8 @@ cached private module Cached {
isGLValue = false
}
cached Opcode getInstructionOpcode(Instruction instruction) {
cached
Opcode getInstructionOpcode(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getOpcode()
@@ -288,7 +312,8 @@ cached private module Cached {
result instanceof Opcode::Unreached
}
cached IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
@@ -305,46 +330,59 @@ cached private module Cached {
instruction = Unreached(result.getFunction())
}
cached IRVariable getInstructionVariable(Instruction instruction) {
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
cached
IRVariable getInstructionVariable(Instruction instruction) {
result = getNewIRVariable(getOldInstruction(instruction)
.(OldIR::VariableInstruction)
.getVariable())
}
cached Field getInstructionField(Instruction instruction) {
cached
Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached Function getInstructionFunction(Instruction instruction) {
cached
Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
}
cached string getInstructionConstantValue(Instruction instruction) {
cached
string getInstructionConstantValue(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
cached
StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
}
cached BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation()
cached
BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction)
.(OldIR::BuiltInOperationInstruction)
.getBuiltInOperation()
}
cached Type getInstructionExceptionType(Instruction instruction) {
cached
Type getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
}
cached int getInstructionElementSize(Instruction instruction) {
cached
int getInstructionElementSize(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
}
cached int getInstructionResultSize(Instruction instruction) {
cached
int getInstructionResultSize(Instruction instruction) {
// Only return a result for instructions that needed an explicit result size.
instruction.getResultType() instanceof UnknownType and
result = getOldInstruction(instruction).getResultSize()
}
cached predicate getInstructionInheritance(Instruction instruction, Class baseClass,
Class derivedClass) {
cached
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and
@@ -352,7 +390,8 @@ cached private module Cached {
)
}
cached Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
cached
Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
exists(OldIR::SideEffectInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
result = getNewInstruction(oldInstruction.getPrimaryInstruction())
@@ -365,9 +404,7 @@ cached private module Cached {
}
}
private Instruction getNewInstruction(OldInstruction instr) {
getOldInstruction(result) = instr
}
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
/**
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
@@ -413,16 +450,18 @@ private module PhiInsertion {
}
/**
* Holds if the memory location `defLocation` has a definition in block `block`, either because of an existing
* instruction, a `Phi` node, or a `Chi` node.
*/
* Holds if the memory location `defLocation` has a definition in block `block`, either because of an existing
* instruction, a `Phi` node, or a `Chi` node.
*/
private predicate definitionHasDefinitionInBlock(Alias::MemoryLocation defLocation, OldBlock block) {
definitionHasPhiNode(defLocation, block) or
definitionHasPhiNode(defLocation, block)
or
exists(OldInstruction def, Alias::MemoryLocation resultLocation |
def.getBlock() = block and
resultLocation = Alias::getResultMemoryLocation(def) and
(
defLocation = resultLocation or
defLocation = resultLocation
or
// For a virtual variable, any definition of a member location will either generate a `Chi` node that defines
// the virtual variable, or will totally overlap the virtual variable. Either way, treat this as a definition of
// the virtual variable.
@@ -438,16 +477,17 @@ private module PhiInsertion {
private predicate definitionHasUse(Alias::MemoryLocation defLocation, OldBlock block, int index) {
exists(OldInstruction use |
block.getInstruction(index) = use and
if defLocation instanceof Alias::VirtualVariable then (
if defLocation instanceof Alias::VirtualVariable
then (
exists(Alias::MemoryLocation useLocation |
// For a virtual variable, any use of a location that is a member of the virtual variable counts as a use.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
defLocation = useLocation.getVirtualVariable()
) or
// For a virtual variable, any use of a location that is a member of the virtual variable counts as a use.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
defLocation = useLocation.getVirtualVariable()
)
or
// A `Chi` instruction consumes the enclosing virtual variable of its use location.
hasChiNode(defLocation, use)
)
else (
) else (
// For other locations, only an exactly-overlapping use of the same location counts as a use.
defLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
Alias::getOverlap(defLocation, defLocation) instanceof MustExactlyOverlap
@@ -460,11 +500,14 @@ private module PhiInsertion {
* there is a definition that would prevent a previous definition of `defLocation` from being consumed as the operand
* of a `Phi` node that occurs after the redefinition.
*/
private predicate definitionHasRedefinition(Alias::MemoryLocation defLocation, OldBlock block, int index) {
private predicate definitionHasRedefinition(
Alias::MemoryLocation defLocation, OldBlock block, int index
) {
exists(OldInstruction redef, Alias::MemoryLocation redefLocation |
block.getInstruction(index) = redef and
redefLocation = Alias::getResultMemoryLocation(redef) and
if defLocation instanceof Alias::VirtualVariable then (
if defLocation instanceof Alias::VirtualVariable
then
// For a virtual variable, the definition may be consumed by any use of a location that is a member of the
// virtual variable. Thus, the definition is live until a subsequent redefinition of the entire virtual
// variable.
@@ -472,20 +515,18 @@ private module PhiInsertion {
overlap = Alias::getOverlap(redefLocation, defLocation) and
not overlap instanceof MayPartiallyOverlap
)
)
else (
else
// For other locations, the definition may only be consumed by an exactly-overlapping use of the same location.
// Thus, the definition is live until a subsequent definition of any location that may overlap the original
// definition location.
exists(Alias::getOverlap(redefLocation, defLocation))
)
)
}
/**
* Holds if the definition `defLocation` is live on entry to block `block`. The definition is live if there is at
* least one use of that definition before any intervening instruction that redefines the definition location.
*/
* Holds if the definition `defLocation` is live on entry to block `block`. The definition is live if there is at
* least one use of that definition before any intervening instruction that redefines the definition location.
*/
predicate definitionLiveOnEntryToBlock(Alias::MemoryLocation defLocation, OldBlock block) {
exists(int firstAccess |
definitionHasUse(defLocation, block, firstAccess) and
@@ -496,7 +537,8 @@ private module PhiInsertion {
)
)
or
(definitionLiveOnExitFromBlock(defLocation, block) and not definitionHasRedefinition(defLocation, block, _))
definitionLiveOnExitFromBlock(defLocation, block) and
not definitionHasRedefinition(defLocation, block, _)
}
/**
@@ -516,7 +558,7 @@ private import DefUse
* computed separately for each unique use `MemoryLocation`. An instruction is treated as a definition of a use location
* if the defined location overlaps the use location in any way. Thus, a single instruction may serve as a definition
* for multiple use locations, since a single definition location may overlap many use locations.
*
*
* Definitions and uses are identified by a block and an integer "offset". An offset of -1 indicates the definition
* from a `Phi` instruction at the beginning of the block. An offset of 2*i indicates a definition or use on the
* instruction at index `i` in the block. An offset of 2*i+1 indicates a definition or use on the `Chi` instruction that
@@ -532,47 +574,46 @@ module DefUse {
/**
* Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
*/
pragma[inline]
bindingset[defOffset, defLocation]
Instruction getDefinitionOrChiInstruction(OldBlock defBlock, int defOffset,
Alias::MemoryLocation defLocation) {
(
defOffset >= 0 and
exists(OldInstruction oldInstr |
oldInstr = defBlock.getInstruction(defOffset / 2) and
if (defOffset % 2) > 0 then (
// An odd offset corresponds to the `Chi` instruction.
result = Chi(oldInstr)
)
else (
// An even offset corresponds to the original instruction.
result = getNewInstruction(oldInstr)
)
)
) or
(
defOffset < 0 and
result = Phi(defBlock, defLocation)
pragma[inline]
Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation
) {
defOffset >= 0 and
exists(OldInstruction oldInstr |
oldInstr = defBlock.getInstruction(defOffset / 2) and
if (defOffset % 2) > 0
then
// An odd offset corresponds to the `Chi` instruction.
result = Chi(oldInstr)
else
// An even offset corresponds to the original instruction.
result = getNewInstruction(oldInstr)
)
or
defOffset < 0 and
result = Phi(defBlock, defLocation)
}
/**
* Gets the rank index of a hyphothetical use one instruction past the end of
* the block. This index can be used to determine if a definition reaches the
* end of the block, even if the definition is the last instruction in the
* block.
*/
* Gets the rank index of a hyphothetical use one instruction past the end of
* the block. This index can be used to determine if a definition reaches the
* end of the block, even if the definition is the last instruction in the
* block.
*/
private int exitRank(Alias::MemoryLocation useLocation, OldBlock block) {
result = max(int rankIndex | defUseRank(useLocation, block, rankIndex, _)) + 1
}
/**
* Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at
* (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`, where `defBlock` and
* `useBlock` are the same block.
*/
private predicate definitionReachesUseWithinBlock(Alias::MemoryLocation useLocation, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
* Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at
* (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`, where `defBlock` and
* `useBlock` are the same block.
*/
private predicate definitionReachesUseWithinBlock(
Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock useBlock,
int useRank
) {
defBlock = useBlock and
hasDefinitionAtRank(useLocation, _, defBlock, defRank, _) and
hasUseAtRank(useLocation, useBlock, useRank, _) and
@@ -580,59 +621,58 @@ module DefUse {
}
/**
* Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at
* (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`.
*/
predicate definitionReachesUse(Alias::MemoryLocation useLocation, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
* Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at
* (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`.
*/
predicate definitionReachesUse(
Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock useBlock,
int useRank
) {
hasUseAtRank(useLocation, useBlock, useRank, _) and
(
definitionReachesUseWithinBlock(useLocation, defBlock, defRank, useBlock,
useRank) or
(
definitionReachesEndOfBlock(useLocation, defBlock, defRank,
useBlock.getAFeasiblePredecessor()) and
not definitionReachesUseWithinBlock(useLocation, useBlock, _, useBlock, useRank)
)
definitionReachesUseWithinBlock(useLocation, defBlock, defRank, useBlock, useRank)
or
definitionReachesEndOfBlock(useLocation, defBlock, defRank, useBlock.getAFeasiblePredecessor()) and
not definitionReachesUseWithinBlock(useLocation, useBlock, _, useBlock, useRank)
)
}
/**
* Holds if the definition that overlaps `useLocation` at `(block, defRank)` reaches the rank
* index `reachesRank` in block `block`.
*/
private predicate definitionReachesRank(Alias::MemoryLocation useLocation, OldBlock block, int defRank,
int reachesRank) {
* Holds if the definition that overlaps `useLocation` at `(block, defRank)` reaches the rank
* index `reachesRank` in block `block`.
*/
private predicate definitionReachesRank(
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
) {
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
(
// The def always reaches the next use, even if there is also a def on the
// use instruction.
reachesRank = defRank + 1 or
(
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
)
reachesRank = defRank + 1
or
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
)
}
/**
* Holds if the definition that overlaps `useLocation` at `(defBlock, defRank)` reaches the end of
* block `block` without any intervening definitions that overlap `useLocation`.
*/
predicate definitionReachesEndOfBlock(Alias::MemoryLocation useLocation, OldBlock defBlock,
int defRank, OldBlock block) {
* Holds if the definition that overlaps `useLocation` at `(defBlock, defRank)` reaches the end of
* block `block` without any intervening definitions that overlap `useLocation`.
*/
predicate definitionReachesEndOfBlock(
Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock block
) {
hasDefinitionAtRank(useLocation, _, defBlock, defRank, _) and
(
(
// If we're looking at the def's own block, just see if it reaches the exit
// rank of the block.
block = defBlock and
locationLiveOnExitFromBlock(useLocation, defBlock) and
definitionReachesRank(useLocation, defBlock, defRank, exitRank(useLocation, defBlock))
) or
// If we're looking at the def's own block, just see if it reaches the exit
// rank of the block.
block = defBlock and
locationLiveOnExitFromBlock(useLocation, defBlock) and
definitionReachesRank(useLocation, defBlock, defRank, exitRank(useLocation, defBlock))
or
exists(OldBlock idom |
definitionReachesEndOfBlock(useLocation, defBlock, defRank, idom) and
noDefinitionsSinceIDominator(useLocation, idom, block)
@@ -641,8 +681,9 @@ module DefUse {
}
pragma[noinline]
private predicate noDefinitionsSinceIDominator(Alias::MemoryLocation useLocation, OldBlock idom,
OldBlock block) {
private predicate noDefinitionsSinceIDominator(
Alias::MemoryLocation useLocation, OldBlock idom, OldBlock block
) {
Dominance::blockImmediatelyDominates(idom, block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
locationLiveOnExitFromBlock(useLocation, block) and
not hasDefinition(useLocation, _, block, _)
@@ -655,16 +696,19 @@ module DefUse {
* instruction whose result totally overlaps the location.
*/
predicate locationLiveOnEntryToBlock(Alias::MemoryLocation useLocation, OldBlock block) {
definitionHasPhiNode(useLocation, block) or
definitionHasPhiNode(useLocation, block)
or
exists(int firstAccess |
hasUse(useLocation, block, firstAccess, _) and
firstAccess = min(int offset |
hasUse(useLocation, block, offset, _)
or
hasNonPhiDefinition(useLocation, _, block, offset)
)
) or
(locationLiveOnExitFromBlock(useLocation, block) and not hasNonPhiDefinition(useLocation, _, block, _))
hasUse(useLocation, block, offset, _)
or
hasNonPhiDefinition(useLocation, _, block, offset)
)
)
or
locationLiveOnExitFromBlock(useLocation, block) and
not hasNonPhiDefinition(useLocation, _, block, _)
}
/**
@@ -675,62 +719,68 @@ module DefUse {
locationLiveOnEntryToBlock(useLocation, block.getAFeasibleSuccessor())
}
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* This predicate does not include definitions for Phi nodes.
*/
private predicate hasNonPhiDefinition(Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation,
OldBlock block, int offset) {
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* This predicate does not include definitions for Phi nodes.
*/
private predicate hasNonPhiDefinition(
Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, int offset
) {
exists(OldInstruction def, Overlap overlap, int index |
defLocation = Alias::getResultMemoryLocation(def) and
block.getInstruction(index) = def and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap then
offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
else
offset = index * 2 // The use will be connected to the definition on the original instruction.
if overlap instanceof MayPartiallyOverlap
then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = index * 2 // The use will be connected to the definition on the original instruction.
)
}
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* This predicate includes definitions for Phi nodes (at offset -1).
*/
private predicate hasDefinition(Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block,
int offset) {
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* This predicate includes definitions for Phi nodes (at offset -1).
*/
private predicate hasDefinition(
Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, int offset
) {
(
// If there is a Phi node for the use location itself, treat that as a definition at offset -1.
offset = -1 and
if definitionHasPhiNode(useLocation, block) then (
defLocation = useLocation
)
if definitionHasPhiNode(useLocation, block)
then defLocation = useLocation
else (
definitionHasPhiNode(defLocation, block) and
defLocation = useLocation.getVirtualVariable()
)
) or
)
or
hasNonPhiDefinition(useLocation, defLocation, block, offset)
}
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* `rankIndex` is the rank of the definition as computed by `defUseRank()`.
*/
predicate hasDefinitionAtRank(Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation,
OldBlock block, int rankIndex, int offset) {
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* `rankIndex` is the rank of the definition as computed by `defUseRank()`.
*/
predicate hasDefinitionAtRank(
Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block,
int rankIndex, int offset
) {
hasDefinition(useLocation, defLocation, block, offset) and
defUseRank(useLocation, block, rankIndex, offset)
}
/**
* Holds if there is a use of `useLocation` on instruction `use` at offset `offset` in block `block`.
*/
private predicate hasUse(Alias::MemoryLocation useLocation, OldBlock block, int offset, OldInstruction use) {
* Holds if there is a use of `useLocation` on instruction `use` at offset `offset` in block `block`.
*/
private predicate hasUse(
Alias::MemoryLocation useLocation, OldBlock block, int offset, OldInstruction use
) {
exists(int index |
block.getInstruction(index) = use and
(
// A direct use of the location.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2 or
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
or
// A `Chi` instruction will include a use of the virtual variable.
hasChiNode(useLocation, use) and offset = (index * 2) + 1
)
@@ -738,10 +788,12 @@ module DefUse {
}
/**
* Holds if there is a use of memory location `useLocation` on instruction `use` in block `block`. `rankIndex` is the
* rank of the use use as computed by `defUseRank`.
*/
predicate hasUseAtRank(Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, OldInstruction use) {
* Holds if there is a use of memory location `useLocation` on instruction `use` in block `block`. `rankIndex` is the
* rank of the use use as computed by `defUseRank`.
*/
predicate hasUseAtRank(
Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, OldInstruction use
) {
exists(int offset |
hasUse(useLocation, block, offset, use) and
defUseRank(useLocation, block, rankIndex, offset)
@@ -749,12 +801,16 @@ module DefUse {
}
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`, or
* a use of `useLocation` at offset `offset` in block `block`. `rankIndex` is the sequence number of the definition
* or use within `block`, counting only uses of `useLocation` and definitions that overlap `useLocation`.
*/
private predicate defUseRank(Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, int offset) {
offset = rank[rankIndex](int j | hasDefinition(useLocation, _, block, j) or hasUse(useLocation, block, j, _))
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`, or
* a use of `useLocation` at offset `offset` in block `block`. `rankIndex` is the sequence number of the definition
* or use within `block`, counting only uses of `useLocation` and definitions that overlap `useLocation`.
*/
private predicate defUseRank(
Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, int offset
) {
offset = rank[rankIndex](int j |
hasDefinition(useLocation, _, block, j) or hasUse(useLocation, block, j, _)
)
}
/**
@@ -763,8 +819,10 @@ module DefUse {
* and overlaps the use operand with overlap relationship `overlap`.
*/
pragma[inline]
predicate hasPhiOperandDefinition(Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation,
OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Overlap overlap) {
predicate hasPhiOperandDefinition(
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
OldBlock predBlock, OldBlock defBlock, int defOffset, Overlap overlap
) {
exists(int defRank |
definitionHasPhiNode(useLocation, phiBlock) and
predBlock = phiBlock.getAFeasiblePredecessor() and
@@ -785,31 +843,34 @@ module DebugSSA {
}
import CachedForDebugging
cached private module CachedForDebugging {
cached string getTempVariableUniqueId(IRTempVariable var) {
cached
private module CachedForDebugging {
cached
string getTempVariableUniqueId(IRTempVariable var) {
result = getOldTempVariable(var).getUniqueId()
}
cached string getInstructionUniqueId(Instruction instr) {
cached
string getInstructionUniqueId(Instruction instr) {
exists(OldInstruction oldInstr |
oldInstr = getOldInstruction(instr) and
result = "NonSSA: " + oldInstr.getUniqueId()
) or
)
or
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
instr = Phi(phiBlock, location) and
result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
if location instanceof Alias::VirtualVariable then (
result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " +
location.getUniqueId() and
if location instanceof Alias::VirtualVariable
then
// Sort Phi nodes for virtual variables before Phi nodes for member locations.
specificity = "g"
)
else (
specificity = "s"
)
) or
(
instr = Unreached(_) and
result = "Unreached"
else specificity = "s"
)
or
instr = Unreached(_) and
result = "Unreached"
}
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {

View File

@@ -13,7 +13,8 @@ class PropertyProvider extends IRPropertyProvider {
exists(MemoryLocation location |
location = getResultMemoryLocation(instruction) and
(
key = "ResultMemoryLocation" and result = location.toString() or
key = "ResultMemoryLocation" and result = location.toString()
or
key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString()
)
)
@@ -21,33 +22,40 @@ class PropertyProvider extends IRPropertyProvider {
exists(MemoryLocation location |
location = getOperandMemoryLocation(instruction.getAnOperand()) and
(
key = "OperandMemoryAccess" and result = location.toString() or
key = "OperandMemoryAccess" and result = location.toString()
or
key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString()
)
) or
)
or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex |
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and
defBlock.getInstruction(defIndex) = instruction and
key = "DefinitionRank[" + useLocation.toString() + "]" and
result = defRank.toString()
) or
)
or
exists(MemoryLocation useLocation, IRBlock useBlock, int useRank |
hasUseAtRank(useLocation, useBlock, useRank, instruction) and
key = "UseRank[" + useLocation.toString() + "]" and
result = useRank.toString()
) or
)
or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex |
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and
defBlock.getInstruction(defIndex) = instruction and
key = "DefinitionReachesUse[" + useLocation.toString() + "]" and
result = strictconcat(IRBlock useBlock, int useRank, int useIndex |
exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
useBlock.getInstruction(useIndex) = useInstruction and
definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank)
) |
useBlock.getDisplayIndex().toString() + "_" + useIndex, ", " order by useBlock.getDisplayIndex(), useIndex
)
exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
useBlock.getInstruction(useIndex) = useInstruction and
definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank)
)
|
useBlock.getDisplayIndex().toString() + "_" + useIndex, ", "
order by
useBlock.getDisplayIndex(), useIndex
)
)
}
@@ -57,53 +65,62 @@ class PropertyProvider extends IRPropertyProvider {
defIndex = -1 and
key = "DefinitionRank(Phi)[" + useLocation.toString() + "]" and
result = defRank.toString()
) or
)
or
exists(MemoryLocation useLocation, MemoryLocation defLocation, int defRank, int defIndex |
hasDefinitionAtRank(useLocation, defLocation, block, defRank, defIndex) and
defIndex = -1 and
key = "DefinitionReachesUse(Phi)[" + useLocation.toString() + "]" and
result = strictconcat(IRBlock useBlock, int useRank, int useIndex |
exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
useBlock.getInstruction(useIndex) = useInstruction and
definitionReachesUse(useLocation, block, defRank, useBlock, useRank) and
exists(getOverlap(defLocation, useLocation))
) |
useBlock.getDisplayIndex().toString() + "_" + useIndex, ", " order by useBlock.getDisplayIndex(), useIndex
)
) or
exists(MemoryLocation useLocation, IRBlock predBlock, IRBlock defBlock, int defIndex, Overlap overlap |
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex, overlap) and
key = "PhiUse[" + useLocation.toString() + " from " + predBlock.getDisplayIndex().toString() + "]" and
result = defBlock.getDisplayIndex().toString() + "_" + defIndex + " (" + overlap.toString() + ")"
) or
(
key = "LiveOnEntry" and
result = strictconcat(MemoryLocation useLocation |
locationLiveOnEntryToBlock(useLocation, block) |
useLocation.toString(), ", " order by useLocation.toString()
)
) or
(
key = "LiveOnExit" and
result = strictconcat(MemoryLocation useLocation |
locationLiveOnExitFromBlock(useLocation, block) |
useLocation.toString(), ", " order by useLocation.toString()
)
) or
(
key = "DefsLiveOnEntry" and
result = strictconcat(MemoryLocation defLocation |
definitionLiveOnEntryToBlock(defLocation, block) |
defLocation.toString(), ", " order by defLocation.toString()
)
) or
(
key = "DefsLiveOnExit" and
result = strictconcat(MemoryLocation defLocation |
definitionLiveOnExitFromBlock(defLocation, block) |
defLocation.toString(), ", " order by defLocation.toString()
)
exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and
useBlock.getInstruction(useIndex) = useInstruction and
definitionReachesUse(useLocation, block, defRank, useBlock, useRank) and
exists(getOverlap(defLocation, useLocation))
)
|
useBlock.getDisplayIndex().toString() + "_" + useIndex, ", "
order by
useBlock.getDisplayIndex(), useIndex
)
)
or
exists(
MemoryLocation useLocation, IRBlock predBlock, IRBlock defBlock, int defIndex, Overlap overlap
|
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex, overlap) and
key = "PhiUse[" + useLocation.toString() + " from " + predBlock.getDisplayIndex().toString() +
"]" and
result = defBlock.getDisplayIndex().toString() + "_" + defIndex + " (" + overlap.toString() +
")"
)
or
key = "LiveOnEntry" and
result = strictconcat(MemoryLocation useLocation |
locationLiveOnEntryToBlock(useLocation, block)
|
useLocation.toString(), ", " order by useLocation.toString()
)
or
key = "LiveOnExit" and
result = strictconcat(MemoryLocation useLocation |
locationLiveOnExitFromBlock(useLocation, block)
|
useLocation.toString(), ", " order by useLocation.toString()
)
or
key = "DefsLiveOnEntry" and
result = strictconcat(MemoryLocation defLocation |
definitionLiveOnEntryToBlock(defLocation, block)
|
defLocation.toString(), ", " order by defLocation.toString()
)
or
key = "DefsLiveOnExit" and
result = strictconcat(MemoryLocation defLocation |
definitionLiveOnExitFromBlock(defLocation, block)
|
defLocation.toString(), ", " order by defLocation.toString()
)
}
}

View File

@@ -6,31 +6,32 @@ private import semmle.code.cpp.ir.internal.Overlap
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached private module Cached {
cached
private module Cached {
private IRBlock getNewBlock(OldBlock oldBlock) {
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
}
cached predicate functionHasIR(Function func) {
exists(OldIR::IRFunction irFunc |
irFunc.getFunction() = func
)
cached
predicate functionHasIR(Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
}
cached OldInstruction getOldInstruction(Instruction instr) {
instr = WrappedInstruction(result)
}
cached
OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) }
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
// This is just a type cast. Both classes derive from the same newtype.
result = var
}
cached newtype TInstruction =
cached
newtype TInstruction =
WrappedInstruction(OldInstruction oldInstruction) {
not oldInstruction instanceof OldIR::PhiInstruction
} or
@@ -48,8 +49,8 @@ cached private module Cached {
)
}
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
Type type) {
cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) {
exists(OldIR::IRTempVariable var |
var.getEnclosingFunction() = func and
var.getAST() = ast and
@@ -58,13 +59,15 @@ cached private module Cached {
)
}
cached predicate hasModeledMemoryResult(Instruction instruction) {
cached
predicate hasModeledMemoryResult(Instruction instruction) {
exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
instruction instanceof PhiInstruction or // Phis always have modeled results
instruction instanceof ChiInstruction // Chis always have modeled results
}
cached Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
@@ -73,16 +76,22 @@ cached private module Cached {
)
}
cached Instruction getMemoryOperandDefinition(Instruction instruction, MemoryOperandTag tag, Overlap overlap) {
cached
Instruction getMemoryOperandDefinition(
Instruction instruction, MemoryOperandTag tag, Overlap overlap
) {
exists(OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
(
(
if exists(Alias::getOperandMemoryLocation(oldOperand)) then (
exists(OldBlock useBlock, int useRank, Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset |
if exists(Alias::getOperandMemoryLocation(oldOperand))
then
exists(
OldBlock useBlock, int useRank, Alias::MemoryLocation useLocation,
Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset
|
useLocation = Alias::getOperandMemoryLocation(oldOperand) and
hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and
hasUseAtRank(useLocation, useBlock, useRank, oldInstruction) and
@@ -90,12 +99,12 @@ cached private module Cached {
overlap = Alias::getOverlap(defLocation, useLocation) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation)
)
)
else (
result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and
overlap instanceof MustTotallyOverlap
)
) or
)
or
// Connect any definitions that are not being modeled in SSA to the
// `UnmodeledUse` instruction.
exists(OldInstruction oldDefinition |
@@ -107,7 +116,8 @@ cached private module Cached {
overlap instanceof MustTotallyOverlap
)
)
) or
)
or
instruction = Chi(getOldInstruction(result)) and
tag instanceof ChiPartialOperandTag and
overlap instanceof MustExactlyOverlap
@@ -124,7 +134,8 @@ cached private module Cached {
overlap instanceof MustExactlyOverlap
}
cached Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
cached
Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |
oldInstruction = getOldInstruction(instr) and
oldOperand = oldInstruction.getAnOperand() and
@@ -133,7 +144,8 @@ cached private module Cached {
)
}
cached int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) {
cached
int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand |
oldInstruction = getOldInstruction(instr) and
oldOperand = oldInstruction.getAnOperand() and
@@ -144,20 +156,28 @@ cached private module Cached {
)
}
cached Instruction getPhiOperandDefinition(PhiInstruction instr,
IRBlock newPredecessorBlock, Overlap overlap) {
exists(Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock,
OldBlock defBlock, int defOffset |
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset, overlap) and
cached
Instruction getPhiOperandDefinition(
PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap
) {
exists(
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
OldBlock predBlock, OldBlock defBlock, int defOffset
|
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset,
overlap) and
instr = Phi(phiBlock, useLocation) and
newPredecessorBlock = getNewBlock(predBlock) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation)
)
}
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock,
int defRank, int defOffset, OldBlock useBlock, int useRank |
cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
|
chiInstr = Chi(oldInstr) and
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
@@ -167,28 +187,32 @@ cached private module Cached {
)
}
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
cached
Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
exists(OldBlock oldBlock |
instr = Phi(oldBlock, _) and
result = getNewInstruction(oldBlock.getFirstInstruction())
)
}
cached Expr getInstructionConvertedResultExpression(Instruction instruction) {
cached
Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression()
}
cached Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
cached
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression()
}
/*
/**
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction
*/
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if(hasChiNode(_, getOldInstruction(instruction)))
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
then
result = Chi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
@@ -196,14 +220,12 @@ cached private module Cached {
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) then (
result = Unreached(instruction.getEnclosingFunction())
)
else (
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = Unreached(instruction.getEnclosingFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
) or
)
or
exists(OldInstruction oldInstruction |
instruction = Chi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
@@ -211,7 +233,8 @@ cached private module Cached {
)
}
cached Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
cached
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
exists(OldInstruction oldInstruction |
not Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) and
// There is only one case for the translation into `result` because the
@@ -228,7 +251,8 @@ cached private module Cached {
)
}
cached Locatable getInstructionAST(Instruction instruction) {
cached
Locatable getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
@@ -245,13 +269,12 @@ cached private module Cached {
instruction = Unreached(result)
}
cached predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
cached
predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
type = oldInstruction.getResultType() and
if oldInstruction.isGLValue()
then isGLValue = true
else isGLValue = false
if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false
)
or
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
@@ -272,7 +295,8 @@ cached private module Cached {
isGLValue = false
}
cached Opcode getInstructionOpcode(Instruction instruction) {
cached
Opcode getInstructionOpcode(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
result = oldInstruction.getOpcode()
@@ -288,7 +312,8 @@ cached private module Cached {
result instanceof Opcode::Unreached
}
cached IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
@@ -305,46 +330,59 @@ cached private module Cached {
instruction = Unreached(result.getFunction())
}
cached IRVariable getInstructionVariable(Instruction instruction) {
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
cached
IRVariable getInstructionVariable(Instruction instruction) {
result = getNewIRVariable(getOldInstruction(instruction)
.(OldIR::VariableInstruction)
.getVariable())
}
cached Field getInstructionField(Instruction instruction) {
cached
Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached Function getInstructionFunction(Instruction instruction) {
cached
Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
}
cached string getInstructionConstantValue(Instruction instruction) {
cached
string getInstructionConstantValue(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
cached
StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
}
cached BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation()
cached
BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction)
.(OldIR::BuiltInOperationInstruction)
.getBuiltInOperation()
}
cached Type getInstructionExceptionType(Instruction instruction) {
cached
Type getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
}
cached int getInstructionElementSize(Instruction instruction) {
cached
int getInstructionElementSize(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
}
cached int getInstructionResultSize(Instruction instruction) {
cached
int getInstructionResultSize(Instruction instruction) {
// Only return a result for instructions that needed an explicit result size.
instruction.getResultType() instanceof UnknownType and
result = getOldInstruction(instruction).getResultSize()
}
cached predicate getInstructionInheritance(Instruction instruction, Class baseClass,
Class derivedClass) {
cached
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and
@@ -352,7 +390,8 @@ cached private module Cached {
)
}
cached Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
cached
Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
exists(OldIR::SideEffectInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
result = getNewInstruction(oldInstruction.getPrimaryInstruction())
@@ -365,9 +404,7 @@ cached private module Cached {
}
}
private Instruction getNewInstruction(OldInstruction instr) {
getOldInstruction(result) = instr
}
private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr }
/**
* Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition
@@ -413,16 +450,18 @@ private module PhiInsertion {
}
/**
* Holds if the memory location `defLocation` has a definition in block `block`, either because of an existing
* instruction, a `Phi` node, or a `Chi` node.
*/
* Holds if the memory location `defLocation` has a definition in block `block`, either because of an existing
* instruction, a `Phi` node, or a `Chi` node.
*/
private predicate definitionHasDefinitionInBlock(Alias::MemoryLocation defLocation, OldBlock block) {
definitionHasPhiNode(defLocation, block) or
definitionHasPhiNode(defLocation, block)
or
exists(OldInstruction def, Alias::MemoryLocation resultLocation |
def.getBlock() = block and
resultLocation = Alias::getResultMemoryLocation(def) and
(
defLocation = resultLocation or
defLocation = resultLocation
or
// For a virtual variable, any definition of a member location will either generate a `Chi` node that defines
// the virtual variable, or will totally overlap the virtual variable. Either way, treat this as a definition of
// the virtual variable.
@@ -438,16 +477,17 @@ private module PhiInsertion {
private predicate definitionHasUse(Alias::MemoryLocation defLocation, OldBlock block, int index) {
exists(OldInstruction use |
block.getInstruction(index) = use and
if defLocation instanceof Alias::VirtualVariable then (
if defLocation instanceof Alias::VirtualVariable
then (
exists(Alias::MemoryLocation useLocation |
// For a virtual variable, any use of a location that is a member of the virtual variable counts as a use.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
defLocation = useLocation.getVirtualVariable()
) or
// For a virtual variable, any use of a location that is a member of the virtual variable counts as a use.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
defLocation = useLocation.getVirtualVariable()
)
or
// A `Chi` instruction consumes the enclosing virtual variable of its use location.
hasChiNode(defLocation, use)
)
else (
) else (
// For other locations, only an exactly-overlapping use of the same location counts as a use.
defLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
Alias::getOverlap(defLocation, defLocation) instanceof MustExactlyOverlap
@@ -460,11 +500,14 @@ private module PhiInsertion {
* there is a definition that would prevent a previous definition of `defLocation` from being consumed as the operand
* of a `Phi` node that occurs after the redefinition.
*/
private predicate definitionHasRedefinition(Alias::MemoryLocation defLocation, OldBlock block, int index) {
private predicate definitionHasRedefinition(
Alias::MemoryLocation defLocation, OldBlock block, int index
) {
exists(OldInstruction redef, Alias::MemoryLocation redefLocation |
block.getInstruction(index) = redef and
redefLocation = Alias::getResultMemoryLocation(redef) and
if defLocation instanceof Alias::VirtualVariable then (
if defLocation instanceof Alias::VirtualVariable
then
// For a virtual variable, the definition may be consumed by any use of a location that is a member of the
// virtual variable. Thus, the definition is live until a subsequent redefinition of the entire virtual
// variable.
@@ -472,20 +515,18 @@ private module PhiInsertion {
overlap = Alias::getOverlap(redefLocation, defLocation) and
not overlap instanceof MayPartiallyOverlap
)
)
else (
else
// For other locations, the definition may only be consumed by an exactly-overlapping use of the same location.
// Thus, the definition is live until a subsequent definition of any location that may overlap the original
// definition location.
exists(Alias::getOverlap(redefLocation, defLocation))
)
)
}
/**
* Holds if the definition `defLocation` is live on entry to block `block`. The definition is live if there is at
* least one use of that definition before any intervening instruction that redefines the definition location.
*/
* Holds if the definition `defLocation` is live on entry to block `block`. The definition is live if there is at
* least one use of that definition before any intervening instruction that redefines the definition location.
*/
predicate definitionLiveOnEntryToBlock(Alias::MemoryLocation defLocation, OldBlock block) {
exists(int firstAccess |
definitionHasUse(defLocation, block, firstAccess) and
@@ -496,7 +537,8 @@ private module PhiInsertion {
)
)
or
(definitionLiveOnExitFromBlock(defLocation, block) and not definitionHasRedefinition(defLocation, block, _))
definitionLiveOnExitFromBlock(defLocation, block) and
not definitionHasRedefinition(defLocation, block, _)
}
/**
@@ -516,7 +558,7 @@ private import DefUse
* computed separately for each unique use `MemoryLocation`. An instruction is treated as a definition of a use location
* if the defined location overlaps the use location in any way. Thus, a single instruction may serve as a definition
* for multiple use locations, since a single definition location may overlap many use locations.
*
*
* Definitions and uses are identified by a block and an integer "offset". An offset of -1 indicates the definition
* from a `Phi` instruction at the beginning of the block. An offset of 2*i indicates a definition or use on the
* instruction at index `i` in the block. An offset of 2*i+1 indicates a definition or use on the `Chi` instruction that
@@ -532,47 +574,46 @@ module DefUse {
/**
* Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
*/
pragma[inline]
bindingset[defOffset, defLocation]
Instruction getDefinitionOrChiInstruction(OldBlock defBlock, int defOffset,
Alias::MemoryLocation defLocation) {
(
defOffset >= 0 and
exists(OldInstruction oldInstr |
oldInstr = defBlock.getInstruction(defOffset / 2) and
if (defOffset % 2) > 0 then (
// An odd offset corresponds to the `Chi` instruction.
result = Chi(oldInstr)
)
else (
// An even offset corresponds to the original instruction.
result = getNewInstruction(oldInstr)
)
)
) or
(
defOffset < 0 and
result = Phi(defBlock, defLocation)
pragma[inline]
Instruction getDefinitionOrChiInstruction(
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation
) {
defOffset >= 0 and
exists(OldInstruction oldInstr |
oldInstr = defBlock.getInstruction(defOffset / 2) and
if (defOffset % 2) > 0
then
// An odd offset corresponds to the `Chi` instruction.
result = Chi(oldInstr)
else
// An even offset corresponds to the original instruction.
result = getNewInstruction(oldInstr)
)
or
defOffset < 0 and
result = Phi(defBlock, defLocation)
}
/**
* Gets the rank index of a hyphothetical use one instruction past the end of
* the block. This index can be used to determine if a definition reaches the
* end of the block, even if the definition is the last instruction in the
* block.
*/
* Gets the rank index of a hyphothetical use one instruction past the end of
* the block. This index can be used to determine if a definition reaches the
* end of the block, even if the definition is the last instruction in the
* block.
*/
private int exitRank(Alias::MemoryLocation useLocation, OldBlock block) {
result = max(int rankIndex | defUseRank(useLocation, block, rankIndex, _)) + 1
}
/**
* Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at
* (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`, where `defBlock` and
* `useBlock` are the same block.
*/
private predicate definitionReachesUseWithinBlock(Alias::MemoryLocation useLocation, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
* Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at
* (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`, where `defBlock` and
* `useBlock` are the same block.
*/
private predicate definitionReachesUseWithinBlock(
Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock useBlock,
int useRank
) {
defBlock = useBlock and
hasDefinitionAtRank(useLocation, _, defBlock, defRank, _) and
hasUseAtRank(useLocation, useBlock, useRank, _) and
@@ -580,59 +621,58 @@ module DefUse {
}
/**
* Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at
* (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`.
*/
predicate definitionReachesUse(Alias::MemoryLocation useLocation, OldBlock defBlock,
int defRank, OldBlock useBlock, int useRank) {
* Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at
* (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`.
*/
predicate definitionReachesUse(
Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock useBlock,
int useRank
) {
hasUseAtRank(useLocation, useBlock, useRank, _) and
(
definitionReachesUseWithinBlock(useLocation, defBlock, defRank, useBlock,
useRank) or
(
definitionReachesEndOfBlock(useLocation, defBlock, defRank,
useBlock.getAFeasiblePredecessor()) and
not definitionReachesUseWithinBlock(useLocation, useBlock, _, useBlock, useRank)
)
definitionReachesUseWithinBlock(useLocation, defBlock, defRank, useBlock, useRank)
or
definitionReachesEndOfBlock(useLocation, defBlock, defRank, useBlock.getAFeasiblePredecessor()) and
not definitionReachesUseWithinBlock(useLocation, useBlock, _, useBlock, useRank)
)
}
/**
* Holds if the definition that overlaps `useLocation` at `(block, defRank)` reaches the rank
* index `reachesRank` in block `block`.
*/
private predicate definitionReachesRank(Alias::MemoryLocation useLocation, OldBlock block, int defRank,
int reachesRank) {
* Holds if the definition that overlaps `useLocation` at `(block, defRank)` reaches the rank
* index `reachesRank` in block `block`.
*/
private predicate definitionReachesRank(
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
) {
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
(
// The def always reaches the next use, even if there is also a def on the
// use instruction.
reachesRank = defRank + 1 or
(
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
)
reachesRank = defRank + 1
or
// If the def reached the previous rank, it also reaches the current rank,
// unless there was another def at the previous rank.
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
)
}
/**
* Holds if the definition that overlaps `useLocation` at `(defBlock, defRank)` reaches the end of
* block `block` without any intervening definitions that overlap `useLocation`.
*/
predicate definitionReachesEndOfBlock(Alias::MemoryLocation useLocation, OldBlock defBlock,
int defRank, OldBlock block) {
* Holds if the definition that overlaps `useLocation` at `(defBlock, defRank)` reaches the end of
* block `block` without any intervening definitions that overlap `useLocation`.
*/
predicate definitionReachesEndOfBlock(
Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock block
) {
hasDefinitionAtRank(useLocation, _, defBlock, defRank, _) and
(
(
// If we're looking at the def's own block, just see if it reaches the exit
// rank of the block.
block = defBlock and
locationLiveOnExitFromBlock(useLocation, defBlock) and
definitionReachesRank(useLocation, defBlock, defRank, exitRank(useLocation, defBlock))
) or
// If we're looking at the def's own block, just see if it reaches the exit
// rank of the block.
block = defBlock and
locationLiveOnExitFromBlock(useLocation, defBlock) and
definitionReachesRank(useLocation, defBlock, defRank, exitRank(useLocation, defBlock))
or
exists(OldBlock idom |
definitionReachesEndOfBlock(useLocation, defBlock, defRank, idom) and
noDefinitionsSinceIDominator(useLocation, idom, block)
@@ -641,8 +681,9 @@ module DefUse {
}
pragma[noinline]
private predicate noDefinitionsSinceIDominator(Alias::MemoryLocation useLocation, OldBlock idom,
OldBlock block) {
private predicate noDefinitionsSinceIDominator(
Alias::MemoryLocation useLocation, OldBlock idom, OldBlock block
) {
Dominance::blockImmediatelyDominates(idom, block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
locationLiveOnExitFromBlock(useLocation, block) and
not hasDefinition(useLocation, _, block, _)
@@ -655,16 +696,19 @@ module DefUse {
* instruction whose result totally overlaps the location.
*/
predicate locationLiveOnEntryToBlock(Alias::MemoryLocation useLocation, OldBlock block) {
definitionHasPhiNode(useLocation, block) or
definitionHasPhiNode(useLocation, block)
or
exists(int firstAccess |
hasUse(useLocation, block, firstAccess, _) and
firstAccess = min(int offset |
hasUse(useLocation, block, offset, _)
or
hasNonPhiDefinition(useLocation, _, block, offset)
)
) or
(locationLiveOnExitFromBlock(useLocation, block) and not hasNonPhiDefinition(useLocation, _, block, _))
hasUse(useLocation, block, offset, _)
or
hasNonPhiDefinition(useLocation, _, block, offset)
)
)
or
locationLiveOnExitFromBlock(useLocation, block) and
not hasNonPhiDefinition(useLocation, _, block, _)
}
/**
@@ -675,62 +719,68 @@ module DefUse {
locationLiveOnEntryToBlock(useLocation, block.getAFeasibleSuccessor())
}
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* This predicate does not include definitions for Phi nodes.
*/
private predicate hasNonPhiDefinition(Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation,
OldBlock block, int offset) {
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* This predicate does not include definitions for Phi nodes.
*/
private predicate hasNonPhiDefinition(
Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, int offset
) {
exists(OldInstruction def, Overlap overlap, int index |
defLocation = Alias::getResultMemoryLocation(def) and
block.getInstruction(index) = def and
overlap = Alias::getOverlap(defLocation, useLocation) and
if overlap instanceof MayPartiallyOverlap then
offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
else
offset = index * 2 // The use will be connected to the definition on the original instruction.
if overlap instanceof MayPartiallyOverlap
then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
else offset = index * 2 // The use will be connected to the definition on the original instruction.
)
}
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* This predicate includes definitions for Phi nodes (at offset -1).
*/
private predicate hasDefinition(Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block,
int offset) {
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* This predicate includes definitions for Phi nodes (at offset -1).
*/
private predicate hasDefinition(
Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, int offset
) {
(
// If there is a Phi node for the use location itself, treat that as a definition at offset -1.
offset = -1 and
if definitionHasPhiNode(useLocation, block) then (
defLocation = useLocation
)
if definitionHasPhiNode(useLocation, block)
then defLocation = useLocation
else (
definitionHasPhiNode(defLocation, block) and
defLocation = useLocation.getVirtualVariable()
)
) or
)
or
hasNonPhiDefinition(useLocation, defLocation, block, offset)
}
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* `rankIndex` is the rank of the definition as computed by `defUseRank()`.
*/
predicate hasDefinitionAtRank(Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation,
OldBlock block, int rankIndex, int offset) {
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`.
* `rankIndex` is the rank of the definition as computed by `defUseRank()`.
*/
predicate hasDefinitionAtRank(
Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block,
int rankIndex, int offset
) {
hasDefinition(useLocation, defLocation, block, offset) and
defUseRank(useLocation, block, rankIndex, offset)
}
/**
* Holds if there is a use of `useLocation` on instruction `use` at offset `offset` in block `block`.
*/
private predicate hasUse(Alias::MemoryLocation useLocation, OldBlock block, int offset, OldInstruction use) {
* Holds if there is a use of `useLocation` on instruction `use` at offset `offset` in block `block`.
*/
private predicate hasUse(
Alias::MemoryLocation useLocation, OldBlock block, int offset, OldInstruction use
) {
exists(int index |
block.getInstruction(index) = use and
(
// A direct use of the location.
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2 or
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
or
// A `Chi` instruction will include a use of the virtual variable.
hasChiNode(useLocation, use) and offset = (index * 2) + 1
)
@@ -738,10 +788,12 @@ module DefUse {
}
/**
* Holds if there is a use of memory location `useLocation` on instruction `use` in block `block`. `rankIndex` is the
* rank of the use use as computed by `defUseRank`.
*/
predicate hasUseAtRank(Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, OldInstruction use) {
* Holds if there is a use of memory location `useLocation` on instruction `use` in block `block`. `rankIndex` is the
* rank of the use use as computed by `defUseRank`.
*/
predicate hasUseAtRank(
Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, OldInstruction use
) {
exists(int offset |
hasUse(useLocation, block, offset, use) and
defUseRank(useLocation, block, rankIndex, offset)
@@ -749,12 +801,16 @@ module DefUse {
}
/**
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`, or
* a use of `useLocation` at offset `offset` in block `block`. `rankIndex` is the sequence number of the definition
* or use within `block`, counting only uses of `useLocation` and definitions that overlap `useLocation`.
*/
private predicate defUseRank(Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, int offset) {
offset = rank[rankIndex](int j | hasDefinition(useLocation, _, block, j) or hasUse(useLocation, block, j, _))
* Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`, or
* a use of `useLocation` at offset `offset` in block `block`. `rankIndex` is the sequence number of the definition
* or use within `block`, counting only uses of `useLocation` and definitions that overlap `useLocation`.
*/
private predicate defUseRank(
Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, int offset
) {
offset = rank[rankIndex](int j |
hasDefinition(useLocation, _, block, j) or hasUse(useLocation, block, j, _)
)
}
/**
@@ -763,8 +819,10 @@ module DefUse {
* and overlaps the use operand with overlap relationship `overlap`.
*/
pragma[inline]
predicate hasPhiOperandDefinition(Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation,
OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Overlap overlap) {
predicate hasPhiOperandDefinition(
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
OldBlock predBlock, OldBlock defBlock, int defOffset, Overlap overlap
) {
exists(int defRank |
definitionHasPhiNode(useLocation, phiBlock) and
predBlock = phiBlock.getAFeasiblePredecessor() and
@@ -785,31 +843,34 @@ module DebugSSA {
}
import CachedForDebugging
cached private module CachedForDebugging {
cached string getTempVariableUniqueId(IRTempVariable var) {
cached
private module CachedForDebugging {
cached
string getTempVariableUniqueId(IRTempVariable var) {
result = getOldTempVariable(var).getUniqueId()
}
cached string getInstructionUniqueId(Instruction instr) {
cached
string getInstructionUniqueId(Instruction instr) {
exists(OldInstruction oldInstr |
oldInstr = getOldInstruction(instr) and
result = "NonSSA: " + oldInstr.getUniqueId()
) or
)
or
exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity |
instr = Phi(phiBlock, location) and
result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and
if location instanceof Alias::VirtualVariable then (
result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " +
location.getUniqueId() and
if location instanceof Alias::VirtualVariable
then
// Sort Phi nodes for virtual variables before Phi nodes for member locations.
specificity = "g"
)
else (
specificity = "s"
)
) or
(
instr = Unreached(_) and
result = "Unreached"
else specificity = "s"
)
or
instr = Unreached(_) and
result = "Unreached"
}
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {

View File

@@ -7,12 +7,16 @@ private import semmle.code.cpp.ir.internal.Overlap
private class IntValue = Ints::IntValue;
private predicate hasResultMemoryAccess(Instruction instr, IRVariable var, Type type, IntValue bitOffset) {
private predicate hasResultMemoryAccess(
Instruction instr, IRVariable var, Type type, IntValue bitOffset
) {
resultPointsTo(instr.getResultAddressOperand().getAnyDef(), var, bitOffset) and
type = instr.getResultType()
}
private predicate hasOperandMemoryAccess(MemoryOperand operand, IRVariable var, Type type, IntValue bitOffset) {
private predicate hasOperandMemoryAccess(
MemoryOperand operand, IRVariable var, Type type, IntValue bitOffset
) {
resultPointsTo(operand.getAddressOperand().getAnyDef(), var, bitOffset) and
type = operand.getType()
}
@@ -27,56 +31,40 @@ private predicate isVariableModeled(IRVariable var) {
// There's no need to check for the right size. An `IRVariable` never has an `UnknownType`, so the test for
// `type = var.getType()` is sufficient.
forall(Instruction instr, Type type, IntValue bitOffset |
hasResultMemoryAccess(instr, var, type, bitOffset) |
hasResultMemoryAccess(instr, var, type, bitOffset)
|
bitOffset = 0 and
type = var.getType()
) and
forall(MemoryOperand operand, Type type, IntValue bitOffset |
hasOperandMemoryAccess(operand, var, type, bitOffset) |
hasOperandMemoryAccess(operand, var, type, bitOffset)
|
bitOffset = 0 and
type = var.getType()
)
}
private newtype TMemoryLocation =
MkMemoryLocation(IRVariable var) {
isVariableModeled(var)
}
private newtype TMemoryLocation = MkMemoryLocation(IRVariable var) { isVariableModeled(var) }
private MemoryLocation getMemoryLocation(IRVariable var) {
result.getIRVariable() = var
}
private MemoryLocation getMemoryLocation(IRVariable var) { result.getIRVariable() = var }
class MemoryLocation extends TMemoryLocation {
IRVariable var;
MemoryLocation() {
this = MkMemoryLocation(var)
}
MemoryLocation() { this = MkMemoryLocation(var) }
final string toString() {
result = var.toString()
}
final string toString() { result = var.toString() }
final IRVariable getIRVariable() {
result = var
}
final IRVariable getIRVariable() { result = var }
final VirtualVariable getVirtualVariable() {
result = this
}
final VirtualVariable getVirtualVariable() { result = this }
final Type getType() {
result = var.getType()
}
final Type getType() { result = var.getType() }
final string getUniqueId() {
result = var.getUniqueId()
}
final string getUniqueId() { result = var.getUniqueId() }
}
class VirtualVariable extends MemoryLocation {
}
class VirtualVariable extends MemoryLocation { }
Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
def = use and result instanceof MustExactlyOverlap

View File

@@ -330,13 +330,7 @@ GlobalOrNamespaceVariable globalVarFromId(string id) {
* A variable that has any kind of upper-bound check anywhere in the program
*/
private predicate hasUpperBoundsCheck(Variable var) {
exists(BinaryOperation oper, VariableAccess access |
(
oper.getOperator() = "<" or
oper.getOperator() = "<=" or
oper.getOperator() = ">" or
oper.getOperator() = ">="
) and
exists(RelationalOperation oper, VariableAccess access |
oper.getLeftOperand() = access and
access.getTarget() = var and
// Comparing to 0 is not an upper bound check

View File

@@ -213,6 +213,253 @@ edges
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | {...} [a] |
| struct_init.c:31:8:31:12 | outer [nestedAB, a] | struct_init.c:31:14:31:21 | nestedAB [a] |
| struct_init.c:31:14:31:21 | nestedAB [a] | struct_init.c:31:23:31:23 | a |
nodes
| A.cpp:41:15:41:21 | new | semmle.label | new |
| A.cpp:43:10:43:12 | & ... | semmle.label | & ... |
| A.cpp:47:12:47:18 | new | semmle.label | new |
| A.cpp:48:12:48:18 | call to make [c] | semmle.label | call to make [c] |
| A.cpp:48:20:48:20 | c | semmle.label | c |
| A.cpp:49:10:49:10 | b [c] | semmle.label | b [c] |
| A.cpp:49:13:49:13 | c | semmle.label | c |
| A.cpp:55:5:55:5 | b [post update] [c] | semmle.label | b [post update] [c] |
| A.cpp:55:12:55:19 | new | semmle.label | new |
| A.cpp:56:10:56:10 | b [c] | semmle.label | b [c] |
| A.cpp:56:13:56:15 | call to get | semmle.label | call to get |
| A.cpp:57:11:57:24 | call to B [c] | semmle.label | call to B [c] |
| A.cpp:57:11:57:24 | new [c] | semmle.label | new [c] |
| A.cpp:57:17:57:23 | new | semmle.label | new |
| A.cpp:57:28:57:30 | call to get | semmle.label | call to get |
| A.cpp:64:10:64:15 | call to setOnB [c] | semmle.label | call to setOnB [c] |
| A.cpp:64:21:64:28 | new | semmle.label | new |
| A.cpp:66:10:66:11 | b2 [c] | semmle.label | b2 [c] |
| A.cpp:66:14:66:14 | c | semmle.label | c |
| A.cpp:73:10:73:19 | call to setOnBWrap [c] | semmle.label | call to setOnBWrap [c] |
| A.cpp:73:25:73:32 | new | semmle.label | new |
| A.cpp:75:10:75:11 | b2 [c] | semmle.label | b2 [c] |
| A.cpp:75:14:75:14 | c | semmle.label | c |
| A.cpp:98:12:98:18 | new | semmle.label | new |
| A.cpp:100:5:100:6 | c1 [post update] [a] | semmle.label | c1 [post update] [a] |
| A.cpp:100:5:100:13 | ... = ... | semmle.label | ... = ... |
| A.cpp:101:8:101:9 | c1 [a] | semmle.label | c1 [a] |
| A.cpp:103:14:103:14 | c [a] | semmle.label | c [a] |
| A.cpp:107:12:107:13 | c1 [a] | semmle.label | c1 [a] |
| A.cpp:107:16:107:16 | a | semmle.label | a |
| A.cpp:120:12:120:13 | c1 [a] | semmle.label | c1 [a] |
| A.cpp:120:16:120:16 | a | semmle.label | a |
| A.cpp:126:5:126:5 | b [post update] [c] | semmle.label | b [post update] [c] |
| A.cpp:126:12:126:18 | new | semmle.label | new |
| A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] |
| A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] |
| A.cpp:132:13:132:13 | c | semmle.label | c |
| A.cpp:142:7:142:7 | b [post update] [c] | semmle.label | b [post update] [c] |
| A.cpp:142:7:142:20 | ... = ... | semmle.label | ... = ... |
| A.cpp:142:14:142:20 | new | semmle.label | new |
| A.cpp:143:7:143:10 | this [post update] [b, c] | semmle.label | this [post update] [b, c] |
| A.cpp:143:7:143:10 | this [post update] [b] | semmle.label | this [post update] [b] |
| A.cpp:143:7:143:31 | ... = ... | semmle.label | ... = ... |
| A.cpp:143:7:143:31 | ... = ... [c] | semmle.label | ... = ... [c] |
| A.cpp:143:25:143:31 | new | semmle.label | new |
| A.cpp:150:12:150:18 | new | semmle.label | new |
| A.cpp:151:12:151:24 | call to D [b, c] | semmle.label | call to D [b, c] |
| A.cpp:151:12:151:24 | call to D [b] | semmle.label | call to D [b] |
| A.cpp:151:18:151:18 | b | semmle.label | b |
| A.cpp:151:18:151:18 | ref arg b [c] | semmle.label | ref arg b [c] |
| A.cpp:152:10:152:10 | d [b] | semmle.label | d [b] |
| A.cpp:152:13:152:13 | b | semmle.label | b |
| A.cpp:153:10:153:10 | d [b, c] | semmle.label | d [b, c] |
| A.cpp:153:13:153:13 | b [c] | semmle.label | b [c] |
| A.cpp:153:16:153:16 | c | semmle.label | c |
| A.cpp:154:10:154:10 | b [c] | semmle.label | b [c] |
| A.cpp:154:13:154:13 | c | semmle.label | c |
| A.cpp:159:12:159:18 | new | semmle.label | new |
| A.cpp:160:18:160:60 | call to MyList [head] | semmle.label | call to MyList [head] |
| A.cpp:160:29:160:29 | b | semmle.label | b |
| A.cpp:161:18:161:40 | call to MyList [next, head] | semmle.label | call to MyList [next, head] |
| A.cpp:161:38:161:39 | l1 [head] | semmle.label | l1 [head] |
| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | semmle.label | call to MyList [next, next, ... (3)] |
| A.cpp:162:38:162:39 | l2 [next, head] | semmle.label | l2 [next, head] |
| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | semmle.label | l3 [next, next, ... (3)] |
| A.cpp:165:14:165:17 | next [next, head] | semmle.label | next [next, head] |
| A.cpp:165:20:165:23 | next [head] | semmle.label | next [head] |
| A.cpp:165:26:165:29 | head | semmle.label | head |
| A.cpp:167:44:167:44 | l [next, head] | semmle.label | l [next, head] |
| A.cpp:167:44:167:44 | l [next, next, ... (3)] | semmle.label | l [next, next, ... (3)] |
| A.cpp:167:47:167:50 | next [head] | semmle.label | next [head] |
| A.cpp:167:47:167:50 | next [next, head] | semmle.label | next [next, head] |
| A.cpp:169:12:169:12 | l [head] | semmle.label | l [head] |
| A.cpp:169:15:169:18 | head | semmle.label | head |
| B.cpp:6:15:6:24 | new | semmle.label | new |
| B.cpp:7:16:7:35 | call to Box1 [elem1] | semmle.label | call to Box1 [elem1] |
| B.cpp:7:25:7:25 | e | semmle.label | e |
| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | semmle.label | call to Box2 [box1, elem1] |
| B.cpp:8:25:8:26 | b1 [elem1] | semmle.label | b1 [elem1] |
| B.cpp:9:10:9:11 | b2 [box1, elem1] | semmle.label | b2 [box1, elem1] |
| B.cpp:9:14:9:17 | box1 [elem1] | semmle.label | box1 [elem1] |
| B.cpp:9:20:9:24 | elem1 | semmle.label | elem1 |
| B.cpp:15:15:15:27 | new | semmle.label | new |
| B.cpp:16:16:16:38 | call to Box1 [elem2] | semmle.label | call to Box1 [elem2] |
| B.cpp:16:37:16:37 | e | semmle.label | e |
| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | semmle.label | call to Box2 [box1, elem2] |
| B.cpp:17:25:17:26 | b1 [elem2] | semmle.label | b1 [elem2] |
| B.cpp:19:10:19:11 | b2 [box1, elem2] | semmle.label | b2 [box1, elem2] |
| B.cpp:19:14:19:17 | box1 [elem2] | semmle.label | box1 [elem2] |
| B.cpp:19:20:19:24 | elem2 | semmle.label | elem2 |
| C.cpp:18:12:18:18 | call to C [s1] | semmle.label | call to C [s1] |
| C.cpp:18:12:18:18 | call to C [s3] | semmle.label | call to C [s3] |
| C.cpp:19:5:19:5 | c [s1] | semmle.label | c [s1] |
| C.cpp:19:5:19:5 | c [s3] | semmle.label | c [s3] |
| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | semmle.label | constructor init of field s1 [post-this] [s1] |
| C.cpp:22:12:22:21 | new | semmle.label | new |
| C.cpp:24:5:24:8 | this [post update] [s3] | semmle.label | this [post update] [s3] |
| C.cpp:24:5:24:25 | ... = ... | semmle.label | ... = ... |
| C.cpp:24:16:24:25 | new | semmle.label | new |
| C.cpp:27:8:27:11 | `this` parameter in func [s1] | semmle.label | `this` parameter in func [s1] |
| C.cpp:27:8:27:11 | `this` parameter in func [s3] | semmle.label | `this` parameter in func [s3] |
| C.cpp:29:10:29:11 | s1 | semmle.label | s1 |
| C.cpp:29:10:29:11 | this [s1] | semmle.label | this [s1] |
| C.cpp:31:10:31:11 | s3 | semmle.label | s3 |
| C.cpp:31:10:31:11 | this [s3] | semmle.label | this [s3] |
| D.cpp:21:30:21:31 | b2 [box, elem] | semmle.label | b2 [box, elem] |
| D.cpp:22:10:22:11 | b2 [box, elem] | semmle.label | b2 [box, elem] |
| D.cpp:22:14:22:20 | call to getBox1 [elem] | semmle.label | call to getBox1 [elem] |
| D.cpp:22:25:22:31 | call to getElem | semmle.label | call to getElem |
| D.cpp:28:15:28:24 | new | semmle.label | new |
| D.cpp:30:5:30:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] |
| D.cpp:30:5:30:20 | ... = ... | semmle.label | ... = ... |
| D.cpp:30:8:30:10 | box [post update] [elem] | semmle.label | box [post update] [elem] |
| D.cpp:31:14:31:14 | b [box, elem] | semmle.label | b [box, elem] |
| D.cpp:35:15:35:24 | new | semmle.label | new |
| D.cpp:37:5:37:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] |
| D.cpp:37:8:37:10 | box [post update] [elem] | semmle.label | box [post update] [elem] |
| D.cpp:37:21:37:21 | e | semmle.label | e |
| D.cpp:38:14:38:14 | b [box, elem] | semmle.label | b [box, elem] |
| D.cpp:42:15:42:24 | new | semmle.label | new |
| D.cpp:44:5:44:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] |
| D.cpp:44:5:44:26 | ... = ... | semmle.label | ... = ... |
| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] |
| D.cpp:45:14:45:14 | b [box, elem] | semmle.label | b [box, elem] |
| D.cpp:49:15:49:24 | new | semmle.label | new |
| D.cpp:51:5:51:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] |
| D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] |
| D.cpp:51:27:51:27 | e | semmle.label | e |
| D.cpp:52:14:52:14 | b [box, elem] | semmle.label | b [box, elem] |
| D.cpp:56:15:56:24 | new | semmle.label | new |
| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | semmle.label | boxfield [post update] [box, elem] |
| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | semmle.label | this [post update] [boxfield, box, ... (3)] |
| D.cpp:58:5:58:27 | ... = ... | semmle.label | ... = ... |
| D.cpp:58:15:58:17 | box [post update] [elem] | semmle.label | box [post update] [elem] |
| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] |
| D.cpp:63:8:63:10 | `this` parameter in f5b [boxfield, box, ... (3)] | semmle.label | `this` parameter in f5b [boxfield, box, ... (3)] |
| D.cpp:64:10:64:17 | boxfield [box, elem] | semmle.label | boxfield [box, elem] |
| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] |
| D.cpp:64:20:64:22 | box [elem] | semmle.label | box [elem] |
| D.cpp:64:25:64:28 | elem | semmle.label | elem |
| aliasing.cpp:9:3:9:3 | s [post update] [m1] | semmle.label | s [post update] [m1] |
| aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... |
| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:13:3:13:3 | s [post update] [m1] | semmle.label | s [post update] [m1] |
| aliasing.cpp:13:3:13:21 | ... = ... | semmle.label | ... = ... |
| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | semmle.label | ref arg & ... [m1] |
| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | semmle.label | ref arg s2 [m1] |
| aliasing.cpp:29:8:29:9 | s1 [m1] | semmle.label | s1 [m1] |
| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 |
| aliasing.cpp:30:8:30:9 | s2 [m1] | semmle.label | s2 [m1] |
| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | semmle.label | s2 [post update] [m1] |
| aliasing.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... |
| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:62:8:62:12 | copy2 [m1] | semmle.label | copy2 [m1] |
| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 |
| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | semmle.label | w [post update] [s, m1] |
| aliasing.cpp:92:3:92:23 | ... = ... | semmle.label | ... = ... |
| aliasing.cpp:92:5:92:5 | s [post update] [m1] | semmle.label | s [post update] [m1] |
| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] |
| aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
| by_reference.cpp:50:3:50:3 | s [post update] [a] | semmle.label | s [post update] [a] |
| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] |
| by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly |
| by_reference.cpp:56:3:56:3 | s [post update] [a] | semmle.label | s [post update] [a] |
| by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:57:8:57:8 | s [a] | semmle.label | s [a] |
| by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly |
| by_reference.cpp:62:3:62:3 | s [post update] [a] | semmle.label | s [post update] [a] |
| by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:63:8:63:8 | s [a] | semmle.label | s [a] |
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember |
| complex.cpp:34:15:34:15 | b [f, a_] | semmle.label | b [f, a_] |
| complex.cpp:34:15:34:15 | b [f, b_] | semmle.label | b [f, b_] |
| complex.cpp:44:8:44:8 | b [f, a_] | semmle.label | b [f, a_] |
| complex.cpp:44:10:44:10 | f [a_] | semmle.label | f [a_] |
| complex.cpp:44:12:44:12 | call to a | semmle.label | call to a |
| complex.cpp:45:8:45:8 | b [f, b_] | semmle.label | b [f, b_] |
| complex.cpp:45:10:45:10 | f [b_] | semmle.label | f [b_] |
| complex.cpp:45:12:45:12 | call to b | semmle.label | call to b |
| complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | semmle.label | b1 [post update] [f, a_] |
| complex.cpp:55:6:55:6 | f [post update] [a_] | semmle.label | f [post update] [a_] |
| complex.cpp:55:13:55:22 | call to user_input | semmle.label | call to user_input |
| complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | semmle.label | b2 [post update] [f, b_] |
| complex.cpp:56:6:56:6 | f [post update] [b_] | semmle.label | f [post update] [b_] |
| complex.cpp:56:13:56:22 | call to user_input | semmle.label | call to user_input |
| complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | semmle.label | b3 [post update] [f, a_] |
| complex.cpp:57:6:57:6 | f [post update] [a_] | semmle.label | f [post update] [a_] |
| complex.cpp:57:13:57:22 | call to user_input | semmle.label | call to user_input |
| complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | semmle.label | b3 [post update] [f, b_] |
| complex.cpp:58:6:58:6 | f [post update] [b_] | semmle.label | f [post update] [b_] |
| complex.cpp:58:13:58:22 | call to user_input | semmle.label | call to user_input |
| complex.cpp:61:7:61:8 | b1 [f, a_] | semmle.label | b1 [f, a_] |
| complex.cpp:64:7:64:8 | b2 [f, b_] | semmle.label | b2 [f, b_] |
| complex.cpp:67:7:67:8 | b3 [f, a_] | semmle.label | b3 [f, a_] |
| complex.cpp:67:7:67:8 | b3 [f, b_] | semmle.label | b3 [f, b_] |
| constructors.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] |
| constructors.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] |
| constructors.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] |
| constructors.cpp:28:12:28:12 | call to a | semmle.label | call to a |
| constructors.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] |
| constructors.cpp:29:12:29:12 | call to b | semmle.label | call to b |
| constructors.cpp:34:11:34:20 | call to user_input | semmle.label | call to user_input |
| constructors.cpp:34:11:34:26 | call to Foo [a_] | semmle.label | call to Foo [a_] |
| constructors.cpp:35:11:35:26 | call to Foo [b_] | semmle.label | call to Foo [b_] |
| constructors.cpp:35:14:35:23 | call to user_input | semmle.label | call to user_input |
| constructors.cpp:36:11:36:20 | call to user_input | semmle.label | call to user_input |
| constructors.cpp:36:11:36:37 | call to Foo [a_] | semmle.label | call to Foo [a_] |
| constructors.cpp:36:11:36:37 | call to Foo [b_] | semmle.label | call to Foo [b_] |
| constructors.cpp:36:25:36:34 | call to user_input | semmle.label | call to user_input |
| constructors.cpp:40:9:40:9 | f [a_] | semmle.label | f [a_] |
| constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] |
| constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] |
| constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] |
| simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] |
| simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] |
| simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] |
| simple.cpp:28:12:28:12 | call to a | semmle.label | call to a |
| simple.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] |
| simple.cpp:29:12:29:12 | call to b | semmle.label | call to b |
| simple.cpp:39:5:39:5 | f [post update] [a_] | semmle.label | f [post update] [a_] |
| simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input |
| simple.cpp:40:5:40:5 | g [post update] [b_] | semmle.label | g [post update] [b_] |
| simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input |
| simple.cpp:41:5:41:5 | h [post update] [a_] | semmle.label | h [post update] [a_] |
| simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input |
| simple.cpp:42:5:42:5 | h [post update] [b_] | semmle.label | h [post update] [b_] |
| simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input |
| simple.cpp:45:9:45:9 | f [a_] | semmle.label | f [a_] |
| simple.cpp:48:9:48:9 | g [b_] | semmle.label | g [b_] |
| simple.cpp:51:9:51:9 | h [a_] | semmle.label | h [a_] |
| simple.cpp:51:9:51:9 | h [b_] | semmle.label | h [b_] |
| struct_init.c:20:17:20:36 | {...} [a] | semmle.label | {...} [a] |
| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input |
| struct_init.c:22:8:22:9 | ab [a] | semmle.label | ab [a] |
| struct_init.c:22:11:22:11 | a | semmle.label | a |
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | semmle.label | {...} [nestedAB, a] |
| struct_init.c:27:5:27:23 | {...} [a] | semmle.label | {...} [a] |
| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input |
| struct_init.c:31:8:31:12 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] |
| struct_init.c:31:14:31:21 | nestedAB [a] | semmle.label | nestedAB [a] |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
#select
| A.cpp:43:10:43:12 | & ... | A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | & ... flows from $@ | A.cpp:41:15:41:21 | new | new |
| A.cpp:49:13:49:13 | c | A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | c flows from $@ | A.cpp:47:12:47:18 | new | new |

View File

@@ -20,6 +20,7 @@ instructionWithoutSuccessor
| ms_try_mix.cpp:11:12:11:15 | Chi: call to C |
| ms_try_mix.cpp:28:12:28:15 | Chi: call to C |
| ms_try_mix.cpp:48:10:48:13 | Chi: call to C |
| pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} |
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... |
| vla.c:5:9:5:14 | Uninitialized: definition of matrix |
| vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef |

View File

@@ -1,53 +1,53 @@
| staticlocals__staticlocals_f2_extractor | false | 31268 | 31268 | f2 |
| staticlocals__staticlocals_f2_extractor | false | 31274 | 31274 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 31277 | 31277 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 31280 | 31280 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 31283 | 31283 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 31286 | 31286 | return ... |
| staticlocals__staticlocals_f2_extractor | false | 31289 | 31289 | { ... } |
| staticlocals__staticlocals_f2_extractor | false | 31292 | 31292 | call to C |
| staticlocals__staticlocals_f2_extractor | false | 31295 | 31295 | initializer for c |
| staticlocals__staticlocals_f2_extractor | false | 31298 | 31298 | call to addOne |
| staticlocals__staticlocals_f2_extractor | false | 31304 | 31304 | 2 |
| staticlocals__staticlocals_f2_extractor | false | 31309 | 31309 | initializer for j |
| staticlocals__staticlocals_f2_extractor | false | 31311 | 31311 | call to addOne |
| staticlocals__staticlocals_f2_extractor | false | 31319 | 31319 | 2 |
| staticlocals__staticlocals_f2_extractor | false | 31321 | 31321 | initializer for two |
| staticlocals__staticlocals_f2_extractor | false | 31325 | 31325 | two |
| staticlocals__staticlocals_f2_extractor | false | 31333 | 31333 | initializer for i |
| staticlocals__staticlocals_f2_extractor | true | 31274 | 31321 | |
| staticlocals__staticlocals_f2_extractor | true | 31277 | 31280 | |
| staticlocals__staticlocals_f2_extractor | true | 31280 | 31283 | |
| staticlocals__staticlocals_f2_extractor | true | 31283 | 31286 | |
| staticlocals__staticlocals_f2_extractor | true | 31286 | 31268 | |
| staticlocals__staticlocals_f2_extractor | true | 31289 | 31274 | |
| staticlocals__staticlocals_f2_extractor | true | 31319 | 31277 | |
| staticlocals__staticlocals_f2_extractor | true | 31321 | 31319 | |
| staticlocals__staticlocals_f2_ql | false | 31268 | 31268 | f2 |
| staticlocals__staticlocals_f2_ql | false | 31274 | 31274 | declaration |
| staticlocals__staticlocals_f2_ql | false | 31277 | 31277 | declaration |
| staticlocals__staticlocals_f2_ql | false | 31280 | 31280 | declaration |
| staticlocals__staticlocals_f2_ql | false | 31283 | 31283 | declaration |
| staticlocals__staticlocals_f2_ql | false | 31286 | 31286 | return ... |
| staticlocals__staticlocals_f2_ql | false | 31289 | 31289 | { ... } |
| staticlocals__staticlocals_f2_ql | false | 31292 | 31292 | call to C |
| staticlocals__staticlocals_f2_ql | false | 31295 | 31295 | initializer for c |
| staticlocals__staticlocals_f2_ql | false | 31298 | 31298 | call to addOne |
| staticlocals__staticlocals_f2_ql | false | 31304 | 31304 | 2 |
| staticlocals__staticlocals_f2_ql | false | 31309 | 31309 | initializer for j |
| staticlocals__staticlocals_f2_ql | false | 31311 | 31311 | call to addOne |
| staticlocals__staticlocals_f2_ql | false | 31319 | 31319 | 2 |
| staticlocals__staticlocals_f2_ql | false | 31321 | 31321 | initializer for two |
| staticlocals__staticlocals_f2_ql | false | 31325 | 31325 | two |
| staticlocals__staticlocals_f2_ql | false | 31333 | 31333 | initializer for i |
| staticlocals__staticlocals_f2_ql | true | 31274 | 31321 | |
| staticlocals__staticlocals_f2_ql | true | 31277 | 31280 | |
| staticlocals__staticlocals_f2_ql | true | 31280 | 31283 | |
| staticlocals__staticlocals_f2_ql | true | 31283 | 31286 | |
| staticlocals__staticlocals_f2_ql | true | 31283 | 31295 | |
| staticlocals__staticlocals_f2_ql | true | 31286 | 31268 | |
| staticlocals__staticlocals_f2_ql | true | 31289 | 31274 | |
| staticlocals__staticlocals_f2_ql | true | 31292 | 31286 | |
| staticlocals__staticlocals_f2_ql | true | 31295 | 31292 | |
| staticlocals__staticlocals_f2_ql | true | 31319 | 31277 | |
| staticlocals__staticlocals_f2_ql | true | 31321 | 31319 | |
| staticlocals__staticlocals_f2_extractor | false | 22465 | 22465 | f2 |
| staticlocals__staticlocals_f2_extractor | false | 22470 | 22470 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 22472 | 22472 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 22474 | 22474 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 22476 | 22476 | declaration |
| staticlocals__staticlocals_f2_extractor | false | 22478 | 22478 | return ... |
| staticlocals__staticlocals_f2_extractor | false | 22480 | 22480 | { ... } |
| staticlocals__staticlocals_f2_extractor | false | 22482 | 22482 | call to C |
| staticlocals__staticlocals_f2_extractor | false | 22484 | 22484 | initializer for c |
| staticlocals__staticlocals_f2_extractor | false | 22486 | 22486 | call to addOne |
| staticlocals__staticlocals_f2_extractor | false | 22490 | 22490 | 2 |
| staticlocals__staticlocals_f2_extractor | false | 22493 | 22493 | initializer for j |
| staticlocals__staticlocals_f2_extractor | false | 22494 | 22494 | call to addOne |
| staticlocals__staticlocals_f2_extractor | false | 22499 | 22499 | 2 |
| staticlocals__staticlocals_f2_extractor | false | 22500 | 22500 | initializer for two |
| staticlocals__staticlocals_f2_extractor | false | 22503 | 22503 | two |
| staticlocals__staticlocals_f2_extractor | false | 22508 | 22508 | initializer for i |
| staticlocals__staticlocals_f2_extractor | true | 22470 | 22500 | |
| staticlocals__staticlocals_f2_extractor | true | 22472 | 22474 | |
| staticlocals__staticlocals_f2_extractor | true | 22474 | 22476 | |
| staticlocals__staticlocals_f2_extractor | true | 22476 | 22478 | |
| staticlocals__staticlocals_f2_extractor | true | 22478 | 22465 | |
| staticlocals__staticlocals_f2_extractor | true | 22480 | 22470 | |
| staticlocals__staticlocals_f2_extractor | true | 22499 | 22472 | |
| staticlocals__staticlocals_f2_extractor | true | 22500 | 22499 | |
| staticlocals__staticlocals_f2_ql | false | 22465 | 22465 | f2 |
| staticlocals__staticlocals_f2_ql | false | 22470 | 22470 | declaration |
| staticlocals__staticlocals_f2_ql | false | 22472 | 22472 | declaration |
| staticlocals__staticlocals_f2_ql | false | 22474 | 22474 | declaration |
| staticlocals__staticlocals_f2_ql | false | 22476 | 22476 | declaration |
| staticlocals__staticlocals_f2_ql | false | 22478 | 22478 | return ... |
| staticlocals__staticlocals_f2_ql | false | 22480 | 22480 | { ... } |
| staticlocals__staticlocals_f2_ql | false | 22482 | 22482 | call to C |
| staticlocals__staticlocals_f2_ql | false | 22484 | 22484 | initializer for c |
| staticlocals__staticlocals_f2_ql | false | 22486 | 22486 | call to addOne |
| staticlocals__staticlocals_f2_ql | false | 22490 | 22490 | 2 |
| staticlocals__staticlocals_f2_ql | false | 22493 | 22493 | initializer for j |
| staticlocals__staticlocals_f2_ql | false | 22494 | 22494 | call to addOne |
| staticlocals__staticlocals_f2_ql | false | 22499 | 22499 | 2 |
| staticlocals__staticlocals_f2_ql | false | 22500 | 22500 | initializer for two |
| staticlocals__staticlocals_f2_ql | false | 22503 | 22503 | two |
| staticlocals__staticlocals_f2_ql | false | 22508 | 22508 | initializer for i |
| staticlocals__staticlocals_f2_ql | true | 22470 | 22500 | |
| staticlocals__staticlocals_f2_ql | true | 22472 | 22474 | |
| staticlocals__staticlocals_f2_ql | true | 22474 | 22476 | |
| staticlocals__staticlocals_f2_ql | true | 22476 | 22478 | |
| staticlocals__staticlocals_f2_ql | true | 22476 | 22484 | |
| staticlocals__staticlocals_f2_ql | true | 22478 | 22465 | |
| staticlocals__staticlocals_f2_ql | true | 22480 | 22470 | |
| staticlocals__staticlocals_f2_ql | true | 22482 | 22478 | |
| staticlocals__staticlocals_f2_ql | true | 22484 | 22482 | |
| staticlocals__staticlocals_f2_ql | true | 22499 | 22472 | |
| staticlocals__staticlocals_f2_ql | true | 22500 | 22499 | |

View File

@@ -28,3 +28,9 @@ int usePM(int PM::* pm) {
return acc;
}
void pmIsConst() {
static const struct {
int PM::* pm1;
} pms = { &PM::x1 };
}

View File

@@ -7,6 +7,7 @@ missingOperand
| misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) |
| pointer_to_member.cpp:35:13:35:19 | FieldAddress: x1 | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
| range_analysis.c:368:10:368:21 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) |
| range_analysis.c:369:10:369:36 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) |
| range_analysis.c:370:10:370:38 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) |
@@ -65,6 +66,7 @@ instructionWithoutSuccessor
| ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C |
| ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... |
| ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } |
| pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} |
| static_init_templates.cpp:80:27:80:36 | Convert: (void *)... |
| static_init_templates.cpp:80:27:80:36 | Convert: (void *)... |
| static_init_templates.cpp:89:27:89:36 | Convert: (void *)... |
@@ -671,6 +673,7 @@ useNotDominatedByDefinition
| ms_try_mix.cpp:38:16:38:19 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:27:6:27:19 | IR: ms_finally_mix | void ms_finally_mix(int) |
| ms_try_mix.cpp:41:12:41:15 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:27:6:27:19 | IR: ms_finally_mix | void ms_finally_mix(int) |
| ms_try_mix.cpp:51:5:51:11 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:47:6:47:28 | IR: ms_empty_finally_at_end | void ms_empty_finally_at_end() |
| pointer_to_member.cpp:35:13:35:19 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() |
| stmt_expr.cpp:30:20:30:21 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | stmt_expr.cpp:21:6:21:6 | IR: g | void stmtexpr::g(int) |
| stmt_expr.cpp:31:16:31:18 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | stmt_expr.cpp:21:6:21:6 | IR: g | void stmtexpr::g(int) |
| try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) |

View File

@@ -29,6 +29,7 @@ instructionWithoutSuccessor
| ms_try_mix.cpp:11:12:11:15 | CallSideEffect: call to C |
| ms_try_mix.cpp:28:12:28:15 | CallSideEffect: call to C |
| ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C |
| pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} |
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... |
| vla.c:5:9:5:14 | Uninitialized: definition of matrix |
| vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef |

View File

@@ -1,35 +1,44 @@
| variables.cpp:2:13:2:13 | pi | variables.cpp:25:12:25:16 | pi | 0 | T |
| variables.cpp:2:13:2:13 | pi | variables.cpp:25:12:25:16 | pi | 0 | float |
| variables.cpp:2:13:2:13 | pi | variables.cpp:25:12:25:16 | pi | 0 | int |
| variables.cpp:2:13:2:13 | pi | variables.cpp:37:16:37:24 | pi | 0 | float |
| variables.cpp:2:13:2:13 | pi | variables.cpp:38:16:38:22 | pi | 0 | int |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | multi_arg | 0 | S |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | multi_arg | 0 | float |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | multi_arg | 0 | short |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | multi_arg | 1 | T |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | multi_arg | 1 | char |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | multi_arg | 1 | long |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:40:23:40:60 | multi_arg | 0 | unsigned int |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:40:23:40:60 | multi_arg | 1 | unsigned char |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:41:23:41:42 | multi_arg | 0 | int |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:41:23:41:42 | multi_arg | 1 | char |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:26:3:26:16 | mutable_val | 0 | T |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:26:3:26:16 | mutable_val | 0 | float |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:26:3:26:16 | mutable_val | 0 | int |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:43:3:43:18 | mutable_val | 0 | int |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:44:3:44:19 | mutable_val | 0 | long |
| variables.cpp:19:8:19:8 | bar | variables.cpp:27:3:27:13 | bar | 0 | T |
| variables.cpp:19:8:19:8 | bar | variables.cpp:27:3:27:13 | bar | 0 | float |
| variables.cpp:19:8:19:8 | bar | variables.cpp:27:3:27:13 | bar | 0 | int |
| variables.cpp:19:8:19:8 | bar | variables.cpp:46:3:46:17 | bar | 0 | short |
| variables.cpp:19:8:19:8 | bar | variables.cpp:47:3:47:18 | bar | 0 | double |
| variables.cpp:21:5:21:15 | no_template | variables.cpp:28:3:28:13 | no_template | -1 | <none> |
| variables.cpp:21:5:21:15 | no_template | variables.cpp:28:3:28:13 | no_template | -1 | <none> |
| variables.cpp:21:5:21:15 | no_template | variables.cpp:28:3:28:13 | no_template | -1 | <none> |
| variables.cpp:21:5:21:15 | no_template | variables.cpp:49:3:49:13 | no_template | -1 | <none> |
| variables.cpp:24:27:24:29 | val | variables.cpp:26:20:26:22 | val | -1 | <none> |
| variables.cpp:24:27:24:29 | val | variables.cpp:26:20:26:22 | val | -1 | <none> |
| variables.cpp:24:27:24:29 | val | variables.cpp:26:20:26:22 | val | -1 | <none> |
| variables.cpp:24:27:24:29 | val | variables.cpp:27:17:27:19 | val | -1 | <none> |
| variables.cpp:24:27:24:29 | val | variables.cpp:27:17:27:19 | val | -1 | <none> |
| variables.cpp:24:27:24:29 | val | variables.cpp:27:17:27:19 | val | -1 | <none> |
| file://:0:0:0:0 | fp_offset | | | |
| file://:0:0:0:0 | gp_offset | | | |
| file://:0:0:0:0 | overflow_arg_area | | | |
| file://:0:0:0:0 | p#0 | | | |
| file://:0:0:0:0 | p#0 | | | |
| file://:0:0:0:0 | p#0 | | | |
| file://:0:0:0:0 | p#0 | | | |
| file://:0:0:0:0 | reg_save_area | | | |
| variables.cpp:2:13:2:13 | pi | variables.cpp:25:12:25:16 | T | |
| variables.cpp:2:13:2:13 | pi | variables.cpp:25:12:25:16, variables.cpp:37:16:37:24 | float | |
| variables.cpp:2:13:2:13 | pi | variables.cpp:25:12:25:16, variables.cpp:38:16:38:22 | int | |
| variables.cpp:2:16:2:16 | pi | | T | TemplateVariable |
| variables.cpp:5:23:5:37 | pi | | const char * | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | S, T | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | float, char | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:33:19:33:33 | short, long | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:40:23:40:60 | unsigned int, unsigned char | |
| variables.cpp:8:13:8:13 | multi_arg | variables.cpp:41:23:41:42 | int, char | |
| variables.cpp:8:23:8:23 | multi_arg | | S, T | TemplateVariable |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:26:3:26:16 | T | |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:26:3:26:16 | float | |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:26:3:26:16, variables.cpp:43:3:43:18 | int | |
| variables.cpp:11:3:11:3 | mutable_val | variables.cpp:44:3:44:19 | long | |
| variables.cpp:11:15:11:15 | mutable_val | | T | TemplateVariable |
| variables.cpp:19:3:19:10 | bar | | T | TemplateVariable |
| variables.cpp:19:8:19:8 | bar | variables.cpp:27:3:27:13 | T | |
| variables.cpp:19:8:19:8 | bar | variables.cpp:27:3:27:13 | float | |
| variables.cpp:19:8:19:8 | bar | variables.cpp:27:3:27:13 | int | |
| variables.cpp:19:8:19:8 | bar | variables.cpp:46:3:46:17 | short | |
| variables.cpp:19:8:19:8 | bar | variables.cpp:47:3:47:18 | double | |
| variables.cpp:21:5:21:15 | no_template | variables.cpp:28:3:28:13, variables.cpp:28:3:28:13, variables.cpp:28:3:28:13, variables.cpp:49:3:49:13 | | |
| variables.cpp:24:27:24:29 | val | variables.cpp:26:20:26:22, variables.cpp:27:17:27:19 | | |
| variables.cpp:24:27:24:29 | val | variables.cpp:26:20:26:22, variables.cpp:27:17:27:19 | | |
| variables.cpp:24:27:24:29 | val | variables.cpp:26:20:26:22, variables.cpp:27:17:27:19 | | |
| variables.cpp:25:5:25:8 | pi_t | | | |
| variables.cpp:25:5:25:8 | pi_t | | | |
| variables.cpp:25:5:25:8 | pi_t | | | |
| variables.cpp:33:5:33:15 | multi_arg_s | | | |
| variables.cpp:33:5:33:15 | multi_arg_s | | | |
| variables.cpp:33:5:33:15 | multi_arg_s | | | |
| variables.cpp:37:9:37:12 | pi_f | | | |
| variables.cpp:38:9:38:12 | pi_i | | | |
| variables.cpp:40:9:40:19 | multi_arg_a | | | |
| variables.cpp:41:9:41:19 | multi_arg_b | | | |

View File

@@ -1,11 +1,10 @@
import cpp
from Variable v, VariableAccess a, int i, string s
where
v = a.getTarget() and
if exists(v.getATemplateArgument())
then s = v.getTemplateArgument(i).toString()
else (
s = "<none>" and i = -1
)
select v, a, i, s
string describe(Variable v) {
v instanceof TemplateVariable and
result = "TemplateVariable"
}
from Variable v
select v, concat(VariableAccess a | a.getTarget() = v | a.getLocation().toString(), ", "),
concat(int i | | v.getTemplateArgument(i).toString(), ", " order by i), concat(describe(v), ", ")

View File

@@ -14,6 +14,26 @@ edges
| test.cpp:88:21:88:22 | d2 | test.cpp:34:31:34:31 | b |
| test.cpp:95:21:95:21 | d | test.cpp:50:31:50:31 | b |
| test.cpp:96:21:96:23 | dss | test.cpp:50:31:50:31 | b |
nodes
| test.cpp:26:29:26:29 | b | semmle.label | b |
| test.cpp:27:2:27:2 | b | semmle.label | b |
| test.cpp:30:34:30:34 | b | semmle.label | b |
| test.cpp:31:2:31:2 | b | semmle.label | b |
| test.cpp:34:31:34:31 | b | semmle.label | b |
| test.cpp:35:2:35:2 | b | semmle.label | b |
| test.cpp:50:31:50:31 | b | semmle.label | b |
| test.cpp:51:11:51:11 | b | semmle.label | b |
| test.cpp:57:19:57:19 | d | semmle.label | d |
| test.cpp:58:25:58:25 | d | semmle.label | d |
| test.cpp:59:21:59:21 | d | semmle.label | d |
| test.cpp:74:19:74:21 | dss | semmle.label | dss |
| test.cpp:75:25:75:27 | dss | semmle.label | dss |
| test.cpp:76:21:76:23 | dss | semmle.label | dss |
| test.cpp:86:19:86:20 | d2 | semmle.label | d2 |
| test.cpp:87:25:87:26 | d2 | semmle.label | d2 |
| test.cpp:88:21:88:22 | d2 | semmle.label | d2 |
| test.cpp:95:21:95:21 | d | semmle.label | d |
| test.cpp:96:21:96:23 | dss | semmle.label | dss |
#select
| test.cpp:27:2:27:2 | b | test.cpp:57:19:57:19 | d | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:57:19:57:19 | d | here |
| test.cpp:27:2:27:2 | b | test.cpp:74:19:74:21 | dss | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:74:19:74:21 | dss | here |

View File

@@ -92,6 +92,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SymbolKind.Event:
kind = ExprKind.EVENT_ACCESS;
break;
case SymbolKind.Namespace:
kind = ExprKind.NAMESPACE_ACCESS;
break;
default:
info.Context.ModelError(info.Node, "Unhandled symbol for member access");
kind = ExprKind.UNKNOWN;

View File

@@ -567,6 +567,7 @@ module AssignableDefinitions {
* entry point of `p`'s callable to basic block `bb` without passing through
* any assignments to `p`.
*/
pragma[nomagic]
private predicate parameterReachesWithoutDef(Parameter p, ControlFlow::BasicBlock bb) {
forall(AssignableDefinition def | basicBlockRefParamDef(bb, p, def) |
isUncertainRefCall(def.getTargetAccess())

View File

@@ -65,6 +65,7 @@ predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) {
* `I.M()` is compatible with `A.M()` for types `A` and `B`, but not
* for type `C`, because `C.M()` conflicts.
*/
pragma[nomagic]
private Virtualizable getAnImplementedInterfaceMemberForSubType(Virtualizable m, ValueOrRefType t) {
result = getACompatibleInterfaceMember(m) and
t = m.getDeclaringType()
@@ -86,6 +87,7 @@ private predicate hasMemberCompatibleWithInterfaceMember(ValueOrRefType t, Virtu
* signature, and where `m` can potentially be accessed when
* the interface member is accessed.
*/
pragma[nomagic]
private Virtualizable getACompatibleInterfaceMember(Virtualizable m) {
result = getACompatibleInterfaceMemberAux(m) and
(
@@ -97,12 +99,14 @@ private Virtualizable getACompatibleInterfaceMember(Virtualizable m) {
)
}
pragma[nomagic]
private Virtualizable getACompatibleExplicitInterfaceMember(Virtualizable m, ValueOrRefType declType) {
result = getACompatibleInterfaceMemberAux(m) and
declType = m.getDeclaringType() and
m.implementsExplicitInterface()
}
pragma[nomagic]
private Virtualizable getACompatibleInterfaceMemberAux(Virtualizable m) {
result = getACompatibleInterfaceAccessor(m) or
result = getACompatibleInterfaceIndexer(m) or

View File

@@ -32,19 +32,19 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
* several `ControlFlow::Node`s, for example to represent the continuation
* flow in a `try/catch/finally` construction.
*/
Node getAControlFlowNode() { result.getElement() = this }
Nodes::ElementNode getAControlFlowNode() { result.getElement() = this }
/**
* Gets a first control flow node executed within this element.
*/
Node getAControlFlowEntryNode() {
Nodes::ElementNode getAControlFlowEntryNode() {
result = Internal::getAControlFlowEntryNode(this).getAControlFlowNode()
}
/**
* Gets a potential last control flow node executed within this element.
*/
Node getAControlFlowExitNode() {
Nodes::ElementNode getAControlFlowExitNode() {
result = Internal::getAControlFlowExitNode(this).getAControlFlowNode()
}

View File

@@ -317,6 +317,8 @@ module ControlFlow {
class ExceptionHandlerSplit = ExceptionHandlerSplitting::ExceptionHandlerSplitImpl;
class BooleanSplit = BooleanSplitting::BooleanSplitImpl;
class LoopUnrollingSplit = LoopUnrollingSplitting::LoopUnrollingSplitImpl;
}
class BasicBlock = BBs::BasicBlock;

View File

@@ -12,6 +12,9 @@ private import semmle.code.csharp.commons.StructuralComparison::Internal
private import semmle.code.csharp.controlflow.BasicBlocks
private import semmle.code.csharp.controlflow.internal.Completion
private import semmle.code.csharp.frameworks.System
private import semmle.code.csharp.frameworks.system.Linq
private import semmle.code.csharp.frameworks.system.Collections
private import semmle.code.csharp.frameworks.system.collections.Generic
/** An expression whose value may control the execution of another element. */
class Guard extends Expr {
@@ -53,6 +56,28 @@ abstract class AbstractValue extends TAbstractValue {
*/
abstract predicate isSingleton();
/**
* Holds if this value describes a referential property. For example, emptiness
* of a collection is a referential property.
*
* Such values only propagate through adjacent reads, for example, in
*
* ```
* int M()
* {
* var x = new string[]{ "a", "b", "c" }.ToList();
* x.Clear();
* return x.Count;
* }
* ```
*
* the non-emptiness of `new string[]{ "a", "b", "c" }.ToList()` only propagates
* to the read of `x` in `x.Clear()` and not in `x.Count`.
*
* Aliasing is not taken into account in the analyses.
*/
predicate isReferentialProperty() { none() }
/** Gets a textual representation of this abstract value. */
abstract string toString();
}
@@ -112,6 +137,9 @@ module AbstractValues {
/** Holds if this value represents `null`. */
predicate isNull() { this = TNullValue(true) }
/** Holds if this value represents non-`null`. */
predicate isNonNull() { this = TNullValue(false) }
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
this = TNullValue(s.(NullnessSuccessor).getValue()) and
exists(NullnessCompletion c | s.matchesCompletion(c) |
@@ -121,7 +149,7 @@ module AbstractValues {
}
override NullValue getDualValue() {
if this.isNull() then not result.isNull() else result.isNull()
if this.isNull() then result.isNonNull() else result.isNull()
}
override DereferenceableExpr getAnExpr() {
@@ -174,6 +202,9 @@ module AbstractValues {
/** Holds if this value represents an empty collection. */
predicate isEmpty() { this = TEmptyCollectionValue(true) }
/** Holds if this value represents a non-empty collection. */
predicate isNonEmpty() { this = TEmptyCollectionValue(false) }
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
this = TEmptyCollectionValue(s.(EmptinessSuccessor).getValue()) and
exists(EmptinessCompletion c, ForeachStmt fs | s.matchesCompletion(c) |
@@ -184,13 +215,21 @@ module AbstractValues {
}
override EmptyCollectionValue getDualValue() {
if this.isEmpty() then not result.isEmpty() else result.isEmpty()
if this.isEmpty() then result.isNonEmpty() else result.isEmpty()
}
override Expr getAnExpr() { none() }
override Expr getAnExpr() {
this.isEmpty() and
emptyValue(result)
or
this.isNonEmpty() and
nonEmptyValue(result)
}
override predicate isSingleton() { none() }
override predicate isReferentialProperty() { any() }
override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" }
}
}
@@ -254,7 +293,7 @@ class DereferenceableExpr extends Expr {
exists(ComparisonTest ct, ComparisonKind ck, Expr e | ct.getExpr() = result |
ct.getAnArgument() = this and
ct.getAnArgument() = e and
e = any(NullValue nv | not nv.isNull()).getAnExpr() and
e = any(NullValue nv | nv.isNonNull()).getAnExpr() and
ck = ct.getComparisonKind() and
this != e and
isNull = false and
@@ -363,7 +402,7 @@ class DereferenceableExpr extends Expr {
v.isNull() and
isNull = true
) else (
not v.isNull() and
v.isNonNull() and
isNull = false
)
)
@@ -388,6 +427,113 @@ class DereferenceableExpr extends Expr {
}
}
/**
* An expression that evaluates to a collection. That is, an expression whose
* (transitive, reflexive) base type is `IEnumerable`.
*/
class CollectionExpr extends Expr {
CollectionExpr() {
this.getType().(ValueOrRefType).getABaseType*() instanceof SystemCollectionsIEnumerableInterface
}
/**
* Gets an expression that computes the size of this collection. `lowerBound`
* indicates whether the expression only computes a lower bound.
*/
private Expr getASizeExpr(boolean lowerBound) {
lowerBound = false and
result = any(PropertyRead pr |
this = pr.getQualifier() and
pr.getTarget() = any(SystemArrayClass x).getLengthProperty()
)
or
lowerBound = false and
result = any(PropertyRead pr |
this = pr.getQualifier() and
pr
.getTarget()
.overridesOrImplementsOrEquals(any(Property p |
p.getSourceDeclaration() = any(SystemCollectionsGenericICollectionInterface x)
.getCountProperty()
))
)
or
result = any(MethodCall mc |
mc.getTarget().getSourceDeclaration() = any(SystemLinq::SystemLinqEnumerableClass x)
.getACountMethod() and
this = mc.getArgument(0) and
if mc.getNumberOfArguments() = 1 then lowerBound = false else lowerBound = true
)
}
private Expr getABooleanEmptinessCheck(BooleanValue v, boolean isEmpty) {
exists(boolean branch | branch = v.getValue() |
result = any(ComparisonTest ct |
exists(boolean lowerBound |
ct.getAnArgument() = this.getASizeExpr(lowerBound) and
if isEmpty = true then lowerBound = false else any()
|
// x.Length == 0
ct.getComparisonKind().isEquality() and
ct.getAnArgument().getValue().toInt() = 0 and
branch = isEmpty
or
// x.Length == k, k > 0
ct.getComparisonKind().isEquality() and
ct.getAnArgument().getValue().toInt() > 0 and
branch = true and
isEmpty = false
or
// x.Length != 0
ct.getComparisonKind().isInequality() and
ct.getAnArgument().getValue().toInt() = 0 and
branch = isEmpty.booleanNot()
or
// x.Length != k, k != 0
ct.getComparisonKind().isInequality() and
ct.getAnArgument().getValue().toInt() != 0 and
branch = false and
isEmpty = false
or
// x.Length > k, k >= 0
ct.getComparisonKind().isLessThan() and
ct.getFirstArgument().getValue().toInt() >= 0 and
branch = true and
isEmpty = false
or
// x.Length >= k, k > 0
ct.getComparisonKind().isLessThanEquals() and
ct.getFirstArgument().getValue().toInt() > 0 and
branch = true and
isEmpty = false
)
).getExpr()
or
result = any(MethodCall mc |
mc.getTarget().getSourceDeclaration() = any(SystemLinq::SystemLinqEnumerableClass x)
.getAnAnyMethod() and
this = mc.getArgument(0) and
branch = isEmpty.booleanNot() and
if branch = false then mc.getNumberOfArguments() = 1 else any()
)
)
}
/**
* Gets an expression that tests whether this expression is empty.
*
* If the returned expression has abstract value `v`, then this expression is
* guaranteed to be empty if `isEmpty` is true, and non-empty if `isEmpty` is
* false.
*
* For example, if the expression `x.Length != 0` evaluates to `true` then the
* expression `x` is guaranteed to be non-empty.
*/
Expr getAnEmptinessCheck(AbstractValue v, boolean isEmpty) {
result = this.getABooleanEmptinessCheck(v, isEmpty)
}
}
/** An expression that accesses/calls a declaration. */
class AccessOrCallExpr extends Expr {
private Declaration target;
@@ -630,12 +776,12 @@ class GuardedDataFlowNode extends DataFlow::ExprNode {
/** An expression guarded by a `null` check. */
class NullGuardedExpr extends GuardedExpr {
NullGuardedExpr() { this.mustHaveValue(any(NullValue v | not v.isNull())) }
NullGuardedExpr() { this.mustHaveValue(any(NullValue v | v.isNonNull())) }
}
/** A data flow node guarded by a `null` check. */
class NullGuardedDataFlowNode extends GuardedDataFlowNode {
NullGuardedDataFlowNode() { this.mustHaveValue(any(NullValue v | not v.isNull())) }
NullGuardedDataFlowNode() { this.mustHaveValue(any(NullValue v | v.isNonNull())) }
}
/** INTERNAL: Do not use. */
@@ -755,7 +901,7 @@ module Internal {
bao.getAnOperand() = o and
// The other operand must be provably non-null in order
// for `only if` to hold
o = any(NullValue nv | not nv.isNull()).getAnExpr() and
o = any(NullValue nv | nv.isNonNull()).getAnExpr() and
e != o
)
}
@@ -834,7 +980,7 @@ module Internal {
v.(NullValue).isNull()
or
a.getAssertMethod() instanceof AssertNonNullMethod and
v = any(NullValue nv | not nv.isNull())
v.(NullValue).isNonNull()
)
}
@@ -871,7 +1017,7 @@ module Internal {
}
/** Holds if pre-basic-block `bb` only is reached when guard `g` has abstract value `v`. */
private predicate preControls(Guard g, PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
predicate preControls(Guard g, PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
exists(AbstractValue v0, Guard g0 | preControlsDirect(g0, bb, v0) |
preImpliesSteps(g0, v0, g, v)
)
@@ -1257,25 +1403,39 @@ module Internal {
nonNullValueImplied(def.getDefinition().getSource())
}
private predicate emptyDef(PreSsa::Definition def) {
emptyValue(def.getDefinition().getSource())
}
private predicate nonEmptyDef(PreSsa::Definition def) {
nonEmptyValue(def.getDefinition().getSource())
}
cached
private module CachedWithCFG {
private import semmle.code.csharp.Caching
cached
predicate isGuard(Expr e, AbstractValue val) {
Stages::ControlFlowStage::forceCachingInSameStage() and
e.getType() instanceof BoolType and
not e instanceof BoolLiteral and
not e instanceof SwitchCaseExpr and
not e instanceof PatternExpr and
val = TBooleanValue(_)
or
e instanceof DereferenceableExpr and
val = TNullValue(_)
or
val.branch(_, _, e)
or
asserts(_, e, val)
(
e.getType() instanceof BoolType and
not e instanceof BoolLiteral and
not e instanceof SwitchCaseExpr and
not e instanceof PatternExpr and
val = TBooleanValue(_)
or
e instanceof DereferenceableExpr and
val = TNullValue(_)
or
val.branch(_, _, e)
or
asserts(_, e, val)
or
e instanceof CollectionExpr and
val = TEmptyCollectionValue(_)
) and
not e = any(ExprStmt es).getExpr() and
not e = any(LocalVariableDeclStmt s).getAVariableDeclExpr()
}
cached
@@ -1287,6 +1447,15 @@ module Internal {
)
}
private predicate firstReadSameVarUniquePredecesssor(
PreSsa::Definition def, AssignableRead read
) {
PreSsa::firstReadSameVar(def, read) and
not exists(AssignableRead other | PreSsa::adjacentReadPairSameVar(other, read) |
other != read
)
}
/**
* Holds if the assumption that `g1` has abstract value `v1` implies that
* `g2` has abstract value `v2`, using one step of reasoning. That is, the
@@ -1373,6 +1542,13 @@ module Internal {
(g1 != g2 or v1 != v2)
)
or
exists(boolean isEmpty | g1 = g2.(CollectionExpr).getAnEmptinessCheck(v1, isEmpty) |
v2 = any(EmptyCollectionValue ecv |
if ecv.isEmpty() then isEmpty = true else isEmpty = false
) and
g1 != g2
)
or
g1 instanceof DereferenceableExpr and
g1 = getNullEquivParent(g2) and
v1 instanceof NullValue and
@@ -1380,7 +1556,7 @@ module Internal {
or
g1 instanceof DereferenceableExpr and
g2 = getANullImplyingChild(g1) and
v1 = any(NullValue nv | not nv.isNull()) and
v1.(NullValue).isNonNull() and
v2 = v1
or
g2 = g1.(AssignExpr).getRValue() and
@@ -1395,10 +1571,12 @@ module Internal {
isGuard(g1, v1) and
v2 = v1.(NullValue)
or
exists(PreSsa::Definition def | def.getDefinition().getSource() = g2 |
exists(PreSsa::Definition def |
def.getDefinition().getSource() = g2 and
g1 = def.getARead() and
isGuard(g1, v1) and
v2 = v1
v2 = v1 and
if v1.isReferentialProperty() then firstReadSameVarUniquePredecesssor(def, g1) else any()
)
or
exists(PreSsa::Definition def, AbstractValue v |
@@ -1449,6 +1627,63 @@ module Internal {
forex(PreSsa::Definition u | u = def.getAnUltimateDefinition() | nonNullDef(u))
).getARead()
}
private predicate adjacentReadPairSameVarUniquePredecessor(
AssignableRead read1, AssignableRead read2
) {
PreSsa::adjacentReadPairSameVar(read1, read2) and
not exists(AssignableRead other |
PreSsa::adjacentReadPairSameVar(other, read2) and
other != read1 and
other != read2
)
}
cached
predicate emptyValue(Expr e) {
e.(ArrayCreation).getALengthArgument().getValue().toInt() = 0
or
e.(ArrayInitializer).hasNoElements()
or
exists(Expr mid | emptyValue(mid) |
mid = e.(AssignExpr).getRValue()
or
mid = e.(Cast).getExpr()
)
or
exists(PreSsa::Definition def | emptyDef(def) | firstReadSameVarUniquePredecesssor(def, e))
or
exists(MethodCall mc |
mc.getTarget().getAnUltimateImplementee().getSourceDeclaration() = any(SystemCollectionsGenericICollectionInterface c
).getClearMethod() and
adjacentReadPairSameVarUniquePredecessor(mc.getQualifier(), e)
)
}
cached
predicate nonEmptyValue(Expr e) {
forex(Expr length | length = e.(ArrayCreation).getALengthArgument() |
length.getValue().toInt() != 0
)
or
e.(ArrayInitializer).getNumberOfElements() > 0
or
exists(Expr mid | nonEmptyValue(mid) |
mid = e.(AssignExpr).getRValue()
or
mid = e.(Cast).getExpr()
)
or
exists(PreSsa::Definition def | nonEmptyDef(def) |
firstReadSameVarUniquePredecesssor(def, e)
)
or
exists(MethodCall mc |
mc.getTarget().getAnUltimateImplementee().getSourceDeclaration() = any(SystemCollectionsGenericICollectionInterface c
).getAddMethod() and
adjacentReadPairSameVarUniquePredecessor(mc.getQualifier(), e)
)
}
}
import CachedWithCFG
@@ -1515,14 +1750,29 @@ module Internal {
exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded))
}
private predicate adjacentReadPairSameVarUniquePredecessor(
Ssa::Definition def, ControlFlow::Node cfn1, ControlFlow::Node cfn2
) {
Ssa::Internal::adjacentReadPairSameVar(def, cfn1, cfn2) and
not exists(ControlFlow::Node other |
Ssa::Internal::adjacentReadPairSameVar(def, other, cfn2) and
other != cfn1 and
other != cfn2
)
}
cached
predicate isGuardedByExpr(
AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v
) {
isGuardedByExpr1(guarded, g, sub, v) and
sub = getAChildExprStar(g) and
forall(Ssa::Definition def | def = sub.getAnSsaQualifier(_) |
def = guarded.getAnSsaQualifier(_)
forall(Ssa::Definition def, ControlFlow::Node subCfn | def = sub.getAnSsaQualifier(subCfn) |
exists(ControlFlow::Node defCfn | def = guarded.getAnSsaQualifier(defCfn) |
if v.isReferentialProperty()
then adjacentReadPairSameVarUniquePredecessor(def, subCfn, defCfn)
else any()
)
)
}
@@ -1550,7 +1800,20 @@ module Internal {
) {
isGuardedByNode1(guarded, g, sub, v) and
sub = getAChildExprStar(g) and
forall(Ssa::Definition def | def = sub.getAnSsaQualifier(_) | isGuardedByNode2(guarded, def))
forall(Ssa::Definition def, ControlFlow::Node subCfn | def = sub.getAnSsaQualifier(subCfn) |
isGuardedByNode2(guarded, def) and
if v.isReferentialProperty()
then adjacentReadPairSameVarUniquePredecessor(def, subCfn, guarded)
else any()
)
}
private predicate firstReadUniquePredecessor(Ssa::ExplicitDefinition def, ControlFlow::Node cfn) {
exists(def.getAFirstReadAtNode(cfn)) and
not exists(ControlFlow::Node other |
Ssa::Internal::adjacentReadPairSameVar(def, other, cfn) and
other != cfn
)
}
/**
@@ -1564,11 +1827,12 @@ module Internal {
predicate impliesStep(Guard g1, AbstractValue v1, Guard g2, AbstractValue v2) {
preImpliesStep(g1, v1, g2, v2)
or
forex(ControlFlow::Node cfn | cfn = g1.getAControlFlowNode() |
forex(ControlFlow::Node cfn1 | cfn1 = g1.getAControlFlowNode() |
exists(Ssa::ExplicitDefinition def | def.getADefinition().getSource() = g2 |
g1 = def.getAReadAtNode(cfn) and
g1 = def.getAReadAtNode(cfn1) and
isGuard(g1, v1) and
v2 = v1
v2 = v1 and
if v1.isReferentialProperty() then firstReadUniquePredecessor(def, cfn1) else any()
)
)
}

View File

@@ -54,6 +54,28 @@ private newtype TCompletion =
exists(boolean b | inner = TBooleanCompletion(b) and outer = TBooleanCompletion(b.booleanNot()))
}
pragma[noinline]
private predicate completionIsValidForStmt(Stmt s, Completion c) {
s instanceof BreakStmt and
c = TBreakCompletion()
or
s instanceof ContinueStmt and
c = TContinueCompletion()
or
s instanceof GotoStmt and
c = TGotoCompletion(s.(GotoStmt).getLabel())
or
s instanceof ReturnStmt and
c = TReturnCompletion()
or
s instanceof YieldBreakStmt and
// `yield break` behaves like a return statement
c = TReturnCompletion()
or
mustHaveEmptinessCompletion(s) and
c = TEmptinessCompletion(_)
}
/**
* A completion of a statement or an expression.
*/
@@ -68,76 +90,59 @@ class Completion extends TCompletion {
* otherwise it is a normal non-Boolean completion.
*/
predicate isValidFor(ControlFlowElement cfe) {
if cfe instanceof NonReturningCall
then this = cfe.(NonReturningCall).getACompletion()
else (
this = TThrowCompletion(cfe.(TriedControlFlowElement).getAThrownException())
cfe instanceof NonReturningCall and
this = cfe.(NonReturningCall).getACompletion()
or
this = TThrowCompletion(cfe.(TriedControlFlowElement).getAThrownException())
or
cfe instanceof ThrowElement and
this = TThrowCompletion(cfe.(ThrowElement).getThrownExceptionType())
or
completionIsValidForStmt(cfe, this)
or
mustHaveBooleanCompletion(cfe) and
(
exists(boolean value | isBooleanConstant(cfe, value) | this = TBooleanCompletion(value))
or
cfe instanceof ThrowElement and
this = TThrowCompletion(cfe.(ThrowElement).getThrownExceptionType())
or
cfe instanceof BreakStmt and
this = TBreakCompletion()
or
cfe instanceof ContinueStmt and
this = TContinueCompletion()
or
cfe instanceof GotoStmt and
this = TGotoCompletion(cfe.(GotoStmt).getLabel())
or
cfe instanceof ReturnStmt and
this = TReturnCompletion()
or
cfe instanceof YieldBreakStmt and
// `yield break` behaves like a return statement
this = TReturnCompletion()
or
mustHaveBooleanCompletion(cfe) and
(
exists(boolean value | isBooleanConstant(cfe, value) | this = TBooleanCompletion(value))
or
not isBooleanConstant(cfe, _) and
this = TBooleanCompletion(_)
or
// Corner case: In `if (x ?? y) { ... }`, `x` must have both a `true`
// completion, a `false` completion, and a `null` completion (but not a
// non-`null` completion)
mustHaveNullnessCompletion(cfe) and
this = TNullnessCompletion(true)
)
not isBooleanConstant(cfe, _) and
this = TBooleanCompletion(_)
or
// Corner case: In `if (x ?? y) { ... }`, `x` must have both a `true`
// completion, a `false` completion, and a `null` completion (but not a
// non-`null` completion)
mustHaveNullnessCompletion(cfe) and
not mustHaveBooleanCompletion(cfe) and
(
exists(boolean value | isNullnessConstant(cfe, value) | this = TNullnessCompletion(value))
or
not isNullnessConstant(cfe, _) and
this = TNullnessCompletion(_)
)
or
mustHaveMatchingCompletion(cfe) and
(
exists(boolean value | isMatchingConstant(cfe, value) | this = TMatchingCompletion(value))
or
not isMatchingConstant(cfe, _) and
this = TMatchingCompletion(_)
)
or
mustHaveEmptinessCompletion(cfe) and
this = TEmptinessCompletion(_)
or
not cfe instanceof ThrowElement and
not cfe instanceof BreakStmt and
not cfe instanceof ContinueStmt and
not cfe instanceof GotoStmt and
not cfe instanceof ReturnStmt and
not cfe instanceof YieldBreakStmt and
not mustHaveBooleanCompletion(cfe) and
not mustHaveNullnessCompletion(cfe) and
not mustHaveMatchingCompletion(cfe) and
not mustHaveEmptinessCompletion(cfe) and
this = TNormalCompletion()
this = TNullnessCompletion(true)
)
or
mustHaveNullnessCompletion(cfe) and
not mustHaveBooleanCompletion(cfe) and
(
exists(boolean value | isNullnessConstant(cfe, value) | this = TNullnessCompletion(value))
or
not isNullnessConstant(cfe, _) and
this = TNullnessCompletion(_)
)
or
mustHaveMatchingCompletion(cfe) and
(
exists(boolean value | isMatchingConstant(cfe, value) | this = TMatchingCompletion(value))
or
not isMatchingConstant(cfe, _) and
this = TMatchingCompletion(_)
)
or
not cfe instanceof NonReturningCall and
not cfe instanceof ThrowElement and
not cfe instanceof BreakStmt and
not cfe instanceof ContinueStmt and
not cfe instanceof GotoStmt and
not cfe instanceof ReturnStmt and
not cfe instanceof YieldBreakStmt and
not mustHaveBooleanCompletion(cfe) and
not mustHaveNullnessCompletion(cfe) and
not mustHaveMatchingCompletion(cfe) and
not mustHaveEmptinessCompletion(cfe) and
this = TNormalCompletion()
}
/**
@@ -264,7 +269,10 @@ private predicate assemblyCompiledWithCoreLib(Assembly a, CoreLib core) {
private class TriedControlFlowElement extends ControlFlowElement {
TryStmt try;
TriedControlFlowElement() { this = try.getATriedElement() }
TriedControlFlowElement() {
this = try.getATriedElement() and
not this instanceof NonReturningCall
}
/**
* Gets an exception class that is potentially thrown by this element, if any.
@@ -372,7 +380,8 @@ private predicate invalidCastCandidate(CastExpr ce) {
*/
private predicate mustHaveBooleanCompletion(Expr e) {
inBooleanContext(e, _) and
not inBooleanContext(e.getAChildExpr(), true)
not inBooleanContext(e.getAChildExpr(), true) and
not e instanceof NonReturningCall
}
/**
@@ -442,7 +451,8 @@ private predicate inBooleanContext(Expr e, boolean isBooleanCompletionForParent)
*/
private predicate mustHaveNullnessCompletion(Expr e) {
inNullnessContext(e, _) and
not inNullnessContext(e.getAChildExpr(), true)
not inNullnessContext(e.getAChildExpr(), true) and
not e instanceof NonReturningCall
}
/**

View File

@@ -29,7 +29,8 @@ private module Cached {
TInitializerSplitKind() or
TFinallySplitKind() or
TExceptionHandlerSplitKind() or
TBooleanSplitKind(BooleanSplitting::BooleanSplitSubKind kind) { kind.startsSplit(_) }
TBooleanSplitKind(BooleanSplitting::BooleanSplitSubKind kind) { kind.startsSplit(_) } or
TLoopUnrollingSplitKind(LoopUnrollingSplitting::UnrollableLoopStmt loop)
cached
newtype TSplit =
@@ -39,7 +40,8 @@ private module Cached {
TBooleanSplit(BooleanSplitting::BooleanSplitSubKind kind, boolean branch) {
kind.startsSplit(_) and
(branch = true or branch = false)
}
} or
TLoopUnrollingSplit(LoopUnrollingSplitting::UnrollableLoopStmt loop)
cached
newtype TSplits =
@@ -1023,6 +1025,153 @@ module BooleanSplitting {
}
}
module LoopUnrollingSplitting {
private import semmle.code.csharp.controlflow.Guards as Guards
private import PreBasicBlocks
private import PreSsa
/** Holds if `ce` is guarded by a (non-)empty check, as specified by `v`. */
private predicate emptinessGuarded(
Guards::Guard g, Guards::CollectionExpr ce, Guards::AbstractValues::EmptyCollectionValue v
) {
exists(PreBasicBlock bb | Guards::Internal::preControls(g, bb, v) |
PreSsa::adjacentReadPairSameVar(g, ce) and
bb.getAnElement() = ce
)
}
/**
* A loop where the body is guaranteed to be executed at least once, and
* can therefore be unrolled in the control flow graph.
*/
abstract class UnrollableLoopStmt extends LoopStmt {
/** Holds if the step `pred --c--> succ` should start loop unrolling. */
abstract predicate startUnroll(ControlFlowElement pred, ControlFlowElement succ, Completion c);
/** Holds if the step `pred --c--> succ` should stop loop unrolling. */
abstract predicate stopUnroll(ControlFlowElement pred, ControlFlowElement succ, Completion c);
/**
* Holds if any step `pred --c--> _` should be pruned from the unrolled loop
* (the loop condition evaluating to `false`).
*/
abstract predicate pruneLoopCondition(ControlFlowElement pred, ConditionalCompletion c);
}
private class UnrollableForeachStmt extends UnrollableLoopStmt, ForeachStmt {
UnrollableForeachStmt() {
exists(Guards::AbstractValues::EmptyCollectionValue v | v.isNonEmpty() |
emptinessGuarded(_, this.getIterableExpr(), v)
or
this.getIterableExpr() = v.getAnExpr()
)
}
override predicate startUnroll(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
pred = last(this.getIterableExpr(), c) and
succ = this
}
override predicate stopUnroll(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
pred = this and
succ = succ(pred, c)
}
override predicate pruneLoopCondition(ControlFlowElement pred, ConditionalCompletion c) {
pred = this and
c.(EmptinessCompletion).isEmpty()
}
}
/**
* A split for loops where the body is guaranteed to be executed at least once, and
* can therefore be unrolled in the control flow graph. For example, in
*
* ```
* void M(string[] args)
* {
* if (args.Length == 0)
* return;
* foreach (var arg in args)
* System.Console.WriteLine(args);
* }
* ```
*
* the `foreach` loop is guaranteed to be executed at least once, as a result of the
* `args.Length == 0` check.
*/
class LoopUnrollingSplitImpl extends SplitImpl, TLoopUnrollingSplit {
UnrollableLoopStmt loop;
LoopUnrollingSplitImpl() { this = TLoopUnrollingSplit(loop) }
override string toString() {
result = "unroll (line " + loop.getLocation().getStartLine() + ")"
}
}
private int getListOrder(UnrollableLoopStmt loop) {
exists(Callable c, int r | c = loop.getEnclosingCallable() |
result = r + BooleanSplitting::getNextListOrder() - 1 and
loop = rank[r](UnrollableLoopStmt loop0 |
loop0.getEnclosingCallable() = c
|
loop0 order by loop0.getLocation().getStartLine(), loop0.getLocation().getStartColumn()
)
)
}
int getNextListOrder() {
result = max(int i | i = getListOrder(_) + 1 or i = BooleanSplitting::getNextListOrder())
}
private class LoopUnrollingSplitKind extends SplitKind, TLoopUnrollingSplitKind {
private UnrollableLoopStmt loop;
LoopUnrollingSplitKind() { this = TLoopUnrollingSplitKind(loop) }
override int getListOrder() { result = getListOrder(loop) }
override string toString() { result = "Unroll" }
}
private class LoopUnrollingSplitInternal extends SplitInternal, LoopUnrollingSplitImpl {
override LoopUnrollingSplitKind getKind() { result = TLoopUnrollingSplitKind(loop) }
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
loop.startUnroll(pred, succ, c)
}
override predicate hasEntry(Callable pred, ControlFlowElement succ) { none() }
/**
* Holds if this split applies to control flow element `pred`, where `pred`
* is a valid predecessor.
*/
private predicate appliesToPredecessor(ControlFlowElement pred, Completion c) {
this.appliesTo(pred) and
(exists(succ(pred, c)) or exists(succExit(pred, c))) and
not loop.pruneLoopCondition(pred, c)
}
override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
this.appliesToPredecessor(pred, c) and
loop.stopUnroll(pred, succ, c)
}
override Callable hasExit(ControlFlowElement pred, Completion c) {
this.appliesToPredecessor(pred, c) and
result = succExit(pred, c)
}
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
this.appliesToPredecessor(pred, c) and
succ = succ(pred, c) and
not loop.stopUnroll(pred, succ, c)
}
}
}
/**
* A set of control flow node splits. The set is represented by a list of splits,
* ordered by ascending rank.

View File

@@ -143,7 +143,7 @@ private predicate ensureNotNullAt(BasicBlock bb, int i, Ssa::Definition def) {
G::Internal::asserts(bb.getNode(i).getElement(), e, v)
|
exprImpliesSsaDef(e, v, def, nv) and
not nv.isNull()
nv.isNonNull()
)
}
@@ -258,7 +258,7 @@ private predicate defNullImpliesStep(
bb1.getLastNode() = getANullCheck(def1, s, nv).getAControlFlowNode()
|
bb2 = bb1.getASuccessorByType(s) and
not nv.isNull()
nv.isNonNull()
)
}

View File

@@ -9,14 +9,13 @@ module BaseSsa {
private import ControlFlow
private import AssignableDefinitions
pragma[noinline]
Callable getAnAssigningCallable(LocalScopeVariable v) {
result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable()
}
private class SimpleLocalScopeVariable extends LocalScopeVariable {
SimpleLocalScopeVariable() {
not exists(AssignableDefinition def1, AssignableDefinition def2 |
def1.getTarget() = this and
def2.getTarget() = this and
def1.getEnclosingCallable() != def2.getEnclosingCallable()
)
}
SimpleLocalScopeVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) }
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -1260,7 +1260,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1647,6 +1647,11 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
}
/**

View File

@@ -54,6 +54,9 @@ class SystemActionTDelegateType extends SystemUnboundGenericDelegateType {
/** `System.Array` class. */
class SystemArrayClass extends SystemClass {
SystemArrayClass() { this.hasName("Array") }
/** Gets the `Length` property. */
Property getLengthProperty() { result = this.getProperty("Length") }
}
/** `System.Attribute` class. */

View File

@@ -18,4 +18,15 @@ module SystemLinq {
class Class extends csharp::Class {
Class() { this.getNamespace() instanceof Namespace }
}
/** The `System.Linq.Enumerable` class. */
class SystemLinqEnumerableClass extends Class {
SystemLinqEnumerableClass() { this.hasName("Enumerable") }
/** Gets a `Count()` method. */
csharp::ExtensionMethod getACountMethod() { result = this.getAMethod("Count") }
/** Gets an `Any()` method. */
csharp::ExtensionMethod getAnAnyMethod() { result = this.getAMethod("Any") }
}
}

View File

@@ -18,6 +18,13 @@ class SystemCollectionsGenericUnboundGenericInterface extends UnboundGenericInte
}
}
/** An unbound generic class in the `System.Collections.Generic` namespace. */
class SystemCollectionsGenericUnboundGenericClass extends UnboundGenericClass {
SystemCollectionsGenericUnboundGenericClass() {
this.getNamespace() instanceof SystemCollectionsGenericNamespace
}
}
/** An unbound generic struct in the `System.Collections.Generic` namespace. */
class SystemCollectionsGenericUnboundGenericStruct extends UnboundGenericStruct {
SystemCollectionsGenericUnboundGenericStruct() {
@@ -86,6 +93,14 @@ class SystemCollectionsGenericIListTInterface extends SystemCollectionsGenericUn
}
}
/** The `System.Collections.Generic.List<T>` class. */
class SystemCollectionsGenericListClass extends SystemCollectionsGenericUnboundGenericClass {
SystemCollectionsGenericListClass() {
this.hasName("List<>") and
this.getNumberOfTypeParameters() = 1
}
}
/** The `System.Collections.Generic.KeyValuePair<TKey, TValue>` structure. */
class SystemCollectionsGenericKeyValuePairStruct extends SystemCollectionsGenericUnboundGenericStruct {
SystemCollectionsGenericKeyValuePairStruct() {
@@ -111,4 +126,13 @@ class SystemCollectionsGenericKeyValuePairStruct extends SystemCollectionsGeneri
/** The `System.Collections.Generic.ICollection<>` interface. */
class SystemCollectionsGenericICollectionInterface extends SystemCollectionsGenericUnboundGenericInterface {
SystemCollectionsGenericICollectionInterface() { this.hasName("ICollection<>") }
/** Gets the `Count` property. */
Property getCountProperty() { result = this.getProperty("Count") }
/** Gets the `Clear` method. */
Method getClearMethod() { result = this.getAMethod("Clear") }
/** Gets the `Add` method. */
Method getAddMethod() { result = this.getAMethod("Add") }
}

View File

@@ -179,7 +179,7 @@ private module Cached {
exists(TranslatedElement bodyOrUpdate |
bodyOrUpdate = s.getBody()
or
bodyOrUpdate = s.getUpdate()
bodyOrUpdate = s.getUpdate(_)
|
inLoop = bodyOrUpdate.getAChild*()
) and

View File

@@ -4,13 +4,14 @@ private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
private import TranslatedInitialization
private import semmle.code.csharp.ir.Util
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
/**
* The IR translation of a call to a function. The function can be a normal function
* (ie. `MethodCall`) or a constructor call (ie. `ObjectCreation`). Notice that the
* (e.g. `MethodCall`) or a constructor call (e.g. `ObjectCreation`). Notice that the
* AST generated translated calls are tied to an expression (unlike compiler generated ones,
* which can be attached to either a statement or an expression).
*/
@@ -50,7 +51,13 @@ class TranslatedFunctionCall extends TranslatedNonConstantExpr, TranslatedCall {
result = getTranslatedExpr(expr.(QualifiableExpr).getQualifier())
}
override Instruction getQualifierResult() { result = this.getQualifier().getResult() }
override Instruction getQualifierResult() {
// since `ElementInitializer`s do not have a qualifier, the qualifier's result is retrieved
// from the enclosing initialization context
if expr.getParent() instanceof CollectionInitializer
then result = getTranslatedExpr(expr.getParent()).(InitializationContext).getTargetAddress()
else result = this.getQualifier().getResult()
}
override Type getCallResultType() { result = expr.getTarget().getReturnType() }

View File

@@ -169,6 +169,11 @@ newtype TTranslatedElement =
not isNativeCondition(expr) and
not isFlexibleCondition(expr)
} or
// A creation expression
TTranslatedCreationExpr(Expr expr) {
not ignoreExpr(expr) and
(expr instanceof ObjectCreation or expr instanceof DelegateCreation)
} or
// A separate element to handle the lvalue-to-rvalue conversion step of an
// expression.
TTranslatedLoad(Expr expr) {
@@ -219,32 +224,21 @@ newtype TTranslatedElement =
// we deal with all the types of initialization separately.
// First only simple local variable initialization (ie. `int x = 0`)
exists(LocalVariableDeclAndInitExpr lvInit |
lvInit.getInitializer() = expr and
not expr instanceof ArrayCreation and
not expr instanceof ObjectCreation and
not expr instanceof DelegateCreation
lvInit.getInitializer() = expr
)
or
// Then treat more complex ones
expr instanceof ObjectCreation
or
expr instanceof DelegateCreation
or
expr instanceof ArrayInitializer
or
expr instanceof ObjectInitializer
or
expr = any(ThrowExpr throw).getExpr()
expr = any(ThrowElement throwElement).getExpr()
or
expr = any(CollectionInitializer colInit).getAnElementInitializer()
or
expr = any(ReturnStmt returnStmt).getExpr()
or
expr = any(ArrayInitializer arrInit).getAnElement()
or
expr = any(LambdaExpr lambda).getSourceDeclaration()
or
expr = any(AnonymousMethodExpr anonMethExpr).getSourceDeclaration()
)
} or
// The initialization of an array element via a member of an initializer list.

View File

@@ -24,7 +24,11 @@ private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
*/
TranslatedExpr getTranslatedExpr(Expr expr) {
result.getExpr() = expr and
result.producesExprResult()
result.producesExprResult() and
// When a constructor call is needed, we fetch it manually.
// This is because of how we translate object creations: the translated expression
// and the translated constructor call are attached to the same element.
(expr instanceof ObjectCreation implies not result instanceof TranslatedConstructorCall)
}
/**
@@ -481,11 +485,7 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial
}
override TranslatedElement getChild(int id) {
exists(AssignExpr assign |
result = getTranslatedExpr(expr.getChild(id)) and
expr.getAChild() = assign and
assign.getIndex() = id
)
result = getTranslatedExpr(expr.getMemberInitializer(id))
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
@@ -499,9 +499,57 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial
)
}
override Instruction getTargetAddress() { result = this.getParent().getInstruction(NewObjTag()) }
override Instruction getTargetAddress() {
// The target address is the address of the newly allocated object,
// which can be retrieved from the parent `TranslatedObjectCreation`.
result = this.getParent().getInstruction(NewObjTag())
}
override Type getTargetType() { none() }
override Type getTargetType() {
result = this.getParent().getInstruction(NewObjTag()).getResultType()
}
}
class TranslatedCollectionInitializer extends TranslatedNonConstantExpr, InitializationContext {
override CollectionInitializer expr;
override Instruction getResult() { none() }
override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
none()
}
override TranslatedElement getChild(int id) {
result = getTranslatedExpr(expr.getElementInitializer(id))
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
exists(int index |
child = this.getChild(index) and
(
result = this.getChild(index + 1).getFirstInstruction()
or
not exists(this.getChild(index + 1)) and
result = this.getParent().getChildSuccessor(this)
)
)
}
override Instruction getTargetAddress() {
// The target address is the address of the newly allocated object,
// which can be retrieved from the parent `TranslatedObjectCreation`.
result = this.getParent().getInstruction(NewObjTag())
}
override Type getTargetType() {
result = this.getParent().getInstruction(NewObjTag()).getResultType()
}
}
/**
@@ -1918,3 +1966,88 @@ class TranslatedDelegateCall extends TranslatedNonConstantExpr {
result = DelegateElements::getInvoke(expr)
}
}
/**
* Represents the IR translation of creation expression. Can be the translation of an
* `ObjectCreation` or a `DelegateCreation`.
* The `NewObj` instruction denotes the fact that during initialization a new
* object is allocated, which is then initialized by the constructor.
*/
abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreationExpr,
ConstructorCallContext {
TranslatedCreation() { this = TTranslatedCreationExpr(expr) }
override TranslatedElement getChild(int id) {
id = 0 and result = this.getConstructorCall()
or
id = 1 and result = this.getInitializerExpr()
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
// Instruction that allocated space for a new object,
// and returns its address
tag = NewObjTag() and
opcode instanceof Opcode::NewObj and
resultType = expr.getType() and
isLValue = false
}
final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) }
override Instruction getResult() { result = getInstruction(NewObjTag()) }
override Instruction getReceiver() { result = getInstruction(NewObjTag()) }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
tag = NewObjTag() and
result = this.getConstructorCall().getFirstInstruction()
}
override Instruction getChildSuccessor(TranslatedElement child) {
(
child = this.getConstructorCall() and
if exists(this.getInitializerExpr())
then result = this.getInitializerExpr().getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
)
or
child = this.getInitializerExpr() and
result = this.getParent().getChildSuccessor(this)
}
abstract TranslatedElement getConstructorCall();
abstract TranslatedExpr getInitializerExpr();
}
/**
* Represents the IR translation of an `ObjectCreation`.
*/
class TranslatedObjectCreation extends TranslatedCreation {
override ObjectCreation expr;
override TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) }
override TranslatedConstructorCall getConstructorCall() {
// Since calls are also expressions, we can't
// use the predicate getTranslatedExpr (since that would
// also return `this`).
result.getAST() = this.getAST()
}
}
/**
* Represents the IR translation of a `DelegateCreation`.
*/
class TranslatedDelegateCreation extends TranslatedCreation {
override DelegateCreation expr;
override TranslatedExpr getInitializerExpr() { none() }
override TranslatedElement getConstructorCall() {
result = DelegateElements::getConstructor(expr)
}
}

View File

@@ -123,13 +123,9 @@ class TranslatedArrayListInitialization extends TranslatedListInitialization {
*/
class TranslatedDirectInitialization extends TranslatedInitialization {
TranslatedDirectInitialization() {
// TODO: Make sure this is complete and correct
not expr instanceof ArrayInitializer and
not expr instanceof ObjectInitializer and
not expr instanceof DelegateCreation and
not expr instanceof CollectionInitializer and
not expr instanceof ObjectCreation and
not expr instanceof StringLiteral
not expr instanceof CollectionInitializer
}
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitializer() }
@@ -145,64 +141,6 @@ class TranslatedDirectInitialization extends TranslatedInitialization {
opcode instanceof Opcode::Store and
resultType = this.getContext().getTargetType() and
isLValue = false
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = InitializerStoreTag() and
result = this.getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInitializer() and result = this.getInstruction(InitializerStoreTag())
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = InitializerStoreTag() and
(
operandTag instanceof AddressOperandTag and
result = this.getContext().getTargetAddress()
or
operandTag instanceof StoreValueOperandTag and
result = this.getInitializer().getResult()
)
}
TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) }
}
/**
* Represents the IR translation of an initialization from a constructor.
* The `NewObj` instruction denotes the fact that during initialization a new
* object of type `expr.getType()` is allocated, which is then initialized by the
* constructor.
*/
class TranslatedObjectInitialization extends TranslatedInitialization, ConstructorCallContext {
override ObjectCreation expr;
override TranslatedElement getChild(int id) {
id = 0 and result = this.getConstructorCall()
or
id = 1 and result = this.getInitializerExpr()
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
// Instruction that allocated space for a new object,
// and returns its address
tag = NewObjTag() and
opcode instanceof Opcode::NewObj and
resultType = expr.getType() and
isLValue = false
or
// Store op used to assign the variable that
// is initialized the address of the newly allocated
// object
tag = InitializerStoreTag() and
opcode instanceof Opcode::Store and
resultType = expr.getType() and
isLValue = false
or
needsConversion() and
tag = AssignmentConvertRightTag() and
@@ -214,39 +152,22 @@ class TranslatedObjectInitialization extends TranslatedInitialization, Construct
isLValue = false
}
final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
(
tag = NewObjTag() and
result = this.getConstructorCall().getFirstInstruction()
or
tag = InitializerStoreTag() and
result = this.getParent().getChildSuccessor(this)
or
tag = AssignmentConvertRightTag() and
result = this.getInstruction(InitializerStoreTag())
)
tag = InitializerStoreTag() and
result = this.getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
or
needsConversion() and
tag = AssignmentConvertRightTag() and
result = getInstruction(InitializerStoreTag()) and
kind instanceof GotoEdge
}
override Instruction getChildSuccessor(TranslatedElement child) {
(
child = this.getConstructorCall() and
if exists(this.getInitializerExpr())
then result = this.getInitializerExpr().getFirstInstruction()
else
if this.needsConversion()
then result = this.getInstruction(AssignmentConvertRightTag())
else result = this.getInstruction(InitializerStoreTag())
)
or
(
child = this.getInitializerExpr() and
if this.needsConversion()
then result = this.getInstruction(AssignmentConvertRightTag())
else result = this.getInstruction(InitializerStoreTag())
)
child = this.getInitializer() and
if this.needsConversion()
then result = this.getInstruction(AssignmentConvertRightTag())
else result = this.getInstruction(InitializerStoreTag())
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -256,33 +177,28 @@ class TranslatedObjectInitialization extends TranslatedInitialization, Construct
result = this.getParent().(InitializationContext).getTargetAddress()
or
(
operandTag instanceof AddressOperandTag and
result = this.getContext().getTargetAddress()
or
operandTag instanceof StoreValueOperandTag and
if needsConversion()
then result = this.getInstruction(AssignmentConvertRightTag())
else result = this.getInstruction(NewObjTag())
result = this.getInitializer().getResult()
)
)
or
tag = AssignmentConvertRightTag() and
operandTag instanceof UnaryOperandTag and
result = this.getInitializer().getResult()
or
tag = AssignmentConvertRightTag() and
operandTag instanceof UnaryOperandTag and
result = this.getInstruction(NewObjTag())
}
private TranslatedExpr getConstructorCall() { result = getTranslatedExpr(expr) }
private TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) }
override Instruction getReceiver() {
// The newly allocated object will be the target of the constructor call
result = this.getInstruction(NewObjTag())
}
TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) }
private predicate needsConversion() { expr.getType() != this.getContext().getTargetType() }
}
//private string getZeroValue(Type type) {
// if type instanceof FloatingPointType then result = "0.0" else result = "0"
//}
/**
* Represents the IR translation of the initialization of an array element from
* an element of an initializer list.
@@ -424,7 +340,7 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons
TTranslatedConstructorInitializer {
TranslatedConstructorInitializer() { this = TTranslatedConstructorInitializer(call) }
override string toString() { result = "constuructor init: " + call.toString() }
override string toString() { result = "constructor init: " + call.toString() }
override Instruction getFirstInstruction() {
if needsConversion()
@@ -472,58 +388,3 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons
derivedClass = this.getFunction().getDeclaringType()
}
}
/**
* Represents the IR translation of a delegate creation.
*/
class TranslatedDelegateCreation extends TranslatedInitialization, ConstructorCallContext {
override DelegateCreation expr;
override TranslatedElement getChild(int id) { id = 0 and result = getConstructorCall() }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = NewObjTag() and
opcode instanceof Opcode::NewObj and
resultType = expr.getType() and
isLValue = false
or
tag = InitializerStoreTag() and
opcode instanceof Opcode::Store and
resultType = expr.getType() and
isLValue = false
}
final override Instruction getFirstInstruction() { result = getInstruction(NewObjTag()) }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = NewObjTag() and
result = getConstructorCall().getFirstInstruction() and
kind instanceof GotoEdge
or
tag = InitializerStoreTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getConstructorCall() and
result = getInstruction(InitializerStoreTag())
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = InitializerStoreTag() and
(
operandTag instanceof AddressOperandTag and
result = getParent().(InitializationContext).getTargetAddress()
or
operandTag instanceof StoreValueOperandTag and
result = getInstruction(NewObjTag())
)
}
private TranslatedElement getConstructorCall() { result = DelegateElements::getConstructor(expr) }
override Instruction getReceiver() { result = getInstruction(NewObjTag()) }
}

View File

@@ -651,43 +651,68 @@ class TranslatedForStmt extends TranslatedLoop {
override ForStmt stmt;
override TranslatedElement getChild(int id) {
id = 0 and result = this.getDeclAndInit()
initializerIndex(id) and result = this.getDeclAndInit(id)
or
id = 1 and result = this.getCondition()
result = this.getUpdate(updateIndex(id))
or
id = 2 and result = this.getUpdate()
id = initializersNo() + updatesNo() and result = this.getCondition()
or
id = 3 and result = this.getBody()
id = initializersNo() + updatesNo() + 1 and result = this.getBody()
}
private TranslatedLocalDeclaration getDeclAndInit() {
result = getTranslatedLocalDeclaration(stmt.getAnInitializer())
private TranslatedElement getDeclAndInit(int index) {
if stmt.getInitializer(index) instanceof LocalVariableDeclExpr
then result = getTranslatedLocalDeclaration(stmt.getInitializer(index))
else result = getTranslatedExpr(stmt.getInitializer(index))
}
private predicate hasInitialization() { exists(stmt.getAnInitializer()) }
TranslatedExpr getUpdate() { result = getTranslatedExpr(stmt.getAnUpdate()) }
TranslatedExpr getUpdate(int index) { result = getTranslatedExpr(stmt.getUpdate(index)) }
private predicate hasUpdate() { exists(stmt.getAnUpdate()) }
private int initializersNo() { result = count(stmt.getAnInitializer()) }
private int updatesNo() { result = count(stmt.getAnUpdate()) }
private predicate initializerIndex(int index) { index in [0 .. initializersNo() - 1] }
private int updateIndex(int index) {
result in [0 .. updatesNo() - 1] and
index = initializersNo() + result
}
override Instruction getFirstInstruction() {
if this.hasInitialization()
then result = this.getDeclAndInit().getFirstInstruction()
then result = this.getDeclAndInit(0).getFirstInstruction()
else result = this.getFirstConditionInstruction()
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getDeclAndInit() and
exists(int index |
child = this.getDeclAndInit(index) and
index < initializersNo() - 1 and
result = this.getDeclAndInit(index + 1).getFirstInstruction()
)
or
child = this.getDeclAndInit(initializersNo() - 1) and
result = this.getFirstConditionInstruction()
or
(
child = this.getBody() and
if this.hasUpdate()
then result = this.getUpdate().getFirstInstruction()
then result = this.getUpdate(0).getFirstInstruction()
else result = this.getFirstConditionInstruction()
)
or
child = this.getUpdate() and result = this.getFirstConditionInstruction()
exists(int index |
child = this.getUpdate(index) and
result = this.getUpdate(index + 1).getFirstInstruction()
)
or
child = this.getUpdate(updatesNo() - 1) and
result = this.getFirstConditionInstruction()
}
}
@@ -708,34 +733,63 @@ abstract class TranslatedSpecificJump extends TranslatedStmt {
isLValue = false
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind instanceof GotoEdge and
result = getTargetInstruction()
}
override Instruction getChildSuccessor(TranslatedElement child) { none() }
/**
* Gets the instruction that is the target of the jump.
*/
abstract Instruction getTargetInstruction();
}
class TranslatedBreakStmt extends TranslatedSpecificJump {
override BreakStmt stmt;
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind instanceof GotoEdge and
result = this.getEnclosingLoopOrSwitchNextInstr(stmt)
override Instruction getTargetInstruction() {
result = getEnclosingLoopOrSwitchNextInstr(stmt)
}
}
private Instruction getEnclosingLoopOrSwitchNextInstr(Stmt crtStmt) {
if crtStmt instanceof LoopStmt or crtStmt instanceof SwitchStmt
then
result = getTranslatedStmt(crtStmt).getParent().getChildSuccessor(getTranslatedStmt(crtStmt))
else result = this.getEnclosingLoopOrSwitchNextInstr(crtStmt.getParent())
private Instruction getEnclosingLoopOrSwitchNextInstr(Stmt crtStmt) {
if crtStmt instanceof LoopStmt or crtStmt instanceof SwitchStmt
then
result = getTranslatedStmt(crtStmt).getParent().getChildSuccessor(getTranslatedStmt(crtStmt))
else result = getEnclosingLoopOrSwitchNextInstr(crtStmt.getParent())
}
class TranslatedContinueStmt extends TranslatedSpecificJump {
override ContinueStmt stmt;
override Instruction getTargetInstruction() {
result = getEnclosingLoopTargetInstruction(stmt)
}
}
private Instruction getEnclosingLoopTargetInstruction(Stmt crtStmt) {
if crtStmt instanceof ForStmt
then result = getNextForInstruction(crtStmt)
else if crtStmt instanceof LoopStmt
then result = getTranslatedStmt(crtStmt).getFirstInstruction()
else result = getEnclosingLoopTargetInstruction(crtStmt.getParent())
}
private Instruction getNextForInstruction(ForStmt for) {
if exists(for.getUpdate(0))
then result = getTranslatedStmt(for).(TranslatedForStmt).getUpdate(0).getFirstInstruction()
else if exists(for.getCondition())
then result = getTranslatedStmt(for).(TranslatedForStmt).getCondition().getFirstInstruction()
else result = getTranslatedStmt(for).(TranslatedForStmt).getBody().getFirstInstruction()
}
class TranslatedGotoLabelStmt extends TranslatedSpecificJump {
override GotoLabelStmt stmt;
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind instanceof GotoEdge and
override Instruction getTargetInstruction() {
result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction()
}
}
@@ -743,44 +797,40 @@ class TranslatedGotoLabelStmt extends TranslatedSpecificJump {
class TranslatedGotoCaseStmt extends TranslatedSpecificJump {
override GotoCaseStmt stmt;
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind instanceof GotoEdge and
result = this.getCase(stmt, stmt.getExpr()).getFirstInstruction()
override Instruction getTargetInstruction() {
result = getCase(stmt, stmt.getExpr()).getFirstInstruction()
}
}
private TranslatedStmt getCase(Stmt crtStmt, Expr expr) {
if crtStmt instanceof SwitchStmt
then
exists(CaseStmt caseStmt |
caseStmt = crtStmt.(SwitchStmt).getACase() and
// We check for the constant value of the expression
// since we can't check for equality between `PatternExpr` and `Expr`
caseStmt.getPattern().getValue() = expr.getValue() and
result = getTranslatedStmt(caseStmt)
)
else result = this.getCase(crtStmt.getParent(), expr)
}
private TranslatedStmt getCase(Stmt crtStmt, Expr expr) {
if crtStmt instanceof SwitchStmt
then
exists(CaseStmt caseStmt |
caseStmt = crtStmt.(SwitchStmt).getACase() and
// We check for the constant value of the expression
// since we can't check for equality between `PatternExpr` and `Expr`
caseStmt.getPattern().getValue() = expr.getValue() and
result = getTranslatedStmt(caseStmt)
)
else result = getCase(crtStmt.getParent(), expr)
}
class TranslatedGotoDefaultStmt extends TranslatedSpecificJump {
override GotoDefaultStmt stmt;
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind instanceof GotoEdge and
override Instruction getTargetInstruction() {
result = getDefaultCase(stmt).getFirstInstruction()
}
}
private TranslatedStmt getDefaultCase(Stmt crtStmt) {
if crtStmt instanceof SwitchStmt
then
exists(CaseStmt caseStmt |
caseStmt = crtStmt.(SwitchStmt).getDefaultCase() and
result = getTranslatedStmt(caseStmt)
)
else result = this.getDefaultCase(crtStmt.getParent())
}
private TranslatedStmt getDefaultCase(Stmt crtStmt) {
if crtStmt instanceof SwitchStmt
then
exists(CaseStmt caseStmt |
caseStmt = crtStmt.(SwitchStmt).getDefaultCase() and
result = getTranslatedStmt(caseStmt)
)
else result = getDefaultCase(crtStmt.getParent())
}
class TranslatedSwitchStmt extends TranslatedStmt {

View File

@@ -3,7 +3,6 @@
* (both AST generated and compiler generated).
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
@@ -18,129 +17,112 @@ abstract class TranslatedCallBase extends TranslatedElement {
override final TranslatedElement getChild(int id) {
// We choose the child's id in the order of evaluation.
// Note: some calls do need qualifiers, though instructions for them have already
// been generated; eg. a constructor does not need to generate a qualifier,
// been generated; eg. a constructor does not need to generate a qualifier,
// though the `this` argument exists and is the result of the instruction
// that allocated the new object. For those calls, `getQualifier()` should
// be void.
id = -1 and result = getQualifier() or
id = -1 and result = getQualifier()
or
result = getArgument(id)
}
override final Instruction getFirstInstruction() {
if exists(getQualifier()) then
result = getQualifier().getFirstInstruction()
else
result = getInstruction(CallTargetTag())
final override Instruction getFirstInstruction() {
if exists(getQualifier())
then result = getQualifier().getFirstInstruction()
else result = getInstruction(CallTargetTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = CallTag() and
opcode instanceof Opcode::Call and
resultType = getCallResultType() and
isLValue = false
or
hasSideEffect() and
tag = CallSideEffectTag() and
(
tag = CallTag() and
opcode instanceof Opcode::Call and
resultType = getCallResultType() and
isLValue = false
) or
(
hasSideEffect() and
tag = CallSideEffectTag() and
(
if hasWriteSideEffect() then (
opcode instanceof Opcode::CallSideEffect and
resultType instanceof Language::UnknownType
)
else (
opcode instanceof Opcode::CallReadSideEffect and
resultType instanceof Language::UnknownType
)
) and
isLValue = false
) or
(
tag = CallTargetTag() and
opcode instanceof Opcode::FunctionAddress and
// Since the DB does not have a function type,
// we just use the UnknownType
resultType instanceof Language::UnknownType and
isLValue = true
)
if hasWriteSideEffect()
then (
opcode instanceof Opcode::CallSideEffect and
resultType instanceof Language::UnknownType
) else (
opcode instanceof Opcode::CallReadSideEffect and
resultType instanceof Language::UnknownType
)
) and
isLValue = false
or
tag = CallTargetTag() and
opcode instanceof Opcode::FunctionAddress and
// Since the DB does not have a function type,
// we just use the UnknownType
resultType instanceof Language::UnknownType and
isLValue = true
}
override Instruction getChildSuccessor(TranslatedElement child) {
(
child = getQualifier() and
result = getInstruction(CallTargetTag())
) or
child = getQualifier() and
result = getInstruction(CallTargetTag())
or
exists(int argIndex |
child = getArgument(argIndex) and
if exists(getArgument(argIndex + 1)) then
result = getArgument(argIndex + 1).getFirstInstruction()
else
result = getInstruction(CallTag())
if exists(getArgument(argIndex + 1))
then result = getArgument(argIndex + 1).getFirstInstruction()
else result = getInstruction(CallTag())
)
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
(
(
tag = CallTag() and
if hasSideEffect() then
result = getInstruction(CallSideEffectTag())
else
result = getParent().getChildSuccessor(this)
) or
(
hasSideEffect() and
tag = CallSideEffectTag() and
result = getParent().getChildSuccessor(this)
) or
(
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = getFirstArgumentOrCallInstruction()
if hasSideEffect()
then result = getInstruction(CallSideEffectTag())
else result = getParent().getChildSuccessor(this)
)
)
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
(
tag = CallTag() and
(
(
operandTag instanceof CallTargetOperandTag and
result = getInstruction(CallTargetTag())
) or
(
operandTag instanceof ThisArgumentOperandTag and
result = getQualifierResult()
) or
exists(PositionalArgumentOperandTag argTag |
argTag = operandTag and
result = getArgument(argTag.getArgIndex()).getResult()
)
)
) or
(
tag = CallSideEffectTag() and
or
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result = getUnmodeledDefinitionInstruction()
tag = CallSideEffectTag() and
result = getParent().getChildSuccessor(this)
or
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = getFirstArgumentOrCallInstruction()
)
}
override final Type getInstructionOperandType(InstructionTag tag,
TypedOperandTag operandTag) {
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = CallTag() and
(
operandTag instanceof CallTargetOperandTag and
result = getInstruction(CallTargetTag())
or
operandTag instanceof ThisArgumentOperandTag and
result = getQualifierResult()
or
exists(PositionalArgumentOperandTag argTag |
argTag = operandTag and
result = getArgument(argTag.getArgIndex()).getResult()
)
)
or
tag = CallSideEffectTag() and
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result = getUnmodeledDefinitionInstruction()
}
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag = CallSideEffectTag() and
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result instanceof Language::UnknownType
}
Instruction getResult() {
result = getInstruction(CallTag())
}
Instruction getResult() { result = getInstruction(CallTag()) }
/**
* Gets the result type of the call.
@@ -152,16 +134,14 @@ abstract class TranslatedCallBase extends TranslatedElement {
* function (of the element this call is attached to).
*/
abstract Instruction getUnmodeledDefinitionInstruction();
/**
* Holds if the call has a `this` argument.
*/
predicate hasQualifier() {
exists(getQualifier())
}
predicate hasQualifier() { exists(getQualifier()) }
/**
* Gets the expr for the qualifier of the call.
* Gets the expr for the qualifier of the call.
*/
abstract TranslatedExprBase getQualifier();
@@ -186,10 +166,9 @@ abstract class TranslatedCallBase extends TranslatedElement {
* argument. Otherwise, returns the call instruction.
*/
final Instruction getFirstArgumentOrCallInstruction() {
if hasArguments() then
result = getArgument(0).getFirstInstruction()
else
result = getInstruction(CallTag())
if hasArguments()
then result = getArgument(0).getFirstInstruction()
else result = getInstruction(CallTag())
}
/**
@@ -199,21 +178,15 @@ abstract class TranslatedCallBase extends TranslatedElement {
exists(getArgument(0))
}
predicate hasReadSideEffect() {
any()
}
predicate hasReadSideEffect() { any() }
predicate hasWriteSideEffect() {
any()
}
predicate hasWriteSideEffect() { any() }
private predicate hasSideEffect() {
hasReadSideEffect() or hasWriteSideEffect()
}
private predicate hasSideEffect() { hasReadSideEffect() or hasWriteSideEffect() }
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
hasSideEffect() and
tag = CallSideEffectTag() and
result = getResult()
hasSideEffect() and
tag = CallSideEffectTag() and
result = getResult()
}
}
}

View File

@@ -11,7 +11,6 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
/**
* Represents the context of the condition, ie. provides
* information about the instruction that follows a conditional branch.
@@ -23,30 +22,25 @@ abstract class ConditionContext extends TranslatedElement {
}
/**
* Abstract class that serves as a Base for the classes that deal with both the AST generated conditions
* Abstract class that serves as a Base for the classes that deal with both the AST generated conditions
* and the compiler generated ones (captures the common patterns).
*/
abstract class ConditionBase extends TranslatedElement {
final ConditionContext getConditionContext() {
result = getParent()
}
final ConditionContext getConditionContext() { result = getParent() }
}
/**
* Abstract class that serves as a Base for the classes that deal with both the AST generated _value_ conditions
* Abstract class that serves as a Base for the classes that deal with both the AST generated _value_ conditions
* and the compiler generated ones (captures the common patterns).
*/
abstract class ValueConditionBase extends ConditionBase {
override TranslatedElement getChild(int id) {
id = 0 and result = getValueExpr()
}
override TranslatedElement getChild(int id) { id = 0 and result = getValueExpr() }
override Instruction getFirstInstruction() {
result = getValueExpr().getFirstInstruction()
}
override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() }
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = ValueConditionConditionalBranchTag() and
opcode instanceof Opcode::ConditionalBranch and
resultType instanceof VoidType and
@@ -58,23 +52,18 @@ abstract class ValueConditionBase extends ConditionBase {
result = getInstruction(ValueConditionConditionalBranchTag())
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = ValueConditionConditionalBranchTag() and
(
(
kind instanceof TrueEdge and
result = getConditionContext().getChildTrueSuccessor(this)
) or
(
kind instanceof FalseEdge and
result = getConditionContext().getChildFalseSuccessor(this)
)
kind instanceof TrueEdge and
result = getConditionContext().getChildTrueSuccessor(this)
or
kind instanceof FalseEdge and
result = getConditionContext().getChildFalseSuccessor(this)
)
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = ValueConditionConditionalBranchTag() and
operandTag instanceof ConditionOperandTag and
result = valueExprResult()
@@ -84,9 +73,9 @@ abstract class ValueConditionBase extends ConditionBase {
* Gets the instruction that represents the result of the value expression.
*/
abstract Instruction valueExprResult();
/**
/**
* Gets the `TranslatedElements that represents the value expression.
*/
abstract TranslatedElement getValueExpr();
}
}

View File

@@ -1,5 +1,5 @@
/**
* Contains an abstract class that serves as a Base for the classes that deal with both the AST
* Contains an abstract class that serves as a Base for the classes that deal with both the AST
* generated declarations and the compiler generated ones (captures the common patterns).
*/
@@ -13,55 +13,47 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class LocalVariableDeclarationBase extends TranslatedElement {
override TranslatedElement getChild(int id) {
id = 0 and result = getInitialization()
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
override Instruction getFirstInstruction() { result = getVarAddress() }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = getVarType() and
isLValue = true
or
hasUninitializedInstruction() and
tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and
resultType = getVarType() and
isLValue = false
}
override Instruction getFirstInstruction() {
result = getVarAddress()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
(
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = getVarType() and
isLValue = true
) or
(
hasUninitializedInstruction() and
tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and
resultType = getVarType() and
isLValue = false
)
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
(
tag = InitializerVariableAddressTag() and
kind instanceof GotoEdge and
if hasUninitializedInstruction() then
result = getInstruction(InitializerStoreTag())
if hasUninitializedInstruction()
then result = getInstruction(InitializerStoreTag())
else
if isInitializedByElement() then
if isInitializedByElement()
then
// initialization is done by an element
result = getParent().getChildSuccessor(this)
else
result = getInitialization().getFirstInstruction()
) or
else result = getInitialization().getFirstInstruction()
)
or
hasUninitializedInstruction() and
kind instanceof GotoEdge and
tag = InitializerStoreTag() and
(
hasUninitializedInstruction() and
kind instanceof GotoEdge and
tag = InitializerStoreTag() and
(
result = getInitialization().getFirstInstruction() or
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
)
result = getInitialization().getFirstInstruction()
or
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
)
}
@@ -75,11 +67,11 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
operandTag instanceof AddressOperandTag and
result = getVarAddress()
}
/**
* Holds if the declaration should have an `Uninitialized` instruction.
* Compiler generated elements should override this predicate and
* make it empty, since we always initialize the vars declared during the
* make it empty, since we always initialize the vars declared during the
* desugaring process.
*/
predicate hasUninitializedInstruction() {
@@ -89,29 +81,27 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
) and
not isInitializedByElement()
}
Instruction getVarAddress() {
result = getInstruction(InitializerVariableAddressTag())
}
Instruction getVarAddress() { result = getInstruction(InitializerVariableAddressTag()) }
/**
* Gets the declared variable. For compiler generated elements, this
* Gets the declared variable. For compiler generated elements, this
* should be empty (since we treat temp vars differently).
*/
abstract LocalVariable getDeclVar();
/**
* Gets the type of the declared variable.
*/
abstract Type getVarType();
/**
* Gets the initialization, if there is one.
* For compiler generated elements we don't treat the initialization
* as a different step, but do it during the declaration.
*/
abstract TranslatedElement getInitialization();
/**
* Holds if a declaration is not explicitly initialized,
* but will be implicitly initialized by an element.

View File

@@ -11,4 +11,4 @@ abstract class TranslatedExprBase extends TranslatedElement {
* Gets the instruction that produces the result of the expression.
*/
abstract Instruction getResult();
}
}

View File

@@ -285,6 +285,42 @@
| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | exit Sub | 11 |
| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 8 |
| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 18 |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:9:13:9:28 | ... == ... | 7 |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | 1 |
| LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | 1 |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | 5 |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | 2 |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | 11 |
| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 | 1 |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | 5 |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:24:29:24:32 | access to parameter args | 3 |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | exit M3 | 1 |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | 1 |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:25:13:26:40 | [unroll (line 25)] foreach (... ... in ...) ... | 3 |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | 5 |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | 7 |
| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | exit M4 | 1 |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | 1 |
| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | 4 |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | 18 |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 | 1 |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | 1 |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | 3 |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | 7 |
| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:49:9:52:9 | {...} | 13 |
| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:51:13:51:23 | goto ...; | 5 |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:60:17:60:17 | access to parameter b | 15 |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | exit M7 | 1 |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | 4 |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | 4 |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | 9 |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | 3 |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:69:14:69:23 | call to method Any | 6 |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | exit M8 | 1 |
| LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:70:13:70:19 | return ...; | 1 |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:72:28:72:31 | access to parameter args | 4 |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | 1 |
| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | 4 |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i | 3 |
| NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | exit M1 | 1 |
| NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:28:3:28 | 0 | 1 |

View File

@@ -227,6 +227,40 @@ conditionBlock
| Foreach.cs:32:9:33:11 | foreach (... ... in ...) ... | Foreach.cs:32:23:32:23 | String x | false |
| Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:36:10:36:11 | exit M6 | true |
| Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | false |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:10:13:10:19 | return ...; | true |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:21:11:23 | String arg | false |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:28:11:31 | access to parameter args | false |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:21:11:23 | String arg | false |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 | false |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:18:21:18:21 | String x | false |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | exit M2 | true |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | exit M3 | true |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:22:24:24 | Char arg | false |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:25:26:25:29 | Char arg0 | false |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:25:26:25:29 | Char arg0 | false |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 | true |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x | false |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 | false |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | false |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:21:40:21 | String x | false |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:41:25:41:25 | String y | false |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | exit M5 | true |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | exit M5 | false |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | false |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:25:41:25 | String y | false |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | exit M5 | true |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | true |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | false |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | true |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | true |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | false |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | false |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | false |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:70:13:70:19 | return ...; | false |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:71:9:71:21 | ...; | true |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | true |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:72:21:72:23 | String arg | true |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg | false |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:28:3:28 | 0 | true |
| NullCoalescing.cs:5:9:5:10 | enter M2 | NullCoalescing.cs:5:30:5:34 | false | true |
| NullCoalescing.cs:5:9:5:10 | enter M2 | NullCoalescing.cs:5:39:5:39 | 0 | true |
@@ -822,6 +856,16 @@ conditionFlow
| ExitMethods.cs:111:16:111:25 | ... != ... | ExitMethods.cs:111:69:111:75 | "input" | false |
| ExitMethods.cs:116:16:116:30 | call to method Contains | ExitMethods.cs:116:34:116:34 | 0 | true |
| ExitMethods.cs:116:16:116:30 | call to method Contains | ExitMethods.cs:116:38:116:38 | 1 | false |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:10:13:10:19 | return ...; | true |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args | false |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | false |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | true |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | true |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | false |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | false |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; | true |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:70:13:70:19 | return ...; | false |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:71:9:71:21 | ...; | true |
| NullCoalescing.cs:5:25:5:25 | access to parameter b | NullCoalescing.cs:5:39:5:39 | 0 | true |
| NullCoalescing.cs:5:25:5:25 | access to parameter b | NullCoalescing.cs:5:43:5:43 | 1 | false |
| NullCoalescing.cs:5:30:5:34 | false | NullCoalescing.cs:5:43:5:43 | 1 | false |

View File

@@ -1310,6 +1310,155 @@ dominance
| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:37:33:37 | access to parameter j |
| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:29:33:37 | ... = ... |
| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:37 | ... + ... |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:8:5:13:5 | {...} |
| LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:9:9:10:19 | if (...) ... |
| LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:13:9:16 | access to parameter args |
| LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:9:13:9:23 | access to property Length |
| LoopUnrolling.cs:9:13:9:23 | access to property Length | LoopUnrolling.cs:9:28:9:28 | 0 |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:10:13:10:19 | return ...; |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args |
| LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:13:9:28 | ... == ... |
| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:11:21:11:23 | String arg |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:12:13:12:35 | ...; |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:12:31:12:33 | access to local variable arg |
| LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:16:5:20:5 | {...} |
| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:17:9:17:47 | ... ...; |
| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] |
| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:18:26:18:27 | access to local variable xs |
| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:32:17:34 | "a" |
| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... |
| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:37:17:39 | "b" |
| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:42:17:44 | "c" |
| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:30:17:46 | { ..., ... } |
| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:18:21:18:21 | String x |
| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:15:10:15:11 | exit M2 |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:19:13:19:33 | ...; |
| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:19:31:19:31 | access to local variable x |
| LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:23:5:27:5 | {...} |
| LoopUnrolling.cs:23:5:27:5 | {...} | LoopUnrolling.cs:24:29:24:32 | access to parameter args |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | exit M3 |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:25:34:25:37 | access to parameter args |
| LoopUnrolling.cs:24:29:24:32 | access to parameter args | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:25:13:26:40 | [unroll (line 25)] foreach (... ... in ...) ... | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:26:17:26:40 | ...; |
| LoopUnrolling.cs:25:34:25:37 | access to parameter args | LoopUnrolling.cs:25:13:26:40 | [unroll (line 25)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:26:17:26:40 | ...; | LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 |
| LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | LoopUnrolling.cs:26:17:26:39 | call to method WriteLine |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:30:5:34:5 | {...} |
| LoopUnrolling.cs:30:5:34:5 | {...} | LoopUnrolling.cs:31:9:31:31 | ... ...; |
| LoopUnrolling.cs:31:9:31:31 | ... ...; | LoopUnrolling.cs:31:29:31:29 | 0 |
| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:32:26:32:27 | access to local variable xs |
| LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... |
| LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x |
| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:33:13:33:33 | ...; |
| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:33:31:33:31 | access to local variable x |
| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:37:5:43:5 | {...} |
| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:38:9:38:47 | ... ...; |
| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] |
| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:39:9:39:47 | ... ...; |
| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:32:38:34 | "a" |
| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... |
| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:37:38:39 | "b" |
| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:42:38:44 | "c" |
| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:30:38:46 | { ..., ... } |
| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] |
| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:40:26:40:27 | access to local variable xs |
| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:32:39:34 | "0" |
| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... |
| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:37:39:39 | "1" |
| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:42:39:44 | "2" |
| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:30:39:46 | { ..., ... } |
| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:40:21:40:21 | String x |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | exit M5 |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:30:41:31 | access to local variable ys |
| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:41:25:41:25 | String y |
| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:42:17:42:41 | ...; |
| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:42:35:42:35 | access to local variable x |
| LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:39:42:39 | access to local variable y |
| LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine |
| LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:35:42:39 | ... + ... |
| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:46:5:53:5 | {...} |
| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:47:9:47:47 | ... ...; |
| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] |
| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:48:26:48:27 | access to local variable xs |
| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:32:47:34 | "a" |
| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... |
| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:37:47:39 | "b" |
| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:42:47:44 | "c" |
| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:30:47:46 | { ..., ... } |
| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:48:21:48:21 | String x |
| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:49:9:52:9 | {...} |
| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:50:13:50:17 | Label: |
| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:20:50:40 | ...; |
| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:51:13:51:23 | goto ...; |
| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:38:50:38 | access to local variable x |
| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:56:5:65:5 | {...} |
| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:57:9:57:47 | ... ...; |
| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] |
| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:58:26:58:27 | access to local variable xs |
| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:32:57:34 | "a" |
| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... |
| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:37:57:39 | "b" |
| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:42:57:44 | "c" |
| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:30:57:46 | { ..., ... } |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x |
| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | String x |
| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:59:9:64:9 | {...} |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} |
| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... |
| LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:60:13:61:37 | if (...) ... |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... | LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b |
| LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:60:17:60:17 | access to parameter b |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... |
| LoopUnrolling.cs:61:17:61:36 | [b (line 55): true] call to method WriteLine | LoopUnrolling.cs:62:13:63:37 | [b (line 55): true] if (...) ... |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:61:35:61:35 | [b (line 55): true] access to local variable x |
| LoopUnrolling.cs:61:35:61:35 | [b (line 55): true] access to local variable x | LoopUnrolling.cs:61:17:61:36 | [b (line 55): true] call to method WriteLine |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): true] if (...) ... | LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; |
| LoopUnrolling.cs:63:17:63:36 | [b (line 55): true] call to method WriteLine | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... |
| LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; | LoopUnrolling.cs:63:35:63:35 | [b (line 55): true] access to local variable x |
| LoopUnrolling.cs:63:35:63:35 | [b (line 55): true] access to local variable x | LoopUnrolling.cs:63:17:63:36 | [b (line 55): true] call to method WriteLine |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:68:5:74:5 | {...} |
| LoopUnrolling.cs:68:5:74:5 | {...} | LoopUnrolling.cs:69:9:70:19 | if (...) ... |
| LoopUnrolling.cs:69:9:70:19 | if (...) ... | LoopUnrolling.cs:69:13:69:23 | !... |
| LoopUnrolling.cs:69:13:69:23 | !... | LoopUnrolling.cs:69:14:69:17 | access to parameter args |
| LoopUnrolling.cs:69:14:69:17 | access to parameter args | LoopUnrolling.cs:69:14:69:23 | call to method Any |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:70:13:70:19 | return ...; |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:71:9:71:21 | ...; |
| LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:71:9:71:20 | call to method Clear |
| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:72:28:72:31 | access to parameter args |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:12 | access to parameter args |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg |
| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:73:13:73:35 | ...; |
| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:73:31:73:33 | access to local variable arg |
| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:28 | ... ?? ... |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:9:3:10 | exit M1 |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:28:3:28 | 0 |
@@ -3946,6 +4095,154 @@ postDominance
| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:29:33:29 | this access |
| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:37:33:37 | access to parameter j |
| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:33 | access to parameter i |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:10:13:10:19 | return ...; |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:7:10:7:11 | enter M1 |
| LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:8:5:13:5 | {...} |
| LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:9:9:10:19 | if (...) ... |
| LoopUnrolling.cs:9:13:9:23 | access to property Length | LoopUnrolling.cs:9:13:9:16 | access to parameter args |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:9:28:9:28 | 0 |
| LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:13:9:23 | access to property Length |
| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args |
| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:12:31:12:33 | access to local variable arg |
| LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:11:21:11:23 | String arg |
| LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:13:12:35 | ...; |
| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:15:10:15:11 | enter M2 |
| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:16:5:20:5 | {...} |
| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:17:30:17:46 | { ..., ... } |
| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:9:17:47 | ... ...; |
| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:42:17:44 | "c" |
| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] |
| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:32:17:34 | "a" |
| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:37:17:39 | "b" |
| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:18:26:18:27 | access to local variable xs |
| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... |
| LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:19:31:19:31 | access to local variable x |
| LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:18:21:18:21 | String x |
| LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:13:19:33 | ...; |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:23:5:27:5 | {...} | LoopUnrolling.cs:22:10:22:11 | enter M3 |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:29:24:32 | access to parameter args |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:24:29:24:32 | access to parameter args | LoopUnrolling.cs:23:5:27:5 | {...} |
| LoopUnrolling.cs:25:13:26:40 | [unroll (line 25)] foreach (... ... in ...) ... | LoopUnrolling.cs:25:34:25:37 | access to parameter args |
| LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:26:17:26:39 | call to method WriteLine |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:25:13:26:40 | [unroll (line 25)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:25:34:25:37 | access to parameter args | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 |
| LoopUnrolling.cs:26:17:26:40 | ...; | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | LoopUnrolling.cs:26:17:26:40 | ...; |
| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:30:5:34:5 | {...} | LoopUnrolling.cs:29:10:29:11 | enter M4 |
| LoopUnrolling.cs:31:9:31:31 | ... ...; | LoopUnrolling.cs:30:5:34:5 | {...} |
| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] |
| LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:29:31:29 | 0 |
| LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:9:31:31 | ... ...; |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:26:32:27 | access to local variable xs |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine |
| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... |
| LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:33:31:33:31 | access to local variable x |
| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:32:21:32:21 | String x |
| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:13:33:33 | ...; |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:36:10:36:11 | enter M5 |
| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:37:5:43:5 | {...} |
| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:38:30:38:46 | { ..., ... } |
| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:9:38:47 | ... ...; |
| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:42:38:44 | "c" |
| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] |
| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:32:38:34 | "a" |
| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:37:38:39 | "b" |
| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... |
| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:39:30:39:46 | { ..., ... } |
| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:9:39:47 | ... ...; |
| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:42:39:44 | "2" |
| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] |
| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:32:39:34 | "0" |
| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:37:39:39 | "1" |
| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:40:26:40:27 | access to local variable xs |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... |
| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:41:30:41:31 | access to local variable ys |
| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:40:21:40:21 | String x |
| LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:42:35:42:39 | ... + ... |
| LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:41:25:41:25 | String y |
| LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:17:42:41 | ...; |
| LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:42:39:42:39 | access to local variable y |
| LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:35:42:35 | access to local variable x |
| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:45:10:45:11 | enter M6 |
| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:46:5:53:5 | {...} |
| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:47:30:47:46 | { ..., ... } |
| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:9:47:47 | ... ...; |
| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:42:47:44 | "c" |
| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] |
| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:32:47:34 | "a" |
| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:37:47:39 | "b" |
| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:48:26:48:27 | access to local variable xs |
| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... |
| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:48:21:48:21 | String x |
| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:50:38:50:38 | access to local variable x |
| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:13:50:17 | Label: |
| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:20:50:40 | ...; |
| LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... |
| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:55:10:55:11 | enter M7 |
| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:56:5:65:5 | {...} |
| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:57:30:57:46 | { ..., ... } |
| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:9:57:47 | ... ...; |
| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:42:57:44 | "c" |
| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] |
| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:32:57:34 | "a" |
| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:37:57:39 | "b" |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:63:17:63:36 | [b (line 55): true] call to method WriteLine |
| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:58:26:58:27 | access to local variable xs |
| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... |
| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x |
| LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:58:21:58:21 | String x |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} |
| LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:59:9:64:9 | {...} |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:60:13:61:37 | if (...) ... |
| LoopUnrolling.cs:61:17:61:36 | [b (line 55): true] call to method WriteLine | LoopUnrolling.cs:61:35:61:35 | [b (line 55): true] access to local variable x |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b |
| LoopUnrolling.cs:61:35:61:35 | [b (line 55): true] access to local variable x | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): true] if (...) ... | LoopUnrolling.cs:61:17:61:36 | [b (line 55): true] call to method WriteLine |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:62:13:63:37 | [b (line 55): true] if (...) ... |
| LoopUnrolling.cs:63:17:63:36 | [b (line 55): true] call to method WriteLine | LoopUnrolling.cs:63:35:63:35 | [b (line 55): true] access to local variable x |
| LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; | LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b |
| LoopUnrolling.cs:63:35:63:35 | [b (line 55): true] access to local variable x | LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:70:13:70:19 | return ...; |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:68:5:74:5 | {...} | LoopUnrolling.cs:67:10:67:11 | enter M8 |
| LoopUnrolling.cs:69:9:70:19 | if (...) ... | LoopUnrolling.cs:68:5:74:5 | {...} |
| LoopUnrolling.cs:69:13:69:23 | !... | LoopUnrolling.cs:69:9:70:19 | if (...) ... |
| LoopUnrolling.cs:69:14:69:17 | access to parameter args | LoopUnrolling.cs:69:13:69:23 | !... |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:69:14:69:17 | access to parameter args |
| LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:71:9:71:21 | ...; |
| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:71:9:71:12 | access to parameter args |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:28:72:31 | access to parameter args |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine |
| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:71:9:71:20 | call to method Clear |
| LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:73:31:73:33 | access to local variable arg |
| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:72:21:72:23 | String arg |
| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:13:73:35 | ...; |
| NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i |
| NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:28:3:28 | 0 |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:28 | ... ?? ... |
@@ -5934,6 +6231,89 @@ blockDominance
| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | enter Sub |
| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | enter Sub |
| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | enter Sub |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:10:13:10:19 | return ...; |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:21:11:23 | String arg |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:11:28:11:31 | access to parameter args |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 |
| LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:21:11:23 | String arg |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:21:11:23 | String arg |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:28:11:31 | access to parameter args |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | enter M2 |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:18:21:18:21 | String x |
| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | exit M2 |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:21:18:21 | String x |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:22:10:22:11 | enter M3 |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:22:10:22:11 | exit M3 |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | exit M3 |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | exit M3 |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | enter M4 |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | exit M4 |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:32:21:32:21 | String x |
| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | exit M4 |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x |
| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:32:21:32:21 | String x |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | enter M5 |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:40:21:40:21 | String x |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:41:25:41:25 | String y |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | exit M5 |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | exit M5 |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:21:40:21 | String x |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:25:41:25 | String y |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | exit M5 |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:25:41:25 | String y |
| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:45:10:45:11 | enter M6 |
| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:50:13:50:17 | Label: |
| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:13:50:17 | Label: |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | enter M7 |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | exit M7 |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | exit M7 |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:67:10:67:11 | enter M8 |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:67:10:67:11 | exit M8 |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:70:13:70:19 | return ...; |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:71:9:71:21 | ...; |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:72:21:72:23 | String arg |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | exit M8 |
| LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:70:13:70:19 | return ...; |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:21 | ...; |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:72:21:72:23 | String arg |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg |
| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:72:21:72:23 | String arg |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | exit M1 |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:28:3:28 | 0 |
@@ -8030,6 +8410,87 @@ postBlockDominance
| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | enter Sub |
| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | enter Sub |
| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | enter Sub |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:10:13:10:19 | return ...; |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:21:11:23 | String arg |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:28:11:31 | access to parameter args |
| LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:21:11:23 | String arg |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:28:11:31 | access to parameter args |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:28:11:31 | access to parameter args |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | enter M2 |
| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | enter M2 |
| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | exit M2 |
| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:18:21:18:21 | String x |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | enter M2 |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:21:18:21 | String x |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:22:10:22:11 | enter M3 |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | enter M3 |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | exit M3 |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | enter M3 |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | enter M4 |
| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | enter M4 |
| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | exit M4 |
| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:32:21:32:21 | String x |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | enter M4 |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x |
| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:32:21:32:21 | String x |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | enter M5 |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | enter M5 |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | exit M5 |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:40:21:40:21 | String x |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:41:25:41:25 | String y |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | enter M5 |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:21:40:21 | String x |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:25:41:25 | String y |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | enter M5 |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:21:40:21 | String x |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | enter M5 |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:40:21:40:21 | String x |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:25:41:25 | String y |
| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:45:10:45:11 | enter M6 |
| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:13:50:17 | Label: |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | enter M7 |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | enter M7 |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | exit M7 |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:67:10:67:11 | enter M8 |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | enter M8 |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | exit M8 |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:70:13:70:19 | return ...; |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:71:9:71:21 | ...; |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:72:21:72:23 | String arg |
| LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:70:13:70:19 | return ...; |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:21 | ...; |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:71:9:71:21 | ...; |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg |
| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:72:21:72:23 | String arg |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 |
| NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | enter M1 |
| NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | exit M1 |

View File

@@ -1428,6 +1428,166 @@ nodeEnclosing
| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:9:33:11 | Sub |
| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:9:33:11 | Sub |
| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:9:33:11 | Sub |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:9:13:9:23 | access to property Length | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:23:5:27:5 | {...} | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:24:29:24:32 | access to parameter args | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:25:13:26:40 | [unroll (line 25)] foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:25:34:25:37 | access to parameter args | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:26:17:26:40 | ...; | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:30:5:34:5 | {...} | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:31:9:31:31 | ... ...; | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:61:17:61:36 | [b (line 55): true] call to method WriteLine | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:61:35:61:35 | [b (line 55): true] access to local variable x | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): true] if (...) ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:63:17:63:36 | [b (line 55): true] call to method WriteLine | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:63:35:63:35 | [b (line 55): true] access to local variable x | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:68:5:74:5 | {...} | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:69:9:70:19 | if (...) ... | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:69:13:69:23 | !... | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:69:14:69:17 | access to parameter args | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:67:10:67:11 | M8 |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | M1 |
| NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | M1 |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:9:3:10 | M1 |
@@ -3150,6 +3310,42 @@ blockEnclosing
| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | Sub |
| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | Sub |
| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | Sub |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:7:10:7:11 | M1 |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:15:10:15:11 | exit M2 | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:15:10:15:11 | M2 |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:22:10:22:11 | exit M3 | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:22:10:22:11 | M3 |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:29:10:29:11 | exit M4 | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:29:10:29:11 | M4 |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:36:10:36:11 | exit M5 | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:36:10:36:11 | M5 |
| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:45:10:45:11 | M6 |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:55:10:55:11 | exit M7 | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:55:10:55:11 | M7 |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:67:10:67:11 | exit M8 | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:67:10:67:11 | M8 |
| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:67:10:67:11 | M8 |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | M1 |
| NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | M1 |
| NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:9:3:10 | M1 |

View File

@@ -1075,6 +1075,139 @@
| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:33:33:33 | access to parameter i |
| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:33:33:33 | access to parameter i |
| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:37:33:37 | access to parameter j |
| LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:8:5:13:5 | {...} |
| LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:9:10:19 | if (...) ... |
| LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:9:13:9:16 | access to parameter args |
| LoopUnrolling.cs:9:13:9:23 | access to property Length | LoopUnrolling.cs:9:13:9:16 | access to parameter args |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:9:13:9:16 | access to parameter args |
| LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:28:9:28 | 0 |
| LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; |
| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:21:11:23 | String arg |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:28:11:31 | access to parameter args |
| LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:12:31:12:33 | access to local variable arg |
| LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:12:13:12:35 | ...; |
| LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:31:12:33 | access to local variable arg |
| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:16:5:20:5 | {...} |
| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:17:9:17:47 | ... ...; |
| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] |
| LoopUnrolling.cs:17:18:17:46 | 3 | LoopUnrolling.cs:17:18:17:46 | 3 |
| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] |
| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:32:17:34 | "a" |
| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:32:17:34 | "a" |
| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:37:17:39 | "b" |
| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:42:17:44 | "c" |
| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:18:26:18:27 | access to local variable xs |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:21:18:21 | String x |
| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:18:26:18:27 | access to local variable xs |
| LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:19:31:19:31 | access to local variable x |
| LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:19:13:19:33 | ...; |
| LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:31:19:31 | access to local variable x |
| LoopUnrolling.cs:23:5:27:5 | {...} | LoopUnrolling.cs:23:5:27:5 | {...} |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:29:24:32 | access to parameter args |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:24:22:24:24 | Char arg |
| LoopUnrolling.cs:24:29:24:32 | access to parameter args | LoopUnrolling.cs:24:29:24:32 | access to parameter args |
| LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:25:34:25:37 | access to parameter args |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:25:26:25:29 | Char arg0 |
| LoopUnrolling.cs:25:34:25:37 | access to parameter args | LoopUnrolling.cs:25:34:25:37 | access to parameter args |
| LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 |
| LoopUnrolling.cs:26:17:26:40 | ...; | LoopUnrolling.cs:26:17:26:40 | ...; |
| LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 |
| LoopUnrolling.cs:30:5:34:5 | {...} | LoopUnrolling.cs:30:5:34:5 | {...} |
| LoopUnrolling.cs:31:9:31:31 | ... ...; | LoopUnrolling.cs:31:9:31:31 | ... ...; |
| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:31:29:31:29 | 0 |
| LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:29:31:29 | 0 |
| LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:29:31:29 | 0 |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:26:32:27 | access to local variable xs |
| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:32:21:32:21 | String x |
| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:32:26:32:27 | access to local variable xs |
| LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:33:31:33:31 | access to local variable x |
| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:33:13:33:33 | ...; |
| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:31:33:31 | access to local variable x |
| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:37:5:43:5 | {...} |
| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:38:9:38:47 | ... ...; |
| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] |
| LoopUnrolling.cs:38:18:38:46 | 3 | LoopUnrolling.cs:38:18:38:46 | 3 |
| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] |
| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:32:38:34 | "a" |
| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:32:38:34 | "a" |
| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:37:38:39 | "b" |
| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:42:38:44 | "c" |
| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:39:9:39:47 | ... ...; |
| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] |
| LoopUnrolling.cs:39:18:39:46 | 3 | LoopUnrolling.cs:39:18:39:46 | 3 |
| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] |
| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:32:39:34 | "0" |
| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:32:39:34 | "0" |
| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:37:39:39 | "1" |
| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:42:39:44 | "2" |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:26:40:27 | access to local variable xs |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:21:40:21 | String x |
| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:40:26:40:27 | access to local variable xs |
| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:30:41:31 | access to local variable ys |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:25:41:25 | String y |
| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:41:30:41:31 | access to local variable ys |
| LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:42:35:42:35 | access to local variable x |
| LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:42:17:42:41 | ...; |
| LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:35:42:35 | access to local variable x |
| LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:42:35:42:35 | access to local variable x |
| LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:39:42:39 | access to local variable y |
| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:46:5:53:5 | {...} |
| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:47:9:47:47 | ... ...; |
| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] |
| LoopUnrolling.cs:47:18:47:46 | 3 | LoopUnrolling.cs:47:18:47:46 | 3 |
| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] |
| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:32:47:34 | "a" |
| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:32:47:34 | "a" |
| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:37:47:39 | "b" |
| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:42:47:44 | "c" |
| LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:48:26:48:27 | access to local variable xs |
| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:48:21:48:21 | String x |
| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:48:26:48:27 | access to local variable xs |
| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:49:9:52:9 | {...} |
| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:13:50:17 | Label: |
| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:50:38:50:38 | access to local variable x |
| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:20:50:40 | ...; |
| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:38:50:38 | access to local variable x |
| LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:51:13:51:23 | goto ...; |
| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:56:5:65:5 | {...} |
| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:57:9:57:47 | ... ...; |
| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] |
| LoopUnrolling.cs:57:18:57:46 | 3 | LoopUnrolling.cs:57:18:57:46 | 3 |
| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] |
| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:32:57:34 | "a" |
| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:32:57:34 | "a" |
| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:37:57:39 | "b" |
| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:42:57:44 | "c" |
| LoopUnrolling.cs:58:9:64:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:58:26:58:27 | access to local variable xs |
| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:58:21:58:21 | String x |
| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:58:26:58:27 | access to local variable xs |
| LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:59:9:64:9 | {...} |
| LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:60:13:61:37 | if (...) ... |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:60:17:60:17 | access to parameter b |
| LoopUnrolling.cs:61:17:61:36 | call to method WriteLine | LoopUnrolling.cs:61:35:61:35 | access to local variable x |
| LoopUnrolling.cs:61:17:61:37 | ...; | LoopUnrolling.cs:61:17:61:37 | ...; |
| LoopUnrolling.cs:61:35:61:35 | access to local variable x | LoopUnrolling.cs:61:35:61:35 | access to local variable x |
| LoopUnrolling.cs:62:13:63:37 | if (...) ... | LoopUnrolling.cs:62:13:63:37 | if (...) ... |
| LoopUnrolling.cs:62:17:62:17 | access to parameter b | LoopUnrolling.cs:62:17:62:17 | access to parameter b |
| LoopUnrolling.cs:63:17:63:36 | call to method WriteLine | LoopUnrolling.cs:63:35:63:35 | access to local variable x |
| LoopUnrolling.cs:63:17:63:37 | ...; | LoopUnrolling.cs:63:17:63:37 | ...; |
| LoopUnrolling.cs:63:35:63:35 | access to local variable x | LoopUnrolling.cs:63:35:63:35 | access to local variable x |
| LoopUnrolling.cs:68:5:74:5 | {...} | LoopUnrolling.cs:68:5:74:5 | {...} |
| LoopUnrolling.cs:69:9:70:19 | if (...) ... | LoopUnrolling.cs:69:9:70:19 | if (...) ... |
| LoopUnrolling.cs:69:13:69:23 | !... | LoopUnrolling.cs:69:13:69:23 | !... |
| LoopUnrolling.cs:69:14:69:17 | access to parameter args | LoopUnrolling.cs:69:14:69:17 | access to parameter args |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:69:14:69:17 | access to parameter args |
| LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:70:13:70:19 | return ...; |
| LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:71:9:71:12 | access to parameter args |
| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:71:9:71:12 | access to parameter args |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:21 | ...; |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:28:72:31 | access to parameter args |
| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:72:21:72:23 | String arg |
| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:72:28:72:31 | access to parameter args |
| LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:73:31:73:33 | access to local variable arg |
| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:73:13:73:35 | ...; |
| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:31:73:33 | access to local variable arg |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i |
| NullCoalescing.cs:3:23:3:28 | ... ?? ... | NullCoalescing.cs:3:23:3:28 | ... ?? ... |
| NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:28:3:28 | 0 |

View File

@@ -1372,6 +1372,153 @@
| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:33:33:33 | access to parameter i | normal |
| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:33:33:37 | ... + ... | normal |
| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:37:33:37 | access to parameter j | normal |
| LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:10:13:10:19 | return ...; | return |
| LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:13:9:28 | ... == ... | false |
| LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:10:13:10:19 | return ...; | return |
| LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:9:13:9:16 | access to parameter args | normal |
| LoopUnrolling.cs:9:13:9:23 | access to property Length | LoopUnrolling.cs:9:13:9:23 | access to property Length | normal |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:9:13:9:28 | ... == ... | false |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:9:13:9:28 | ... == ... | true |
| LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:28:9:28 | 0 | normal |
| LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | return |
| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:11:21:11:23 | String arg | normal |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:28:11:31 | access to parameter args | normal |
| LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | normal |
| LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | normal |
| LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | normal |
| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | normal |
| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | normal |
| LoopUnrolling.cs:17:18:17:46 | 3 | LoopUnrolling.cs:17:18:17:46 | 3 | normal |
| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:30:17:46 | { ..., ... } | normal |
| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:30:17:46 | { ..., ... } | normal |
| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:32:17:34 | "a" | normal |
| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:37:17:39 | "b" | normal |
| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:42:17:44 | "c" | normal |
| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:18:21:18:21 | String x | normal |
| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:18:26:18:27 | access to local variable xs | normal |
| LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | normal |
| LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | normal |
| LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:31:19:31 | access to local variable x | normal |
| LoopUnrolling.cs:23:5:27:5 | {...} | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:24:22:24:24 | Char arg | normal |
| LoopUnrolling.cs:24:29:24:32 | access to parameter args | LoopUnrolling.cs:24:29:24:32 | access to parameter args | normal |
| LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:25:26:25:29 | Char arg0 | normal |
| LoopUnrolling.cs:25:34:25:37 | access to parameter args | LoopUnrolling.cs:25:34:25:37 | access to parameter args | normal |
| LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | normal |
| LoopUnrolling.cs:26:17:26:40 | ...; | LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | normal |
| LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | normal |
| LoopUnrolling.cs:30:5:34:5 | {...} | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:31:9:31:31 | ... ...; | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | normal |
| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | normal |
| LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | normal |
| LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:29:31:29 | 0 | normal |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:32:21:32:21 | String x | normal |
| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | normal |
| LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | normal |
| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | normal |
| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:31:33:31 | access to local variable x | normal |
| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | normal |
| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | normal |
| LoopUnrolling.cs:38:18:38:46 | 3 | LoopUnrolling.cs:38:18:38:46 | 3 | normal |
| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:30:38:46 | { ..., ... } | normal |
| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:30:38:46 | { ..., ... } | normal |
| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:32:38:34 | "a" | normal |
| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:37:38:39 | "b" | normal |
| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:42:38:44 | "c" | normal |
| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | normal |
| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | normal |
| LoopUnrolling.cs:39:18:39:46 | 3 | LoopUnrolling.cs:39:18:39:46 | 3 | normal |
| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:30:39:46 | { ..., ... } | normal |
| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:30:39:46 | { ..., ... } | normal |
| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:32:39:34 | "0" | normal |
| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:37:39:39 | "1" | normal |
| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:42:39:44 | "2" | normal |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:40:21:40:21 | String x | normal |
| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:40:26:40:27 | access to local variable xs | normal |
| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:41:25:41:25 | String y | normal |
| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:41:30:41:31 | access to local variable ys | normal |
| LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | normal |
| LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | normal |
| LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:35:42:35 | access to local variable x | normal |
| LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:42:35:42:39 | ... + ... | normal |
| LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:39:42:39 | access to local variable y | normal |
| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:51:13:51:23 | goto ...; | goto(Label) |
| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | normal |
| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | normal |
| LoopUnrolling.cs:47:18:47:46 | 3 | LoopUnrolling.cs:47:18:47:46 | 3 | normal |
| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:30:47:46 | { ..., ... } | normal |
| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:30:47:46 | { ..., ... } | normal |
| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:32:47:34 | "a" | normal |
| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:37:47:39 | "b" | normal |
| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:42:47:44 | "c" | normal |
| LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:48:9:52:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:51:13:51:23 | goto ...; | goto(Label) |
| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:48:21:48:21 | String x | normal |
| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:48:26:48:27 | access to local variable xs | normal |
| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:51:13:51:23 | goto ...; | goto(Label) |
| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:13:50:17 | Label: | normal |
| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | normal |
| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | normal |
| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:38:50:38 | access to local variable x | normal |
| LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:51:13:51:23 | goto ...; | goto(Label) |
| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:58:9:64:9 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | normal |
| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | normal |
| LoopUnrolling.cs:57:18:57:46 | 3 | LoopUnrolling.cs:57:18:57:46 | 3 | normal |
| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:30:57:46 | { ..., ... } | normal |
| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:30:57:46 | { ..., ... } | normal |
| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:32:57:34 | "a" | normal |
| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:37:57:39 | "b" | normal |
| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:42:57:44 | "c" | normal |
| LoopUnrolling.cs:58:9:64:9 | foreach (... ... in ...) ... | LoopUnrolling.cs:58:9:64:9 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:58:21:58:21 | String x | normal |
| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:58:26:58:27 | access to local variable xs | normal |
| LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:62:17:62:17 | access to parameter b | false |
| LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:63:17:63:36 | call to method WriteLine | normal |
| LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:60:17:60:17 | access to parameter b | false |
| LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:61:17:61:36 | call to method WriteLine | normal |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:60:17:60:17 | access to parameter b | false |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:60:17:60:17 | access to parameter b | true |
| LoopUnrolling.cs:61:17:61:36 | call to method WriteLine | LoopUnrolling.cs:61:17:61:36 | call to method WriteLine | normal |
| LoopUnrolling.cs:61:17:61:37 | ...; | LoopUnrolling.cs:61:17:61:36 | call to method WriteLine | normal |
| LoopUnrolling.cs:61:35:61:35 | access to local variable x | LoopUnrolling.cs:61:35:61:35 | access to local variable x | normal |
| LoopUnrolling.cs:62:13:63:37 | if (...) ... | LoopUnrolling.cs:62:17:62:17 | access to parameter b | false |
| LoopUnrolling.cs:62:13:63:37 | if (...) ... | LoopUnrolling.cs:63:17:63:36 | call to method WriteLine | normal |
| LoopUnrolling.cs:62:17:62:17 | access to parameter b | LoopUnrolling.cs:62:17:62:17 | access to parameter b | false |
| LoopUnrolling.cs:62:17:62:17 | access to parameter b | LoopUnrolling.cs:62:17:62:17 | access to parameter b | true |
| LoopUnrolling.cs:63:17:63:36 | call to method WriteLine | LoopUnrolling.cs:63:17:63:36 | call to method WriteLine | normal |
| LoopUnrolling.cs:63:17:63:37 | ...; | LoopUnrolling.cs:63:17:63:36 | call to method WriteLine | normal |
| LoopUnrolling.cs:63:35:63:35 | access to local variable x | LoopUnrolling.cs:63:35:63:35 | access to local variable x | normal |
| LoopUnrolling.cs:68:5:74:5 | {...} | LoopUnrolling.cs:70:13:70:19 | return ...; | return |
| LoopUnrolling.cs:68:5:74:5 | {...} | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:69:9:70:19 | if (...) ... | LoopUnrolling.cs:69:14:69:23 | call to method Any | false [true] |
| LoopUnrolling.cs:69:9:70:19 | if (...) ... | LoopUnrolling.cs:70:13:70:19 | return ...; | return |
| LoopUnrolling.cs:69:13:69:23 | !... | LoopUnrolling.cs:69:14:69:23 | call to method Any | false [true] |
| LoopUnrolling.cs:69:13:69:23 | !... | LoopUnrolling.cs:69:14:69:23 | call to method Any | true [false] |
| LoopUnrolling.cs:69:14:69:17 | access to parameter args | LoopUnrolling.cs:69:14:69:17 | access to parameter args | normal |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:69:14:69:23 | call to method Any | false |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:69:14:69:23 | call to method Any | true |
| LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:70:13:70:19 | return ...; | return |
| LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:71:9:71:12 | access to parameter args | normal |
| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:71:9:71:20 | call to method Clear | normal |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:20 | call to method Clear | normal |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | empty |
| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:72:21:72:23 | String arg | normal |
| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:72:28:72:31 | access to parameter args | normal |
| LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | normal |
| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | normal |
| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | normal |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | non-null |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | null |
| NullCoalescing.cs:3:23:3:28 | ... ?? ... | NullCoalescing.cs:3:23:3:23 | access to parameter i | non-null |

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
class LoopUnrolling
{
void M1(string[] args)
{
if (args.Length == 0)
return;
foreach(var arg in args) // unroll
Console.WriteLine(arg);
}
void M2()
{
var xs = new string[]{ "a", "b", "c" };
foreach(var x in xs) // unroll
Console.WriteLine(x);
}
void M3(string args)
{
foreach (var arg in args) // no unroll
foreach (var arg0 in args) // unroll
Console.WriteLine(arg0);
}
void M4()
{
var xs = new string[0];
foreach(var x in xs) // no unroll
Console.WriteLine(x);
}
void M5()
{
var xs = new string[]{ "a", "b", "c" };
var ys = new string[]{ "0", "1", "2" };
foreach(var x in xs) // unroll
foreach(var y in ys) // unroll
Console.WriteLine(x + y);
}
void M6()
{
var xs = new string[]{ "a", "b", "c" };
foreach(var x in xs) // unroll
{
Label: Console.WriteLine(x);
goto Label;
}
}
void M7(bool b)
{
var xs = new string[]{ "a", "b", "c" };
foreach(var x in xs) // unroll
{
if (b)
Console.WriteLine(x);
if (b)
Console.WriteLine(x);
}
}
void M8(List<string> args)
{
if (!args.Any())
return;
args.Clear();
foreach(var arg in args) // no unroll
Console.WriteLine(arg);
}
}

View File

@@ -1447,6 +1447,172 @@
| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:37:33:37 | access to parameter j | semmle.label | successor |
| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:29:33:37 | ... = ... | semmle.label | successor |
| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:37 | ... + ... | semmle.label | successor |
| LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:8:5:13:5 | {...} | semmle.label | successor |
| LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:9:9:10:19 | if (...) ... | semmle.label | successor |
| LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:13:9:16 | access to parameter args | semmle.label | successor |
| LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:9:13:9:23 | access to property Length | semmle.label | successor |
| LoopUnrolling.cs:9:13:9:23 | access to property Length | LoopUnrolling.cs:9:28:9:28 | 0 | semmle.label | successor |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:10:13:10:19 | return ...; | semmle.label | true |
| LoopUnrolling.cs:9:13:9:28 | ... == ... | LoopUnrolling.cs:11:28:11:31 | access to parameter args | semmle.label | false |
| LoopUnrolling.cs:9:28:9:28 | 0 | LoopUnrolling.cs:9:13:9:28 | ... == ... | semmle.label | successor |
| LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:7:10:7:11 | exit M1 | semmle.label | return |
| LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | LoopUnrolling.cs:11:21:11:23 | String arg | semmle.label | non-empty |
| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:7:10:7:11 | exit M1 | semmle.label | empty |
| LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:11:21:11:23 | String arg | semmle.label | non-empty |
| LoopUnrolling.cs:11:21:11:23 | String arg | LoopUnrolling.cs:12:13:12:35 | ...; | semmle.label | successor |
| LoopUnrolling.cs:11:28:11:31 | access to parameter args | LoopUnrolling.cs:11:9:12:35 | [unroll (line 11)] foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:12:13:12:35 | ...; | LoopUnrolling.cs:12:31:12:33 | access to local variable arg | semmle.label | successor |
| LoopUnrolling.cs:12:31:12:33 | access to local variable arg | LoopUnrolling.cs:12:13:12:34 | call to method WriteLine | semmle.label | successor |
| LoopUnrolling.cs:15:10:15:11 | enter M2 | LoopUnrolling.cs:16:5:20:5 | {...} | semmle.label | successor |
| LoopUnrolling.cs:16:5:20:5 | {...} | LoopUnrolling.cs:17:9:17:47 | ... ...; | semmle.label | successor |
| LoopUnrolling.cs:17:9:17:47 | ... ...; | LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | semmle.label | successor |
| LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | LoopUnrolling.cs:18:26:18:27 | access to local variable xs | semmle.label | successor |
| LoopUnrolling.cs:17:18:17:46 | array creation of type String[] | LoopUnrolling.cs:17:32:17:34 | "a" | semmle.label | successor |
| LoopUnrolling.cs:17:30:17:46 | { ..., ... } | LoopUnrolling.cs:17:13:17:46 | String[] xs = ... | semmle.label | successor |
| LoopUnrolling.cs:17:32:17:34 | "a" | LoopUnrolling.cs:17:37:17:39 | "b" | semmle.label | successor |
| LoopUnrolling.cs:17:37:17:39 | "b" | LoopUnrolling.cs:17:42:17:44 | "c" | semmle.label | successor |
| LoopUnrolling.cs:17:42:17:44 | "c" | LoopUnrolling.cs:17:30:17:46 | { ..., ... } | semmle.label | successor |
| LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | LoopUnrolling.cs:18:21:18:21 | String x | semmle.label | non-empty |
| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:15:10:15:11 | exit M2 | semmle.label | empty |
| LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:18:21:18:21 | String x | semmle.label | non-empty |
| LoopUnrolling.cs:18:21:18:21 | String x | LoopUnrolling.cs:19:13:19:33 | ...; | semmle.label | successor |
| LoopUnrolling.cs:18:26:18:27 | access to local variable xs | LoopUnrolling.cs:18:9:19:33 | [unroll (line 18)] foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | LoopUnrolling.cs:18:9:19:33 | foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:19:13:19:33 | ...; | LoopUnrolling.cs:19:31:19:31 | access to local variable x | semmle.label | successor |
| LoopUnrolling.cs:19:31:19:31 | access to local variable x | LoopUnrolling.cs:19:13:19:32 | call to method WriteLine | semmle.label | successor |
| LoopUnrolling.cs:22:10:22:11 | enter M3 | LoopUnrolling.cs:23:5:27:5 | {...} | semmle.label | successor |
| LoopUnrolling.cs:23:5:27:5 | {...} | LoopUnrolling.cs:24:29:24:32 | access to parameter args | semmle.label | successor |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:22:10:22:11 | exit M3 | semmle.label | empty |
| LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:22:24:24 | Char arg | semmle.label | non-empty |
| LoopUnrolling.cs:24:22:24:24 | Char arg | LoopUnrolling.cs:25:34:25:37 | access to parameter args | semmle.label | successor |
| LoopUnrolling.cs:24:29:24:32 | access to parameter args | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:25:13:26:40 | [unroll (line 25)] foreach (... ... in ...) ... | LoopUnrolling.cs:25:26:25:29 | Char arg0 | semmle.label | non-empty |
| LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:24:9:26:40 | foreach (... ... in ...) ... | semmle.label | empty |
| LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | LoopUnrolling.cs:25:26:25:29 | Char arg0 | semmle.label | non-empty |
| LoopUnrolling.cs:25:26:25:29 | Char arg0 | LoopUnrolling.cs:26:17:26:40 | ...; | semmle.label | successor |
| LoopUnrolling.cs:25:34:25:37 | access to parameter args | LoopUnrolling.cs:25:13:26:40 | [unroll (line 25)] foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | LoopUnrolling.cs:25:13:26:40 | foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:26:17:26:40 | ...; | LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | semmle.label | successor |
| LoopUnrolling.cs:26:35:26:38 | access to local variable arg0 | LoopUnrolling.cs:26:17:26:39 | call to method WriteLine | semmle.label | successor |
| LoopUnrolling.cs:29:10:29:11 | enter M4 | LoopUnrolling.cs:30:5:34:5 | {...} | semmle.label | successor |
| LoopUnrolling.cs:30:5:34:5 | {...} | LoopUnrolling.cs:31:9:31:31 | ... ...; | semmle.label | successor |
| LoopUnrolling.cs:31:9:31:31 | ... ...; | LoopUnrolling.cs:31:29:31:29 | 0 | semmle.label | successor |
| LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | LoopUnrolling.cs:32:26:32:27 | access to local variable xs | semmle.label | successor |
| LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | LoopUnrolling.cs:31:13:31:30 | String[] xs = ... | semmle.label | successor |
| LoopUnrolling.cs:31:29:31:29 | 0 | LoopUnrolling.cs:31:18:31:30 | array creation of type String[] | semmle.label | successor |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:29:10:29:11 | exit M4 | semmle.label | empty |
| LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | LoopUnrolling.cs:32:21:32:21 | String x | semmle.label | non-empty |
| LoopUnrolling.cs:32:21:32:21 | String x | LoopUnrolling.cs:33:13:33:33 | ...; | semmle.label | successor |
| LoopUnrolling.cs:32:26:32:27 | access to local variable xs | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | LoopUnrolling.cs:32:9:33:33 | foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:33:13:33:33 | ...; | LoopUnrolling.cs:33:31:33:31 | access to local variable x | semmle.label | successor |
| LoopUnrolling.cs:33:31:33:31 | access to local variable x | LoopUnrolling.cs:33:13:33:32 | call to method WriteLine | semmle.label | successor |
| LoopUnrolling.cs:36:10:36:11 | enter M5 | LoopUnrolling.cs:37:5:43:5 | {...} | semmle.label | successor |
| LoopUnrolling.cs:37:5:43:5 | {...} | LoopUnrolling.cs:38:9:38:47 | ... ...; | semmle.label | successor |
| LoopUnrolling.cs:38:9:38:47 | ... ...; | LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | semmle.label | successor |
| LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | LoopUnrolling.cs:39:9:39:47 | ... ...; | semmle.label | successor |
| LoopUnrolling.cs:38:18:38:46 | array creation of type String[] | LoopUnrolling.cs:38:32:38:34 | "a" | semmle.label | successor |
| LoopUnrolling.cs:38:30:38:46 | { ..., ... } | LoopUnrolling.cs:38:13:38:46 | String[] xs = ... | semmle.label | successor |
| LoopUnrolling.cs:38:32:38:34 | "a" | LoopUnrolling.cs:38:37:38:39 | "b" | semmle.label | successor |
| LoopUnrolling.cs:38:37:38:39 | "b" | LoopUnrolling.cs:38:42:38:44 | "c" | semmle.label | successor |
| LoopUnrolling.cs:38:42:38:44 | "c" | LoopUnrolling.cs:38:30:38:46 | { ..., ... } | semmle.label | successor |
| LoopUnrolling.cs:39:9:39:47 | ... ...; | LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | semmle.label | successor |
| LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | LoopUnrolling.cs:40:26:40:27 | access to local variable xs | semmle.label | successor |
| LoopUnrolling.cs:39:18:39:46 | array creation of type String[] | LoopUnrolling.cs:39:32:39:34 | "0" | semmle.label | successor |
| LoopUnrolling.cs:39:30:39:46 | { ..., ... } | LoopUnrolling.cs:39:13:39:46 | String[] ys = ... | semmle.label | successor |
| LoopUnrolling.cs:39:32:39:34 | "0" | LoopUnrolling.cs:39:37:39:39 | "1" | semmle.label | successor |
| LoopUnrolling.cs:39:37:39:39 | "1" | LoopUnrolling.cs:39:42:39:44 | "2" | semmle.label | successor |
| LoopUnrolling.cs:39:42:39:44 | "2" | LoopUnrolling.cs:39:30:39:46 | { ..., ... } | semmle.label | successor |
| LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | LoopUnrolling.cs:40:21:40:21 | String x | semmle.label | non-empty |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:36:10:36:11 | exit M5 | semmle.label | empty |
| LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:21:40:21 | String x | semmle.label | non-empty |
| LoopUnrolling.cs:40:21:40:21 | String x | LoopUnrolling.cs:41:30:41:31 | access to local variable ys | semmle.label | successor |
| LoopUnrolling.cs:40:26:40:27 | access to local variable xs | LoopUnrolling.cs:40:9:42:41 | [unroll (line 40)] foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | LoopUnrolling.cs:41:25:41:25 | String y | semmle.label | non-empty |
| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:40:9:42:41 | foreach (... ... in ...) ... | semmle.label | empty |
| LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | LoopUnrolling.cs:41:25:41:25 | String y | semmle.label | non-empty |
| LoopUnrolling.cs:41:25:41:25 | String y | LoopUnrolling.cs:42:17:42:41 | ...; | semmle.label | successor |
| LoopUnrolling.cs:41:30:41:31 | access to local variable ys | LoopUnrolling.cs:41:13:42:41 | [unroll (line 41)] foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | LoopUnrolling.cs:41:13:42:41 | foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:42:17:42:41 | ...; | LoopUnrolling.cs:42:35:42:35 | access to local variable x | semmle.label | successor |
| LoopUnrolling.cs:42:35:42:35 | access to local variable x | LoopUnrolling.cs:42:39:42:39 | access to local variable y | semmle.label | successor |
| LoopUnrolling.cs:42:35:42:39 | ... + ... | LoopUnrolling.cs:42:17:42:40 | call to method WriteLine | semmle.label | successor |
| LoopUnrolling.cs:42:39:42:39 | access to local variable y | LoopUnrolling.cs:42:35:42:39 | ... + ... | semmle.label | successor |
| LoopUnrolling.cs:45:10:45:11 | enter M6 | LoopUnrolling.cs:46:5:53:5 | {...} | semmle.label | successor |
| LoopUnrolling.cs:46:5:53:5 | {...} | LoopUnrolling.cs:47:9:47:47 | ... ...; | semmle.label | successor |
| LoopUnrolling.cs:47:9:47:47 | ... ...; | LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | semmle.label | successor |
| LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | LoopUnrolling.cs:48:26:48:27 | access to local variable xs | semmle.label | successor |
| LoopUnrolling.cs:47:18:47:46 | array creation of type String[] | LoopUnrolling.cs:47:32:47:34 | "a" | semmle.label | successor |
| LoopUnrolling.cs:47:30:47:46 | { ..., ... } | LoopUnrolling.cs:47:13:47:46 | String[] xs = ... | semmle.label | successor |
| LoopUnrolling.cs:47:32:47:34 | "a" | LoopUnrolling.cs:47:37:47:39 | "b" | semmle.label | successor |
| LoopUnrolling.cs:47:37:47:39 | "b" | LoopUnrolling.cs:47:42:47:44 | "c" | semmle.label | successor |
| LoopUnrolling.cs:47:42:47:44 | "c" | LoopUnrolling.cs:47:30:47:46 | { ..., ... } | semmle.label | successor |
| LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | LoopUnrolling.cs:48:21:48:21 | String x | semmle.label | non-empty |
| LoopUnrolling.cs:48:21:48:21 | String x | LoopUnrolling.cs:49:9:52:9 | {...} | semmle.label | successor |
| LoopUnrolling.cs:48:26:48:27 | access to local variable xs | LoopUnrolling.cs:48:9:52:9 | [unroll (line 48)] foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:49:9:52:9 | {...} | LoopUnrolling.cs:50:13:50:17 | Label: | semmle.label | successor |
| LoopUnrolling.cs:50:13:50:17 | Label: | LoopUnrolling.cs:50:20:50:40 | ...; | semmle.label | successor |
| LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | LoopUnrolling.cs:51:13:51:23 | goto ...; | semmle.label | successor |
| LoopUnrolling.cs:50:20:50:40 | ...; | LoopUnrolling.cs:50:38:50:38 | access to local variable x | semmle.label | successor |
| LoopUnrolling.cs:50:38:50:38 | access to local variable x | LoopUnrolling.cs:50:20:50:39 | call to method WriteLine | semmle.label | successor |
| LoopUnrolling.cs:51:13:51:23 | goto ...; | LoopUnrolling.cs:50:13:50:17 | Label: | semmle.label | goto(Label) |
| LoopUnrolling.cs:55:10:55:11 | enter M7 | LoopUnrolling.cs:56:5:65:5 | {...} | semmle.label | successor |
| LoopUnrolling.cs:56:5:65:5 | {...} | LoopUnrolling.cs:57:9:57:47 | ... ...; | semmle.label | successor |
| LoopUnrolling.cs:57:9:57:47 | ... ...; | LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | semmle.label | successor |
| LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | LoopUnrolling.cs:58:26:58:27 | access to local variable xs | semmle.label | successor |
| LoopUnrolling.cs:57:18:57:46 | array creation of type String[] | LoopUnrolling.cs:57:32:57:34 | "a" | semmle.label | successor |
| LoopUnrolling.cs:57:30:57:46 | { ..., ... } | LoopUnrolling.cs:57:13:57:46 | String[] xs = ... | semmle.label | successor |
| LoopUnrolling.cs:57:32:57:34 | "a" | LoopUnrolling.cs:57:37:57:39 | "b" | semmle.label | successor |
| LoopUnrolling.cs:57:37:57:39 | "b" | LoopUnrolling.cs:57:42:57:44 | "c" | semmle.label | successor |
| LoopUnrolling.cs:57:42:57:44 | "c" | LoopUnrolling.cs:57:30:57:46 | { ..., ... } | semmle.label | successor |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | exit M7 | semmle.label | empty |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | semmle.label | non-empty |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:55:10:55:11 | exit M7 | semmle.label | empty |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | semmle.label | non-empty |
| LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | LoopUnrolling.cs:58:21:58:21 | String x | semmle.label | non-empty |
| LoopUnrolling.cs:58:21:58:21 | String x | LoopUnrolling.cs:59:9:64:9 | {...} | semmle.label | successor |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | semmle.label | successor |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | semmle.label | successor |
| LoopUnrolling.cs:58:26:58:27 | access to local variable xs | LoopUnrolling.cs:58:9:64:9 | [unroll (line 58)] foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | semmle.label | successor |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... | semmle.label | successor |
| LoopUnrolling.cs:59:9:64:9 | {...} | LoopUnrolling.cs:60:13:61:37 | if (...) ... | semmle.label | successor |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | semmle.label | successor |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... | LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | semmle.label | successor |
| LoopUnrolling.cs:60:13:61:37 | if (...) ... | LoopUnrolling.cs:60:17:60:17 | access to parameter b | semmle.label | successor |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | semmle.label | false |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | semmle.label | true |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | semmle.label | true |
| LoopUnrolling.cs:60:17:60:17 | access to parameter b | LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | semmle.label | false |
| LoopUnrolling.cs:61:17:61:36 | [b (line 55): true] call to method WriteLine | LoopUnrolling.cs:62:13:63:37 | [b (line 55): true] if (...) ... | semmle.label | successor |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | LoopUnrolling.cs:61:35:61:35 | [b (line 55): true] access to local variable x | semmle.label | successor |
| LoopUnrolling.cs:61:35:61:35 | [b (line 55): true] access to local variable x | LoopUnrolling.cs:61:17:61:36 | [b (line 55): true] call to method WriteLine | semmle.label | successor |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b | semmle.label | successor |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): true] if (...) ... | LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b | semmle.label | successor |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b | LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | semmle.label | false |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b | LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; | semmle.label | true |
| LoopUnrolling.cs:63:17:63:36 | [b (line 55): true] call to method WriteLine | LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; | LoopUnrolling.cs:63:35:63:35 | [b (line 55): true] access to local variable x | semmle.label | successor |
| LoopUnrolling.cs:63:35:63:35 | [b (line 55): true] access to local variable x | LoopUnrolling.cs:63:17:63:36 | [b (line 55): true] call to method WriteLine | semmle.label | successor |
| LoopUnrolling.cs:67:10:67:11 | enter M8 | LoopUnrolling.cs:68:5:74:5 | {...} | semmle.label | successor |
| LoopUnrolling.cs:68:5:74:5 | {...} | LoopUnrolling.cs:69:9:70:19 | if (...) ... | semmle.label | successor |
| LoopUnrolling.cs:69:9:70:19 | if (...) ... | LoopUnrolling.cs:69:13:69:23 | !... | semmle.label | successor |
| LoopUnrolling.cs:69:13:69:23 | !... | LoopUnrolling.cs:69:14:69:17 | access to parameter args | semmle.label | successor |
| LoopUnrolling.cs:69:14:69:17 | access to parameter args | LoopUnrolling.cs:69:14:69:23 | call to method Any | semmle.label | successor |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:70:13:70:19 | return ...; | semmle.label | false |
| LoopUnrolling.cs:69:14:69:23 | call to method Any | LoopUnrolling.cs:71:9:71:21 | ...; | semmle.label | true |
| LoopUnrolling.cs:70:13:70:19 | return ...; | LoopUnrolling.cs:67:10:67:11 | exit M8 | semmle.label | return |
| LoopUnrolling.cs:71:9:71:12 | access to parameter args | LoopUnrolling.cs:71:9:71:20 | call to method Clear | semmle.label | successor |
| LoopUnrolling.cs:71:9:71:20 | call to method Clear | LoopUnrolling.cs:72:28:72:31 | access to parameter args | semmle.label | successor |
| LoopUnrolling.cs:71:9:71:21 | ...; | LoopUnrolling.cs:71:9:71:12 | access to parameter args | semmle.label | successor |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:67:10:67:11 | exit M8 | semmle.label | empty |
| LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | LoopUnrolling.cs:72:21:72:23 | String arg | semmle.label | non-empty |
| LoopUnrolling.cs:72:21:72:23 | String arg | LoopUnrolling.cs:73:13:73:35 | ...; | semmle.label | successor |
| LoopUnrolling.cs:72:28:72:31 | access to parameter args | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | LoopUnrolling.cs:72:9:73:35 | foreach (... ... in ...) ... | semmle.label | successor |
| LoopUnrolling.cs:73:13:73:35 | ...; | LoopUnrolling.cs:73:31:73:33 | access to local variable arg | semmle.label | successor |
| LoopUnrolling.cs:73:31:73:33 | access to local variable arg | LoopUnrolling.cs:73:13:73:34 | call to method WriteLine | semmle.label | successor |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:28 | ... ?? ... | semmle.label | successor |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:9:3:10 | exit M1 | semmle.label | non-null |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:28:3:28 | 0 | semmle.label | null |

View File

@@ -222,6 +222,26 @@ booleanNode
| Conditions.cs:137:21:137:37 | [Field1 (line 129): true, Field2 (line 129): true] call to method ToString | Field2 (line 129): true |
| Conditions.cs:137:21:137:38 | [Field1 (line 129): true, Field2 (line 129): true] ...; | Field1 (line 129): true |
| Conditions.cs:137:21:137:38 | [Field1 (line 129): true, Field2 (line 129): true] ...; | Field2 (line 129): true |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): false] foreach (... ... in ...) ... | b (line 55): false |
| LoopUnrolling.cs:58:9:64:9 | [b (line 55): true] foreach (... ... in ...) ... | b (line 55): true |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): false] String x | b (line 55): false |
| LoopUnrolling.cs:58:21:58:21 | [b (line 55): true] String x | b (line 55): true |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): false] {...} | b (line 55): false |
| LoopUnrolling.cs:59:9:64:9 | [b (line 55): true] {...} | b (line 55): true |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): false] if (...) ... | b (line 55): false |
| LoopUnrolling.cs:60:13:61:37 | [b (line 55): true] if (...) ... | b (line 55): true |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): false] access to parameter b | b (line 55): false |
| LoopUnrolling.cs:60:17:60:17 | [b (line 55): true] access to parameter b | b (line 55): true |
| LoopUnrolling.cs:61:17:61:36 | [b (line 55): true] call to method WriteLine | b (line 55): true |
| LoopUnrolling.cs:61:17:61:37 | [b (line 55): true] ...; | b (line 55): true |
| LoopUnrolling.cs:61:35:61:35 | [b (line 55): true] access to local variable x | b (line 55): true |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): false] if (...) ... | b (line 55): false |
| LoopUnrolling.cs:62:13:63:37 | [b (line 55): true] if (...) ... | b (line 55): true |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): false] access to parameter b | b (line 55): false |
| LoopUnrolling.cs:62:17:62:17 | [b (line 55): true] access to parameter b | b (line 55): true |
| LoopUnrolling.cs:63:17:63:36 | [b (line 55): true] call to method WriteLine | b (line 55): true |
| LoopUnrolling.cs:63:17:63:37 | [b (line 55): true] ...; | b (line 55): true |
| LoopUnrolling.cs:63:35:63:35 | [b (line 55): true] access to local variable x | b (line 55): true |
finallyNode
| BreakInTry.cs:30:13:33:13 | [finally: break] {...} | BreakInTry.cs:24:13:33:13 | try {...} ... |
| BreakInTry.cs:31:17:32:21 | [finally: break] if (...) ... | BreakInTry.cs:24:13:33:13 | try {...} ... |
@@ -621,6 +641,14 @@ entryPoint
| Initializers.cs:29:9:29:11 | Sub | Initializers.cs:29:17:29:20 | call to constructor NoConstructor |
| Initializers.cs:31:9:31:11 | Sub | Initializers.cs:31:22:31:25 | call to constructor Sub |
| Initializers.cs:33:9:33:11 | Sub | Initializers.cs:20:23:20:23 | this access |
| LoopUnrolling.cs:7:10:7:11 | M1 | LoopUnrolling.cs:8:5:13:5 | {...} |
| LoopUnrolling.cs:15:10:15:11 | M2 | LoopUnrolling.cs:16:5:20:5 | {...} |
| LoopUnrolling.cs:22:10:22:11 | M3 | LoopUnrolling.cs:23:5:27:5 | {...} |
| LoopUnrolling.cs:29:10:29:11 | M4 | LoopUnrolling.cs:30:5:34:5 | {...} |
| LoopUnrolling.cs:36:10:36:11 | M5 | LoopUnrolling.cs:37:5:43:5 | {...} |
| LoopUnrolling.cs:45:10:45:11 | M6 | LoopUnrolling.cs:46:5:53:5 | {...} |
| LoopUnrolling.cs:55:10:55:11 | M7 | LoopUnrolling.cs:56:5:65:5 | {...} |
| LoopUnrolling.cs:67:10:67:11 | M8 | LoopUnrolling.cs:68:5:74:5 | {...} |
| NullCoalescing.cs:3:9:3:10 | M1 | NullCoalescing.cs:3:23:3:28 | ... ?? ... |
| NullCoalescing.cs:5:9:5:10 | M2 | NullCoalescing.cs:5:24:5:43 | ... ? ... : ... |
| NullCoalescing.cs:7:12:7:13 | M3 | NullCoalescing.cs:7:40:7:53 | ... ?? ... |

View File

@@ -0,0 +1,286 @@
abstractValue
| 0 | Collections.cs:12:32:12:32 | 0 |
| 0 | Collections.cs:14:28:14:28 | 0 |
| 0 | Collections.cs:16:27:16:27 | 0 |
| 0 | Collections.cs:17:28:17:28 | 0 |
| 0 | Collections.cs:23:31:23:31 | 0 |
| 0 | Collections.cs:25:27:25:27 | 0 |
| 0 | Collections.cs:27:26:27:26 | 0 |
| 0 | Collections.cs:28:27:28:27 | 0 |
| 0 | Collections.cs:34:33:34:33 | 0 |
| 0 | Collections.cs:36:29:36:29 | 0 |
| 0 | Collections.cs:38:28:38:28 | 0 |
| 0 | Collections.cs:39:29:39:29 | 0 |
| 0 | Collections.cs:50:27:50:27 | 0 |
| 0 | Collections.cs:57:24:57:24 | 0 |
| 0 | Collections.cs:65:24:65:24 | 0 |
| 0 | Collections.cs:76:36:76:36 | 0 |
| 0 | Collections.cs:78:36:78:36 | 0 |
| 0 | Collections.cs:80:35:80:35 | 0 |
| 0 | Collections.cs:81:36:81:36 | 0 |
| 0 | Collections.cs:87:17:87:31 | 0 |
| 0 | Guards.cs:12:24:12:24 | 0 |
| 0 | Guards.cs:78:26:78:26 | 0 |
| 0 | Guards.cs:80:25:80:25 | 0 |
| 0 | Guards.cs:82:26:82:26 | 0 |
| 0 | Guards.cs:92:30:92:30 | 0 |
| 0 | Guards.cs:241:17:241:17 | 0 |
| 0 | Guards.cs:255:17:255:19 | access to constant A |
| 0 | Guards.cs:298:21:298:21 | 0 |
| 0 | Guards.cs:310:21:310:21 | 0 |
| 0 | Guards.cs:317:17:317:17 | 0 |
| 0 | Guards.cs:322:18:322:18 | 0 |
| 0 | Guards.cs:329:17:329:19 | access to constant A |
| 0 | Guards.cs:334:20:334:20 | 0 |
| 0 | Splitting.cs:136:20:136:20 | 0 |
| 1 | Collections.cs:13:28:13:28 | 1 |
| 1 | Collections.cs:15:28:15:28 | 1 |
| 1 | Collections.cs:18:28:18:28 | 1 |
| 1 | Collections.cs:24:27:24:27 | 1 |
| 1 | Collections.cs:26:27:26:27 | 1 |
| 1 | Collections.cs:29:27:29:27 | 1 |
| 1 | Collections.cs:35:29:35:29 | 1 |
| 1 | Collections.cs:37:29:37:29 | 1 |
| 1 | Collections.cs:40:29:40:29 | 1 |
| 1 | Collections.cs:77:36:77:36 | 1 |
| 1 | Collections.cs:79:36:79:36 | 1 |
| 1 | Collections.cs:82:36:82:36 | 1 |
| 1 | Collections.cs:89:13:89:32 | 1 |
| 1 | Guards.cs:92:25:92:25 | 1 |
| 1 | Guards.cs:243:17:243:17 | 1 |
| 1 | Guards.cs:246:18:246:18 | 1 |
| 1 | Guards.cs:257:17:257:19 | access to constant B |
| 1 | Guards.cs:260:18:260:20 | access to constant B |
| 1 | Guards.cs:299:18:299:18 | 1 |
| 1 | Guards.cs:311:18:311:18 | 1 |
| 1 | Guards.cs:319:17:319:17 | 1 |
| 1 | Guards.cs:322:13:322:13 | 1 |
| 1 | Guards.cs:323:18:323:18 | 1 |
| 1 | Guards.cs:331:17:331:19 | access to constant B |
| 1 | Guards.cs:334:13:334:15 | access to constant B |
| 1 | Guards.cs:335:18:335:18 | 1 |
| 3 | Collections.cs:55:13:55:41 | 3 |
| 3 | Collections.cs:63:17:63:45 | 3 |
| 10 | Guards.cs:84:25:84:26 | 10 |
| 10 | Guards.cs:86:26:86:27 | 10 |
| empty | Collections.cs:54:13:54:16 | access to parameter args |
| empty | Collections.cs:57:9:57:25 | ... = ... |
| empty | Collections.cs:57:13:57:25 | array creation of type String[] |
| empty | Collections.cs:58:9:58:13 | ... = ... |
| empty | Collections.cs:58:13:58:13 | access to local variable x |
| empty | Collections.cs:65:13:65:13 | access to local variable x |
| empty | Collections.cs:87:17:87:31 | array creation of type String[] |
| empty | Collections.cs:87:30:87:31 | { ..., ... } |
| empty | Collections.cs:88:22:88:23 | { ..., ... } |
| false | Guards.cs:178:16:178:20 | false |
| false | Guards.cs:181:52:181:56 | false |
| false | Guards.cs:217:18:217:22 | false |
| false | Guards.cs:228:18:228:22 | false |
| false | Guards.cs:295:18:295:22 | false |
| false | Guards.cs:305:18:305:22 | false |
| non-empty | Collections.cs:55:9:55:41 | ... = ... |
| non-empty | Collections.cs:55:13:55:41 | array creation of type String[] |
| non-empty | Collections.cs:55:25:55:41 | { ..., ... } |
| non-empty | Collections.cs:56:9:56:13 | ... = ... |
| non-empty | Collections.cs:56:13:56:13 | access to local variable x |
| non-empty | Collections.cs:63:17:63:45 | array creation of type String[] |
| non-empty | Collections.cs:63:29:63:45 | { ..., ... } |
| non-empty | Collections.cs:68:13:68:13 | access to local variable x |
| non-empty | Collections.cs:89:9:89:32 | ... = ... |
| non-empty | Collections.cs:89:13:89:32 | array creation of type String[] |
| non-empty | Collections.cs:89:26:89:32 | { ..., ... } |
| non-empty | Collections.cs:90:22:90:28 | { ..., ... } |
| non-null | Assert.cs:9:31:9:32 | "" |
| non-null | Assert.cs:16:31:16:32 | "" |
| non-null | Assert.cs:23:31:23:32 | "" |
| non-null | Assert.cs:30:31:30:32 | "" |
| non-null | Assert.cs:37:31:37:32 | "" |
| non-null | Assert.cs:44:31:44:32 | "" |
| non-null | Assert.cs:51:31:51:32 | "" |
| non-null | Assert.cs:58:31:58:32 | "" |
| non-null | Assert.cs:65:31:65:32 | "" |
| non-null | Assert.cs:72:31:72:32 | "" |
| non-null | Assert.cs:79:31:79:32 | "" |
| non-null | Collections.cs:55:9:55:41 | ... = ... |
| non-null | Collections.cs:55:13:55:41 | array creation of type String[] |
| non-null | Collections.cs:55:27:55:29 | "a" |
| non-null | Collections.cs:55:32:55:34 | "b" |
| non-null | Collections.cs:55:37:55:39 | "c" |
| non-null | Collections.cs:56:9:56:13 | ... = ... |
| non-null | Collections.cs:56:13:56:13 | access to local variable x |
| non-null | Collections.cs:57:9:57:25 | ... = ... |
| non-null | Collections.cs:57:13:57:25 | array creation of type String[] |
| non-null | Collections.cs:58:9:58:13 | ... = ... |
| non-null | Collections.cs:58:13:58:13 | access to local variable x |
| non-null | Collections.cs:63:17:63:45 | array creation of type String[] |
| non-null | Collections.cs:63:31:63:33 | "a" |
| non-null | Collections.cs:63:36:63:38 | "b" |
| non-null | Collections.cs:63:41:63:43 | "c" |
| non-null | Collections.cs:67:19:67:21 | "a" |
| non-null | Collections.cs:68:19:68:21 | "b" |
| non-null | Collections.cs:74:40:74:41 | "" |
| non-null | Collections.cs:87:17:87:31 | array creation of type String[] |
| non-null | Collections.cs:88:22:88:23 | array creation of type String[] |
| non-null | Collections.cs:89:9:89:32 | ... = ... |
| non-null | Collections.cs:89:13:89:32 | array creation of type String[] |
| non-null | Collections.cs:89:28:89:30 | "a" |
| non-null | Collections.cs:90:22:90:28 | array creation of type String[] |
| non-null | Collections.cs:90:24:90:26 | "a" |
| non-null | Guards.cs:18:31:18:46 | "<empty string>" |
| non-null | Guards.cs:33:31:33:35 | ... + ... |
| non-null | Guards.cs:36:32:36:36 | ... + ... |
| non-null | Guards.cs:39:31:39:35 | ... + ... |
| non-null | Guards.cs:42:32:42:36 | ... + ... |
| non-null | Guards.cs:44:13:44:17 | this access |
| non-null | Guards.cs:45:31:45:42 | object creation of type Guards |
| non-null | Guards.cs:47:13:47:17 | this access |
| non-null | Guards.cs:48:31:48:34 | this access |
| non-null | Guards.cs:61:19:61:33 | object creation of type Exception |
| non-null | Guards.cs:78:26:78:26 | (...) ... |
| non-null | Guards.cs:80:25:80:25 | (...) ... |
| non-null | Guards.cs:82:26:82:26 | (...) ... |
| non-null | Guards.cs:84:25:84:26 | (...) ... |
| non-null | Guards.cs:86:26:86:27 | (...) ... |
| non-null | Guards.cs:92:25:92:25 | (...) ... |
| non-null | Guards.cs:92:30:92:30 | (...) ... |
| non-null | Guards.cs:96:18:96:19 | "" |
| non-null | Guards.cs:105:19:105:33 | object creation of type Exception |
| non-null | Guards.cs:183:37:183:48 | this access |
| non-null | Guards.cs:189:14:189:25 | this access |
| non-null | Guards.cs:191:14:191:25 | this access |
| non-null | Guards.cs:193:14:193:25 | this access |
| non-null | Guards.cs:195:13:195:27 | this access |
| non-null | Guards.cs:197:14:197:29 | this access |
| non-null | Guards.cs:268:30:268:41 | call to method GetType |
| non-null | Splitting.cs:33:24:33:25 | "" |
| non-null | Splitting.cs:132:21:132:29 | this access |
| null | Assert.cs:9:24:9:27 | null |
| null | Assert.cs:10:27:10:30 | null |
| null | Assert.cs:16:24:16:27 | null |
| null | Assert.cs:23:24:23:27 | null |
| null | Assert.cs:30:24:30:27 | null |
| null | Assert.cs:31:28:31:31 | null |
| null | Assert.cs:37:24:37:27 | null |
| null | Assert.cs:38:28:38:31 | null |
| null | Assert.cs:44:24:44:27 | null |
| null | Assert.cs:45:29:45:32 | null |
| null | Assert.cs:51:24:51:27 | null |
| null | Assert.cs:52:29:52:32 | null |
| null | Assert.cs:58:24:58:27 | null |
| null | Assert.cs:59:28:59:31 | null |
| null | Assert.cs:65:24:65:27 | null |
| null | Assert.cs:66:29:66:32 | null |
| null | Assert.cs:72:24:72:27 | null |
| null | Assert.cs:73:28:73:31 | null |
| null | Assert.cs:79:24:79:27 | null |
| null | Assert.cs:80:29:80:32 | null |
| null | Guards.cs:10:21:10:24 | null |
| null | Guards.cs:24:18:24:21 | null |
| null | Guards.cs:32:47:32:50 | null |
| null | Guards.cs:35:18:35:21 | null |
| null | Guards.cs:35:31:35:34 | null |
| null | Guards.cs:38:20:38:23 | null |
| null | Guards.cs:38:33:38:36 | null |
| null | Guards.cs:41:22:41:25 | null |
| null | Guards.cs:41:35:41:38 | null |
| null | Guards.cs:44:22:44:25 | null |
| null | Guards.cs:47:22:47:25 | null |
| null | Guards.cs:53:24:53:27 | null |
| null | Guards.cs:60:42:60:45 | null |
| null | Guards.cs:68:21:68:24 | null |
| null | Guards.cs:71:13:71:20 | ... = ... |
| null | Guards.cs:71:17:71:20 | null |
| null | Guards.cs:72:31:72:31 | access to parameter s |
| null | Guards.cs:88:26:88:29 | null |
| null | Guards.cs:104:42:104:45 | null |
| null | Guards.cs:106:9:106:25 | ... = ... |
| null | Guards.cs:106:22:106:25 | null |
| null | Guards.cs:115:52:115:55 | null |
| null | Guards.cs:117:9:117:25 | ... = ... |
| null | Guards.cs:117:22:117:25 | null |
| null | Guards.cs:172:38:172:41 | null |
| null | Guards.cs:181:38:181:41 | null |
| null | Guards.cs:185:42:185:45 | null |
| null | Guards.cs:203:18:203:21 | null |
| null | Splitting.cs:12:22:12:25 | null |
| null | Splitting.cs:22:22:22:25 | null |
| null | Splitting.cs:32:22:32:25 | null |
| null | Splitting.cs:41:18:41:21 | null |
| null | Splitting.cs:54:18:54:21 | null |
| null | Splitting.cs:65:18:65:21 | null |
| null | Splitting.cs:76:18:76:21 | null |
| null | Splitting.cs:87:31:87:34 | null |
| null | Splitting.cs:97:31:97:34 | null |
| null | Splitting.cs:105:27:105:30 | null |
| null | Splitting.cs:116:27:116:30 | null |
| null | Splitting.cs:125:20:125:23 | null |
| null | Splitting.cs:128:22:128:25 | null |
| true | Guards.cs:177:20:177:23 | true |
| true | Guards.cs:181:45:181:48 | true |
| true | Guards.cs:185:49:185:52 | true |
| true | Guards.cs:185:56:185:59 | true |
| true | Guards.cs:215:18:215:21 | true |
| true | Guards.cs:220:18:220:21 | true |
| true | Guards.cs:230:18:230:21 | true |
| true | Guards.cs:233:18:233:21 | true |
| true | Guards.cs:293:18:293:21 | true |
| true | Guards.cs:298:13:298:16 | true |
| true | Guards.cs:307:18:307:21 | true |
| true | Guards.cs:310:13:310:16 | true |
dualValue
| empty | non-empty |
| false | true |
| match 1 | non-match 1 |
| match 1 | non-match 1 |
| match "" | non-match "" |
| match "" | non-match "" |
| match Action<String> a | non-match Action<String> a |
| match Action<String> a | non-match Action<String> a |
| match _ | non-match _ |
| match _ | non-match _ |
| match _ | non-match _ |
| match _ | non-match _ |
| match _ | non-match _ |
| match access to constant B | non-match access to constant B |
| match access to constant B | non-match access to constant B |
| match access to type Action<Object> | non-match access to type Action<Object> |
| match access to type Action<Object> | non-match access to type Action<Object> |
| match null | non-match null |
| match null | non-match null |
| match true | non-match true |
| match true | non-match true |
| match true | non-match true |
| match true | non-match true |
| non-empty | empty |
| non-match 1 | match 1 |
| non-match 1 | match 1 |
| non-match "" | match "" |
| non-match "" | match "" |
| non-match Action<String> a | match Action<String> a |
| non-match Action<String> a | match Action<String> a |
| non-match _ | match _ |
| non-match _ | match _ |
| non-match _ | match _ |
| non-match _ | match _ |
| non-match _ | match _ |
| non-match access to constant B | match access to constant B |
| non-match access to constant B | match access to constant B |
| non-match access to type Action<Object> | match access to type Action<Object> |
| non-match access to type Action<Object> | match access to type Action<Object> |
| non-match null | match null |
| non-match null | match null |
| non-match true | match true |
| non-match true | match true |
| non-match true | match true |
| non-match true | match true |
| non-null | null |
| null | non-null |
| true | false |
singletonValue
| 0 |
| 1 |
| 3 |
| 10 |
| false |
| null |
| true |

View File

@@ -0,0 +1,8 @@
import csharp
private import semmle.code.csharp.controlflow.Guards
query predicate abstractValue(AbstractValue value, Expr e) { e = value.getAnExpr() }
query predicate dualValue(AbstractValue value, AbstractValue dual) { dual = value.getDualValue() }
query predicate singletonValue(AbstractValue value) { value.isSingleton() }

View File

@@ -15,6 +15,11 @@
| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true |
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false |
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false |
| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
| Collections.cs:53:9:53:12 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
| Collections.cs:54:13:54:16 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
| Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:12:13:12:24 | ... > ... | Guards.cs:12:13:12:13 | access to parameter s | true |

View File

@@ -0,0 +1,93 @@
// semmle-extractor-options: /r:System.Collections.Specialized.dll /r:System.Collections.dll /r:System.Linq.dll
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
public class Collections
{
void M1(string[] args)
{
var b = args.Length == 0;
b = args.Length == 1;
b = args.Length != 0;
b = args.Length != 1;
b = args.Length > 0;
b = args.Length >= 0;
b = args.Length >= 1;
}
void M2(ICollection<string> args)
{
var b = args.Count == 0;
b = args.Count == 1;
b = args.Count != 0;
b = args.Count != 1;
b = args.Count > 0;
b = args.Count >= 0;
b = args.Count >= 1;
}
void M3(string[] args)
{
var b = args.Count() == 0;
b = args.Count() == 1;
b = args.Count() != 0;
b = args.Count() != 1;
b = args.Count() > 0;
b = args.Count() >= 0;
b = args.Count() >= 1;
}
void M4(string[] args)
{
var b = args.Any();
}
void M5(List<string> args)
{
if (args.Count == 0)
return;
var x = args.ToArray();
args.Clear();
x = args.ToArray();
x = new string[]{ "a", "b", "c" };
x = x;
x = new string[0];
x = x;
}
void M6()
{
var x = new string[]{ "a", "b", "c" }.ToList();
x.Clear();
if (x.Count == 0)
{
x.Add("a");
x.Add("b");
}
}
void M7(string[] args)
{
bool IsEmpty(string s) => s == "";
var b = args.Any(IsEmpty);
b = args.Count(IsEmpty) == 0;
b = args.Count(IsEmpty) == 1;
b = args.Count(IsEmpty) != 0;
b = args.Count(IsEmpty) != 1;
b = args.Count(IsEmpty) > 0;
b = args.Count(IsEmpty) >= 0;
b = args.Count(IsEmpty) >= 1;
}
void M8()
{
var x = new string[] {};
string[] y = {};
x = new string[] { "a" };
string[] z = { "a" };
}
}

View File

@@ -0,0 +1,37 @@
| Collections.cs:12:17:12:32 | ... == ... | Collections.cs:12:17:12:20 | access to parameter args | false | false |
| Collections.cs:12:17:12:32 | ... == ... | Collections.cs:12:17:12:20 | access to parameter args | true | true |
| Collections.cs:13:13:13:28 | ... == ... | Collections.cs:13:13:13:16 | access to parameter args | true | false |
| Collections.cs:14:13:14:28 | ... != ... | Collections.cs:14:13:14:16 | access to parameter args | false | true |
| Collections.cs:14:13:14:28 | ... != ... | Collections.cs:14:13:14:16 | access to parameter args | true | false |
| Collections.cs:15:13:15:28 | ... != ... | Collections.cs:15:13:15:16 | access to parameter args | false | false |
| Collections.cs:16:13:16:27 | ... > ... | Collections.cs:16:13:16:16 | access to parameter args | true | false |
| Collections.cs:18:13:18:28 | ... >= ... | Collections.cs:18:13:18:16 | access to parameter args | true | false |
| Collections.cs:23:17:23:31 | ... == ... | Collections.cs:23:17:23:20 | access to parameter args | false | false |
| Collections.cs:23:17:23:31 | ... == ... | Collections.cs:23:17:23:20 | access to parameter args | true | true |
| Collections.cs:24:13:24:27 | ... == ... | Collections.cs:24:13:24:16 | access to parameter args | true | false |
| Collections.cs:25:13:25:27 | ... != ... | Collections.cs:25:13:25:16 | access to parameter args | false | true |
| Collections.cs:25:13:25:27 | ... != ... | Collections.cs:25:13:25:16 | access to parameter args | true | false |
| Collections.cs:26:13:26:27 | ... != ... | Collections.cs:26:13:26:16 | access to parameter args | false | false |
| Collections.cs:27:13:27:26 | ... > ... | Collections.cs:27:13:27:16 | access to parameter args | true | false |
| Collections.cs:29:13:29:27 | ... >= ... | Collections.cs:29:13:29:16 | access to parameter args | true | false |
| Collections.cs:34:17:34:33 | ... == ... | Collections.cs:34:17:34:20 | access to parameter args | false | false |
| Collections.cs:34:17:34:33 | ... == ... | Collections.cs:34:17:34:20 | access to parameter args | true | true |
| Collections.cs:35:13:35:29 | ... == ... | Collections.cs:35:13:35:16 | access to parameter args | true | false |
| Collections.cs:36:13:36:29 | ... != ... | Collections.cs:36:13:36:16 | access to parameter args | false | true |
| Collections.cs:36:13:36:29 | ... != ... | Collections.cs:36:13:36:16 | access to parameter args | true | false |
| Collections.cs:37:13:37:29 | ... != ... | Collections.cs:37:13:37:16 | access to parameter args | false | false |
| Collections.cs:38:13:38:28 | ... > ... | Collections.cs:38:13:38:16 | access to parameter args | true | false |
| Collections.cs:40:13:40:29 | ... >= ... | Collections.cs:40:13:40:16 | access to parameter args | true | false |
| Collections.cs:45:17:45:26 | call to method Any | Collections.cs:45:17:45:20 | access to parameter args | false | true |
| Collections.cs:45:17:45:26 | call to method Any | Collections.cs:45:17:45:20 | access to parameter args | true | false |
| Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false | false |
| Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | true | true |
| Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | false | false |
| Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | true |
| Collections.cs:75:17:75:33 | call to method Any | Collections.cs:75:17:75:20 | access to parameter args | true | false |
| Collections.cs:76:13:76:36 | ... == ... | Collections.cs:76:13:76:16 | access to parameter args | false | false |
| Collections.cs:77:13:77:36 | ... == ... | Collections.cs:77:13:77:16 | access to parameter args | true | false |
| Collections.cs:78:13:78:36 | ... != ... | Collections.cs:78:13:78:16 | access to parameter args | true | false |
| Collections.cs:79:13:79:36 | ... != ... | Collections.cs:79:13:79:16 | access to parameter args | false | false |
| Collections.cs:80:13:80:35 | ... > ... | Collections.cs:80:13:80:16 | access to parameter args | true | false |
| Collections.cs:82:13:82:36 | ... >= ... | Collections.cs:82:13:82:16 | access to parameter args | true | false |

View File

@@ -0,0 +1,6 @@
import csharp
private import semmle.code.csharp.controlflow.Guards
query predicate emptinessCheck(Expr check, CollectionExpr collection, AbstractValue v, boolean isEmpty) {
check = collection.getAnEmptinessCheck(v, isEmpty)
}

View File

@@ -30,6 +30,13 @@
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null |
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false |
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false |
| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | non-empty |
| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
| Collections.cs:53:9:53:12 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
| Collections.cs:54:13:54:16 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | empty |
| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
| Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |

View File

@@ -30,6 +30,13 @@
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null |
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false |
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false |
| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | Collections.cs:50:13:50:16 | access to parameter args | non-empty |
| Collections.cs:52:17:52:20 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
| Collections.cs:53:9:53:12 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
| Collections.cs:54:13:54:16 | access to parameter args | Collections.cs:50:13:50:27 | ... == ... | Collections.cs:50:13:50:16 | access to parameter args | false |
| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | empty |
| Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
| Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true |
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |

View File

@@ -1,9 +1,9 @@
| Assert.cs:9:16:9:32 | String s = ... | non-null | Assert.cs:9:16:9:16 | access to local variable s | non-null |
| Assert.cs:9:16:9:32 | String s = ... | null | Assert.cs:9:16:9:16 | access to local variable s | null |
| Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | Assert.cs:9:20:9:20 | access to parameter b | false |
| Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | Assert.cs:9:31:9:32 | "" | non-null |
| Assert.cs:9:20:9:32 | ... ? ... : ... | null | Assert.cs:9:20:9:20 | access to parameter b | true |
| Assert.cs:9:20:9:32 | ... ? ... : ... | null | Assert.cs:9:24:9:27 | null | null |
| Assert.cs:10:22:10:22 | access to local variable s | empty | Assert.cs:9:20:9:32 | ... ? ... : ... | empty |
| Assert.cs:10:22:10:22 | access to local variable s | non-empty | Assert.cs:9:20:9:32 | ... ? ... : ... | non-empty |
| Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null |
| Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null |
| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:9:20:9:20 | access to parameter b | true |
@@ -12,32 +12,32 @@
| Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:10:22:10:22 | access to local variable s | non-null |
| Assert.cs:11:27:11:27 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null |
| Assert.cs:11:27:11:27 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null |
| Assert.cs:16:16:16:32 | String s = ... | non-null | Assert.cs:16:16:16:16 | access to local variable s | non-null |
| Assert.cs:16:16:16:32 | String s = ... | null | Assert.cs:16:16:16:16 | access to local variable s | null |
| Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | Assert.cs:16:20:16:20 | access to parameter b | false |
| Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | Assert.cs:16:31:16:32 | "" | non-null |
| Assert.cs:16:20:16:32 | ... ? ... : ... | null | Assert.cs:16:20:16:20 | access to parameter b | true |
| Assert.cs:16:20:16:32 | ... ? ... : ... | null | Assert.cs:16:24:16:27 | null | null |
| Assert.cs:17:23:17:23 | access to local variable s | empty | Assert.cs:16:20:16:32 | ... ? ... : ... | empty |
| Assert.cs:17:23:17:23 | access to local variable s | non-empty | Assert.cs:16:20:16:32 | ... ? ... : ... | non-empty |
| Assert.cs:17:23:17:23 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null |
| Assert.cs:17:23:17:23 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null |
| Assert.cs:18:27:18:27 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null |
| Assert.cs:18:27:18:27 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null |
| Assert.cs:23:16:23:32 | String s = ... | non-null | Assert.cs:23:16:23:16 | access to local variable s | non-null |
| Assert.cs:23:16:23:32 | String s = ... | null | Assert.cs:23:16:23:16 | access to local variable s | null |
| Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | Assert.cs:23:20:23:20 | access to parameter b | false |
| Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | Assert.cs:23:31:23:32 | "" | non-null |
| Assert.cs:23:20:23:32 | ... ? ... : ... | null | Assert.cs:23:20:23:20 | access to parameter b | true |
| Assert.cs:23:20:23:32 | ... ? ... : ... | null | Assert.cs:23:24:23:27 | null | null |
| Assert.cs:24:26:24:26 | access to local variable s | empty | Assert.cs:23:20:23:32 | ... ? ... : ... | empty |
| Assert.cs:24:26:24:26 | access to local variable s | non-empty | Assert.cs:23:20:23:32 | ... ? ... : ... | non-empty |
| Assert.cs:24:26:24:26 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null |
| Assert.cs:24:26:24:26 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null |
| Assert.cs:25:27:25:27 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null |
| Assert.cs:25:27:25:27 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null |
| Assert.cs:30:16:30:32 | String s = ... | non-null | Assert.cs:30:16:30:16 | access to local variable s | non-null |
| Assert.cs:30:16:30:32 | String s = ... | null | Assert.cs:30:16:30:16 | access to local variable s | null |
| Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | Assert.cs:30:20:30:20 | access to parameter b | false |
| Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | Assert.cs:30:31:30:32 | "" | non-null |
| Assert.cs:30:20:30:32 | ... ? ... : ... | null | Assert.cs:30:20:30:20 | access to parameter b | true |
| Assert.cs:30:20:30:32 | ... ? ... : ... | null | Assert.cs:30:24:30:27 | null | null |
| Assert.cs:31:23:31:23 | access to local variable s | empty | Assert.cs:30:20:30:32 | ... ? ... : ... | empty |
| Assert.cs:31:23:31:23 | access to local variable s | non-empty | Assert.cs:30:20:30:32 | ... ? ... : ... | non-empty |
| Assert.cs:31:23:31:23 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null |
| Assert.cs:31:23:31:23 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null |
| Assert.cs:31:23:31:31 | ... == ... | false | Assert.cs:30:20:30:20 | access to parameter b | false |
@@ -46,12 +46,12 @@
| Assert.cs:31:23:31:31 | ... == ... | true | Assert.cs:31:23:31:23 | access to local variable s | null |
| Assert.cs:32:27:32:27 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null |
| Assert.cs:32:27:32:27 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null |
| Assert.cs:37:16:37:32 | String s = ... | non-null | Assert.cs:37:16:37:16 | access to local variable s | non-null |
| Assert.cs:37:16:37:32 | String s = ... | null | Assert.cs:37:16:37:16 | access to local variable s | null |
| Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | Assert.cs:37:20:37:20 | access to parameter b | false |
| Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | Assert.cs:37:31:37:32 | "" | non-null |
| Assert.cs:37:20:37:32 | ... ? ... : ... | null | Assert.cs:37:20:37:20 | access to parameter b | true |
| Assert.cs:37:20:37:32 | ... ? ... : ... | null | Assert.cs:37:24:37:27 | null | null |
| Assert.cs:38:23:38:23 | access to local variable s | empty | Assert.cs:37:20:37:32 | ... ? ... : ... | empty |
| Assert.cs:38:23:38:23 | access to local variable s | non-empty | Assert.cs:37:20:37:32 | ... ? ... : ... | non-empty |
| Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null |
| Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null |
| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:37:20:37:20 | access to parameter b | true |
@@ -60,12 +60,12 @@
| Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:38:23:38:23 | access to local variable s | non-null |
| Assert.cs:39:27:39:27 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null |
| Assert.cs:39:27:39:27 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null |
| Assert.cs:44:16:44:32 | String s = ... | non-null | Assert.cs:44:16:44:16 | access to local variable s | non-null |
| Assert.cs:44:16:44:32 | String s = ... | null | Assert.cs:44:16:44:16 | access to local variable s | null |
| Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | Assert.cs:44:20:44:20 | access to parameter b | false |
| Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | Assert.cs:44:31:44:32 | "" | non-null |
| Assert.cs:44:20:44:32 | ... ? ... : ... | null | Assert.cs:44:20:44:20 | access to parameter b | true |
| Assert.cs:44:20:44:32 | ... ? ... : ... | null | Assert.cs:44:24:44:27 | null | null |
| Assert.cs:45:24:45:24 | access to local variable s | empty | Assert.cs:44:20:44:32 | ... ? ... : ... | empty |
| Assert.cs:45:24:45:24 | access to local variable s | non-empty | Assert.cs:44:20:44:32 | ... ? ... : ... | non-empty |
| Assert.cs:45:24:45:24 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null |
| Assert.cs:45:24:45:24 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null |
| Assert.cs:45:24:45:32 | ... != ... | false | Assert.cs:44:20:44:20 | access to parameter b | true |
@@ -74,12 +74,12 @@
| Assert.cs:45:24:45:32 | ... != ... | true | Assert.cs:45:24:45:24 | access to local variable s | non-null |
| Assert.cs:46:27:46:27 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null |
| Assert.cs:46:27:46:27 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null |
| Assert.cs:51:16:51:32 | String s = ... | non-null | Assert.cs:51:16:51:16 | access to local variable s | non-null |
| Assert.cs:51:16:51:32 | String s = ... | null | Assert.cs:51:16:51:16 | access to local variable s | null |
| Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | Assert.cs:51:20:51:20 | access to parameter b | false |
| Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | Assert.cs:51:31:51:32 | "" | non-null |
| Assert.cs:51:20:51:32 | ... ? ... : ... | null | Assert.cs:51:20:51:20 | access to parameter b | true |
| Assert.cs:51:20:51:32 | ... ? ... : ... | null | Assert.cs:51:24:51:27 | null | null |
| Assert.cs:52:24:52:24 | access to local variable s | empty | Assert.cs:51:20:51:32 | ... ? ... : ... | empty |
| Assert.cs:52:24:52:24 | access to local variable s | non-empty | Assert.cs:51:20:51:32 | ... ? ... : ... | non-empty |
| Assert.cs:52:24:52:24 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null |
| Assert.cs:52:24:52:24 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null |
| Assert.cs:52:24:52:32 | ... == ... | false | Assert.cs:51:20:51:20 | access to parameter b | false |
@@ -88,12 +88,12 @@
| Assert.cs:52:24:52:32 | ... == ... | true | Assert.cs:52:24:52:24 | access to local variable s | null |
| Assert.cs:53:27:53:27 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null |
| Assert.cs:53:27:53:27 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null |
| Assert.cs:58:16:58:32 | String s = ... | non-null | Assert.cs:58:16:58:16 | access to local variable s | non-null |
| Assert.cs:58:16:58:32 | String s = ... | null | Assert.cs:58:16:58:16 | access to local variable s | null |
| Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | Assert.cs:58:20:58:20 | access to parameter b | false |
| Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | Assert.cs:58:31:58:32 | "" | non-null |
| Assert.cs:58:20:58:32 | ... ? ... : ... | null | Assert.cs:58:20:58:20 | access to parameter b | true |
| Assert.cs:58:20:58:32 | ... ? ... : ... | null | Assert.cs:58:24:58:27 | null | null |
| Assert.cs:59:23:59:23 | access to local variable s | empty | Assert.cs:58:20:58:32 | ... ? ... : ... | empty |
| Assert.cs:59:23:59:23 | access to local variable s | non-empty | Assert.cs:58:20:58:32 | ... ? ... : ... | non-empty |
| Assert.cs:59:23:59:23 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null |
| Assert.cs:59:23:59:23 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null |
| Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:58:20:58:20 | access to parameter b | true |
@@ -104,12 +104,12 @@
| Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:36:59:36 | access to parameter b | true |
| Assert.cs:60:27:60:27 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null |
| Assert.cs:60:27:60:27 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null |
| Assert.cs:65:16:65:32 | String s = ... | non-null | Assert.cs:65:16:65:16 | access to local variable s | non-null |
| Assert.cs:65:16:65:32 | String s = ... | null | Assert.cs:65:16:65:16 | access to local variable s | null |
| Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | Assert.cs:65:20:65:20 | access to parameter b | false |
| Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | Assert.cs:65:31:65:32 | "" | non-null |
| Assert.cs:65:20:65:32 | ... ? ... : ... | null | Assert.cs:65:20:65:20 | access to parameter b | true |
| Assert.cs:65:20:65:32 | ... ? ... : ... | null | Assert.cs:65:24:65:27 | null | null |
| Assert.cs:66:24:66:24 | access to local variable s | empty | Assert.cs:65:20:65:32 | ... ? ... : ... | empty |
| Assert.cs:66:24:66:24 | access to local variable s | non-empty | Assert.cs:65:20:65:32 | ... ? ... : ... | non-empty |
| Assert.cs:66:24:66:24 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null |
| Assert.cs:66:24:66:24 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null |
| Assert.cs:66:24:66:32 | ... == ... | false | Assert.cs:65:20:65:20 | access to parameter b | false |
@@ -120,12 +120,12 @@
| Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:37:66:37 | access to parameter b | false |
| Assert.cs:67:27:67:27 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null |
| Assert.cs:67:27:67:27 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null |
| Assert.cs:72:16:72:32 | String s = ... | non-null | Assert.cs:72:16:72:16 | access to local variable s | non-null |
| Assert.cs:72:16:72:32 | String s = ... | null | Assert.cs:72:16:72:16 | access to local variable s | null |
| Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | Assert.cs:72:20:72:20 | access to parameter b | false |
| Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | Assert.cs:72:31:72:32 | "" | non-null |
| Assert.cs:72:20:72:32 | ... ? ... : ... | null | Assert.cs:72:20:72:20 | access to parameter b | true |
| Assert.cs:72:20:72:32 | ... ? ... : ... | null | Assert.cs:72:24:72:27 | null | null |
| Assert.cs:73:23:73:23 | access to local variable s | empty | Assert.cs:72:20:72:32 | ... ? ... : ... | empty |
| Assert.cs:73:23:73:23 | access to local variable s | non-empty | Assert.cs:72:20:72:32 | ... ? ... : ... | non-empty |
| Assert.cs:73:23:73:23 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null |
| Assert.cs:73:23:73:23 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null |
| Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:72:20:72:20 | access to parameter b | false |
@@ -136,12 +136,12 @@
| Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:36:73:36 | access to parameter b | true |
| Assert.cs:74:27:74:27 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null |
| Assert.cs:74:27:74:27 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null |
| Assert.cs:79:16:79:32 | String s = ... | non-null | Assert.cs:79:16:79:16 | access to local variable s | non-null |
| Assert.cs:79:16:79:32 | String s = ... | null | Assert.cs:79:16:79:16 | access to local variable s | null |
| Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | Assert.cs:79:20:79:20 | access to parameter b | false |
| Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | Assert.cs:79:31:79:32 | "" | non-null |
| Assert.cs:79:20:79:32 | ... ? ... : ... | null | Assert.cs:79:20:79:20 | access to parameter b | true |
| Assert.cs:79:20:79:32 | ... ? ... : ... | null | Assert.cs:79:24:79:27 | null | null |
| Assert.cs:80:24:80:24 | access to local variable s | empty | Assert.cs:79:20:79:32 | ... ? ... : ... | empty |
| Assert.cs:80:24:80:24 | access to local variable s | non-empty | Assert.cs:79:20:79:32 | ... ? ... : ... | non-empty |
| Assert.cs:80:24:80:24 | access to local variable s | non-null | Assert.cs:79:20:79:32 | ... ? ... : ... | non-null |
| Assert.cs:80:24:80:24 | access to local variable s | null | Assert.cs:79:20:79:32 | ... ? ... : ... | null |
| Assert.cs:80:24:80:32 | ... != ... | false | Assert.cs:79:20:79:20 | access to parameter b | true |
@@ -152,6 +152,62 @@
| Assert.cs:80:24:80:37 | ... \|\| ... | false | Assert.cs:80:37:80:37 | access to parameter b | false |
| Assert.cs:81:27:81:27 | access to local variable s | non-null | Assert.cs:79:20:79:32 | ... ? ... : ... | non-null |
| Assert.cs:81:27:81:27 | access to local variable s | null | Assert.cs:79:20:79:32 | ... ? ... : ... | null |
| Collections.cs:12:17:12:32 | ... == ... | false | Collections.cs:12:17:12:20 | access to parameter args | non-empty |
| Collections.cs:12:17:12:32 | ... == ... | true | Collections.cs:12:17:12:20 | access to parameter args | empty |
| Collections.cs:13:13:13:28 | ... == ... | true | Collections.cs:13:13:13:16 | access to parameter args | non-empty |
| Collections.cs:14:13:14:28 | ... != ... | false | Collections.cs:14:13:14:16 | access to parameter args | empty |
| Collections.cs:14:13:14:28 | ... != ... | true | Collections.cs:14:13:14:16 | access to parameter args | non-empty |
| Collections.cs:15:13:15:28 | ... != ... | false | Collections.cs:15:13:15:16 | access to parameter args | non-empty |
| Collections.cs:16:13:16:27 | ... > ... | true | Collections.cs:16:13:16:16 | access to parameter args | non-empty |
| Collections.cs:18:13:18:28 | ... >= ... | true | Collections.cs:18:13:18:16 | access to parameter args | non-empty |
| Collections.cs:23:17:23:31 | ... == ... | false | Collections.cs:23:17:23:20 | access to parameter args | non-empty |
| Collections.cs:23:17:23:31 | ... == ... | true | Collections.cs:23:17:23:20 | access to parameter args | empty |
| Collections.cs:24:13:24:27 | ... == ... | true | Collections.cs:24:13:24:16 | access to parameter args | non-empty |
| Collections.cs:25:13:25:27 | ... != ... | false | Collections.cs:25:13:25:16 | access to parameter args | empty |
| Collections.cs:25:13:25:27 | ... != ... | true | Collections.cs:25:13:25:16 | access to parameter args | non-empty |
| Collections.cs:26:13:26:27 | ... != ... | false | Collections.cs:26:13:26:16 | access to parameter args | non-empty |
| Collections.cs:27:13:27:26 | ... > ... | true | Collections.cs:27:13:27:16 | access to parameter args | non-empty |
| Collections.cs:29:13:29:27 | ... >= ... | true | Collections.cs:29:13:29:16 | access to parameter args | non-empty |
| Collections.cs:34:17:34:33 | ... == ... | false | Collections.cs:34:17:34:20 | access to parameter args | non-empty |
| Collections.cs:34:17:34:33 | ... == ... | true | Collections.cs:34:17:34:20 | access to parameter args | empty |
| Collections.cs:35:13:35:29 | ... == ... | true | Collections.cs:35:13:35:16 | access to parameter args | non-empty |
| Collections.cs:36:13:36:29 | ... != ... | false | Collections.cs:36:13:36:16 | access to parameter args | empty |
| Collections.cs:36:13:36:29 | ... != ... | true | Collections.cs:36:13:36:16 | access to parameter args | non-empty |
| Collections.cs:37:13:37:29 | ... != ... | false | Collections.cs:37:13:37:16 | access to parameter args | non-empty |
| Collections.cs:38:13:38:28 | ... > ... | true | Collections.cs:38:13:38:16 | access to parameter args | non-empty |
| Collections.cs:40:13:40:29 | ... >= ... | true | Collections.cs:40:13:40:16 | access to parameter args | non-empty |
| Collections.cs:45:17:45:26 | call to method Any | false | Collections.cs:45:17:45:20 | access to parameter args | empty |
| Collections.cs:45:17:45:26 | call to method Any | true | Collections.cs:45:17:45:20 | access to parameter args | non-empty |
| Collections.cs:50:13:50:27 | ... == ... | false | Collections.cs:50:13:50:16 | access to parameter args | non-empty |
| Collections.cs:50:13:50:27 | ... == ... | true | Collections.cs:50:13:50:16 | access to parameter args | empty |
| Collections.cs:56:13:56:13 | access to local variable x | empty | Collections.cs:55:13:55:41 | array creation of type String[] | empty |
| Collections.cs:56:13:56:13 | access to local variable x | non-empty | Collections.cs:55:13:55:41 | array creation of type String[] | non-empty |
| Collections.cs:56:13:56:13 | access to local variable x | non-null | Collections.cs:55:13:55:41 | array creation of type String[] | non-null |
| Collections.cs:56:13:56:13 | access to local variable x | null | Collections.cs:55:13:55:41 | array creation of type String[] | null |
| Collections.cs:58:13:58:13 | access to local variable x | empty | Collections.cs:57:13:57:25 | array creation of type String[] | empty |
| Collections.cs:58:13:58:13 | access to local variable x | non-empty | Collections.cs:57:13:57:25 | array creation of type String[] | non-empty |
| Collections.cs:58:13:58:13 | access to local variable x | non-null | Collections.cs:57:13:57:25 | array creation of type String[] | non-null |
| Collections.cs:58:13:58:13 | access to local variable x | null | Collections.cs:57:13:57:25 | array creation of type String[] | null |
| Collections.cs:64:9:64:9 | access to local variable x | empty | Collections.cs:63:17:63:54 | call to method ToList | empty |
| Collections.cs:64:9:64:9 | access to local variable x | non-empty | Collections.cs:63:17:63:54 | call to method ToList | non-empty |
| Collections.cs:64:9:64:9 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null |
| Collections.cs:64:9:64:9 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null |
| Collections.cs:65:13:65:13 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null |
| Collections.cs:65:13:65:13 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null |
| Collections.cs:65:13:65:24 | ... == ... | false | Collections.cs:65:13:65:13 | access to local variable x | non-empty |
| Collections.cs:65:13:65:24 | ... == ... | true | Collections.cs:65:13:65:13 | access to local variable x | empty |
| Collections.cs:67:13:67:13 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null |
| Collections.cs:67:13:67:13 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null |
| Collections.cs:68:13:68:13 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null |
| Collections.cs:68:13:68:13 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null |
| Collections.cs:74:35:74:41 | ... == ... | true | Collections.cs:74:35:74:35 | access to parameter s | non-null |
| Collections.cs:75:17:75:33 | call to method Any | true | Collections.cs:75:17:75:20 | access to parameter args | non-empty |
| Collections.cs:76:13:76:36 | ... == ... | false | Collections.cs:76:13:76:16 | access to parameter args | non-empty |
| Collections.cs:77:13:77:36 | ... == ... | true | Collections.cs:77:13:77:16 | access to parameter args | non-empty |
| Collections.cs:78:13:78:36 | ... != ... | true | Collections.cs:78:13:78:16 | access to parameter args | non-empty |
| Collections.cs:79:13:79:36 | ... != ... | false | Collections.cs:79:13:79:16 | access to parameter args | non-empty |
| Collections.cs:80:13:80:35 | ... > ... | true | Collections.cs:80:13:80:16 | access to parameter args | non-empty |
| Collections.cs:82:13:82:36 | ... >= ... | true | Collections.cs:82:13:82:16 | access to parameter args | non-empty |
| Guards.cs:10:13:10:25 | !... | false | Guards.cs:10:14:10:25 | !... | true |
| Guards.cs:10:13:10:25 | !... | true | Guards.cs:10:14:10:25 | !... | false |
| Guards.cs:10:14:10:25 | !... | false | Guards.cs:10:16:10:24 | ... == ... | true |
@@ -213,10 +269,8 @@
| Guards.cs:60:13:60:45 | ... == ... | true | Guards.cs:60:13:60:37 | access to field Field | null |
| Guards.cs:68:16:68:24 | ... != ... | false | Guards.cs:68:16:68:16 | access to parameter s | null |
| Guards.cs:68:16:68:24 | ... != ... | true | Guards.cs:68:16:68:16 | access to parameter s | non-null |
| Guards.cs:71:13:71:20 | ... = ... | non-null | Guards.cs:71:13:71:13 | access to parameter s | non-null |
| Guards.cs:71:13:71:20 | ... = ... | non-null | Guards.cs:71:17:71:20 | null | non-null |
| Guards.cs:71:13:71:20 | ... = ... | null | Guards.cs:71:13:71:13 | access to parameter s | null |
| Guards.cs:71:13:71:20 | ... = ... | null | Guards.cs:71:17:71:20 | null | null |
| Guards.cs:72:31:72:31 | access to parameter s | empty | Guards.cs:71:17:71:20 | null | empty |
| Guards.cs:72:31:72:31 | access to parameter s | non-empty | Guards.cs:71:17:71:20 | null | non-empty |
| Guards.cs:72:31:72:31 | access to parameter s | non-null | Guards.cs:71:17:71:20 | null | non-null |
| Guards.cs:72:31:72:31 | access to parameter s | null | Guards.cs:71:17:71:20 | null | null |
| Guards.cs:78:13:78:26 | ... == ... | true | Guards.cs:78:15:78:21 | access to property Length | non-null |
@@ -247,36 +301,18 @@
| Guards.cs:96:13:96:19 | ... == ... | true | Guards.cs:96:13:96:13 | access to parameter s | non-null |
| Guards.cs:104:13:104:45 | ... == ... | false | Guards.cs:104:13:104:37 | access to field Field | non-null |
| Guards.cs:104:13:104:45 | ... == ... | true | Guards.cs:104:13:104:37 | access to field Field | null |
| Guards.cs:106:9:106:25 | ... = ... | non-null | Guards.cs:106:9:106:18 | access to property Property | non-null |
| Guards.cs:106:9:106:25 | ... = ... | non-null | Guards.cs:106:22:106:25 | null | non-null |
| Guards.cs:106:9:106:25 | ... = ... | null | Guards.cs:106:9:106:18 | access to property Property | null |
| Guards.cs:106:9:106:25 | ... = ... | null | Guards.cs:106:22:106:25 | null | null |
| Guards.cs:107:27:107:36 | access to property Property | non-null | Guards.cs:106:22:106:25 | null | non-null |
| Guards.cs:107:27:107:36 | access to property Property | null | Guards.cs:106:22:106:25 | null | null |
| Guards.cs:108:27:108:36 | access to property Property | non-null | Guards.cs:106:22:106:25 | null | non-null |
| Guards.cs:108:27:108:36 | access to property Property | null | Guards.cs:106:22:106:25 | null | null |
| Guards.cs:113:13:114:38 | String dummy = ... | non-null | Guards.cs:113:13:113:17 | access to local variable dummy | non-null |
| Guards.cs:113:13:114:38 | String dummy = ... | null | Guards.cs:113:13:113:17 | access to local variable dummy | null |
| Guards.cs:113:21:114:38 | ... ?? ... | null | Guards.cs:113:21:113:45 | access to field Field | null |
| Guards.cs:113:21:114:38 | ... ?? ... | null | Guards.cs:114:14:114:38 | access to field Field | null |
| Guards.cs:115:9:115:55 | ... = ... | non-null | Guards.cs:115:9:115:13 | access to local variable dummy | non-null |
| Guards.cs:115:9:115:55 | ... = ... | non-null | Guards.cs:115:17:115:55 | ... ?? ... | non-null |
| Guards.cs:115:9:115:55 | ... = ... | null | Guards.cs:115:9:115:13 | access to local variable dummy | null |
| Guards.cs:115:9:115:55 | ... = ... | null | Guards.cs:115:17:115:55 | ... ?? ... | null |
| Guards.cs:115:17:115:55 | ... ?? ... | null | Guards.cs:115:17:115:41 | access to field Field | null |
| Guards.cs:115:17:115:55 | ... ?? ... | null | Guards.cs:115:46:115:55 | throw ... | null |
| Guards.cs:117:9:117:25 | ... = ... | non-null | Guards.cs:117:9:117:18 | access to property Property | non-null |
| Guards.cs:117:9:117:25 | ... = ... | non-null | Guards.cs:117:22:117:25 | null | non-null |
| Guards.cs:117:9:117:25 | ... = ... | null | Guards.cs:117:9:117:18 | access to property Property | null |
| Guards.cs:117:9:117:25 | ... = ... | null | Guards.cs:117:22:117:25 | null | null |
| Guards.cs:118:27:118:36 | access to property Property | non-null | Guards.cs:117:22:117:25 | null | non-null |
| Guards.cs:118:27:118:36 | access to property Property | null | Guards.cs:117:22:117:25 | null | null |
| Guards.cs:119:27:119:36 | access to property Property | non-null | Guards.cs:117:22:117:25 | null | non-null |
| Guards.cs:119:27:119:36 | access to property Property | null | Guards.cs:117:22:117:25 | null | null |
| Guards.cs:124:13:124:30 | Boolean b1 = ... | false | Guards.cs:124:13:124:14 | access to local variable b1 | false |
| Guards.cs:124:13:124:30 | Boolean b1 = ... | true | Guards.cs:124:13:124:14 | access to local variable b1 | true |
| Guards.cs:125:13:125:31 | Nullable<Boolean> b2 = ... | non-null | Guards.cs:125:13:125:14 | access to local variable b2 | non-null |
| Guards.cs:125:13:125:31 | Nullable<Boolean> b2 = ... | null | Guards.cs:125:13:125:14 | access to local variable b2 | null |
| Guards.cs:125:21:125:31 | call to method Equals | non-null | Guards.cs:125:18:125:19 | access to parameter s1 | non-null |
| Guards.cs:125:21:125:31 | call to method Equals | null | Guards.cs:125:18:125:19 | access to parameter s1 | null |
| Guards.cs:130:13:130:21 | ... is ... | false | Guards.cs:130:13:130:13 | access to parameter s | non-null |
@@ -284,6 +320,8 @@
| Guards.cs:137:13:137:25 | ... is ... | false | Guards.cs:137:13:137:13 | access to parameter s | null |
| Guards.cs:137:13:137:25 | ... is ... | true | Guards.cs:137:13:137:13 | access to parameter s | non-null |
| Guards.cs:144:13:144:25 | ... is ... | true | Guards.cs:144:13:144:13 | access to parameter o | non-null |
| Guards.cs:145:20:145:20 | access to local variable s | empty | Guards.cs:144:13:144:13 | access to parameter o | empty |
| Guards.cs:145:20:145:20 | access to local variable s | non-empty | Guards.cs:144:13:144:13 | access to parameter o | non-empty |
| Guards.cs:145:20:145:20 | access to local variable s | non-null | Guards.cs:144:13:144:13 | access to parameter o | non-null |
| Guards.cs:145:20:145:20 | access to local variable s | null | Guards.cs:144:13:144:13 | access to parameter o | null |
| Guards.cs:151:17:151:17 | access to parameter o | match "" | Guards.cs:151:17:151:17 | access to parameter o | non-null |
@@ -330,16 +368,8 @@
| Guards.cs:197:13:197:29 | !... | true | Guards.cs:197:14:197:29 | call to method NullTestWrong | false |
| Guards.cs:203:13:203:21 | ... != ... | false | Guards.cs:203:13:203:13 | access to parameter o | null |
| Guards.cs:203:13:203:21 | ... != ... | true | Guards.cs:203:13:203:13 | access to parameter o | non-null |
| Guards.cs:215:13:215:21 | Boolean b2 = ... | false | Guards.cs:215:13:215:14 | access to local variable b2 | false |
| Guards.cs:215:13:215:21 | Boolean b2 = ... | true | Guards.cs:215:13:215:14 | access to local variable b2 | true |
| Guards.cs:217:13:217:22 | ... = ... | false | Guards.cs:217:13:217:14 | access to local variable b2 | false |
| Guards.cs:217:13:217:22 | ... = ... | true | Guards.cs:217:13:217:14 | access to local variable b2 | true |
| Guards.cs:218:17:218:18 | access to local variable b2 | match true | Guards.cs:216:13:216:14 | access to parameter b1 | false |
| Guards.cs:218:17:218:18 | access to local variable b2 | match true | Guards.cs:218:17:218:18 | access to local variable b2 | true |
| Guards.cs:228:13:228:22 | Boolean b2 = ... | false | Guards.cs:228:13:228:14 | access to local variable b2 | false |
| Guards.cs:228:13:228:22 | Boolean b2 = ... | true | Guards.cs:228:13:228:14 | access to local variable b2 | true |
| Guards.cs:230:13:230:21 | ... = ... | false | Guards.cs:230:13:230:14 | access to local variable b2 | false |
| Guards.cs:230:13:230:21 | ... = ... | true | Guards.cs:230:13:230:14 | access to local variable b2 | true |
| Guards.cs:231:17:231:18 | access to local variable b2 | match true | Guards.cs:229:13:229:14 | access to parameter b1 | true |
| Guards.cs:231:17:231:18 | access to local variable b2 | match true | Guards.cs:231:17:231:18 | access to local variable b2 | true |
| Guards.cs:231:17:231:18 | access to local variable b2 | non-match true | Guards.cs:229:13:229:14 | access to parameter b1 | false |
@@ -360,16 +390,8 @@
| Guards.cs:276:16:276:16 | access to parameter o | non-match null | Guards.cs:276:16:276:16 | access to parameter o | non-null |
| Guards.cs:281:17:281:17 | access to local variable a | non-null | Guards.cs:276:16:276:16 | access to parameter o | non-null |
| Guards.cs:281:17:281:17 | access to local variable a | null | Guards.cs:276:16:276:16 | access to parameter o | null |
| Guards.cs:293:13:293:21 | Boolean b2 = ... | false | Guards.cs:293:13:293:14 | access to local variable b2 | false |
| Guards.cs:293:13:293:21 | Boolean b2 = ... | true | Guards.cs:293:13:293:14 | access to local variable b2 | true |
| Guards.cs:295:13:295:22 | ... = ... | false | Guards.cs:295:13:295:14 | access to local variable b2 | false |
| Guards.cs:295:13:295:22 | ... = ... | true | Guards.cs:295:13:295:14 | access to local variable b2 | true |
| Guards.cs:296:16:296:17 | access to local variable b2 | match true | Guards.cs:294:13:294:14 | access to parameter b1 | false |
| Guards.cs:296:16:296:17 | access to local variable b2 | match true | Guards.cs:296:16:296:17 | access to local variable b2 | true |
| Guards.cs:305:13:305:22 | Boolean b2 = ... | false | Guards.cs:305:13:305:14 | access to local variable b2 | false |
| Guards.cs:305:13:305:22 | Boolean b2 = ... | true | Guards.cs:305:13:305:14 | access to local variable b2 | true |
| Guards.cs:307:13:307:21 | ... = ... | false | Guards.cs:307:13:307:14 | access to local variable b2 | false |
| Guards.cs:307:13:307:21 | ... = ... | true | Guards.cs:307:13:307:14 | access to local variable b2 | true |
| Guards.cs:308:16:308:17 | access to local variable b2 | match true | Guards.cs:306:13:306:14 | access to parameter b1 | true |
| Guards.cs:308:16:308:17 | access to local variable b2 | match true | Guards.cs:308:16:308:17 | access to local variable b2 | true |
| Guards.cs:308:16:308:17 | access to local variable b2 | non-match true | Guards.cs:306:13:306:14 | access to parameter b1 | false |
@@ -401,13 +423,7 @@
| Splitting.cs:105:22:105:30 | ... != ... | true | Splitting.cs:105:22:105:22 | access to parameter o | non-null |
| Splitting.cs:116:22:116:30 | ... != ... | false | Splitting.cs:116:22:116:22 | access to parameter o | null |
| Splitting.cs:116:22:116:30 | ... != ... | true | Splitting.cs:116:22:116:22 | access to parameter o | non-null |
| Splitting.cs:125:16:125:23 | Object o = ... | non-null | Splitting.cs:125:16:125:16 | access to local variable o | non-null |
| Splitting.cs:125:16:125:23 | Object o = ... | null | Splitting.cs:125:16:125:16 | access to local variable o | null |
| Splitting.cs:128:17:128:25 | ... != ... | false | Splitting.cs:128:17:128:17 | access to local variable o | null |
| Splitting.cs:128:17:128:25 | ... != ... | true | Splitting.cs:128:17:128:17 | access to local variable o | non-null |
| Splitting.cs:132:17:132:29 | ... = ... | non-null | Splitting.cs:132:17:132:17 | access to local variable o | non-null |
| Splitting.cs:132:17:132:29 | ... = ... | non-null | Splitting.cs:132:21:132:29 | call to method M11 | non-null |
| Splitting.cs:132:17:132:29 | ... = ... | null | Splitting.cs:132:17:132:17 | access to local variable o | null |
| Splitting.cs:132:17:132:29 | ... = ... | null | Splitting.cs:132:21:132:29 | call to method M11 | null |
| Splitting.cs:133:17:133:17 | access to local variable o | non-null | Splitting.cs:132:21:132:29 | call to method M11 | non-null |
| Splitting.cs:133:17:133:17 | access to local variable o | null | Splitting.cs:132:21:132:29 | call to method M11 | null |

View File

@@ -173,6 +173,204 @@ edges
| G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] | G.cs:52:14:52:26 | access to field Box1 [Elem] |
| G.cs:52:14:52:21 | this access [boxfield, Box1, ... (3)] | G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] |
| G.cs:52:14:52:26 | access to field Box1 [Elem] | G.cs:52:14:52:31 | access to field Elem |
nodes
| A.cs:5:17:5:23 | object creation of type C | semmle.label | object creation of type C |
| A.cs:6:17:6:25 | call to method Make [c] | semmle.label | call to method Make [c] |
| A.cs:6:24:6:24 | access to local variable c | semmle.label | access to local variable c |
| A.cs:7:14:7:14 | access to local variable b [c] | semmle.label | access to local variable b [c] |
| A.cs:7:14:7:16 | access to field c | semmle.label | access to field c |
| A.cs:13:9:13:9 | [post] access to local variable b [c] | semmle.label | [post] access to local variable b [c] |
| A.cs:13:15:13:22 | object creation of type C1 | semmle.label | object creation of type C1 |
| A.cs:14:14:14:14 | access to local variable b [c] | semmle.label | access to local variable b [c] |
| A.cs:14:14:14:20 | call to method Get | semmle.label | call to method Get |
| A.cs:15:14:15:35 | call to method Get | semmle.label | call to method Get |
| A.cs:15:15:15:28 | object creation of type B [c] | semmle.label | object creation of type B [c] |
| A.cs:15:21:15:27 | object creation of type C | semmle.label | object creation of type C |
| A.cs:22:14:22:33 | call to method SetOnB [c] | semmle.label | call to method SetOnB [c] |
| A.cs:22:25:22:32 | object creation of type C2 | semmle.label | object creation of type C2 |
| A.cs:24:14:24:15 | access to local variable b2 [c] | semmle.label | access to local variable b2 [c] |
| A.cs:24:14:24:17 | access to field c | semmle.label | access to field c |
| A.cs:31:14:31:37 | call to method SetOnBWrap [c] | semmle.label | call to method SetOnBWrap [c] |
| A.cs:31:29:31:36 | object creation of type C2 | semmle.label | object creation of type C2 |
| A.cs:33:14:33:15 | access to local variable b2 [c] | semmle.label | access to local variable b2 [c] |
| A.cs:33:14:33:17 | access to field c | semmle.label | access to field c |
| A.cs:55:17:55:23 | object creation of type A | semmle.label | object creation of type A |
| A.cs:57:9:57:10 | [post] access to local variable c1 [a] | semmle.label | [post] access to local variable c1 [a] |
| A.cs:57:16:57:16 | access to local variable a | semmle.label | access to local variable a |
| A.cs:58:12:58:13 | access to local variable c1 [a] | semmle.label | access to local variable c1 [a] |
| A.cs:60:22:60:22 | c [a] | semmle.label | c [a] |
| A.cs:64:18:64:26 | access to field a | semmle.label | access to field a |
| A.cs:64:19:64:23 | (...) ... [a] | semmle.label | (...) ... [a] |
| A.cs:69:18:69:22 | (...) ... [a] | semmle.label | (...) ... [a] |
| A.cs:77:18:77:27 | access to field a | semmle.label | access to field a |
| A.cs:77:19:77:24 | (...) ... [a] | semmle.label | (...) ... [a] |
| A.cs:83:9:83:9 | [post] access to parameter b [c] | semmle.label | [post] access to parameter b [c] |
| A.cs:83:15:83:21 | object creation of type C | semmle.label | object creation of type C |
| A.cs:88:12:88:12 | [post] access to local variable b [c] | semmle.label | [post] access to local variable b [c] |
| A.cs:89:14:89:14 | access to local variable b [c] | semmle.label | access to local variable b [c] |
| A.cs:89:14:89:16 | access to field c | semmle.label | access to field c |
| A.cs:97:13:97:13 | [post] access to parameter b [c] | semmle.label | [post] access to parameter b [c] |
| A.cs:97:19:97:25 | object creation of type C | semmle.label | object creation of type C |
| A.cs:98:13:98:16 | [post] this access [b, c] | semmle.label | [post] this access [b, c] |
| A.cs:98:13:98:16 | [post] this access [b] | semmle.label | [post] this access [b] |
| A.cs:98:22:98:36 | ... ? ... : ... | semmle.label | ... ? ... : ... |
| A.cs:98:22:98:36 | ... ? ... : ... [c] | semmle.label | ... ? ... : ... [c] |
| A.cs:98:30:98:36 | object creation of type B | semmle.label | object creation of type B |
| A.cs:104:17:104:23 | object creation of type B | semmle.label | object creation of type B |
| A.cs:105:17:105:29 | object creation of type D [b, c] | semmle.label | object creation of type D [b, c] |
| A.cs:105:17:105:29 | object creation of type D [b] | semmle.label | object creation of type D [b] |
| A.cs:105:23:105:23 | [post] access to local variable b [c] | semmle.label | [post] access to local variable b [c] |
| A.cs:105:23:105:23 | access to local variable b | semmle.label | access to local variable b |
| A.cs:106:14:106:14 | access to local variable d [b] | semmle.label | access to local variable d [b] |
| A.cs:106:14:106:16 | access to field b | semmle.label | access to field b |
| A.cs:107:14:107:14 | access to local variable d [b, c] | semmle.label | access to local variable d [b, c] |
| A.cs:107:14:107:16 | access to field b [c] | semmle.label | access to field b [c] |
| A.cs:107:14:107:18 | access to field c | semmle.label | access to field c |
| A.cs:108:14:108:14 | access to local variable b [c] | semmle.label | access to local variable b [c] |
| A.cs:108:14:108:16 | access to field c | semmle.label | access to field c |
| A.cs:113:17:113:23 | object creation of type B | semmle.label | object creation of type B |
| A.cs:114:18:114:54 | object creation of type MyList [head] | semmle.label | object creation of type MyList [head] |
| A.cs:114:29:114:29 | access to local variable b | semmle.label | access to local variable b |
| A.cs:115:18:115:37 | object creation of type MyList [next, head] | semmle.label | object creation of type MyList [next, head] |
| A.cs:115:35:115:36 | access to local variable l1 [head] | semmle.label | access to local variable l1 [head] |
| A.cs:116:18:116:37 | object creation of type MyList [next, next, ... (3)] | semmle.label | object creation of type MyList [next, next, ... (3)] |
| A.cs:116:35:116:36 | access to local variable l2 [next, head] | semmle.label | access to local variable l2 [next, head] |
| A.cs:119:14:119:15 | access to local variable l3 [next, next, ... (3)] | semmle.label | access to local variable l3 [next, next, ... (3)] |
| A.cs:119:14:119:20 | access to field next [next, head] | semmle.label | access to field next [next, head] |
| A.cs:119:14:119:25 | access to field next [head] | semmle.label | access to field next [head] |
| A.cs:119:14:119:30 | access to field head | semmle.label | access to field head |
| A.cs:121:41:121:41 | access to local variable l [next, head] | semmle.label | access to local variable l [next, head] |
| A.cs:121:41:121:41 | access to local variable l [next, next, ... (3)] | semmle.label | access to local variable l [next, next, ... (3)] |
| A.cs:121:41:121:46 | access to field next [head] | semmle.label | access to field next [head] |
| A.cs:121:41:121:46 | access to field next [next, head] | semmle.label | access to field next [next, head] |
| A.cs:123:18:123:18 | access to local variable l [head] | semmle.label | access to local variable l [head] |
| A.cs:123:18:123:23 | access to field head | semmle.label | access to field head |
| B.cs:5:17:5:26 | object creation of type Elem | semmle.label | object creation of type Elem |
| B.cs:6:18:6:34 | object creation of type Box1 [elem1] | semmle.label | object creation of type Box1 [elem1] |
| B.cs:6:27:6:27 | access to local variable e | semmle.label | access to local variable e |
| B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] | semmle.label | object creation of type Box2 [box1, elem1] |
| B.cs:7:27:7:28 | access to local variable b1 [elem1] | semmle.label | access to local variable b1 [elem1] |
| B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] | semmle.label | access to local variable b2 [box1, elem1] |
| B.cs:8:14:8:20 | access to field box1 [elem1] | semmle.label | access to field box1 [elem1] |
| B.cs:8:14:8:26 | access to field elem1 | semmle.label | access to field elem1 |
| B.cs:14:17:14:26 | object creation of type Elem | semmle.label | object creation of type Elem |
| B.cs:15:18:15:34 | object creation of type Box1 [elem2] | semmle.label | object creation of type Box1 [elem2] |
| B.cs:15:33:15:33 | access to local variable e | semmle.label | access to local variable e |
| B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] | semmle.label | object creation of type Box2 [box1, elem2] |
| B.cs:16:27:16:28 | access to local variable b1 [elem2] | semmle.label | access to local variable b1 [elem2] |
| B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] | semmle.label | access to local variable b2 [box1, elem2] |
| B.cs:18:14:18:20 | access to field box1 [elem2] | semmle.label | access to field box1 [elem2] |
| B.cs:18:14:18:26 | access to field elem2 | semmle.label | access to field elem2 |
| C.cs:3:18:3:19 | [post] this access [s1] | semmle.label | [post] this access [s1] |
| C.cs:3:23:3:32 | object creation of type Elem | semmle.label | object creation of type Elem |
| C.cs:4:27:4:28 | [post] this access [s2] | semmle.label | [post] this access [s2] |
| C.cs:4:32:4:41 | object creation of type Elem | semmle.label | object creation of type Elem |
| C.cs:6:30:6:39 | object creation of type Elem | semmle.label | object creation of type Elem |
| C.cs:7:18:7:19 | [post] this access [s5] | semmle.label | [post] this access [s5] |
| C.cs:7:37:7:46 | object creation of type Elem | semmle.label | object creation of type Elem |
| C.cs:8:30:8:39 | object creation of type Elem | semmle.label | object creation of type Elem |
| C.cs:12:15:12:21 | object creation of type C [s1] | semmle.label | object creation of type C [s1] |
| C.cs:12:15:12:21 | object creation of type C [s2] | semmle.label | object creation of type C [s2] |
| C.cs:12:15:12:21 | object creation of type C [s3] | semmle.label | object creation of type C [s3] |
| C.cs:12:15:12:21 | object creation of type C [s5] | semmle.label | object creation of type C [s5] |
| C.cs:13:9:13:9 | access to local variable c [s1] | semmle.label | access to local variable c [s1] |
| C.cs:13:9:13:9 | access to local variable c [s2] | semmle.label | access to local variable c [s2] |
| C.cs:13:9:13:9 | access to local variable c [s3] | semmle.label | access to local variable c [s3] |
| C.cs:13:9:13:9 | access to local variable c [s5] | semmle.label | access to local variable c [s5] |
| C.cs:18:9:18:12 | [post] this access [s3] | semmle.label | [post] this access [s3] |
| C.cs:18:19:18:28 | object creation of type Elem | semmle.label | object creation of type Elem |
| C.cs:21:17:21:18 | this [s1] | semmle.label | this [s1] |
| C.cs:21:17:21:18 | this [s2] | semmle.label | this [s2] |
| C.cs:21:17:21:18 | this [s3] | semmle.label | this [s3] |
| C.cs:21:17:21:18 | this [s5] | semmle.label | this [s5] |
| C.cs:23:14:23:15 | access to field s1 | semmle.label | access to field s1 |
| C.cs:23:14:23:15 | this access [s1] | semmle.label | this access [s1] |
| C.cs:24:14:24:15 | access to field s2 | semmle.label | access to field s2 |
| C.cs:24:14:24:15 | this access [s2] | semmle.label | this access [s2] |
| C.cs:25:14:25:15 | access to field s3 | semmle.label | access to field s3 |
| C.cs:25:14:25:15 | this access [s3] | semmle.label | this access [s3] |
| C.cs:26:14:26:15 | access to field s4 | semmle.label | access to field s4 |
| C.cs:27:14:27:15 | access to property s5 | semmle.label | access to property s5 |
| C.cs:27:14:27:15 | this access [s5] | semmle.label | this access [s5] |
| C.cs:28:14:28:15 | access to property s6 | semmle.label | access to property s6 |
| D.cs:29:17:29:28 | object creation of type Object | semmle.label | object creation of type Object |
| D.cs:31:17:31:37 | call to method Create [AutoProp] | semmle.label | call to method Create [AutoProp] |
| D.cs:31:24:31:24 | access to local variable o | semmle.label | access to local variable o |
| D.cs:32:14:32:14 | access to local variable d [AutoProp] | semmle.label | access to local variable d [AutoProp] |
| D.cs:32:14:32:23 | access to property AutoProp | semmle.label | access to property AutoProp |
| D.cs:37:13:37:33 | call to method Create [trivialPropField] | semmle.label | call to method Create [trivialPropField] |
| D.cs:37:26:37:26 | access to local variable o | semmle.label | access to local variable o |
| D.cs:39:14:39:14 | access to local variable d [trivialPropField] | semmle.label | access to local variable d [trivialPropField] |
| D.cs:39:14:39:26 | access to property TrivialProp | semmle.label | access to property TrivialProp |
| D.cs:40:14:40:14 | access to local variable d [trivialPropField] | semmle.label | access to local variable d [trivialPropField] |
| D.cs:40:14:40:31 | access to field trivialPropField | semmle.label | access to field trivialPropField |
| D.cs:41:14:41:14 | access to local variable d [trivialPropField] | semmle.label | access to local variable d [trivialPropField] |
| D.cs:41:14:41:26 | access to property ComplexProp | semmle.label | access to property ComplexProp |
| D.cs:43:13:43:33 | call to method Create [trivialPropField] | semmle.label | call to method Create [trivialPropField] |
| D.cs:43:32:43:32 | access to local variable o | semmle.label | access to local variable o |
| D.cs:45:14:45:14 | access to local variable d [trivialPropField] | semmle.label | access to local variable d [trivialPropField] |
| D.cs:45:14:45:26 | access to property TrivialProp | semmle.label | access to property TrivialProp |
| D.cs:46:14:46:14 | access to local variable d [trivialPropField] | semmle.label | access to local variable d [trivialPropField] |
| D.cs:46:14:46:31 | access to field trivialPropField | semmle.label | access to field trivialPropField |
| D.cs:47:14:47:14 | access to local variable d [trivialPropField] | semmle.label | access to local variable d [trivialPropField] |
| D.cs:47:14:47:26 | access to property ComplexProp | semmle.label | access to property ComplexProp |
| E.cs:22:17:22:28 | object creation of type Object | semmle.label | object creation of type Object |
| E.cs:23:17:23:26 | call to method CreateS [Field] | semmle.label | call to method CreateS [Field] |
| E.cs:23:25:23:25 | access to local variable o | semmle.label | access to local variable o |
| E.cs:24:14:24:14 | access to local variable s [Field] | semmle.label | access to local variable s [Field] |
| E.cs:24:14:24:20 | access to field Field | semmle.label | access to field Field |
| F.cs:10:17:10:28 | object creation of type Object | semmle.label | object creation of type Object |
| F.cs:11:17:11:31 | call to method Create [Field1] | semmle.label | call to method Create [Field1] |
| F.cs:11:24:11:24 | access to local variable o | semmle.label | access to local variable o |
| F.cs:12:14:12:14 | access to local variable f [Field1] | semmle.label | access to local variable f [Field1] |
| F.cs:12:14:12:21 | access to field Field1 | semmle.label | access to field Field1 |
| F.cs:15:13:15:27 | call to method Create [Field2] | semmle.label | call to method Create [Field2] |
| F.cs:15:26:15:26 | access to local variable o | semmle.label | access to local variable o |
| F.cs:17:14:17:14 | access to local variable f [Field2] | semmle.label | access to local variable f [Field2] |
| F.cs:17:14:17:21 | access to field Field2 | semmle.label | access to field Field2 |
| F.cs:19:13:19:34 | object creation of type F [Field1] | semmle.label | object creation of type F [Field1] |
| F.cs:19:32:19:32 | access to local variable o | semmle.label | access to local variable o |
| F.cs:20:14:20:14 | access to local variable f [Field1] | semmle.label | access to local variable f [Field1] |
| F.cs:20:14:20:21 | access to field Field1 | semmle.label | access to field Field1 |
| F.cs:23:13:23:34 | object creation of type F [Field2] | semmle.label | object creation of type F [Field2] |
| F.cs:23:32:23:32 | access to local variable o | semmle.label | access to local variable o |
| F.cs:25:14:25:14 | access to local variable f [Field2] | semmle.label | access to local variable f [Field2] |
| F.cs:25:14:25:21 | access to field Field2 | semmle.label | access to field Field2 |
| G.cs:7:18:7:27 | object creation of type Elem | semmle.label | object creation of type Elem |
| G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] | semmle.label | [post] access to local variable b [Box1, Elem] |
| G.cs:9:9:9:14 | [post] access to field Box1 [Elem] | semmle.label | [post] access to field Box1 [Elem] |
| G.cs:9:23:9:23 | access to local variable e | semmle.label | access to local variable e |
| G.cs:10:18:10:18 | access to local variable b [Box1, Elem] | semmle.label | access to local variable b [Box1, Elem] |
| G.cs:15:18:15:27 | object creation of type Elem | semmle.label | object creation of type Elem |
| G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] | semmle.label | [post] access to local variable b [Box1, Elem] |
| G.cs:17:9:17:14 | [post] access to field Box1 [Elem] | semmle.label | [post] access to field Box1 [Elem] |
| G.cs:17:24:17:24 | access to local variable e | semmle.label | access to local variable e |
| G.cs:18:18:18:18 | access to local variable b [Box1, Elem] | semmle.label | access to local variable b [Box1, Elem] |
| G.cs:23:18:23:27 | object creation of type Elem | semmle.label | object creation of type Elem |
| G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] | semmle.label | [post] access to local variable b [Box1, Elem] |
| G.cs:25:9:25:19 | [post] call to method GetBox1 [Elem] | semmle.label | [post] call to method GetBox1 [Elem] |
| G.cs:25:28:25:28 | access to local variable e | semmle.label | access to local variable e |
| G.cs:26:18:26:18 | access to local variable b [Box1, Elem] | semmle.label | access to local variable b [Box1, Elem] |
| G.cs:31:18:31:27 | object creation of type Elem | semmle.label | object creation of type Elem |
| G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] | semmle.label | [post] access to local variable b [Box1, Elem] |
| G.cs:33:9:33:19 | [post] call to method GetBox1 [Elem] | semmle.label | [post] call to method GetBox1 [Elem] |
| G.cs:33:29:33:29 | access to local variable e | semmle.label | access to local variable e |
| G.cs:34:18:34:18 | access to local variable b [Box1, Elem] | semmle.label | access to local variable b [Box1, Elem] |
| G.cs:37:38:37:39 | b2 [Box1, Elem] | semmle.label | b2 [Box1, Elem] |
| G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] | semmle.label | access to parameter b2 [Box1, Elem] |
| G.cs:39:14:39:25 | call to method GetBox1 [Elem] | semmle.label | call to method GetBox1 [Elem] |
| G.cs:39:14:39:35 | call to method GetElem | semmle.label | call to method GetElem |
| G.cs:44:18:44:27 | object creation of type Elem | semmle.label | object creation of type Elem |
| G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] | semmle.label | [post] access to field boxfield [Box1, Elem] |
| G.cs:46:9:46:16 | [post] this access [boxfield, Box1, ... (3)] | semmle.label | [post] this access [boxfield, Box1, ... (3)] |
| G.cs:46:9:46:21 | [post] access to field Box1 [Elem] | semmle.label | [post] access to field Box1 [Elem] |
| G.cs:46:30:46:30 | access to local variable e | semmle.label | access to local variable e |
| G.cs:47:9:47:13 | this access [boxfield, Box1, ... (3)] | semmle.label | this access [boxfield, Box1, ... (3)] |
| G.cs:50:18:50:20 | this [boxfield, Box1, ... (3)] | semmle.label | this [boxfield, Box1, ... (3)] |
| G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] | semmle.label | access to field boxfield [Box1, Elem] |
| G.cs:52:14:52:21 | this access [boxfield, Box1, ... (3)] | semmle.label | this access [boxfield, Box1, ... (3)] |
| G.cs:52:14:52:26 | access to field Box1 [Elem] | semmle.label | access to field Box1 [Elem] |
| G.cs:52:14:52:31 | access to field Elem | semmle.label | access to field Elem |
#select
| A.cs:7:14:7:16 | access to field c | A.cs:5:17:5:23 | object creation of type C | A.cs:7:14:7:16 | access to field c | $@ | A.cs:5:17:5:23 | object creation of type C | object creation of type C |
| A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:22 | object creation of type C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:22 | object creation of type C1 | object creation of type C1 |

View File

@@ -192,6 +192,159 @@ edges
| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | Splitting.cs:34:19:34:19 | access to local variable x |
| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element |
| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element |
nodes
| Capture.cs:7:20:7:26 | tainted | semmle.label | tainted |
| Capture.cs:9:9:13:9 | SSA capture def(tainted) | semmle.label | SSA capture def(tainted) |
| Capture.cs:12:19:12:24 | access to local variable sink27 | semmle.label | access to local variable sink27 |
| Capture.cs:14:9:14:20 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:18:13:22:13 | SSA capture def(tainted) | semmle.label | SSA capture def(tainted) |
| Capture.cs:21:23:21:28 | access to local variable sink28 | semmle.label | access to local variable sink28 |
| Capture.cs:25:9:25:20 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:27:43:32:9 | SSA capture def(tainted) | semmle.label | SSA capture def(tainted) |
| Capture.cs:30:19:30:24 | access to local variable sink29 | semmle.label | access to local variable sink29 |
| Capture.cs:33:9:33:40 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:57:13:57:35 | SSA def(sink30) | semmle.label | SSA def(sink30) |
| Capture.cs:57:22:57:35 | "taint source" | semmle.label | "taint source" |
| Capture.cs:59:9:59:21 | SSA call def(sink30) | semmle.label | SSA call def(sink30) |
| Capture.cs:60:15:60:20 | access to local variable sink30 | semmle.label | access to local variable sink30 |
| Capture.cs:67:17:67:39 | SSA def(sink31) | semmle.label | SSA def(sink31) |
| Capture.cs:67:26:67:39 | "taint source" | semmle.label | "taint source" |
| Capture.cs:71:9:71:21 | SSA call def(sink31) | semmle.label | SSA call def(sink31) |
| Capture.cs:72:15:72:20 | access to local variable sink31 | semmle.label | access to local variable sink31 |
| Capture.cs:77:13:77:35 | SSA def(sink32) | semmle.label | SSA def(sink32) |
| Capture.cs:77:22:77:35 | "taint source" | semmle.label | "taint source" |
| Capture.cs:80:9:80:41 | SSA call def(sink32) | semmle.label | SSA call def(sink32) |
| Capture.cs:81:15:81:20 | access to local variable sink32 | semmle.label | access to local variable sink32 |
| Capture.cs:101:25:101:31 | tainted | semmle.label | tainted |
| Capture.cs:108:9:108:25 | SSA call def(sink33) | semmle.label | SSA call def(sink33) |
| Capture.cs:108:9:108:25 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:109:15:109:20 | access to local variable sink33 | semmle.label | access to local variable sink33 |
| Capture.cs:120:9:120:25 | SSA call def(sink34) | semmle.label | SSA call def(sink34) |
| Capture.cs:120:9:120:25 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:121:15:121:20 | access to local variable sink34 | semmle.label | access to local variable sink34 |
| Capture.cs:129:9:129:45 | SSA call def(sink35) | semmle.label | SSA call def(sink35) |
| Capture.cs:129:9:129:45 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:130:15:130:20 | access to local variable sink35 | semmle.label | access to local variable sink35 |
| Capture.cs:136:22:136:38 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:136:22:136:38 | call to local function CaptureThrough4 | semmle.label | call to local function CaptureThrough4 |
| Capture.cs:137:15:137:20 | access to local variable sink36 | semmle.label | access to local variable sink36 |
| Capture.cs:144:9:144:32 | SSA call def(sink37) | semmle.label | SSA call def(sink37) |
| Capture.cs:144:25:144:31 | access to parameter tainted | semmle.label | access to parameter tainted |
| Capture.cs:145:15:145:20 | access to local variable sink37 | semmle.label | access to local variable sink37 |
| Capture.cs:170:22:170:32 | call to local function Id | semmle.label | call to local function Id |
| Capture.cs:170:25:170:31 | access to parameter tainted | semmle.label | access to parameter tainted |
| Capture.cs:171:15:171:20 | access to local variable sink38 | semmle.label | access to local variable sink38 |
| GlobalDataFlow.cs:17:27:17:40 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | semmle.label | access to field SinkField0 |
| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 | semmle.label | sinkParam2 |
| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 |
| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:53:15:53:15 | x | semmle.label | x |
| GlobalDataFlow.cs:53:24:53:24 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:56:37:56:37 | x | semmle.label | x |
| GlobalDataFlow.cs:56:46:56:46 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | semmle.label | access to parameter nonSinkParam0 |
| GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | semmle.label | access to parameter nonSinkParam0 |
| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:70:21:70:46 | call to method Return | semmle.label | call to method Return |
| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | semmle.label | access to local variable sink0 |
| GlobalDataFlow.cs:72:21:72:101 | (...) ... | semmle.label | (...) ... |
| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | semmle.label | call to method Invoke |
| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | semmle.label | access to local variable sink0 |
| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | semmle.label | access to local variable sink1 |
| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | semmle.label | access to local variable sink1 |
| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | semmle.label | SSA def(sink2) |
| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | semmle.label | access to local variable sink2 |
| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | semmle.label | access to local variable sink2 |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | semmle.label | SSA def(sink3) |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | semmle.label | access to local variable sink3 |
| GlobalDataFlow.cs:135:21:135:34 | delegate call | semmle.label | delegate call |
| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | semmle.label | access to local variable sink3 |
| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | semmle.label | access to local variable sink4 |
| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | semmle.label | call to method ApplyFunc |
| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | semmle.label | access to local variable sink4 |
| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | semmle.label | access to local variable sink5 |
| GlobalDataFlow.cs:153:21:153:25 | call to method Out | semmle.label | call to method Out |
| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | semmle.label | access to local variable sink6 |
| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | semmle.label | SSA def(sink7) |
| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | semmle.label | access to local variable sink7 |
| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | semmle.label | SSA def(sink8) |
| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | semmle.label | access to local variable sink8 |
| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | semmle.label | call to method TaintedParam |
| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | semmle.label | access to local variable sink23 |
| GlobalDataFlow.cs:179:35:179:48 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:180:21:180:26 | delegate call | semmle.label | delegate call |
| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 |
| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func<String> | semmle.label | [output] delegate creation of type Func<String> |
| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 |
| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | semmle.label | access to property OutProperty |
| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 |
| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | semmle.label | sinkParam0 |
| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 |
| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 |
| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 | semmle.label | sinkParam1 |
| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 |
| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | semmle.label | sinkParam3 |
| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 |
| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | semmle.label | sinkParam4 |
| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 |
| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | semmle.label | sinkParam5 |
| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 |
| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | semmle.label | sinkParam6 |
| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 |
| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | semmle.label | sinkParam7 |
| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 |
| GlobalDataFlow.cs:318:16:318:29 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) | semmle.label | SSA def(x) |
| GlobalDataFlow.cs:323:13:323:26 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) | semmle.label | SSA def(x) |
| GlobalDataFlow.cs:328:13:328:26 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:359:41:359:41 | x | semmle.label | x |
| GlobalDataFlow.cs:359:41:359:41 | x | semmle.label | x |
| GlobalDataFlow.cs:361:11:361:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:361:11:361:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:373:52:373:52 | x | semmle.label | x |
| GlobalDataFlow.cs:373:52:373:52 | x | semmle.label | x |
| GlobalDataFlow.cs:373:52:373:52 | x | semmle.label | x |
| GlobalDataFlow.cs:375:11:375:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:375:11:375:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:375:11:375:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:378:39:378:45 | tainted | semmle.label | tainted |
| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | semmle.label | access to local variable sink11 |
| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | semmle.label | access to local variable sink11 |
| GlobalDataFlow.cs:404:9:404:11 | value | semmle.label | value |
| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | semmle.label | access to local variable sink20 |
| GlobalDataFlow.cs:415:22:415:35 | "taint source" | semmle.label | "taint source" |
| Splitting.cs:3:28:3:34 | tainted | semmle.label | tainted |
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | semmle.label | [b (line 3): false] call to method Return |
| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | semmle.label | [b (line 3): true] call to method Return |
| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | semmle.label | [b (line 3): false] access to parameter tainted |
| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | semmle.label | [b (line 3): true] access to parameter tainted |
| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | semmle.label | [b (line 3): false] access to local variable x |
| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | semmle.label | [b (line 3): true] access to local variable x |
| Splitting.cs:11:19:11:19 | access to local variable x | semmle.label | access to local variable x |
| Splitting.cs:21:9:21:11 | value | semmle.label | value |
| Splitting.cs:21:28:21:32 | access to parameter value | semmle.label | access to parameter value |
| Splitting.cs:24:28:24:34 | tainted | semmle.label | tainted |
| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted | semmle.label | [b (line 24): false] access to parameter tainted |
| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | semmle.label | [b (line 24): true] access to parameter tainted |
| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | semmle.label | [b (line 24): false] dynamic access to element |
| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | semmle.label | [b (line 24): true] dynamic access to element |
| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | semmle.label | [b (line 24): false] access to parameter tainted |
| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | semmle.label | [b (line 24): true] access to parameter tainted |
| Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | semmle.label | [b (line 24): false] access to local variable x |
| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | semmle.label | [b (line 24): true] access to local variable x |
| Splitting.cs:34:19:34:19 | access to local variable x | semmle.label | access to local variable x |
#select
| Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | Splitting.cs:24:28:24:34 | tainted | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | [b (line 24): false] access to local variable x |
| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | Splitting.cs:24:28:24:34 | tainted | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | [b (line 24): true] access to local variable x |

View File

@@ -239,6 +239,205 @@ edges
| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | Splitting.cs:34:19:34:19 | access to local variable x |
| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element |
| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element |
nodes
| Capture.cs:7:20:7:26 | tainted | semmle.label | tainted |
| Capture.cs:9:9:13:9 | SSA capture def(tainted) | semmle.label | SSA capture def(tainted) |
| Capture.cs:12:19:12:24 | access to local variable sink27 | semmle.label | access to local variable sink27 |
| Capture.cs:14:9:14:20 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:18:13:22:13 | SSA capture def(tainted) | semmle.label | SSA capture def(tainted) |
| Capture.cs:21:23:21:28 | access to local variable sink28 | semmle.label | access to local variable sink28 |
| Capture.cs:25:9:25:20 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:27:43:32:9 | SSA capture def(tainted) | semmle.label | SSA capture def(tainted) |
| Capture.cs:30:19:30:24 | access to local variable sink29 | semmle.label | access to local variable sink29 |
| Capture.cs:33:9:33:40 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:57:13:57:35 | SSA def(sink30) | semmle.label | SSA def(sink30) |
| Capture.cs:57:22:57:35 | "taint source" | semmle.label | "taint source" |
| Capture.cs:59:9:59:21 | SSA call def(sink30) | semmle.label | SSA call def(sink30) |
| Capture.cs:60:15:60:20 | access to local variable sink30 | semmle.label | access to local variable sink30 |
| Capture.cs:67:17:67:39 | SSA def(sink31) | semmle.label | SSA def(sink31) |
| Capture.cs:67:26:67:39 | "taint source" | semmle.label | "taint source" |
| Capture.cs:71:9:71:21 | SSA call def(sink31) | semmle.label | SSA call def(sink31) |
| Capture.cs:72:15:72:20 | access to local variable sink31 | semmle.label | access to local variable sink31 |
| Capture.cs:77:13:77:35 | SSA def(sink32) | semmle.label | SSA def(sink32) |
| Capture.cs:77:22:77:35 | "taint source" | semmle.label | "taint source" |
| Capture.cs:80:9:80:41 | SSA call def(sink32) | semmle.label | SSA call def(sink32) |
| Capture.cs:81:15:81:20 | access to local variable sink32 | semmle.label | access to local variable sink32 |
| Capture.cs:101:25:101:31 | tainted | semmle.label | tainted |
| Capture.cs:108:9:108:25 | SSA call def(sink33) | semmle.label | SSA call def(sink33) |
| Capture.cs:108:9:108:25 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:109:15:109:20 | access to local variable sink33 | semmle.label | access to local variable sink33 |
| Capture.cs:120:9:120:25 | SSA call def(sink34) | semmle.label | SSA call def(sink34) |
| Capture.cs:120:9:120:25 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:121:15:121:20 | access to local variable sink34 | semmle.label | access to local variable sink34 |
| Capture.cs:129:9:129:45 | SSA call def(sink35) | semmle.label | SSA call def(sink35) |
| Capture.cs:129:9:129:45 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:130:15:130:20 | access to local variable sink35 | semmle.label | access to local variable sink35 |
| Capture.cs:136:22:136:38 | [implicit argument] tainted | semmle.label | [implicit argument] tainted |
| Capture.cs:136:22:136:38 | call to local function CaptureThrough4 | semmle.label | call to local function CaptureThrough4 |
| Capture.cs:137:15:137:20 | access to local variable sink36 | semmle.label | access to local variable sink36 |
| Capture.cs:144:9:144:32 | SSA call def(sink37) | semmle.label | SSA call def(sink37) |
| Capture.cs:144:25:144:31 | access to parameter tainted | semmle.label | access to parameter tainted |
| Capture.cs:145:15:145:20 | access to local variable sink37 | semmle.label | access to local variable sink37 |
| Capture.cs:170:22:170:32 | call to local function Id | semmle.label | call to local function Id |
| Capture.cs:170:25:170:31 | access to parameter tainted | semmle.label | access to parameter tainted |
| Capture.cs:171:15:171:20 | access to local variable sink38 | semmle.label | access to local variable sink38 |
| GlobalDataFlow.cs:17:27:17:40 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | semmle.label | access to field SinkField0 |
| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 | semmle.label | sinkParam2 |
| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 |
| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:53:15:53:15 | x | semmle.label | x |
| GlobalDataFlow.cs:53:24:53:24 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:56:37:56:37 | x | semmle.label | x |
| GlobalDataFlow.cs:56:46:56:46 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | semmle.label | access to parameter nonSinkParam0 |
| GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | semmle.label | access to parameter nonSinkParam0 |
| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:70:21:70:46 | call to method Return | semmle.label | call to method Return |
| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 |
| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | semmle.label | access to local variable sink0 |
| GlobalDataFlow.cs:72:21:72:101 | (...) ... | semmle.label | (...) ... |
| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | semmle.label | call to method Invoke |
| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | semmle.label | access to local variable sink0 |
| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | semmle.label | access to local variable sink1 |
| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | semmle.label | access to local variable sink1 |
| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | semmle.label | SSA def(sink2) |
| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | semmle.label | access to local variable sink2 |
| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | semmle.label | access to local variable sink2 |
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | semmle.label | SSA def(sink3) |
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | semmle.label | access to local variable sink3 |
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | semmle.label | call to method SelectEven |
| GlobalDataFlow.cs:80:23:80:65 | (...) ... | semmle.label | (...) ... |
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | semmle.label | access to local variable sink13 |
| GlobalDataFlow.cs:82:23:82:74 | (...) ... | semmle.label | (...) ... |
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> | semmle.label | [output] delegate creation of type Func<String,String> |
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 |
| GlobalDataFlow.cs:84:23:84:74 | (...) ... | semmle.label | (...) ... |
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | semmle.label | [output] (...) => ... |
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 |
| GlobalDataFlow.cs:86:70:86:121 | (...) ... | semmle.label | (...) ... |
| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | semmle.label | [output] (...) => ... |
| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 |
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | semmle.label | access to local variable sink14 |
| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | semmle.label | [output] (...) => ... |
| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... | semmle.label | [output] (...) => ... |
| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | semmle.label | access to local variable sink17 |
| GlobalDataFlow.cs:90:75:90:88 | call to method First | semmle.label | call to method First |
| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | semmle.label | [output] (...) => ... |
| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... | semmle.label | [output] (...) => ... |
| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | semmle.label | access to local variable sink18 |
| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | semmle.label | access to local variable sink21 |
| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | semmle.label | access to local variable sink22 |
| GlobalDataFlow.cs:135:21:135:34 | delegate call | semmle.label | delegate call |
| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | semmle.label | access to local variable sink3 |
| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | semmle.label | access to local variable sink4 |
| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | semmle.label | call to method ApplyFunc |
| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | semmle.label | access to local variable sink4 |
| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | semmle.label | access to local variable sink5 |
| GlobalDataFlow.cs:153:21:153:25 | call to method Out | semmle.label | call to method Out |
| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | semmle.label | access to local variable sink6 |
| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | semmle.label | SSA def(sink7) |
| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | semmle.label | access to local variable sink7 |
| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | semmle.label | SSA def(sink8) |
| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | semmle.label | access to local variable sink8 |
| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | semmle.label | call to method OutYield |
| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | semmle.label | access to local variable sink12 |
| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | semmle.label | call to method TaintedParam |
| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | semmle.label | access to local variable sink23 |
| GlobalDataFlow.cs:179:35:179:48 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:180:21:180:26 | delegate call | semmle.label | delegate call |
| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 |
| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func<String> | semmle.label | [output] delegate creation of type Func<String> |
| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 |
| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | semmle.label | access to property OutProperty |
| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 |
| GlobalDataFlow.cs:205:39:205:45 | tainted | semmle.label | tainted |
| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | semmle.label | sinkParam10 |
| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 |
| GlobalDataFlow.cs:209:71:209:71 | x | semmle.label | x |
| GlobalDataFlow.cs:209:89:209:89 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted | semmle.label | access to parameter tainted |
| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 | semmle.label | [output] access to local variable f1 |
| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | semmle.label | access to local variable sink24 |
| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | semmle.label | access to parameter tainted |
| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | semmle.label | [output] access to local variable f2 |
| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | semmle.label | access to local variable sink25 |
| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | semmle.label | access to parameter tainted |
| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func<String,String> | semmle.label | [output] delegate creation of type Func<String,String> |
| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | semmle.label | access to local variable sink26 |
| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | semmle.label | sinkParam0 |
| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 |
| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 |
| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 | semmle.label | sinkParam1 |
| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 |
| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | semmle.label | sinkParam3 |
| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 |
| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | semmle.label | sinkParam4 |
| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 |
| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | semmle.label | sinkParam5 |
| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 |
| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | semmle.label | sinkParam6 |
| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 |
| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | semmle.label | sinkParam7 |
| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 |
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | semmle.label | sinkParam8 |
| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 |
| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 | semmle.label | sinkParam9 |
| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 |
| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | semmle.label | sinkParam11 |
| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 |
| GlobalDataFlow.cs:318:16:318:29 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) | semmle.label | SSA def(x) |
| GlobalDataFlow.cs:323:13:323:26 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) | semmle.label | SSA def(x) |
| GlobalDataFlow.cs:328:13:328:26 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:334:22:334:35 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:334:22:334:35 | "taint source" | semmle.label | "taint source" |
| GlobalDataFlow.cs:359:41:359:41 | x | semmle.label | x |
| GlobalDataFlow.cs:359:41:359:41 | x | semmle.label | x |
| GlobalDataFlow.cs:361:11:361:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:361:11:361:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:373:52:373:52 | x | semmle.label | x |
| GlobalDataFlow.cs:373:52:373:52 | x | semmle.label | x |
| GlobalDataFlow.cs:373:52:373:52 | x | semmle.label | x |
| GlobalDataFlow.cs:375:11:375:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:375:11:375:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:375:11:375:11 | access to parameter x | semmle.label | access to parameter x |
| GlobalDataFlow.cs:378:39:378:45 | tainted | semmle.label | tainted |
| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | semmle.label | access to local variable sink11 |
| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | semmle.label | access to local variable sink11 |
| GlobalDataFlow.cs:404:9:404:11 | value | semmle.label | value |
| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | semmle.label | access to local variable sink20 |
| GlobalDataFlow.cs:415:22:415:35 | "taint source" | semmle.label | "taint source" |
| Splitting.cs:3:28:3:34 | tainted | semmle.label | tainted |
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | semmle.label | [b (line 3): false] call to method Return |
| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | semmle.label | [b (line 3): true] call to method Return |
| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | semmle.label | [b (line 3): false] access to parameter tainted |
| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | semmle.label | [b (line 3): true] access to parameter tainted |
| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | semmle.label | [b (line 3): false] access to local variable x |
| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | semmle.label | [b (line 3): true] access to local variable x |
| Splitting.cs:11:19:11:19 | access to local variable x | semmle.label | access to local variable x |
| Splitting.cs:21:9:21:11 | value | semmle.label | value |
| Splitting.cs:21:28:21:32 | access to parameter value | semmle.label | access to parameter value |
| Splitting.cs:24:28:24:34 | tainted | semmle.label | tainted |
| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted | semmle.label | [b (line 24): false] access to parameter tainted |
| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | semmle.label | [b (line 24): true] access to parameter tainted |
| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | semmle.label | [b (line 24): false] dynamic access to element |
| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | semmle.label | [b (line 24): true] dynamic access to element |
| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | semmle.label | [b (line 24): false] access to parameter tainted |
| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | semmle.label | [b (line 24): true] access to parameter tainted |
| Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | semmle.label | [b (line 24): false] access to local variable x |
| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | semmle.label | [b (line 24): true] access to local variable x |
| Splitting.cs:34:19:34:19 | access to local variable x | semmle.label | access to local variable x |
#select
| Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 |
| Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 |

View File

@@ -0,0 +1,19 @@
using System.Collections.Generic;
public class Collections
{
class MyClass
{
public string a;
public string b;
}
public static void Main()
{
var dict = new Dictionary<int, MyClass>()
{
{ 0, new MyClass { a="Hello", b="World" } },
{ 1, new MyClass { a="Foo", b="Bar" } }
};
}
}

View File

@@ -0,0 +1,40 @@
using System;
class Jumps
{
public static void Main()
{
for (int i = 1; i <= 10; i++)
{
if (i == 3)
continue;
else if (i == 5)
break;
Console.WriteLine("BreakAndContinue");
}
for (int i = 0 ; i < 10 ; )
{
i++;
continue;
}
int a = 0;
while (true)
{
a++;
if (a == 5)
continue;
if (a == 10)
break;
}
for (int i = 1; i <= 10; i++)
{
if (i == 5)
goto done;
}
done:
Console.WriteLine("Done");
}
}

View File

@@ -13,11 +13,17 @@ public class ObjCreation
x = _x;
}
}
public static void SomeFun(MyClass x)
{
}
public static void Main()
{
MyClass obj = new MyClass(100);
MyClass obj_initlist = new MyClass { x = 101 };
int a = obj.x;
SomeFun(new MyClass(100));
}
}

View File

@@ -161,6 +161,50 @@ casts.cs:
# 11| v0_20(Void) = UnmodeledUse : mu*
# 11| v0_21(Void) = ExitFunction :
collections.cs:
# 11| System.Void Collections.Main()
# 11| Block 0
# 11| v0_0(Void) = EnterFunction :
# 11| mu0_1(null) = AliasedDefinition :
# 11| mu0_2(null) = UnmodeledDefinition :
# 13| r0_3(glval<Dictionary<Int32,MyClass>>) = VariableAddress[dict] :
# 13| r0_4(Dictionary<Int32,MyClass>) = NewObj :
# 13| r0_5(glval<null>) = FunctionAddress[Dictionary] :
# 13| v0_6(Void) = Call : func:r0_5, this:r0_4
# 13| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 15| r0_8(glval<null>) = FunctionAddress[Add] :
# 15| r0_9(Int32) = Constant[0] :
# 15| r0_10(MyClass) = NewObj :
# 15| r0_11(glval<null>) = FunctionAddress[MyClass] :
# 15| v0_12(Void) = Call : func:r0_11, this:r0_10
# 15| mu0_13(null) = ^CallSideEffect : ~mu0_2
# 15| r0_14(String) = StringConstant["Hello"] :
# 15| r0_15(glval<String>) = FieldAddress[a] : r0_10
# 15| mu0_16(String) = Store : &:r0_15, r0_14
# 15| r0_17(String) = StringConstant["World"] :
# 15| r0_18(glval<String>) = FieldAddress[b] : r0_10
# 15| mu0_19(String) = Store : &:r0_18, r0_17
# 15| v0_20(Void) = Call : func:r0_8, this:r0_4, 0:r0_9, 1:r0_10
# 15| mu0_21(null) = ^CallSideEffect : ~mu0_2
# 16| r0_22(glval<null>) = FunctionAddress[Add] :
# 16| r0_23(Int32) = Constant[1] :
# 16| r0_24(MyClass) = NewObj :
# 16| r0_25(glval<null>) = FunctionAddress[MyClass] :
# 16| v0_26(Void) = Call : func:r0_25, this:r0_24
# 16| mu0_27(null) = ^CallSideEffect : ~mu0_2
# 16| r0_28(String) = StringConstant["Foo"] :
# 16| r0_29(glval<String>) = FieldAddress[a] : r0_24
# 16| mu0_30(String) = Store : &:r0_29, r0_28
# 16| r0_31(String) = StringConstant["Bar"] :
# 16| r0_32(glval<String>) = FieldAddress[b] : r0_24
# 16| mu0_33(String) = Store : &:r0_32, r0_31
# 16| v0_34(Void) = Call : func:r0_22, this:r0_4, 0:r0_23, 1:r0_24
# 16| mu0_35(null) = ^CallSideEffect : ~mu0_2
# 13| mu0_36(Dictionary<Int32,MyClass>) = Store : &:r0_3, r0_4
# 11| v0_37(Void) = ReturnVoid :
# 11| v0_38(Void) = UnmodeledUse : mu*
# 11| v0_39(Void) = ExitFunction :
constructor_init.cs:
# 5| System.Void BaseClass..ctor()
# 5| Block 0
@@ -534,7 +578,7 @@ inheritance_polymorphism.cs:
# 33| v0_28(Void) = Call : func:r0_27, this:r0_26
# 33| mu0_29(null) = ^CallSideEffect : ~mu0_2
# 33| r0_30(A) = Convert : r0_26
# 33| mu0_31(C) = Store : &:r0_25, r0_30
# 33| mu0_31(A) = Store : &:r0_25, r0_26
# 34| r0_32(glval<A>) = VariableAddress[objC] :
# 34| r0_33(A) = Load : &:r0_32, ~mu0_2
# 34| r0_34(glval<null>) = FunctionAddress[function] :
@@ -547,21 +591,23 @@ inheritance_polymorphism.cs:
isexpr.cs:
# 8| System.Void IsExpr.Main()
# 8| Block 0
# 8| v0_0(Void) = EnterFunction :
# 8| mu0_1(null) = AliasedDefinition :
# 8| mu0_2(null) = UnmodeledDefinition :
# 10| r0_3(glval<Is_A>) = VariableAddress[obj] :
# 10| r0_4(null) = Constant[null] :
# 10| mu0_5(Is_A) = Store : &:r0_3, r0_4
# 12| r0_6(glval<Object>) = VariableAddress[o] :
# 12| r0_7(glval<Is_A>) = VariableAddress[obj] :
# 12| mu0_8(Object) = Store : &:r0_6, r0_7
# 13| r0_9(glval<Object>) = VariableAddress[o] :
# 13| r0_10(Object) = Load : &:r0_9, ~mu0_2
# 13| r0_11(Is_A) = CheckedConvertOrNull : r0_10
# 13| r0_12(Is_A) = Constant[0] :
# 13| r0_13(Boolean) = CompareNE : r0_11, r0_12
# 13| r0_14(Boolean) = ConditionalBranch : r0_13
# 8| v0_0(Void) = EnterFunction :
# 8| mu0_1(null) = AliasedDefinition :
# 8| mu0_2(null) = UnmodeledDefinition :
# 10| r0_3(glval<Is_A>) = VariableAddress[obj] :
# 10| r0_4(null) = Constant[null] :
# 10| r0_5(Is_A) = Convert : r0_4
# 10| mu0_6(Is_A) = Store : &:r0_3, r0_4
# 12| r0_7(glval<Object>) = VariableAddress[o] :
# 12| r0_8(glval<Is_A>) = VariableAddress[obj] :
# 12| r0_9(Object) = Convert : r0_8
# 12| mu0_10(Object) = Store : &:r0_7, r0_8
# 13| r0_11(glval<Object>) = VariableAddress[o] :
# 13| r0_12(Object) = Load : &:r0_11, ~mu0_2
# 13| r0_13(Is_A) = CheckedConvertOrNull : r0_12
# 13| r0_14(Is_A) = Constant[0] :
# 13| r0_15(Boolean) = CompareNE : r0_13, r0_14
# 13| r0_16(Boolean) = ConditionalBranch : r0_15
#-----| False -> Block 2
#-----| True -> Block 3
@@ -571,13 +617,13 @@ isexpr.cs:
# 8| v1_2(Void) = ExitFunction :
# 13| Block 2
# 13| v2_0(Void) = ConditionalBranch : r0_13
# 13| v2_0(Void) = ConditionalBranch : r0_15
#-----| False -> Block 5
#-----| True -> Block 4
# 13| Block 3
# 13| r3_0(glval<Is_A>) = VariableAddress[tmp] :
# 13| mu3_1(Is_A) = Store : &:r3_0, r0_11
# 13| mu3_1(Is_A) = Store : &:r3_0, r0_13
#-----| Goto -> Block 2
# 15| Block 4
@@ -603,6 +649,180 @@ isexpr.cs:
# 18| v6_0(Void) = NoOp :
#-----| Goto -> Block 1
jumps.cs:
# 5| System.Void Jumps.Main()
# 5| Block 0
# 5| v0_0(Void) = EnterFunction :
# 5| mu0_1(null) = AliasedDefinition :
# 5| mu0_2(null) = UnmodeledDefinition :
# 7| r0_3(glval<Int32>) = VariableAddress[i] :
# 7| r0_4(Int32) = Constant[1] :
# 7| mu0_5(Int32) = Store : &:r0_3, r0_4
#-----| Goto -> Block 1
# 7| Block 1
# 7| r1_0(glval<Int32>) = VariableAddress[i] :
# 7| r1_1(Int32) = Load : &:r1_0, ~mu0_2
# 7| r1_2(Int32) = Constant[10] :
# 7| r1_3(Boolean) = CompareLE : r1_1, r1_2
# 7| v1_4(Void) = ConditionalBranch : r1_3
#-----| False -> Block 7
#-----| True -> Block 2
# 9| Block 2
# 9| r2_0(glval<Int32>) = VariableAddress[i] :
# 9| r2_1(Int32) = Load : &:r2_0, ~mu0_2
# 9| r2_2(Int32) = Constant[3] :
# 9| r2_3(Boolean) = CompareEQ : r2_1, r2_2
# 9| v2_4(Void) = ConditionalBranch : r2_3
#-----| False -> Block 4
#-----| True -> Block 3
# 10| Block 3
# 10| v3_0(Void) = NoOp :
#-----| Goto -> Block 19
# 11| Block 4
# 11| r4_0(glval<Int32>) = VariableAddress[i] :
# 11| r4_1(Int32) = Load : &:r4_0, ~mu0_2
# 11| r4_2(Int32) = Constant[5] :
# 11| r4_3(Boolean) = CompareEQ : r4_1, r4_2
# 11| v4_4(Void) = ConditionalBranch : r4_3
#-----| False -> Block 6
#-----| True -> Block 5
# 12| Block 5
# 12| v5_0(Void) = NoOp :
#-----| Goto -> Block 7
# 13| Block 6
# 13| r6_0(glval<null>) = FunctionAddress[WriteLine] :
# 13| r6_1(String) = StringConstant["BreakAndContinue"] :
# 13| v6_2(Void) = Call : func:r6_0, 0:r6_1
# 13| mu6_3(null) = ^CallSideEffect : ~mu0_2
#-----| Goto -> Block 19
# 16| Block 7
# 16| r7_0(glval<Int32>) = VariableAddress[i] :
# 16| r7_1(Int32) = Constant[0] :
# 16| mu7_2(Int32) = Store : &:r7_0, r7_1
#-----| Goto -> Block 8
# 16| Block 8
# 16| r8_0(glval<Int32>) = VariableAddress[i] :
# 16| r8_1(Int32) = Load : &:r8_0, ~mu0_2
# 16| r8_2(Int32) = Constant[10] :
# 16| r8_3(Boolean) = CompareLT : r8_1, r8_2
# 16| v8_4(Void) = ConditionalBranch : r8_3
#-----| False -> Block 10
#-----| True -> Block 9
# 18| Block 9
# 18| r9_0(glval<Int32>) = VariableAddress[i] :
# 18| r9_1(Int32) = Load : &:r9_0, ~mu0_2
# 18| r9_2(Int32) = Constant[1] :
# 18| r9_3(Int32) = Add : r9_1, r9_2
# 18| mu9_4(Int32) = Store : &:r9_0, r9_3
# 19| v9_5(Void) = NoOp :
#-----| Goto (back edge) -> Block 8
# 22| Block 10
# 22| r10_0(glval<Int32>) = VariableAddress[a] :
# 22| r10_1(Int32) = Constant[0] :
# 22| mu10_2(Int32) = Store : &:r10_0, r10_1
#-----| Goto -> Block 11
# 23| Block 11
# 23| r11_0(Boolean) = Constant[true] :
# 23| v11_1(Void) = ConditionalBranch : r11_0
#-----| False -> Block 16
#-----| True -> Block 12
# 25| Block 12
# 25| r12_0(glval<Int32>) = VariableAddress[a] :
# 25| r12_1(Int32) = Load : &:r12_0, ~mu0_2
# 25| r12_2(Int32) = Constant[1] :
# 25| r12_3(Int32) = Add : r12_1, r12_2
# 25| mu12_4(Int32) = Store : &:r12_0, r12_3
# 26| r12_5(glval<Int32>) = VariableAddress[a] :
# 26| r12_6(Int32) = Load : &:r12_5, ~mu0_2
# 26| r12_7(Int32) = Constant[5] :
# 26| r12_8(Boolean) = CompareEQ : r12_6, r12_7
# 26| v12_9(Void) = ConditionalBranch : r12_8
#-----| False -> Block 14
#-----| True -> Block 13
# 27| Block 13
# 27| v13_0(Void) = NoOp :
#-----| Goto (back edge) -> Block 11
# 28| Block 14
# 28| r14_0(glval<Int32>) = VariableAddress[a] :
# 28| r14_1(Int32) = Load : &:r14_0, ~mu0_2
# 28| r14_2(Int32) = Constant[10] :
# 28| r14_3(Boolean) = CompareEQ : r14_1, r14_2
# 28| v14_4(Void) = ConditionalBranch : r14_3
#-----| False (back edge) -> Block 11
#-----| True -> Block 15
# 29| Block 15
# 29| v15_0(Void) = NoOp :
#-----| Goto -> Block 16
# 32| Block 16
# 32| r16_0(glval<Int32>) = VariableAddress[i] :
# 32| r16_1(Int32) = Constant[1] :
# 32| mu16_2(Int32) = Store : &:r16_0, r16_1
#-----| Goto -> Block 18
# 32| Block 17
# 32| r17_0(glval<Int32>) = VariableAddress[i] :
# 32| r17_1(Int32) = Load : &:r17_0, ~mu0_2
# 32| r17_2(Int32) = Constant[1] :
# 32| r17_3(Int32) = Add : r17_1, r17_2
# 32| mu17_4(Int32) = Store : &:r17_0, r17_3
#-----| Goto (back edge) -> Block 18
# 32| Block 18
# 32| r18_0(glval<Int32>) = VariableAddress[i] :
# 32| r18_1(Int32) = Load : &:r18_0, ~mu0_2
# 32| r18_2(Int32) = Constant[10] :
# 32| r18_3(Boolean) = CompareLE : r18_1, r18_2
# 32| v18_4(Void) = ConditionalBranch : r18_3
#-----| False -> Block 22
#-----| True -> Block 20
# 7| Block 19
# 7| r19_0(glval<Int32>) = VariableAddress[i] :
# 7| r19_1(Int32) = Load : &:r19_0, ~mu0_2
# 7| r19_2(Int32) = Constant[1] :
# 7| r19_3(Int32) = Add : r19_1, r19_2
# 7| mu19_4(Int32) = Store : &:r19_0, r19_3
#-----| Goto (back edge) -> Block 1
# 34| Block 20
# 34| r20_0(glval<Int32>) = VariableAddress[i] :
# 34| r20_1(Int32) = Load : &:r20_0, ~mu0_2
# 34| r20_2(Int32) = Constant[5] :
# 34| r20_3(Boolean) = CompareEQ : r20_1, r20_2
# 34| v20_4(Void) = ConditionalBranch : r20_3
#-----| False -> Block 17
#-----| True -> Block 21
# 35| Block 21
# 35| v21_0(Void) = NoOp :
#-----| Goto -> Block 22
# 37| Block 22
# 37| v22_0(Void) = NoOp :
# 38| r22_1(glval<null>) = FunctionAddress[WriteLine] :
# 38| r22_2(String) = StringConstant["Done"] :
# 38| v22_3(Void) = Call : func:r22_1, 0:r22_2
# 38| mu22_4(null) = ^CallSideEffect : ~mu0_2
# 5| v22_5(Void) = ReturnVoid :
# 5| v22_6(Void) = UnmodeledUse : mu*
# 5| v22_7(Void) = ExitFunction :
lock.cs:
# 5| System.Void LockTest.A()
# 5| Block 0
@@ -684,36 +904,56 @@ obj_creation.cs:
# 11| v0_12(Void) = UnmodeledUse : mu*
# 11| v0_13(Void) = ExitFunction :
# 17| System.Void ObjCreation.Main()
# 17| System.Void ObjCreation.SomeFun(ObjCreation.MyClass)
# 17| Block 0
# 17| v0_0(Void) = EnterFunction :
# 17| mu0_1(null) = AliasedDefinition :
# 17| mu0_2(null) = UnmodeledDefinition :
# 19| r0_3(glval<MyClass>) = VariableAddress[obj] :
# 19| r0_4(MyClass) = NewObj :
# 19| r0_5(glval<null>) = FunctionAddress[MyClass] :
# 19| r0_6(Int32) = Constant[100] :
# 19| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6
# 19| mu0_8(null) = ^CallSideEffect : ~mu0_2
# 19| mu0_9(MyClass) = Store : &:r0_3, r0_4
# 20| r0_10(glval<MyClass>) = VariableAddress[obj_initlist] :
# 20| r0_11(MyClass) = NewObj :
# 20| r0_12(glval<null>) = FunctionAddress[MyClass] :
# 20| v0_13(Void) = Call : func:r0_12, this:r0_11
# 20| mu0_14(null) = ^CallSideEffect : ~mu0_2
# 20| r0_15(Int32) = Constant[101] :
# 20| r0_16(glval<Int32>) = FieldAddress[x] : r0_11
# 20| mu0_17(Int32) = Store : &:r0_16, r0_15
# 20| mu0_18(MyClass) = Store : &:r0_10, r0_11
# 21| r0_19(glval<Int32>) = VariableAddress[a] :
# 21| r0_20(glval<MyClass>) = VariableAddress[obj] :
# 21| r0_21(MyClass) = Load : &:r0_20, ~mu0_2
# 21| r0_22(glval<Int32>) = FieldAddress[x] : r0_21
# 21| r0_23(Int32) = Load : &:r0_22, ~mu0_2
# 21| mu0_24(Int32) = Store : &:r0_19, r0_23
# 17| v0_25(Void) = ReturnVoid :
# 17| v0_26(Void) = UnmodeledUse : mu*
# 17| v0_27(Void) = ExitFunction :
# 17| v0_0(Void) = EnterFunction :
# 17| mu0_1(null) = AliasedDefinition :
# 17| mu0_2(null) = UnmodeledDefinition :
# 17| r0_3(glval<MyClass>) = VariableAddress[x] :
# 17| mu0_4(MyClass) = InitializeParameter[x] : &:r0_3
# 18| v0_5(Void) = NoOp :
# 17| v0_6(Void) = ReturnVoid :
# 17| v0_7(Void) = UnmodeledUse : mu*
# 17| v0_8(Void) = ExitFunction :
# 21| System.Void ObjCreation.Main()
# 21| Block 0
# 21| v0_0(Void) = EnterFunction :
# 21| mu0_1(null) = AliasedDefinition :
# 21| mu0_2(null) = UnmodeledDefinition :
# 23| r0_3(glval<MyClass>) = VariableAddress[obj] :
# 23| r0_4(MyClass) = NewObj :
# 23| r0_5(glval<null>) = FunctionAddress[MyClass] :
# 23| r0_6(Int32) = Constant[100] :
# 23| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6
# 23| mu0_8(null) = ^CallSideEffect : ~mu0_2
# 23| mu0_9(MyClass) = Store : &:r0_3, r0_4
# 24| r0_10(glval<MyClass>) = VariableAddress[obj_initlist] :
# 24| r0_11(MyClass) = NewObj :
# 24| r0_12(glval<null>) = FunctionAddress[MyClass] :
# 24| v0_13(Void) = Call : func:r0_12, this:r0_11
# 24| mu0_14(null) = ^CallSideEffect : ~mu0_2
# 24| r0_15(Int32) = Constant[101] :
# 24| r0_16(glval<Int32>) = FieldAddress[x] : r0_11
# 24| mu0_17(Int32) = Store : &:r0_16, r0_15
# 24| mu0_18(MyClass) = Store : &:r0_10, r0_11
# 25| r0_19(glval<Int32>) = VariableAddress[a] :
# 25| r0_20(glval<MyClass>) = VariableAddress[obj] :
# 25| r0_21(MyClass) = Load : &:r0_20, ~mu0_2
# 25| r0_22(glval<Int32>) = FieldAddress[x] : r0_21
# 25| r0_23(Int32) = Load : &:r0_22, ~mu0_2
# 25| mu0_24(Int32) = Store : &:r0_19, r0_23
# 27| r0_25(glval<null>) = FunctionAddress[SomeFun] :
# 27| r0_26(MyClass) = NewObj :
# 27| r0_27(glval<null>) = FunctionAddress[MyClass] :
# 27| r0_28(Int32) = Constant[100] :
# 27| v0_29(Void) = Call : func:r0_27, this:r0_26, 0:r0_28
# 27| mu0_30(null) = ^CallSideEffect : ~mu0_2
# 27| v0_31(Void) = Call : func:r0_25, 0:r0_26
# 27| mu0_32(null) = ^CallSideEffect : ~mu0_2
# 21| v0_33(Void) = ReturnVoid :
# 21| v0_34(Void) = UnmodeledUse : mu*
# 21| v0_35(Void) = ExitFunction :
prop.cs:
# 7| System.Int32 PropClass.get_Prop()
@@ -1048,6 +1288,9 @@ stmts.cs:
# 71| r0_6(glval<Int32>) = VariableAddress[i] :
# 71| r0_7(Int32) = Constant[0] :
# 71| mu0_8(Int32) = Store : &:r0_6, r0_7
# 71| r0_9(glval<Int32>) = VariableAddress[j] :
# 71| r0_10(Int32) = Constant[10] :
# 71| mu0_11(Int32) = Store : &:r0_9, r0_10
#-----| Goto -> Block 2
# 68| Block 1
@@ -1058,53 +1301,92 @@ stmts.cs:
# 71| Block 2
# 71| r2_0(glval<Int32>) = VariableAddress[i] :
# 71| r2_1(Int32) = Load : &:r2_0, ~mu0_2
# 71| r2_2(Int32) = Constant[10] :
# 71| r2_3(Boolean) = CompareLE : r2_1, r2_2
# 71| v2_4(Void) = ConditionalBranch : r2_3
#-----| False -> Block 1
# 71| r2_2(glval<Int32>) = VariableAddress[j] :
# 71| r2_3(Int32) = Load : &:r2_2, ~mu0_2
# 71| r2_4(Boolean) = CompareLT : r2_1, r2_3
# 71| v2_5(Void) = ConditionalBranch : r2_4
#-----| False -> Block 4
#-----| True -> Block 3
# 73| Block 3
# 73| r3_0(glval<Int32>) = VariableAddress[x] :
# 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2
# 73| r3_2(Int32) = Constant[1] :
# 73| r3_3(Int32) = Sub : r3_1, r3_2
# 73| r3_4(glval<Int32>) = VariableAddress[x] :
# 73| mu3_5(Int32) = Store : &:r3_4, r3_3
# 71| r3_6(glval<Int32>) = VariableAddress[i] :
# 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2
# 71| r3_8(Int32) = Constant[1] :
# 71| r3_9(Int32) = Add : r3_7, r3_8
# 71| mu3_10(Int32) = Store : &:r3_6, r3_9
# 73| r3_0(glval<Int32>) = VariableAddress[x] :
# 73| r3_1(Int32) = Load : &:r3_0, ~mu0_2
# 73| r3_2(Int32) = Constant[1] :
# 73| r3_3(Int32) = Sub : r3_1, r3_2
# 73| r3_4(glval<Int32>) = VariableAddress[x] :
# 73| mu3_5(Int32) = Store : &:r3_4, r3_3
# 71| r3_6(glval<Int32>) = VariableAddress[i] :
# 71| r3_7(Int32) = Load : &:r3_6, ~mu0_2
# 71| r3_8(Int32) = Constant[1] :
# 71| r3_9(Int32) = Add : r3_7, r3_8
# 71| mu3_10(Int32) = Store : &:r3_6, r3_9
# 71| r3_11(glval<Int32>) = VariableAddress[j] :
# 71| r3_12(Int32) = Load : &:r3_11, ~mu0_2
# 71| r3_13(Int32) = Constant[1] :
# 71| r3_14(Int32) = Sub : r3_12, r3_13
# 71| mu3_15(Int32) = Store : &:r3_11, r3_14
#-----| Goto (back edge) -> Block 2
# 77| System.Void test_stmts.doWhile()
# 77| Block 0
# 77| v0_0(Void) = EnterFunction :
# 77| mu0_1(null) = AliasedDefinition :
# 77| mu0_2(null) = UnmodeledDefinition :
# 79| r0_3(glval<Int32>) = VariableAddress[x] :
# 79| r0_4(Int32) = Constant[0] :
# 79| mu0_5(Int32) = Store : &:r0_3, r0_4
# 76| Block 4
# 76| r4_0(glval<Int32>) = VariableAddress[a] :
# 76| mu4_1(Int32) = Uninitialized[a] : &:r4_0
# 76| r4_2(glval<Int32>) = VariableAddress[b] :
# 76| r4_3(Int32) = Constant[10] :
# 76| mu4_4(Int32) = Store : &:r4_2, r4_3
# 77| r4_5(Int32) = Constant[0] :
# 77| r4_6(glval<Int32>) = VariableAddress[a] :
# 77| mu4_7(Int32) = Store : &:r4_6, r4_5
#-----| Goto -> Block 5
# 77| Block 5
# 77| r5_0(glval<Int32>) = VariableAddress[a] :
# 77| r5_1(Int32) = Load : &:r5_0, ~mu0_2
# 77| r5_2(glval<Int32>) = VariableAddress[b] :
# 77| r5_3(Int32) = Load : &:r5_2, ~mu0_2
# 77| r5_4(Boolean) = CompareLT : r5_1, r5_3
# 77| v5_5(Void) = ConditionalBranch : r5_4
#-----| False -> Block 7
#-----| True -> Block 6
# 79| Block 6
# 79| r6_0(glval<Int32>) = VariableAddress[a] :
# 79| r6_1(Int32) = Load : &:r6_0, ~mu0_2
# 79| r6_2(Int32) = Constant[1] :
# 79| r6_3(Int32) = Add : r6_1, r6_2
# 79| mu6_4(Int32) = Store : &:r6_0, r6_3
#-----| Goto (back edge) -> Block 5
# 83| Block 7
# 83| v7_0(Void) = NoOp :
#-----| Goto (back edge) -> Block 7
# 88| System.Void test_stmts.doWhile()
# 88| Block 0
# 88| v0_0(Void) = EnterFunction :
# 88| mu0_1(null) = AliasedDefinition :
# 88| mu0_2(null) = UnmodeledDefinition :
# 90| r0_3(glval<Int32>) = VariableAddress[x] :
# 90| r0_4(Int32) = Constant[0] :
# 90| mu0_5(Int32) = Store : &:r0_3, r0_4
#-----| Goto -> Block 2
# 77| Block 1
# 77| v1_0(Void) = ReturnVoid :
# 77| v1_1(Void) = UnmodeledUse : mu*
# 77| v1_2(Void) = ExitFunction :
# 88| Block 1
# 88| v1_0(Void) = ReturnVoid :
# 88| v1_1(Void) = UnmodeledUse : mu*
# 88| v1_2(Void) = ExitFunction :
# 82| Block 2
# 82| r2_0(glval<Int32>) = VariableAddress[x] :
# 82| r2_1(Int32) = Load : &:r2_0, ~mu0_2
# 82| r2_2(Int32) = Constant[1] :
# 82| r2_3(Int32) = Add : r2_1, r2_2
# 82| r2_4(glval<Int32>) = VariableAddress[x] :
# 82| mu2_5(Int32) = Store : &:r2_4, r2_3
# 84| r2_6(glval<Int32>) = VariableAddress[x] :
# 84| r2_7(Int32) = Load : &:r2_6, ~mu0_2
# 84| r2_8(Int32) = Constant[10] :
# 84| r2_9(Boolean) = CompareLT : r2_7, r2_8
# 84| v2_10(Void) = ConditionalBranch : r2_9
# 93| Block 2
# 93| r2_0(glval<Int32>) = VariableAddress[x] :
# 93| r2_1(Int32) = Load : &:r2_0, ~mu0_2
# 93| r2_2(Int32) = Constant[1] :
# 93| r2_3(Int32) = Add : r2_1, r2_2
# 93| r2_4(glval<Int32>) = VariableAddress[x] :
# 93| mu2_5(Int32) = Store : &:r2_4, r2_3
# 95| r2_6(glval<Int32>) = VariableAddress[x] :
# 95| r2_7(Int32) = Load : &:r2_6, ~mu0_2
# 95| r2_8(Int32) = Constant[10] :
# 95| r2_9(Boolean) = CompareLT : r2_7, r2_8
# 95| v2_10(Void) = ConditionalBranch : r2_9
#-----| False -> Block 1
#-----| True (back edge) -> Block 2

View File

@@ -68,9 +68,20 @@ public class test_stmts
public static void forStmt()
{
int x = 0;
for (int i = 0; i <= 10; i++)
for (int i = 0, j = 10; i < j; i++, j--)
{
x = x - 1;
}
int a, b = 10;
for (a = 0; a < b; )
{
x = x - 1;
a++;
}
for( ; ; )
{
}
}

View File

@@ -1,3 +1,4 @@
| Program.cs:62:17:62:35 | nameof(...) | Program.cs:62:24:62:34 | access to method MethodGroup |
| Program.cs:63:13:63:50 | nameof(...) | Program.cs:63:20:63:49 | access to method MethodGroup |
| Program.cs:169:16:169:29 | nameof(...) | Program.cs:169:23:169:28 | access to namespace System |
| Program.cs:169:33:169:62 | nameof(...) | Program.cs:169:40:169:61 | access to namespace Tasks |

View File

@@ -166,7 +166,7 @@ unsafe class ArrayTypesTest
class NameofNamespace
{
string s = nameof(System);
string s = nameof(System) + nameof(System.Threading.Tasks);
}
class UsingDiscard

Some files were not shown because too many files have changed in this diff Show More