mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge branch 'master' into js/vue-support-1
This commit is contained in:
@@ -26,4 +26,5 @@
|
|||||||
|
|
||||||
## Changes to QL libraries
|
## Changes to QL libraries
|
||||||
|
|
||||||
There is a new `Namespace.isInline()` predicate, which holds if the namespace was declared as `inline namespace`.
|
* There is a new `Namespace.isInline()` predicate, which holds if the namespace was declared as `inline namespace`.
|
||||||
|
* The `Expr.isConstant()` predicate now also holds for _address constant expressions_, which are addresses that will be constant after the program has been linked. These address constants do not have a result for `Expr.getValue()`.
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
| Dereferenced variable may be null (cs/dereferenced-value-may-be-null) | Improved results | The query has been rewritten from scratch, and the analysis is now based on static single assignment (SSA) forms. The query is now enabled by default in LGTM. |
|
| Dereferenced variable may be null (cs/dereferenced-value-may-be-null) | Improved results | The query has been rewritten from scratch, and the analysis is now based on static single assignment (SSA) forms. The query is now enabled by default in LGTM. |
|
||||||
| SQL query built from user-controlled sources (cs/sql-injection), Improper control of generation of code (cs/code-injection), Uncontrolled format string (cs/uncontrolled-format-string), Clear text storage of sensitive information (cs/cleartext-storage-of-sensitive-information), Exposure of private information (cs/exposure-of-sensitive-information) | More results | Data sources have been added from user controls in `System.Windows.Forms`. |
|
| SQL query built from user-controlled sources (cs/sql-injection), Improper control of generation of code (cs/code-injection), Uncontrolled format string (cs/uncontrolled-format-string), Clear text storage of sensitive information (cs/cleartext-storage-of-sensitive-information), Exposure of private information (cs/exposure-of-sensitive-information) | More results | Data sources have been added from user controls in `System.Windows.Forms`. |
|
||||||
| Use of default ToString() (cs/call-to-object-tostring) | Fewer false positives | Results have been removed for `char` arrays passed to `StringBuilder.Append()`, which were incorrectly marked as using `ToString`. |
|
| Use of default ToString() (cs/call-to-object-tostring) | Fewer false positives | Results have been removed for `char` arrays passed to `StringBuilder.Append()`, which were incorrectly marked as using `ToString`. |
|
||||||
|
| Use of default ToString() (cs/call-to-object-tostring) | Fewer results | Results have been removed when the object is an interface or an abstract class. |
|
||||||
|
| Unused format argument (cs/format-argument-unused) | Fewer false positives | Results have been removed where the format string is empty. This is often used as a default value and is not an interesting result. |
|
||||||
|
|
||||||
## Changes to code extraction
|
## Changes to code extraction
|
||||||
|
|
||||||
* Fix extraction of `for` statements where the condition declares new variables using `is`.
|
* Fix extraction of `for` statements where the condition declares new variables using `is`.
|
||||||
@@ -24,6 +26,4 @@
|
|||||||
|
|
||||||
## Changes to QL libraries
|
## Changes to QL libraries
|
||||||
|
|
||||||
* The class `AccessorCall` (and subclasses `PropertyCall`, `IndexerCall`, and `EventCall`) have been redefined, so the expressions they represent are not necessarily the accesses themselves, but rather the expressions that give rise to the accessor calls. For example, in the property assignment `x.Prop = 0`, the call to the setter for `Prop` is no longer represented by the access `x.Prop`, but instead the whole assignment. Consequently, it is no longer safe to cast directly between `AccessorCall`s and `Access`es, and the predicate `AccessorCall::getAccess()` should be used instead.
|
|
||||||
|
|
||||||
## Changes to the autobuilder
|
## Changes to the autobuilder
|
||||||
|
|||||||
@@ -24,5 +24,8 @@
|
|||||||
`semmle.code.java.dataflow.DataFlow`,
|
`semmle.code.java.dataflow.DataFlow`,
|
||||||
`semmle.code.java.dataflow.TaintTracking`, and
|
`semmle.code.java.dataflow.TaintTracking`, and
|
||||||
`semmle.code.java.dataflow.FlowSources` since 1.16.
|
`semmle.code.java.dataflow.FlowSources` since 1.16.
|
||||||
|
* Taint tracking now includes additional default data-flow steps through
|
||||||
|
collections, maps, and iterators. This affects all security queries, which
|
||||||
|
can report more results based on such paths.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,16 @@
|
|||||||
|
|
||||||
* The taint tracking library now recognizes flow through persistent storage, class fields, and callbacks in certain cases. This may give more results for the security queries.
|
* The taint tracking library now recognizes flow through persistent storage, class fields, and callbacks in certain cases. This may give more results for the security queries.
|
||||||
|
|
||||||
|
* Type inference for function calls has been improved. This may give additional results for queries that rely on type inference.
|
||||||
|
|
||||||
|
* The [Closure-Library](https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide) module system is now supported.
|
||||||
|
|
||||||
## New queries
|
## New queries
|
||||||
|
|
||||||
| **Query** | **Tags** | **Purpose** |
|
| **Query** | **Tags** | **Purpose** |
|
||||||
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| Arrow method on Vue instance (`js/vue/arrow-method-on-vue-instance`) | reliability, frameworks/vue | Highlights arrow functions that are used as methods on Vue instances. Results are shown on LGTM by default.|
|
| Arrow method on Vue instance (`js/vue/arrow-method-on-vue-instance`) | reliability, frameworks/vue | Highlights arrow functions that are used as methods on Vue instances. Results are shown on LGTM by default.|
|
||||||
|
| Cross-window communication with unrestricted target origin (`js/cross-window-information-leak`) | security, external/cwe/201, external/cwe/359 | Highlights code that sends potentially sensitive information to another window without restricting the receiver window's origin, indicating a possible violation of [CWE-201](https://cwe.mitre.org/data/definitions/201.html). Results are shown on LGTM by default. |
|
||||||
| Double escaping or unescaping (`js/double-escaping`) | correctness, security, external/cwe/cwe-116 | Highlights potential double escaping or unescaping of special characters, indicating a possible violation of [CWE-116](https://cwe.mitre.org/data/definitions/116.html). Results are shown on LGTM by default. |
|
| Double escaping or unescaping (`js/double-escaping`) | correctness, security, external/cwe/cwe-116 | Highlights potential double escaping or unescaping of special characters, indicating a possible violation of [CWE-116](https://cwe.mitre.org/data/definitions/116.html). Results are shown on LGTM by default. |
|
||||||
| Incomplete regular expression for hostnames (`js/incomplete-hostname-regexp`) | correctness, security, external/cwe/cwe-020 | Highlights hostname sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default.|
|
| Incomplete regular expression for hostnames (`js/incomplete-hostname-regexp`) | correctness, security, external/cwe/cwe-020 | Highlights hostname sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default.|
|
||||||
| Incomplete URL substring sanitization | correctness, security, external/cwe/cwe-020 | Highlights URL sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results shown on LGTM by default. |
|
| Incomplete URL substring sanitization | correctness, security, external/cwe/cwe-020 | Highlights URL sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results shown on LGTM by default. |
|
||||||
@@ -28,6 +33,7 @@
|
|||||||
| **Query** | **Expected impact** | **Change** |
|
| **Query** | **Expected impact** | **Change** |
|
||||||
|--------------------------------------------|------------------------------|------------------------------------------------------------------------------|
|
|--------------------------------------------|------------------------------|------------------------------------------------------------------------------|
|
||||||
| Client-side cross-site scripting | More true-positive results, fewer false-positive results. | This rule now recognizes WinJS functions that are vulnerable to HTML injection, and no longer flags certain safe uses of jQuery. |
|
| Client-side cross-site scripting | More true-positive results, fewer false-positive results. | This rule now recognizes WinJS functions that are vulnerable to HTML injection, and no longer flags certain safe uses of jQuery. |
|
||||||
|
| Hard-coded credentials | Fewer false-positive results | This rule no longer flag the empty string as a hardcoded username. |
|
||||||
| Insecure randomness | More results | This rule now flags insecure uses of `crypto.pseudoRandomBytes`. |
|
| Insecure randomness | More results | This rule now flags insecure uses of `crypto.pseudoRandomBytes`. |
|
||||||
| Uncontrolled data used in network request | More results | This rule now recognizes host values that are vulnerable to injection. |
|
| Uncontrolled data used in network request | More results | This rule now recognizes host values that are vulnerable to injection. |
|
||||||
| Unused parameter | Fewer false-positive results | This rule no longer flags parameters with leading underscore. |
|
| Unused parameter | Fewer false-positive results | This rule no longer flags parameters with leading underscore. |
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class SuppressionScope extends ElementBase {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||||
this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn)
|
this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ int doFoo(Names n) { //wrong: n is passed by value (meaning the entire structure
|
|||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
int doBar(Names &n) { //better, only a reference is passed
|
int doBar(const Names &n) { //better, only a reference is passed
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @name Large object passed by value
|
* @name Large object passed by value
|
||||||
* @description An object larger than 64 bytes is passed by value to a function. Passing large objects by value unnecessarily use up scarce stack space, increase the cost of calling a function and can be a security risk. Use a pointer to the object instead.
|
* @description An object larger than 64 bytes is passed by value to a function. Passing large objects by value unnecessarily use up scarce stack space, increase the cost of calling a function and can be a security risk. Use a const pointer to the object instead.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
* @precision high
|
* @precision high
|
||||||
@@ -20,5 +20,5 @@ where f.getAParameter() = p
|
|||||||
and not t.getUnderlyingType() instanceof ArrayType
|
and not t.getUnderlyingType() instanceof ArrayType
|
||||||
and not f instanceof CopyAssignmentOperator
|
and not f instanceof CopyAssignmentOperator
|
||||||
select
|
select
|
||||||
p, "This parameter of type $@ is " + size.toString() + " bytes - consider passing a pointer/reference instead.",
|
p, "This parameter of type $@ is " + size.toString() + " bytes - consider passing a const pointer/reference instead.",
|
||||||
t, t.toString()
|
t, t.toString()
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ class CommentBlock extends Comment {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ string comparisonOnLiterals(ComparisonOperation op) {
|
|||||||
simple(op.getLeftOperand()) and
|
simple(op.getLeftOperand()) and
|
||||||
simple(op.getRightOperand()) and
|
simple(op.getRightOperand()) and
|
||||||
not op.getAnOperand().isInMacroExpansion() and
|
not op.getAnOperand().isInMacroExpansion() and
|
||||||
if op.isConstant()
|
if exists(op.getValue())
|
||||||
then result = "This comparison involves two literals and is always " + op.getValue() + "."
|
then result = "This comparison involves two literals and is always " + op.getValue() + "."
|
||||||
else result = "This comparison involves two literals and should be simplified."
|
else result = "This comparison involves two literals and should be simplified."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class RangeFunction extends Function {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||||
super.getLocation().hasLocationInfo(path, sl, sc, _, _)
|
super.getLocation().hasLocationInfo(path, sl, sc, _, _)
|
||||||
|
|||||||
@@ -16,18 +16,18 @@ import semmle.code.cpp.security.Overflow
|
|||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.security.Security
|
||||||
import semmle.code.cpp.security.TaintTracking
|
import semmle.code.cpp.security.TaintTracking
|
||||||
|
|
||||||
predicate taintedVarAccess(Expr origin, VariableAccess va) {
|
from Expr origin, Operation op, Expr e, string effect
|
||||||
isUserInput(origin, _) and
|
where isUserInput(origin, _)
|
||||||
tainted(origin, va)
|
and tainted(origin, e)
|
||||||
}
|
and op.getAnOperand() = e
|
||||||
|
|
||||||
from Expr origin, Operation op, VariableAccess va, string effect
|
|
||||||
where taintedVarAccess(origin, va)
|
|
||||||
and op.getAnOperand() = va
|
|
||||||
and
|
and
|
||||||
(
|
(
|
||||||
(missingGuardAgainstUnderflow(op, va) and effect = "underflow") or
|
(missingGuardAgainstUnderflow(op, e) and effect = "underflow") or
|
||||||
(missingGuardAgainstOverflow(op, va) and effect = "overflow")
|
(missingGuardAgainstOverflow(op, e) and effect = "overflow") or
|
||||||
|
(not e instanceof VariableAccess and effect = "overflow")
|
||||||
|
) and (
|
||||||
|
op instanceof UnaryArithmeticOperation or
|
||||||
|
op instanceof BinaryArithmeticOperation
|
||||||
)
|
)
|
||||||
select va, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
|
select e, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
|
||||||
origin, "User-provided value"
|
origin, "User-provided value"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Top extends Element {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(string filepath,
|
predicate hasLocationInfo(string filepath,
|
||||||
int startline, int startcolumn,
|
int startline, int startcolumn,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ abstract class Container extends Locatable, @container {
|
|||||||
* DEPRECATED: Use `getLocation` instead.
|
* DEPRECATED: Use `getLocation` instead.
|
||||||
* Gets a URL representing the location of this container.
|
* Gets a URL representing the location of this container.
|
||||||
*
|
*
|
||||||
* For more information see https://lgtm.com/help/ql/locations#providing-urls.
|
* For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls).
|
||||||
*/
|
*/
|
||||||
deprecated abstract string getURL();
|
deprecated abstract string getURL();
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class Location extends @location {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ class BasicBlock extends ControlFlowNodeBase {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*
|
*
|
||||||
* Yields no result if this basic block spans multiple source files.
|
* Yields no result if this basic block spans multiple source files.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -461,38 +461,16 @@ private predicate skipInitializer(Initializer init) {
|
|||||||
*/
|
*/
|
||||||
private predicate runtimeExprInStaticInitializer(Expr e) {
|
private predicate runtimeExprInStaticInitializer(Expr e) {
|
||||||
inStaticInitializer(e) and
|
inStaticInitializer(e) and
|
||||||
if
|
if e instanceof AggregateLiteral
|
||||||
e instanceof AggregateLiteral
|
|
||||||
or
|
|
||||||
e instanceof PointerArithmeticOperation
|
|
||||||
or
|
|
||||||
// Extractor doesn't populate this specifier at the time of writing, so
|
|
||||||
// this case has not been tested. See CPP-314.
|
|
||||||
e.(FunctionCall).getTarget().hasSpecifier("constexpr")
|
|
||||||
then runtimeExprInStaticInitializer(e.getAChild())
|
then runtimeExprInStaticInitializer(e.getAChild())
|
||||||
else (
|
else not e.getFullyConverted().isConstant()
|
||||||
// Not constant
|
|
||||||
not e.isConstant() and
|
|
||||||
// Not a function address
|
|
||||||
not e instanceof FunctionAccess and
|
|
||||||
// Not a function address-of (same as above)
|
|
||||||
not e.(AddressOfExpr).getOperand() instanceof FunctionAccess and
|
|
||||||
// Not the address of a global variable
|
|
||||||
not exists(Variable v |
|
|
||||||
v.isStatic()
|
|
||||||
or
|
|
||||||
v instanceof GlobalOrNamespaceVariable
|
|
||||||
|
|
|
||||||
e.(AddressOfExpr).getOperand() = v.getAnAccess()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `e` is part of the initializer of a local static variable. */
|
/** Holds if `e` is part of the initializer of a local static variable. */
|
||||||
private predicate inStaticInitializer(Expr e) {
|
private predicate inStaticInitializer(Expr e) {
|
||||||
exists(LocalVariable local |
|
exists(LocalVariable local |
|
||||||
local.isStatic() and
|
local.isStatic() and
|
||||||
e.(Node).getParentNode*() = local.getInitializer()
|
e.getParent+() = local.getInitializer()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import semmle.code.cpp.Element
|
import semmle.code.cpp.Element
|
||||||
private import semmle.code.cpp.Enclosing
|
private import semmle.code.cpp.Enclosing
|
||||||
private import semmle.code.cpp.internal.ResolveClass
|
private import semmle.code.cpp.internal.ResolveClass
|
||||||
|
private import semmle.code.cpp.internal.AddressConstantExpression
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A C/C++ expression.
|
* A C/C++ expression.
|
||||||
@@ -84,7 +85,12 @@ class Expr extends StmtParent, @expr {
|
|||||||
string getValueText() { exists(@value v | values(v,_,result) and valuebind(v,underlyingElement(this))) }
|
string getValueText() { exists(@value v | values(v,_,result) and valuebind(v,underlyingElement(this))) }
|
||||||
|
|
||||||
/** Holds if this expression has a value that can be determined at compile time. */
|
/** Holds if this expression has a value that can be determined at compile time. */
|
||||||
predicate isConstant() { valuebind(_,underlyingElement(this)) }
|
cached
|
||||||
|
predicate isConstant() {
|
||||||
|
valuebind(_,underlyingElement(this))
|
||||||
|
or
|
||||||
|
addressConstantExpression(this)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this expression is side-effect free (conservative
|
* Holds if this expression is side-effect free (conservative
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
private import cpp
|
||||||
|
private import semmle.code.cpp.dataflow.EscapesTree
|
||||||
|
|
||||||
|
predicate addressConstantExpression(Expr e) {
|
||||||
|
constantAddressPointer(e)
|
||||||
|
or
|
||||||
|
constantAddressReference(e)
|
||||||
|
or
|
||||||
|
// Special case for function pointers, where `fp == *fp`.
|
||||||
|
constantAddressLValue(e) and
|
||||||
|
e.getType() instanceof FunctionPointerType
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `v` is a constexpr variable initialized to a constant address. */
|
||||||
|
private predicate addressConstantVariable(Variable v) {
|
||||||
|
addressConstantExpression(v.getInitializer().getExpr().getFullyConverted()) and
|
||||||
|
// Here we should also require that `v` is constexpr, but we don't have that
|
||||||
|
// information in the db. See CPP-314. Instead, we require that the variable
|
||||||
|
// is never defined except in its initializer.
|
||||||
|
forall(Expr def | definition(v, def) | def = any(Initializer init).getExpr())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `lvalue` is an lvalue whose address is an _address constant
|
||||||
|
* expression_.
|
||||||
|
*/
|
||||||
|
private predicate constantAddressLValue(Expr lvalue) {
|
||||||
|
lvalue.(VariableAccess).getTarget() = any(Variable v |
|
||||||
|
v.(Variable).isStatic()
|
||||||
|
or
|
||||||
|
v instanceof GlobalOrNamespaceVariable
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// There is no `Conversion` for the implicit conversion from a function type
|
||||||
|
// to a function _pointer_ type. Instead, the type of a `FunctionAccess`
|
||||||
|
// tells us how it's going to be used.
|
||||||
|
lvalue.(FunctionAccess).getType() instanceof RoutineType
|
||||||
|
or
|
||||||
|
// String literals have array types and undergo array-to-pointer conversion.
|
||||||
|
lvalue instanceof StringLiteral
|
||||||
|
or
|
||||||
|
// lvalue -> lvalue
|
||||||
|
exists(Expr prev |
|
||||||
|
constantAddressLValue(prev) and
|
||||||
|
lvalueToLvalueStep(prev, lvalue)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// pointer -> lvalue
|
||||||
|
exists(Expr prev |
|
||||||
|
constantAddressPointer(prev) and
|
||||||
|
pointerToLvalueStep(prev, lvalue)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// reference -> lvalue
|
||||||
|
exists(Expr prev |
|
||||||
|
constantAddressReference(prev) and
|
||||||
|
referenceToLvalueStep(prev, lvalue)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `pointer` is an _address constant expression_ of pointer type. */
|
||||||
|
private predicate constantAddressPointer(Expr pointer) {
|
||||||
|
// There is no `Conversion` for the implicit conversion from a function type
|
||||||
|
// to a function _pointer_ type. Instead, the type of a `FunctionAccess`
|
||||||
|
// tells us how it's going to be used.
|
||||||
|
pointer.(FunctionAccess).getType() instanceof FunctionPointerType
|
||||||
|
or
|
||||||
|
addressConstantVariable(pointer.(VariableAccess).getTarget()) and
|
||||||
|
pointer.getType().getUnderlyingType() instanceof PointerType
|
||||||
|
or
|
||||||
|
// pointer -> pointer
|
||||||
|
exists(Expr prev |
|
||||||
|
constantAddressPointer(prev) and
|
||||||
|
pointerToPointerStep(prev, pointer)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// lvalue -> pointer
|
||||||
|
exists(Expr prev |
|
||||||
|
constantAddressLValue(prev) and
|
||||||
|
lvalueToPointerStep(prev, pointer)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `reference` is an _address constant expression_ of reference type. */
|
||||||
|
private predicate constantAddressReference(Expr reference) {
|
||||||
|
addressConstantVariable(reference.(VariableAccess).getTarget()) and
|
||||||
|
reference.getType().getUnderlyingType() instanceof ReferenceType
|
||||||
|
or
|
||||||
|
addressConstantVariable(reference.(VariableAccess).getTarget()) and
|
||||||
|
reference.getType().getUnderlyingType() instanceof FunctionReferenceType // not a ReferenceType
|
||||||
|
or
|
||||||
|
// reference -> reference
|
||||||
|
exists(Expr prev |
|
||||||
|
constantAddressReference(prev) and
|
||||||
|
referenceToReferenceStep(prev, reference)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// lvalue -> reference
|
||||||
|
exists(Expr prev |
|
||||||
|
constantAddressLValue(prev) and
|
||||||
|
lvalueToReferenceStep(prev, reference)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
|
||||||
|
lvalueIn = lvalueOut.(DotFieldAccess).getQualifier().getFullyConverted()
|
||||||
|
or
|
||||||
|
lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr)
|
||||||
|
or
|
||||||
|
// Special case for function pointers, where `fp == *fp`.
|
||||||
|
lvalueIn = lvalueOut.(PointerDereferenceExpr).getOperand().getFullyConverted() and
|
||||||
|
lvalueIn.getType() instanceof FunctionPointerType
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate pointerToLvalueStep(Expr pointerIn, Expr lvalueOut) {
|
||||||
|
lvalueOut = any(ArrayExpr ae |
|
||||||
|
pointerIn = ae.getArrayBase().getFullyConverted() and
|
||||||
|
hasConstantValue(ae.getArrayOffset().getFullyConverted())
|
||||||
|
)
|
||||||
|
or
|
||||||
|
pointerIn = lvalueOut.(PointerDereferenceExpr).getOperand().getFullyConverted()
|
||||||
|
or
|
||||||
|
pointerIn = lvalueOut.(PointerFieldAccess).getQualifier().getFullyConverted()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate lvalueToPointerStep(Expr lvalueIn, Expr pointerOut) {
|
||||||
|
lvalueIn.getConversion() = pointerOut.(ArrayToPointerConversion)
|
||||||
|
or
|
||||||
|
lvalueIn = pointerOut.(AddressOfExpr).getOperand().getFullyConverted()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) {
|
||||||
|
(
|
||||||
|
pointerOut instanceof PointerAddExpr
|
||||||
|
or
|
||||||
|
pointerOut instanceof PointerSubExpr
|
||||||
|
) and
|
||||||
|
pointerIn = pointerOut.getAChild().getFullyConverted() and
|
||||||
|
pointerIn.getType().getUnspecifiedType() instanceof PointerType and
|
||||||
|
// The pointer arg won't be constant in the sense of `hasConstantValue`, so
|
||||||
|
// this will have to match the integer argument.
|
||||||
|
hasConstantValue(pointerOut.getAChild().getFullyConverted())
|
||||||
|
or
|
||||||
|
pointerIn = pointerOut.(UnaryPlusExpr).getOperand().getFullyConverted()
|
||||||
|
or
|
||||||
|
pointerIn.getConversion() = pointerOut.(Cast)
|
||||||
|
or
|
||||||
|
pointerIn.getConversion() = pointerOut.(ParenthesisExpr)
|
||||||
|
or
|
||||||
|
pointerOut = any(ConditionalExpr cond |
|
||||||
|
cond.getCondition().getFullyConverted().getValue().toInt() != 0 and
|
||||||
|
pointerIn = cond.getThen().getFullyConverted()
|
||||||
|
or
|
||||||
|
cond.getCondition().getFullyConverted().getValue().toInt() = 0 and
|
||||||
|
pointerIn = cond.getElse().getFullyConverted()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// The comma operator is allowed by C++17 but disallowed by C99. This
|
||||||
|
// disjunct is a compromise that's chosen for being easy to implement.
|
||||||
|
pointerOut = any(CommaExpr comma |
|
||||||
|
hasConstantValue(comma.getLeftOperand()) and
|
||||||
|
pointerIn = comma.getRightOperand().getFullyConverted()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) {
|
||||||
|
lvalueIn.getConversion() = referenceOut.(ReferenceToExpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) {
|
||||||
|
// This probably cannot happen. It would require an expression to be
|
||||||
|
// converted to a reference and back again without an intermediate variable
|
||||||
|
// assignment.
|
||||||
|
referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) {
|
||||||
|
referenceIn.getConversion() = referenceOut.(Cast)
|
||||||
|
or
|
||||||
|
referenceIn.getConversion() = referenceOut.(ParenthesisExpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `e` is constant according to the database. */
|
||||||
|
private predicate hasConstantValue(Expr e) { valuebind(_, underlyingElement(e)) }
|
||||||
@@ -56,6 +56,11 @@ class FunctionIR extends TFunctionIR {
|
|||||||
result.getFunctionIR() = this
|
result.getFunctionIR() = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
final UnmodeledUseInstruction getUnmodeledUseInstruction() {
|
||||||
|
result.getFunctionIR() = this
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the single return instruction for this function.
|
* Gets the single return instruction for this function.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
|
|||||||
blockSuccessor(this, result, kind)
|
blockSuccessor(this, result, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||||
|
backEdgeSuccessor(this, result, kind)
|
||||||
|
}
|
||||||
|
|
||||||
final predicate immediatelyDominates(IRBlock block) {
|
final predicate immediatelyDominates(IRBlock block) {
|
||||||
blockImmediatelyDominates(this, block)
|
blockImmediatelyDominates(this, block)
|
||||||
}
|
}
|
||||||
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
|
|||||||
exists(Instruction predecessor, EdgeKind kind |
|
exists(Instruction predecessor, EdgeKind kind |
|
||||||
instr = predecessor.getSuccessor(kind) and
|
instr = predecessor.getSuccessor(kind) and
|
||||||
not kind instanceof GotoEdge
|
not kind instanceof GotoEdge
|
||||||
) // Incoming edge is not a GotoEdge
|
) or // Incoming edge is not a GotoEdge
|
||||||
|
exists(Instruction predecessor |
|
||||||
|
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
|
||||||
|
) // A back edge enters this instruction
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,24 +159,13 @@ private cached module Cached {
|
|||||||
not startsBasicBlock(i2)
|
not startsBasicBlock(i2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the index of `i` in its `IRBlock`. */
|
/** Holds if `i` is the `index`th instruction the block starting with `first`. */
|
||||||
private int getMemberIndex(Instruction i) {
|
private Instruction getInstructionFromFirst(Instruction first, int index) =
|
||||||
startsBasicBlock(i) and
|
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
|
||||||
result = 0
|
|
||||||
or
|
|
||||||
exists(Instruction iPrev |
|
|
||||||
adjacentInBlock(iPrev, i) and
|
|
||||||
result = getMemberIndex(iPrev) + 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `i` is the `index`th instruction in `block`. */
|
/** Holds if `i` is the `index`th instruction in `block`. */
|
||||||
cached Instruction getInstruction(TIRBlock block, int index) {
|
cached Instruction getInstruction(TIRBlock block, int index) {
|
||||||
exists(Instruction first |
|
result = getInstructionFromFirst(getFirstInstruction(block), index)
|
||||||
block = MkIRBlock(first) and
|
|
||||||
index = getMemberIndex(result) and
|
|
||||||
adjacentInBlock*(first, result)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached int getInstructionCount(TIRBlock block) {
|
cached int getInstructionCount(TIRBlock block) {
|
||||||
@@ -184,6 +180,41 @@ private cached module Cached {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||||
|
backEdgeSuccessorRaw(pred, succ, kind)
|
||||||
|
or
|
||||||
|
forwardEdgeRaw+(pred, pred) and
|
||||||
|
blockSuccessor(pred, succ, kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
|
||||||
|
*/
|
||||||
|
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
|
||||||
|
exists(EdgeKind kind |
|
||||||
|
blockSuccessor(pred, succ, kind) and
|
||||||
|
not backEdgeSuccessorRaw(pred, succ, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
|
||||||
|
* `Construction`.
|
||||||
|
*
|
||||||
|
* There could be loops of non-back-edges if there is a flaw in the IR
|
||||||
|
* construction or back-edge detection, and this could cause non-termination
|
||||||
|
* of subsequent analysis. To prevent that, a subsequent predicate further
|
||||||
|
* classifies all edges as back edges if they are involved in a loop of
|
||||||
|
* non-back-edges.
|
||||||
|
*/
|
||||||
|
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||||
|
exists(Instruction predLast, Instruction succFirst |
|
||||||
|
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
|
||||||
|
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
|
||||||
|
succ = MkIRBlock(succFirst)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
||||||
blockSuccessor(pred, succ, _)
|
blockSuccessor(pred, succ, _)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,31 +3,7 @@ import FunctionIR
|
|||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.ir.implementation.TempVariableTag
|
import semmle.code.cpp.ir.implementation.TempVariableTag
|
||||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||||
|
private import semmle.code.cpp.ir.internal.TIRVariable
|
||||||
private newtype TIRVariable =
|
|
||||||
TIRAutomaticUserVariable(LocalScopeVariable var, FunctionIR funcIR) {
|
|
||||||
exists(Function func |
|
|
||||||
func = funcIR.getFunction() and
|
|
||||||
(
|
|
||||||
var.getFunction() = func or
|
|
||||||
var.(Parameter).getCatchBlock().getEnclosingFunction() = func
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} or
|
|
||||||
TIRStaticUserVariable(Variable var, FunctionIR funcIR) {
|
|
||||||
(
|
|
||||||
var instanceof GlobalOrNamespaceVariable or
|
|
||||||
var instanceof MemberVariable and not var instanceof Field
|
|
||||||
) and
|
|
||||||
exists(VariableAccess access |
|
|
||||||
access.getTarget() = var and
|
|
||||||
access.getEnclosingFunction() = funcIR.getFunction()
|
|
||||||
)
|
|
||||||
} or
|
|
||||||
TIRTempVariable(FunctionIR funcIR, Locatable ast, TempVariableTag tag,
|
|
||||||
Type type) {
|
|
||||||
Construction::hasTempVariable(funcIR.getFunction(), ast, tag, type)
|
|
||||||
}
|
|
||||||
|
|
||||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||||
result.getVariable() = var and
|
result.getVariable() = var and
|
||||||
@@ -40,7 +16,7 @@ IRUserVariable getIRUserVariable(Function func, Variable var) {
|
|||||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||||
*/
|
*/
|
||||||
abstract class IRVariable extends TIRVariable {
|
abstract class IRVariable extends TIRVariable {
|
||||||
FunctionIR funcIR;
|
Function func;
|
||||||
|
|
||||||
abstract string toString();
|
abstract string toString();
|
||||||
|
|
||||||
@@ -72,14 +48,14 @@ abstract class IRVariable extends TIRVariable {
|
|||||||
* Gets the IR for the function that references this variable.
|
* Gets the IR for the function that references this variable.
|
||||||
*/
|
*/
|
||||||
final FunctionIR getFunctionIR() {
|
final FunctionIR getFunctionIR() {
|
||||||
result = funcIR
|
result.getFunction() = func
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the function that references this variable.
|
* Gets the function that references this variable.
|
||||||
*/
|
*/
|
||||||
final Function getFunction() {
|
final Function getFunction() {
|
||||||
result = funcIR.getFunction()
|
result = func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +102,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
|||||||
LocalScopeVariable localVar;
|
LocalScopeVariable localVar;
|
||||||
|
|
||||||
IRAutomaticUserVariable() {
|
IRAutomaticUserVariable() {
|
||||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
this = TIRAutomaticUserVariable(localVar, func) and
|
||||||
var = localVar
|
var = localVar
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +113,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
|||||||
|
|
||||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||||
IRStaticUserVariable() {
|
IRStaticUserVariable() {
|
||||||
this = TIRStaticUserVariable(var, funcIR)
|
this = TIRStaticUserVariable(var, func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +128,7 @@ class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
|||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
IRTempVariable() {
|
IRTempVariable() {
|
||||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
this = TIRTempVariable(func, ast, tag, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Type getType() {
|
override final Type getType() {
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import semmle.code.cpp.ir.implementation.Opcode
|
|||||||
private import semmle.code.cpp.ir.implementation.Opcode
|
private import semmle.code.cpp.ir.implementation.Opcode
|
||||||
private import semmle.code.cpp.ir.internal.OperandTag
|
private import semmle.code.cpp.ir.internal.OperandTag
|
||||||
|
|
||||||
class InstructionTag = Construction::InstructionTagType;
|
|
||||||
|
|
||||||
module InstructionSanity {
|
module InstructionSanity {
|
||||||
/**
|
/**
|
||||||
* Holds if the instruction `instr` should be expected to have an operand
|
* Holds if the instruction `instr` should be expected to have an operand
|
||||||
@@ -157,23 +155,60 @@ module InstructionSanity {
|
|||||||
blockCount = count(instr.getBlock()) and
|
blockCount = count(instr.getBlock()) and
|
||||||
blockCount != 1
|
blockCount != 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||||
|
b1.getASuccessor() = b2 and
|
||||||
|
not b1.getBackEdgeSuccessor(_) = b2
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||||
|
*
|
||||||
|
* This check ensures we don't have too _few_ back edges.
|
||||||
|
*/
|
||||||
|
query predicate containsLoopOfForwardEdges(FunctionIR f) {
|
||||||
|
exists(IRBlock block |
|
||||||
|
forwardEdge+(block, block) and
|
||||||
|
block.getFunctionIR() = f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `block` is reachable from its function entry point but would not
|
||||||
|
* be reachable by traversing only forward edges. This check is skipped for
|
||||||
|
* functions containing `goto` statements as the property does not generally
|
||||||
|
* hold there.
|
||||||
|
*
|
||||||
|
* This check ensures we don't have too _many_ back edges.
|
||||||
|
*/
|
||||||
|
query predicate lostReachability(IRBlock block) {
|
||||||
|
exists(FunctionIR f, IRBlock entry |
|
||||||
|
entry = f.getEntryBlock() and
|
||||||
|
entry.getASuccessor+() = block and
|
||||||
|
not forwardEdge+(entry, block) and
|
||||||
|
not exists(GotoStmt s | s.getEnclosingFunction() = f.getFunction())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the number of back edges differs between the `Instruction` graph
|
||||||
|
* and the `IRBlock` graph.
|
||||||
|
*/
|
||||||
|
query predicate backEdgeCountMismatch(Function f, int fromInstr, int fromBlock) {
|
||||||
|
fromInstr = count(Instruction i1, Instruction i2 |
|
||||||
|
i1.getFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||||
|
) and
|
||||||
|
fromBlock = count(IRBlock b1, IRBlock b2 |
|
||||||
|
b1.getFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||||
|
) and
|
||||||
|
fromInstr != fromBlock
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a single operation in the IR.
|
* Represents a single operation in the IR.
|
||||||
*/
|
*/
|
||||||
class Instruction extends Construction::TInstruction {
|
class Instruction extends Construction::TInstruction {
|
||||||
Opcode opcode;
|
|
||||||
Locatable ast;
|
|
||||||
InstructionTag instructionTag;
|
|
||||||
Type resultType;
|
|
||||||
FunctionIR funcIR;
|
|
||||||
boolean glvalue;
|
|
||||||
|
|
||||||
Instruction() {
|
|
||||||
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
|
||||||
}
|
|
||||||
|
|
||||||
final string toString() {
|
final string toString() {
|
||||||
result = getOpcode().toString() + ": " + getAST().toString()
|
result = getOpcode().toString() + ": " + getAST().toString()
|
||||||
}
|
}
|
||||||
@@ -196,9 +231,9 @@ class Instruction extends Construction::TInstruction {
|
|||||||
*/
|
*/
|
||||||
final string getOperationString() {
|
final string getOperationString() {
|
||||||
if exists(getImmediateString()) then
|
if exists(getImmediateString()) then
|
||||||
result = getOperationPrefix() + opcode.toString() + "[" + getImmediateString() + "]"
|
result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]"
|
||||||
else
|
else
|
||||||
result = getOperationPrefix() + opcode.toString()
|
result = getOperationPrefix() + getOpcode().toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -216,7 +251,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string getResultPrefix() {
|
private string getResultPrefix() {
|
||||||
if resultType instanceof VoidType then
|
if getResultType() instanceof VoidType then
|
||||||
result = "v"
|
result = "v"
|
||||||
else if hasMemoryResult() then
|
else if hasMemoryResult() then
|
||||||
if isResultModeled() then
|
if isResultModeled() then
|
||||||
@@ -261,8 +296,8 @@ class Instruction extends Construction::TInstruction {
|
|||||||
|
|
||||||
private string getResultTypeString() {
|
private string getResultTypeString() {
|
||||||
exists(string valcat |
|
exists(string valcat |
|
||||||
valcat = getValueCategoryString(resultType.toString()) and
|
valcat = getValueCategoryString(getResultType().toString()) and
|
||||||
if (resultType instanceof UnknownType and
|
if (getResultType() instanceof UnknownType and
|
||||||
not isGLValue() and
|
not isGLValue() and
|
||||||
exists(getResultSize())) then (
|
exists(getResultSize())) then (
|
||||||
result = valcat + "[" + getResultSize().toString() + "]"
|
result = valcat + "[" + getResultSize().toString() + "]"
|
||||||
@@ -330,28 +365,28 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* Gets the function that contains this instruction.
|
* Gets the function that contains this instruction.
|
||||||
*/
|
*/
|
||||||
final Function getFunction() {
|
final Function getFunction() {
|
||||||
result = funcIR.getFunction()
|
result = getFunctionIR().getFunction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the FunctionIR object that contains the IR for this instruction.
|
* Gets the FunctionIR object that contains the IR for this instruction.
|
||||||
*/
|
*/
|
||||||
final FunctionIR getFunctionIR() {
|
final FunctionIR getFunctionIR() {
|
||||||
result = funcIR
|
result = Construction::getInstructionEnclosingFunctionIR(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the AST that caused this instruction to be generated.
|
* Gets the AST that caused this instruction to be generated.
|
||||||
*/
|
*/
|
||||||
final Locatable getAST() {
|
final Locatable getAST() {
|
||||||
result = ast
|
result = Construction::getInstructionAST(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location of the source code for this instruction.
|
* Gets the location of the source code for this instruction.
|
||||||
*/
|
*/
|
||||||
final Location getLocation() {
|
final Location getLocation() {
|
||||||
result = ast.getLocation()
|
result = getAST().getLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -373,7 +408,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* instruction does not produce a result, its result type will be `VoidType`.
|
* instruction does not produce a result, its result type will be `VoidType`.
|
||||||
*/
|
*/
|
||||||
final Type getResultType() {
|
final Type getResultType() {
|
||||||
result = resultType
|
Construction::instructionHasType(this, result, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -395,7 +430,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* the integer value loaded from variable `x`.
|
* the integer value loaded from variable `x`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() {
|
final predicate isGLValue() {
|
||||||
glvalue = true
|
Construction::instructionHasType(this, _, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -412,10 +447,10 @@ class Instruction extends Construction::TInstruction {
|
|||||||
result = nullptr.getSize()
|
result = nullptr.getSize()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else if resultType instanceof UnknownType then
|
else if getResultType() instanceof UnknownType then
|
||||||
result = Construction::getInstructionResultSize(this)
|
result = Construction::getInstructionResultSize(this)
|
||||||
else (
|
else (
|
||||||
result = resultType.getSize()
|
result = getResultType().getSize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,11 +458,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* Gets the opcode that specifies the operation performed by this instruction.
|
* Gets the opcode that specifies the operation performed by this instruction.
|
||||||
*/
|
*/
|
||||||
final Opcode getOpcode() {
|
final Opcode getOpcode() {
|
||||||
result = opcode
|
result = Construction::getInstructionOpcode(this)
|
||||||
}
|
|
||||||
|
|
||||||
final InstructionTag getTag() {
|
|
||||||
result = instructionTag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -489,6 +520,24 @@ class Instruction extends Construction::TInstruction {
|
|||||||
result = Construction::getInstructionSuccessor(this, kind)
|
result = Construction::getInstructionSuccessor(this, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the a _back-edge successor_ of this instruction along the control
|
||||||
|
* flow edge specified by `kind`. A back edge in the control-flow graph is
|
||||||
|
* intuitively the edge that goes back around a loop. If all back edges are
|
||||||
|
* removed from the control-flow graph, it becomes acyclic.
|
||||||
|
*/
|
||||||
|
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
|
||||||
|
// We don't take these edges from
|
||||||
|
// `Construction::getInstructionBackEdgeSuccessor` since that relation has
|
||||||
|
// not been treated to remove any loops that might be left over due to
|
||||||
|
// flaws in the IR construction or back-edge detection.
|
||||||
|
exists(IRBlock block |
|
||||||
|
block = this.getBlock() and
|
||||||
|
this = block.getLastInstruction() and
|
||||||
|
result = block.getBackEdgeSuccessor(kind).getFirstInstruction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all direct successors of this instruction.
|
* Gets all direct successors of this instruction.
|
||||||
*/
|
*/
|
||||||
@@ -578,19 +627,19 @@ class ConstantValueInstruction extends Instruction {
|
|||||||
|
|
||||||
class EnterFunctionInstruction extends Instruction {
|
class EnterFunctionInstruction extends Instruction {
|
||||||
EnterFunctionInstruction() {
|
EnterFunctionInstruction() {
|
||||||
opcode instanceof Opcode::EnterFunction
|
getOpcode() instanceof Opcode::EnterFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VariableAddressInstruction extends VariableInstruction {
|
class VariableAddressInstruction extends VariableInstruction {
|
||||||
VariableAddressInstruction() {
|
VariableAddressInstruction() {
|
||||||
opcode instanceof Opcode::VariableAddress
|
getOpcode() instanceof Opcode::VariableAddress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InitializeParameterInstruction extends VariableInstruction {
|
class InitializeParameterInstruction extends VariableInstruction {
|
||||||
InitializeParameterInstruction() {
|
InitializeParameterInstruction() {
|
||||||
opcode instanceof Opcode::InitializeParameter
|
getOpcode() instanceof Opcode::InitializeParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
final Parameter getParameter() {
|
final Parameter getParameter() {
|
||||||
@@ -607,13 +656,13 @@ class InitializeParameterInstruction extends VariableInstruction {
|
|||||||
*/
|
*/
|
||||||
class InitializeThisInstruction extends Instruction {
|
class InitializeThisInstruction extends Instruction {
|
||||||
InitializeThisInstruction() {
|
InitializeThisInstruction() {
|
||||||
opcode instanceof Opcode::InitializeThis
|
getOpcode() instanceof Opcode::InitializeThis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldAddressInstruction extends FieldInstruction {
|
class FieldAddressInstruction extends FieldInstruction {
|
||||||
FieldAddressInstruction() {
|
FieldAddressInstruction() {
|
||||||
opcode instanceof Opcode::FieldAddress
|
getOpcode() instanceof Opcode::FieldAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getObjectAddress() {
|
final Instruction getObjectAddress() {
|
||||||
@@ -623,7 +672,7 @@ class FieldAddressInstruction extends FieldInstruction {
|
|||||||
|
|
||||||
class UninitializedInstruction extends VariableInstruction {
|
class UninitializedInstruction extends VariableInstruction {
|
||||||
UninitializedInstruction() {
|
UninitializedInstruction() {
|
||||||
opcode instanceof Opcode::Uninitialized
|
getOpcode() instanceof Opcode::Uninitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -640,25 +689,25 @@ class UninitializedInstruction extends VariableInstruction {
|
|||||||
|
|
||||||
class NoOpInstruction extends Instruction {
|
class NoOpInstruction extends Instruction {
|
||||||
NoOpInstruction() {
|
NoOpInstruction() {
|
||||||
opcode instanceof Opcode::NoOp
|
getOpcode() instanceof Opcode::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnInstruction extends Instruction {
|
class ReturnInstruction extends Instruction {
|
||||||
ReturnInstruction() {
|
ReturnInstruction() {
|
||||||
opcode instanceof ReturnOpcode
|
getOpcode() instanceof ReturnOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnVoidInstruction extends ReturnInstruction {
|
class ReturnVoidInstruction extends ReturnInstruction {
|
||||||
ReturnVoidInstruction() {
|
ReturnVoidInstruction() {
|
||||||
opcode instanceof Opcode::ReturnVoid
|
getOpcode() instanceof Opcode::ReturnVoid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnValueInstruction extends ReturnInstruction {
|
class ReturnValueInstruction extends ReturnInstruction {
|
||||||
ReturnValueInstruction() {
|
ReturnValueInstruction() {
|
||||||
opcode instanceof Opcode::ReturnValue
|
getOpcode() instanceof Opcode::ReturnValue
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getReturnValue() {
|
final Instruction getReturnValue() {
|
||||||
@@ -668,7 +717,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
|||||||
|
|
||||||
class CopyInstruction extends Instruction {
|
class CopyInstruction extends Instruction {
|
||||||
CopyInstruction() {
|
CopyInstruction() {
|
||||||
opcode instanceof CopyOpcode
|
getOpcode() instanceof CopyOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getSourceValue() {
|
final Instruction getSourceValue() {
|
||||||
@@ -678,13 +727,13 @@ class CopyInstruction extends Instruction {
|
|||||||
|
|
||||||
class CopyValueInstruction extends CopyInstruction {
|
class CopyValueInstruction extends CopyInstruction {
|
||||||
CopyValueInstruction() {
|
CopyValueInstruction() {
|
||||||
opcode instanceof Opcode::CopyValue
|
getOpcode() instanceof Opcode::CopyValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LoadInstruction extends CopyInstruction {
|
class LoadInstruction extends CopyInstruction {
|
||||||
LoadInstruction() {
|
LoadInstruction() {
|
||||||
opcode instanceof Opcode::Load
|
getOpcode() instanceof Opcode::Load
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getSourceAddress() {
|
final Instruction getSourceAddress() {
|
||||||
@@ -694,7 +743,7 @@ class LoadInstruction extends CopyInstruction {
|
|||||||
|
|
||||||
class StoreInstruction extends CopyInstruction {
|
class StoreInstruction extends CopyInstruction {
|
||||||
StoreInstruction() {
|
StoreInstruction() {
|
||||||
opcode instanceof Opcode::Store
|
getOpcode() instanceof Opcode::Store
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -708,7 +757,7 @@ class StoreInstruction extends CopyInstruction {
|
|||||||
|
|
||||||
class ConditionalBranchInstruction extends Instruction {
|
class ConditionalBranchInstruction extends Instruction {
|
||||||
ConditionalBranchInstruction() {
|
ConditionalBranchInstruction() {
|
||||||
opcode instanceof Opcode::ConditionalBranch
|
getOpcode() instanceof Opcode::ConditionalBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getCondition() {
|
final Instruction getCondition() {
|
||||||
@@ -726,25 +775,25 @@ class ConditionalBranchInstruction extends Instruction {
|
|||||||
|
|
||||||
class ExitFunctionInstruction extends Instruction {
|
class ExitFunctionInstruction extends Instruction {
|
||||||
ExitFunctionInstruction() {
|
ExitFunctionInstruction() {
|
||||||
opcode instanceof Opcode::ExitFunction
|
getOpcode() instanceof Opcode::ExitFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConstantInstruction extends ConstantValueInstruction {
|
class ConstantInstruction extends ConstantValueInstruction {
|
||||||
ConstantInstruction() {
|
ConstantInstruction() {
|
||||||
opcode instanceof Opcode::Constant
|
getOpcode() instanceof Opcode::Constant
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IntegerConstantInstruction extends ConstantInstruction {
|
class IntegerConstantInstruction extends ConstantInstruction {
|
||||||
IntegerConstantInstruction() {
|
IntegerConstantInstruction() {
|
||||||
resultType instanceof IntegralType
|
getResultType() instanceof IntegralType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FloatConstantInstruction extends ConstantInstruction {
|
class FloatConstantInstruction extends ConstantInstruction {
|
||||||
FloatConstantInstruction() {
|
FloatConstantInstruction() {
|
||||||
resultType instanceof FloatingPointType
|
getResultType() instanceof FloatingPointType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,7 +815,7 @@ class StringConstantInstruction extends Instruction {
|
|||||||
|
|
||||||
class BinaryInstruction extends Instruction {
|
class BinaryInstruction extends Instruction {
|
||||||
BinaryInstruction() {
|
BinaryInstruction() {
|
||||||
opcode instanceof BinaryOpcode
|
getOpcode() instanceof BinaryOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getLeftOperand() {
|
final Instruction getLeftOperand() {
|
||||||
@@ -789,67 +838,67 @@ class BinaryInstruction extends Instruction {
|
|||||||
|
|
||||||
class AddInstruction extends BinaryInstruction {
|
class AddInstruction extends BinaryInstruction {
|
||||||
AddInstruction() {
|
AddInstruction() {
|
||||||
opcode instanceof Opcode::Add
|
getOpcode() instanceof Opcode::Add
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubInstruction extends BinaryInstruction {
|
class SubInstruction extends BinaryInstruction {
|
||||||
SubInstruction() {
|
SubInstruction() {
|
||||||
opcode instanceof Opcode::Sub
|
getOpcode() instanceof Opcode::Sub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MulInstruction extends BinaryInstruction {
|
class MulInstruction extends BinaryInstruction {
|
||||||
MulInstruction() {
|
MulInstruction() {
|
||||||
opcode instanceof Opcode::Mul
|
getOpcode() instanceof Opcode::Mul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DivInstruction extends BinaryInstruction {
|
class DivInstruction extends BinaryInstruction {
|
||||||
DivInstruction() {
|
DivInstruction() {
|
||||||
opcode instanceof Opcode::Div
|
getOpcode() instanceof Opcode::Div
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemInstruction extends BinaryInstruction {
|
class RemInstruction extends BinaryInstruction {
|
||||||
RemInstruction() {
|
RemInstruction() {
|
||||||
opcode instanceof Opcode::Rem
|
getOpcode() instanceof Opcode::Rem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NegateInstruction extends UnaryInstruction {
|
class NegateInstruction extends UnaryInstruction {
|
||||||
NegateInstruction() {
|
NegateInstruction() {
|
||||||
opcode instanceof Opcode::Negate
|
getOpcode() instanceof Opcode::Negate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitAndInstruction extends BinaryInstruction {
|
class BitAndInstruction extends BinaryInstruction {
|
||||||
BitAndInstruction() {
|
BitAndInstruction() {
|
||||||
opcode instanceof Opcode::BitAnd
|
getOpcode() instanceof Opcode::BitAnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitOrInstruction extends BinaryInstruction {
|
class BitOrInstruction extends BinaryInstruction {
|
||||||
BitOrInstruction() {
|
BitOrInstruction() {
|
||||||
opcode instanceof Opcode::BitOr
|
getOpcode() instanceof Opcode::BitOr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitXorInstruction extends BinaryInstruction {
|
class BitXorInstruction extends BinaryInstruction {
|
||||||
BitXorInstruction() {
|
BitXorInstruction() {
|
||||||
opcode instanceof Opcode::BitXor
|
getOpcode() instanceof Opcode::BitXor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShiftLeftInstruction extends BinaryInstruction {
|
class ShiftLeftInstruction extends BinaryInstruction {
|
||||||
ShiftLeftInstruction() {
|
ShiftLeftInstruction() {
|
||||||
opcode instanceof Opcode::ShiftLeft
|
getOpcode() instanceof Opcode::ShiftLeft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShiftRightInstruction extends BinaryInstruction {
|
class ShiftRightInstruction extends BinaryInstruction {
|
||||||
ShiftRightInstruction() {
|
ShiftRightInstruction() {
|
||||||
opcode instanceof Opcode::ShiftRight
|
getOpcode() instanceof Opcode::ShiftRight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -857,7 +906,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
|||||||
int elementSize;
|
int elementSize;
|
||||||
|
|
||||||
PointerArithmeticInstruction() {
|
PointerArithmeticInstruction() {
|
||||||
opcode instanceof PointerArithmeticOpcode and
|
getOpcode() instanceof PointerArithmeticOpcode and
|
||||||
elementSize = Construction::getInstructionElementSize(this)
|
elementSize = Construction::getInstructionElementSize(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,31 +921,31 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
|||||||
|
|
||||||
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
||||||
PointerOffsetInstruction() {
|
PointerOffsetInstruction() {
|
||||||
opcode instanceof PointerOffsetOpcode
|
getOpcode() instanceof PointerOffsetOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointerAddInstruction extends PointerOffsetInstruction {
|
class PointerAddInstruction extends PointerOffsetInstruction {
|
||||||
PointerAddInstruction() {
|
PointerAddInstruction() {
|
||||||
opcode instanceof Opcode::PointerAdd
|
getOpcode() instanceof Opcode::PointerAdd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointerSubInstruction extends PointerOffsetInstruction {
|
class PointerSubInstruction extends PointerOffsetInstruction {
|
||||||
PointerSubInstruction() {
|
PointerSubInstruction() {
|
||||||
opcode instanceof Opcode::PointerSub
|
getOpcode() instanceof Opcode::PointerSub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
||||||
PointerDiffInstruction() {
|
PointerDiffInstruction() {
|
||||||
opcode instanceof Opcode::PointerDiff
|
getOpcode() instanceof Opcode::PointerDiff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnaryInstruction extends Instruction {
|
class UnaryInstruction extends Instruction {
|
||||||
UnaryInstruction() {
|
UnaryInstruction() {
|
||||||
opcode instanceof UnaryOpcode
|
getOpcode() instanceof UnaryOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getOperand() {
|
final Instruction getOperand() {
|
||||||
@@ -906,7 +955,7 @@ class UnaryInstruction extends Instruction {
|
|||||||
|
|
||||||
class ConvertInstruction extends UnaryInstruction {
|
class ConvertInstruction extends UnaryInstruction {
|
||||||
ConvertInstruction() {
|
ConvertInstruction() {
|
||||||
opcode instanceof Opcode::Convert
|
getOpcode() instanceof Opcode::Convert
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -958,7 +1007,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
|||||||
*/
|
*/
|
||||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||||
ConvertToBaseInstruction() {
|
ConvertToBaseInstruction() {
|
||||||
opcode instanceof Opcode::ConvertToBase
|
getOpcode() instanceof Opcode::ConvertToBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,7 +1017,7 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
|||||||
*/
|
*/
|
||||||
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
||||||
ConvertToVirtualBaseInstruction() {
|
ConvertToVirtualBaseInstruction() {
|
||||||
opcode instanceof Opcode::ConvertToVirtualBase
|
getOpcode() instanceof Opcode::ConvertToVirtualBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -978,37 +1027,37 @@ class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
|||||||
*/
|
*/
|
||||||
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
||||||
ConvertToDerivedInstruction() {
|
ConvertToDerivedInstruction() {
|
||||||
opcode instanceof Opcode::ConvertToDerived
|
getOpcode() instanceof Opcode::ConvertToDerived
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitComplementInstruction extends UnaryInstruction {
|
class BitComplementInstruction extends UnaryInstruction {
|
||||||
BitComplementInstruction() {
|
BitComplementInstruction() {
|
||||||
opcode instanceof Opcode::BitComplement
|
getOpcode() instanceof Opcode::BitComplement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LogicalNotInstruction extends UnaryInstruction {
|
class LogicalNotInstruction extends UnaryInstruction {
|
||||||
LogicalNotInstruction() {
|
LogicalNotInstruction() {
|
||||||
opcode instanceof Opcode::LogicalNot
|
getOpcode() instanceof Opcode::LogicalNot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompareInstruction extends BinaryInstruction {
|
class CompareInstruction extends BinaryInstruction {
|
||||||
CompareInstruction() {
|
CompareInstruction() {
|
||||||
opcode instanceof CompareOpcode
|
getOpcode() instanceof CompareOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompareEQInstruction extends CompareInstruction {
|
class CompareEQInstruction extends CompareInstruction {
|
||||||
CompareEQInstruction() {
|
CompareEQInstruction() {
|
||||||
opcode instanceof Opcode::CompareEQ
|
getOpcode() instanceof Opcode::CompareEQ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompareNEInstruction extends CompareInstruction {
|
class CompareNEInstruction extends CompareInstruction {
|
||||||
CompareNEInstruction() {
|
CompareNEInstruction() {
|
||||||
opcode instanceof Opcode::CompareNE
|
getOpcode() instanceof Opcode::CompareNE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,7 +1066,7 @@ class CompareNEInstruction extends CompareInstruction {
|
|||||||
*/
|
*/
|
||||||
class RelationalInstruction extends CompareInstruction {
|
class RelationalInstruction extends CompareInstruction {
|
||||||
RelationalInstruction() {
|
RelationalInstruction() {
|
||||||
opcode instanceof RelationalOpcode
|
getOpcode() instanceof RelationalOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1050,7 +1099,7 @@ class RelationalInstruction extends CompareInstruction {
|
|||||||
|
|
||||||
class CompareLTInstruction extends RelationalInstruction {
|
class CompareLTInstruction extends RelationalInstruction {
|
||||||
CompareLTInstruction() {
|
CompareLTInstruction() {
|
||||||
opcode instanceof Opcode::CompareLT
|
getOpcode() instanceof Opcode::CompareLT
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1068,7 +1117,7 @@ class CompareLTInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class CompareGTInstruction extends RelationalInstruction {
|
class CompareGTInstruction extends RelationalInstruction {
|
||||||
CompareGTInstruction() {
|
CompareGTInstruction() {
|
||||||
opcode instanceof Opcode::CompareGT
|
getOpcode() instanceof Opcode::CompareGT
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1086,7 +1135,7 @@ class CompareGTInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class CompareLEInstruction extends RelationalInstruction {
|
class CompareLEInstruction extends RelationalInstruction {
|
||||||
CompareLEInstruction() {
|
CompareLEInstruction() {
|
||||||
opcode instanceof Opcode::CompareLE
|
getOpcode() instanceof Opcode::CompareLE
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1104,7 +1153,7 @@ class CompareLEInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class CompareGEInstruction extends RelationalInstruction {
|
class CompareGEInstruction extends RelationalInstruction {
|
||||||
CompareGEInstruction() {
|
CompareGEInstruction() {
|
||||||
opcode instanceof Opcode::CompareGE
|
getOpcode() instanceof Opcode::CompareGE
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1122,7 +1171,7 @@ class CompareGEInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class SwitchInstruction extends Instruction {
|
class SwitchInstruction extends Instruction {
|
||||||
SwitchInstruction() {
|
SwitchInstruction() {
|
||||||
opcode instanceof Opcode::Switch
|
getOpcode() instanceof Opcode::Switch
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getExpression() {
|
final Instruction getExpression() {
|
||||||
@@ -1145,7 +1194,7 @@ class SwitchInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CallInstruction extends Instruction {
|
class CallInstruction extends Instruction {
|
||||||
CallInstruction() {
|
CallInstruction() {
|
||||||
opcode instanceof Opcode::Call
|
getOpcode() instanceof Opcode::Call
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1188,7 +1237,7 @@ class CallInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class SideEffectInstruction extends Instruction {
|
class SideEffectInstruction extends Instruction {
|
||||||
SideEffectInstruction() {
|
SideEffectInstruction() {
|
||||||
opcode instanceof SideEffectOpcode
|
getOpcode() instanceof SideEffectOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getPrimaryInstruction() {
|
final Instruction getPrimaryInstruction() {
|
||||||
@@ -1202,7 +1251,7 @@ class SideEffectInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallSideEffectInstruction() {
|
CallSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::CallSideEffect
|
getOpcode() instanceof Opcode::CallSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1216,7 +1265,7 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallReadSideEffectInstruction() {
|
CallReadSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::CallReadSideEffect
|
getOpcode() instanceof Opcode::CallReadSideEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1225,7 +1274,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
IndirectReadSideEffectInstruction() {
|
IndirectReadSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::IndirectReadSideEffect
|
getOpcode() instanceof Opcode::IndirectReadSideEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1234,7 +1283,7 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
BufferReadSideEffectInstruction() {
|
BufferReadSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::BufferReadSideEffect
|
getOpcode() instanceof Opcode::BufferReadSideEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1243,7 +1292,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
IndirectWriteSideEffectInstruction() {
|
IndirectWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::IndirectWriteSideEffect
|
getOpcode() instanceof Opcode::IndirectWriteSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1257,7 +1306,7 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
BufferWriteSideEffectInstruction() {
|
BufferWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::BufferWriteSideEffect
|
getOpcode() instanceof Opcode::BufferWriteSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1272,7 +1321,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
IndirectMayWriteSideEffectInstruction() {
|
IndirectMayWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::IndirectMayWriteSideEffect
|
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1286,7 +1335,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
BufferMayWriteSideEffectInstruction() {
|
BufferMayWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::BufferMayWriteSideEffect
|
getOpcode() instanceof Opcode::BufferMayWriteSideEffect
|
||||||
}
|
}
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
result instanceof BufferMayMemoryAccess
|
result instanceof BufferMayMemoryAccess
|
||||||
@@ -1298,7 +1347,7 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class ThrowInstruction extends Instruction {
|
class ThrowInstruction extends Instruction {
|
||||||
ThrowInstruction() {
|
ThrowInstruction() {
|
||||||
opcode instanceof ThrowOpcode
|
getOpcode() instanceof ThrowOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1307,7 +1356,7 @@ class ThrowInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class ThrowValueInstruction extends ThrowInstruction {
|
class ThrowValueInstruction extends ThrowInstruction {
|
||||||
ThrowValueInstruction() {
|
ThrowValueInstruction() {
|
||||||
opcode instanceof Opcode::ThrowValue
|
getOpcode() instanceof Opcode::ThrowValue
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1330,7 +1379,7 @@ class ThrowValueInstruction extends ThrowInstruction {
|
|||||||
*/
|
*/
|
||||||
class ReThrowInstruction extends ThrowInstruction {
|
class ReThrowInstruction extends ThrowInstruction {
|
||||||
ReThrowInstruction() {
|
ReThrowInstruction() {
|
||||||
opcode instanceof Opcode::ReThrow
|
getOpcode() instanceof Opcode::ReThrow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1339,7 +1388,7 @@ class ReThrowInstruction extends ThrowInstruction {
|
|||||||
*/
|
*/
|
||||||
class UnwindInstruction extends Instruction {
|
class UnwindInstruction extends Instruction {
|
||||||
UnwindInstruction() {
|
UnwindInstruction() {
|
||||||
opcode instanceof Opcode::Unwind
|
getOpcode() instanceof Opcode::Unwind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,7 +1397,7 @@ class UnwindInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CatchInstruction extends Instruction {
|
class CatchInstruction extends Instruction {
|
||||||
CatchInstruction() {
|
CatchInstruction() {
|
||||||
opcode instanceof CatchOpcode
|
getOpcode() instanceof CatchOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1359,7 +1408,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
|||||||
Type exceptionType;
|
Type exceptionType;
|
||||||
|
|
||||||
CatchByTypeInstruction() {
|
CatchByTypeInstruction() {
|
||||||
opcode instanceof Opcode::CatchByType and
|
getOpcode() instanceof Opcode::CatchByType and
|
||||||
exceptionType = Construction::getInstructionExceptionType(this)
|
exceptionType = Construction::getInstructionExceptionType(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,13 +1429,13 @@ class CatchByTypeInstruction extends CatchInstruction {
|
|||||||
*/
|
*/
|
||||||
class CatchAnyInstruction extends CatchInstruction {
|
class CatchAnyInstruction extends CatchInstruction {
|
||||||
CatchAnyInstruction() {
|
CatchAnyInstruction() {
|
||||||
opcode instanceof Opcode::CatchAny
|
getOpcode() instanceof Opcode::CatchAny
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnmodeledDefinitionInstruction extends Instruction {
|
class UnmodeledDefinitionInstruction extends Instruction {
|
||||||
UnmodeledDefinitionInstruction() {
|
UnmodeledDefinitionInstruction() {
|
||||||
opcode instanceof Opcode::UnmodeledDefinition
|
getOpcode() instanceof Opcode::UnmodeledDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1399,7 +1448,7 @@ class UnmodeledDefinitionInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class AliasedDefinitionInstruction extends Instruction {
|
class AliasedDefinitionInstruction extends Instruction {
|
||||||
AliasedDefinitionInstruction() {
|
AliasedDefinitionInstruction() {
|
||||||
opcode instanceof Opcode::AliasedDefinition
|
getOpcode() instanceof Opcode::AliasedDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1409,7 +1458,7 @@ class AliasedDefinitionInstruction extends Instruction {
|
|||||||
|
|
||||||
class UnmodeledUseInstruction extends Instruction {
|
class UnmodeledUseInstruction extends Instruction {
|
||||||
UnmodeledUseInstruction() {
|
UnmodeledUseInstruction() {
|
||||||
opcode instanceof Opcode::UnmodeledUse
|
getOpcode() instanceof Opcode::UnmodeledUse
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getOperandsString() {
|
override string getOperandsString() {
|
||||||
@@ -1429,7 +1478,7 @@ class UnmodeledUseInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class PhiInstruction extends Instruction {
|
class PhiInstruction extends Instruction {
|
||||||
PhiInstruction() {
|
PhiInstruction() {
|
||||||
opcode instanceof Opcode::Phi
|
getOpcode() instanceof Opcode::Phi
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1481,7 +1530,7 @@ class PhiInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class ChiInstruction extends Instruction {
|
class ChiInstruction extends Instruction {
|
||||||
ChiInstruction() {
|
ChiInstruction() {
|
||||||
opcode instanceof Opcode::Chi
|
getOpcode() instanceof Opcode::Chi
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1511,7 +1560,7 @@ class ChiInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class UnreachedInstruction extends Instruction {
|
class UnreachedInstruction extends Instruction {
|
||||||
UnreachedInstruction() {
|
UnreachedInstruction() {
|
||||||
opcode instanceof Opcode::Unreached
|
getOpcode() instanceof Opcode::Unreached
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1521,6 +1570,6 @@ class UnreachedInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class BuiltInInstruction extends Instruction {
|
class BuiltInInstruction extends Instruction {
|
||||||
BuiltInInstruction() {
|
BuiltInInstruction() {
|
||||||
opcode instanceof BuiltInOpcode
|
getOpcode() instanceof BuiltInOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,7 +287,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
|||||||
(
|
(
|
||||||
(
|
(
|
||||||
key = "semmle.label" and
|
key = "semmle.label" and
|
||||||
value = kind.toString()
|
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||||
|
then value = kind.toString() + " (back edge)"
|
||||||
|
else value = kind.toString()
|
||||||
) or
|
) or
|
||||||
(
|
(
|
||||||
key = "semmle.order" and
|
key = "semmle.order" and
|
||||||
|
|||||||
@@ -14,25 +14,6 @@ cached private module Cached {
|
|||||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
}
|
}
|
||||||
|
|
||||||
cached newtype TInstructionTag =
|
|
||||||
WrappedInstructionTag(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction
|
|
||||||
} or
|
|
||||||
PhiTag(Alias::VirtualVariable vvar, OldBlock block) {
|
|
||||||
hasPhiNode(vvar, block)
|
|
||||||
} or
|
|
||||||
ChiTag(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction and
|
|
||||||
hasChiNode(_, oldInstruction)
|
|
||||||
} or
|
|
||||||
UnreachedTag()
|
|
||||||
|
|
||||||
cached class InstructionTagType extends TInstructionTag {
|
|
||||||
cached final string toString() {
|
|
||||||
result = "Tag"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cached predicate functionHasIR(Function func) {
|
cached predicate functionHasIR(Function func) {
|
||||||
exists(OldIR::FunctionIR funcIR |
|
exists(OldIR::FunctionIR funcIR |
|
||||||
funcIR.getFunction() = func
|
funcIR.getFunction() = func
|
||||||
@@ -40,7 +21,7 @@ cached private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached OldInstruction getOldInstruction(Instruction instr) {
|
cached OldInstruction getOldInstruction(Instruction instr) {
|
||||||
instr.getTag() = WrappedInstructionTag(result)
|
instr = WrappedInstruction(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
private Instruction getNewInstruction(OldInstruction instr) {
|
private Instruction getNewInstruction(OldInstruction instr) {
|
||||||
@@ -52,90 +33,35 @@ cached private module Cached {
|
|||||||
* corresponding to `instr` if there is no `Chi` node.
|
* corresponding to `instr` if there is no `Chi` node.
|
||||||
*/
|
*/
|
||||||
private Instruction getNewFinalInstruction(OldInstruction instr) {
|
private Instruction getNewFinalInstruction(OldInstruction instr) {
|
||||||
result = getChiInstruction(instr)
|
result = Chi(instr)
|
||||||
or
|
or
|
||||||
not exists(getChiInstruction(instr)) and
|
not exists(Chi(instr)) and
|
||||||
result = getNewInstruction(instr)
|
result = getNewInstruction(instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
private PhiInstruction getPhiInstruction(Function func, OldBlock oldBlock,
|
|
||||||
Alias::VirtualVariable vvar) {
|
|
||||||
result.getFunction() = func and
|
|
||||||
result.getAST() = oldBlock.getFirstInstruction().getAST() and
|
|
||||||
result.getTag() = PhiTag(vvar, oldBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChiInstruction getChiInstruction (OldInstruction instr) {
|
|
||||||
hasChiNode(_, instr) and
|
|
||||||
result.getTag() = ChiTag(instr)
|
|
||||||
}
|
|
||||||
|
|
||||||
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
||||||
result.getFunction() = var.getFunction() and
|
// This is just a type cast. Both classes derive from the same newtype.
|
||||||
(
|
result = var
|
||||||
exists(OldIR::IRUserVariable userVar, IRUserVariable newUserVar |
|
|
||||||
userVar = var and
|
|
||||||
newUserVar.getVariable() = userVar.getVariable() and
|
|
||||||
result = newUserVar
|
|
||||||
) or
|
|
||||||
exists(OldIR::IRTempVariable tempVar, IRTempVariable newTempVar |
|
|
||||||
tempVar = var and
|
|
||||||
newTempVar.getAST() = tempVar.getAST() and
|
|
||||||
newTempVar.getTag() = tempVar.getTag() and
|
|
||||||
result = newTempVar
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached newtype TInstruction =
|
cached newtype TInstruction =
|
||||||
MkInstruction(FunctionIR funcIR, Opcode opcode, Locatable ast,
|
WrappedInstruction(OldInstruction oldInstruction) {
|
||||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
not oldInstruction instanceof OldIR::PhiInstruction
|
||||||
hasInstruction(funcIR.getFunction(), opcode, ast, tag,
|
} or
|
||||||
resultType, isGLValue)
|
Phi(OldBlock block, Alias::VirtualVariable vvar) {
|
||||||
|
hasPhiNode(vvar, block)
|
||||||
|
} or
|
||||||
|
Chi(OldInstruction oldInstruction) {
|
||||||
|
not oldInstruction instanceof OldIR::PhiInstruction and
|
||||||
|
hasChiNode(_, oldInstruction)
|
||||||
|
} or
|
||||||
|
Unreached(Function function) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
function = oldInstruction.getFunction() and
|
||||||
|
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate hasInstruction(Function func, Opcode opcode, Locatable ast,
|
|
||||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
|
||||||
exists(OldInstruction instr |
|
|
||||||
instr.getFunction() = func and
|
|
||||||
instr.getOpcode() = opcode and
|
|
||||||
instr.getAST() = ast and
|
|
||||||
WrappedInstructionTag(instr) = tag and
|
|
||||||
instr.getResultType() = resultType and
|
|
||||||
if instr.isGLValue() then
|
|
||||||
isGLValue = true
|
|
||||||
else
|
|
||||||
isGLValue = false
|
|
||||||
) or
|
|
||||||
exists(OldBlock block, Alias::VirtualVariable vvar |
|
|
||||||
hasPhiNode(vvar, block) and
|
|
||||||
block.getFunction() = func and
|
|
||||||
opcode instanceof Opcode::Phi and
|
|
||||||
ast = block.getFirstInstruction().getAST() and
|
|
||||||
tag = PhiTag(vvar, block) and
|
|
||||||
resultType = vvar.getType() and
|
|
||||||
isGLValue = false
|
|
||||||
) or
|
|
||||||
exists(OldInstruction instr, Alias::VirtualVariable vvar |
|
|
||||||
hasChiNode(vvar, instr) and
|
|
||||||
instr.getFunction() = func and
|
|
||||||
opcode instanceof Opcode::Chi and
|
|
||||||
ast = instr.getAST() and
|
|
||||||
tag = ChiTag(instr) and
|
|
||||||
resultType = vvar.getType() and
|
|
||||||
isGLValue = false
|
|
||||||
) or
|
|
||||||
exists(OldInstruction oldInstruction |
|
|
||||||
func = oldInstruction.getFunction() and
|
|
||||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) and
|
|
||||||
tag = UnreachedTag() and
|
|
||||||
opcode instanceof Opcode::Unreached and
|
|
||||||
ast = func and
|
|
||||||
resultType instanceof VoidType and
|
|
||||||
isGLValue = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
||||||
Type type) {
|
Type type) {
|
||||||
exists(OldIR::IRTempVariable var |
|
exists(OldIR::IRTempVariable var |
|
||||||
@@ -169,7 +95,7 @@ cached private module Cached {
|
|||||||
if defIndex >= 0 then
|
if defIndex >= 0 then
|
||||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||||
else
|
else
|
||||||
result = getPhiInstruction(instruction.getFunction(), defBlock, vvar)
|
result = Phi(defBlock, vvar)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else (
|
else (
|
||||||
@@ -189,13 +115,14 @@ cached private module Cached {
|
|||||||
else
|
else
|
||||||
result = getNewInstruction(oldOperand.getDefinitionInstruction())
|
result = getNewInstruction(oldOperand.getDefinitionInstruction())
|
||||||
) or
|
) or
|
||||||
instruction.getTag() = ChiTag(getOldInstruction(result)) and
|
instruction = Chi(getOldInstruction(result)) and
|
||||||
tag instanceof ChiPartialOperandTag
|
tag instanceof ChiPartialOperandTag
|
||||||
or
|
or
|
||||||
instruction instanceof UnmodeledUseInstruction and
|
exists(FunctionIR f |
|
||||||
tag instanceof UnmodeledUseOperandTag and
|
tag instanceof UnmodeledUseOperandTag and
|
||||||
result instanceof UnmodeledDefinitionInstruction and
|
result = f.getUnmodeledDefinitionInstruction() and
|
||||||
instruction.getFunction() = result.getFunction()
|
instruction = f.getUnmodeledUseInstruction()
|
||||||
|
)
|
||||||
or
|
or
|
||||||
tag instanceof ChiTotalOperandTag and
|
tag instanceof ChiTotalOperandTag and
|
||||||
result = getChiInstructionTotalOperand(instruction)
|
result = getChiInstructionTotalOperand(instruction)
|
||||||
@@ -207,21 +134,21 @@ cached private module Cached {
|
|||||||
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
|
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
|
||||||
hasPhiNode(vvar, phiBlock) and
|
hasPhiNode(vvar, phiBlock) and
|
||||||
predBlock = phiBlock.getAFeasiblePredecessor() and
|
predBlock = phiBlock.getAFeasiblePredecessor() and
|
||||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
instr = Phi(phiBlock, vvar) and
|
||||||
newPredecessorBlock = getNewBlock(predBlock) and
|
newPredecessorBlock = getNewBlock(predBlock) and
|
||||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||||
if defIndex >= 0 then
|
if defIndex >= 0 then
|
||||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||||
else
|
else
|
||||||
result = getPhiInstruction(instr.getFunction(), defBlock, vvar)
|
result = Phi(defBlock, vvar)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
|
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
|
||||||
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
|
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
|
||||||
int defRank, int defIndex, OldBlock useBlock, int useRank |
|
int defRank, int defIndex, OldBlock useBlock, int useRank |
|
||||||
ChiTag(oldInstr) = chiInstr.getTag() and
|
chiInstr = Chi(oldInstr) and
|
||||||
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
|
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
|
||||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||||
@@ -229,13 +156,13 @@ cached private module Cached {
|
|||||||
if defIndex >= 0 then
|
if defIndex >= 0 then
|
||||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||||
else
|
else
|
||||||
result = getPhiInstruction(chiInstr.getFunction(), defBlock, vvar)
|
result = Phi(defBlock, vvar)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||||
exists(OldBlock oldBlock |
|
exists(OldBlock oldBlock |
|
||||||
instr.getTag() = PhiTag(_, oldBlock) and
|
instr = Phi(oldBlock, _) and
|
||||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -256,15 +183,14 @@ cached private module Cached {
|
|||||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||||
if(hasChiNode(_, getOldInstruction(instruction)))
|
if(hasChiNode(_, getOldInstruction(instruction)))
|
||||||
then
|
then
|
||||||
result = getChiInstruction(getOldInstruction(instruction)) and
|
result = Chi(getOldInstruction(instruction)) and
|
||||||
kind instanceof GotoEdge
|
kind instanceof GotoEdge
|
||||||
else (
|
else (
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
oldInstruction = getOldInstruction(instruction) and
|
oldInstruction = getOldInstruction(instruction) and
|
||||||
(
|
(
|
||||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) then (
|
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) then (
|
||||||
result.getTag() = UnreachedTag() and
|
result = Unreached(instruction.getFunction())
|
||||||
result.getFunction() = instruction.getFunction()
|
|
||||||
)
|
)
|
||||||
else (
|
else (
|
||||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
@@ -272,12 +198,106 @@ cached private module Cached {
|
|||||||
)
|
)
|
||||||
) or
|
) or
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
instruction = getChiInstruction(oldInstruction) and
|
instruction = Chi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
result = getNewInstruction(oldInstruction.getSuccessor(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
|
||||||
|
// SSA construction never inserts extra instructions _before_ an existing
|
||||||
|
// instruction.
|
||||||
|
getOldInstruction(result) = oldInstruction.getBackEdgeSuccessor(kind) and
|
||||||
|
// There are two cases for the translation into `instruction` because the
|
||||||
|
// SSA construction might have inserted a chi node _after_
|
||||||
|
// `oldInstruction`, in which case the back edge should come out of the
|
||||||
|
// chi node instead.
|
||||||
|
if hasChiNode(_, oldInstruction)
|
||||||
|
then instruction = Chi(oldInstruction)
|
||||||
|
else instruction = getNewInstruction(oldInstruction)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached Locatable getInstructionAST(Instruction instruction) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
instruction = WrappedInstruction(oldInstruction)
|
||||||
|
or
|
||||||
|
instruction = Chi(oldInstruction)
|
||||||
|
|
|
||||||
|
result = oldInstruction.getAST()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(OldBlock block |
|
||||||
|
instruction = Phi(block, _) and
|
||||||
|
result = block.getFirstInstruction().getAST()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
instruction = Unreached(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
|
||||||
|
instruction = Chi(oldInstruction) and
|
||||||
|
hasChiNode(vvar, oldInstruction) and
|
||||||
|
type = vvar.getType() and
|
||||||
|
isGLValue = false
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(Alias::VirtualVariable vvar |
|
||||||
|
instruction = Phi(_, vvar) and
|
||||||
|
type = vvar.getType() and
|
||||||
|
isGLValue = false
|
||||||
|
)
|
||||||
|
or
|
||||||
|
instruction = Unreached(_) and
|
||||||
|
type instanceof VoidType and
|
||||||
|
isGLValue = false
|
||||||
|
}
|
||||||
|
|
||||||
|
cached Opcode getInstructionOpcode(Instruction instruction) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
instruction = WrappedInstruction(oldInstruction) and
|
||||||
|
result = oldInstruction.getOpcode()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
instruction instanceof Chi and
|
||||||
|
result instanceof Opcode::Chi
|
||||||
|
or
|
||||||
|
instruction instanceof Phi and
|
||||||
|
result instanceof Opcode::Phi
|
||||||
|
or
|
||||||
|
instruction instanceof Unreached and
|
||||||
|
result instanceof Opcode::Unreached
|
||||||
|
}
|
||||||
|
|
||||||
|
cached FunctionIR getInstructionEnclosingFunctionIR(Instruction instruction) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
instruction = WrappedInstruction(oldInstruction)
|
||||||
|
or
|
||||||
|
instruction = Chi(oldInstruction)
|
||||||
|
|
|
||||||
|
result.getFunction() = oldInstruction.getFunction()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(OldBlock block |
|
||||||
|
instruction = Phi(block, _) and
|
||||||
|
result.getFunction() = block.getFunction()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
instruction = Unreached(result.getFunction())
|
||||||
|
}
|
||||||
|
|
||||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||||
}
|
}
|
||||||
@@ -328,13 +348,13 @@ cached private module Cached {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldIR::Instruction oldInstruction |
|
exists(OldIR::Instruction oldInstruction |
|
||||||
instruction.getTag() = ChiTag(oldInstruction) and
|
instruction = Chi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction)
|
result = getNewInstruction(oldInstruction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||||
OldInstruction instr, OldBlock block, int index) {
|
OldBlock block, int index, OldInstruction instr) {
|
||||||
block.getInstruction(index) = instr and
|
block.getInstruction(index) = instr and
|
||||||
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
|
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
|
||||||
}
|
}
|
||||||
@@ -352,11 +372,11 @@ cached private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate defUseRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex, int index) {
|
private predicate defUseRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex, int index) {
|
||||||
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
|
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, block, j, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate hasUse(Alias::VirtualVariable vvar, OldInstruction use, OldBlock block,
|
private predicate hasUse(Alias::VirtualVariable vvar, OldBlock block, int index,
|
||||||
int index) {
|
OldInstruction use) {
|
||||||
exists(Alias::MemoryAccess access |
|
exists(Alias::MemoryAccess access |
|
||||||
(
|
(
|
||||||
access = Alias::getOperandMemoryAccess(use.getAnOperand())
|
access = Alias::getOperandMemoryAccess(use.getAnOperand())
|
||||||
@@ -374,10 +394,16 @@ cached private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
|
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
|
||||||
exists (int index | hasUse(vvar, _, block, index) |
|
exists(int firstAccess |
|
||||||
not exists (int j | ssa_variableUpdate(vvar, _, block, j) | j < index)
|
hasUse(vvar, block, firstAccess, _) and
|
||||||
) or
|
firstAccess = min(int index |
|
||||||
(variableLiveOnExitFromBlock(vvar, block) and not ssa_variableUpdate(vvar, _, block, _))
|
hasUse(vvar, block, index, _)
|
||||||
|
or
|
||||||
|
ssa_variableUpdate(vvar, block, index, _)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
(variableLiveOnExitFromBlock(vvar, block) and not ssa_variableUpdate(vvar, block, _, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
@@ -404,7 +430,7 @@ cached private module Cached {
|
|||||||
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
|
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
|
||||||
OldInstruction use) {
|
OldInstruction use) {
|
||||||
exists(int index |
|
exists(int index |
|
||||||
hasUse(vvar, use, block, index) and
|
hasUse(vvar, block, index, use) and
|
||||||
defUseRank(vvar, block, rankIndex, index)
|
defUseRank(vvar, block, rankIndex, index)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -517,11 +543,11 @@ cached private module CachedForDebugging {
|
|||||||
result = "NonSSA: " + oldInstr.getUniqueId()
|
result = "NonSSA: " + oldInstr.getUniqueId()
|
||||||
) or
|
) or
|
||||||
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
|
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
|
||||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
instr = Phi(phiBlock, vvar) and
|
||||||
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
||||||
) or
|
) or
|
||||||
(
|
(
|
||||||
instr.getTag() = UnreachedTag() and
|
instr = Unreached(_) and
|
||||||
result = "Unreached"
|
result = "Unreached"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ class FunctionIR extends TFunctionIR {
|
|||||||
result.getFunctionIR() = this
|
result.getFunctionIR() = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
final UnmodeledUseInstruction getUnmodeledUseInstruction() {
|
||||||
|
result.getFunctionIR() = this
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the single return instruction for this function.
|
* Gets the single return instruction for this function.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
|
|||||||
blockSuccessor(this, result, kind)
|
blockSuccessor(this, result, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||||
|
backEdgeSuccessor(this, result, kind)
|
||||||
|
}
|
||||||
|
|
||||||
final predicate immediatelyDominates(IRBlock block) {
|
final predicate immediatelyDominates(IRBlock block) {
|
||||||
blockImmediatelyDominates(this, block)
|
blockImmediatelyDominates(this, block)
|
||||||
}
|
}
|
||||||
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
|
|||||||
exists(Instruction predecessor, EdgeKind kind |
|
exists(Instruction predecessor, EdgeKind kind |
|
||||||
instr = predecessor.getSuccessor(kind) and
|
instr = predecessor.getSuccessor(kind) and
|
||||||
not kind instanceof GotoEdge
|
not kind instanceof GotoEdge
|
||||||
) // Incoming edge is not a GotoEdge
|
) or // Incoming edge is not a GotoEdge
|
||||||
|
exists(Instruction predecessor |
|
||||||
|
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
|
||||||
|
) // A back edge enters this instruction
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,24 +159,13 @@ private cached module Cached {
|
|||||||
not startsBasicBlock(i2)
|
not startsBasicBlock(i2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the index of `i` in its `IRBlock`. */
|
/** Holds if `i` is the `index`th instruction the block starting with `first`. */
|
||||||
private int getMemberIndex(Instruction i) {
|
private Instruction getInstructionFromFirst(Instruction first, int index) =
|
||||||
startsBasicBlock(i) and
|
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
|
||||||
result = 0
|
|
||||||
or
|
|
||||||
exists(Instruction iPrev |
|
|
||||||
adjacentInBlock(iPrev, i) and
|
|
||||||
result = getMemberIndex(iPrev) + 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `i` is the `index`th instruction in `block`. */
|
/** Holds if `i` is the `index`th instruction in `block`. */
|
||||||
cached Instruction getInstruction(TIRBlock block, int index) {
|
cached Instruction getInstruction(TIRBlock block, int index) {
|
||||||
exists(Instruction first |
|
result = getInstructionFromFirst(getFirstInstruction(block), index)
|
||||||
block = MkIRBlock(first) and
|
|
||||||
index = getMemberIndex(result) and
|
|
||||||
adjacentInBlock*(first, result)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached int getInstructionCount(TIRBlock block) {
|
cached int getInstructionCount(TIRBlock block) {
|
||||||
@@ -184,6 +180,41 @@ private cached module Cached {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||||
|
backEdgeSuccessorRaw(pred, succ, kind)
|
||||||
|
or
|
||||||
|
forwardEdgeRaw+(pred, pred) and
|
||||||
|
blockSuccessor(pred, succ, kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
|
||||||
|
*/
|
||||||
|
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
|
||||||
|
exists(EdgeKind kind |
|
||||||
|
blockSuccessor(pred, succ, kind) and
|
||||||
|
not backEdgeSuccessorRaw(pred, succ, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
|
||||||
|
* `Construction`.
|
||||||
|
*
|
||||||
|
* There could be loops of non-back-edges if there is a flaw in the IR
|
||||||
|
* construction or back-edge detection, and this could cause non-termination
|
||||||
|
* of subsequent analysis. To prevent that, a subsequent predicate further
|
||||||
|
* classifies all edges as back edges if they are involved in a loop of
|
||||||
|
* non-back-edges.
|
||||||
|
*/
|
||||||
|
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||||
|
exists(Instruction predLast, Instruction succFirst |
|
||||||
|
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
|
||||||
|
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
|
||||||
|
succ = MkIRBlock(succFirst)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
||||||
blockSuccessor(pred, succ, _)
|
blockSuccessor(pred, succ, _)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,31 +3,7 @@ import FunctionIR
|
|||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.ir.implementation.TempVariableTag
|
import semmle.code.cpp.ir.implementation.TempVariableTag
|
||||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||||
|
private import semmle.code.cpp.ir.internal.TIRVariable
|
||||||
private newtype TIRVariable =
|
|
||||||
TIRAutomaticUserVariable(LocalScopeVariable var, FunctionIR funcIR) {
|
|
||||||
exists(Function func |
|
|
||||||
func = funcIR.getFunction() and
|
|
||||||
(
|
|
||||||
var.getFunction() = func or
|
|
||||||
var.(Parameter).getCatchBlock().getEnclosingFunction() = func
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} or
|
|
||||||
TIRStaticUserVariable(Variable var, FunctionIR funcIR) {
|
|
||||||
(
|
|
||||||
var instanceof GlobalOrNamespaceVariable or
|
|
||||||
var instanceof MemberVariable and not var instanceof Field
|
|
||||||
) and
|
|
||||||
exists(VariableAccess access |
|
|
||||||
access.getTarget() = var and
|
|
||||||
access.getEnclosingFunction() = funcIR.getFunction()
|
|
||||||
)
|
|
||||||
} or
|
|
||||||
TIRTempVariable(FunctionIR funcIR, Locatable ast, TempVariableTag tag,
|
|
||||||
Type type) {
|
|
||||||
Construction::hasTempVariable(funcIR.getFunction(), ast, tag, type)
|
|
||||||
}
|
|
||||||
|
|
||||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||||
result.getVariable() = var and
|
result.getVariable() = var and
|
||||||
@@ -40,7 +16,7 @@ IRUserVariable getIRUserVariable(Function func, Variable var) {
|
|||||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||||
*/
|
*/
|
||||||
abstract class IRVariable extends TIRVariable {
|
abstract class IRVariable extends TIRVariable {
|
||||||
FunctionIR funcIR;
|
Function func;
|
||||||
|
|
||||||
abstract string toString();
|
abstract string toString();
|
||||||
|
|
||||||
@@ -72,14 +48,14 @@ abstract class IRVariable extends TIRVariable {
|
|||||||
* Gets the IR for the function that references this variable.
|
* Gets the IR for the function that references this variable.
|
||||||
*/
|
*/
|
||||||
final FunctionIR getFunctionIR() {
|
final FunctionIR getFunctionIR() {
|
||||||
result = funcIR
|
result.getFunction() = func
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the function that references this variable.
|
* Gets the function that references this variable.
|
||||||
*/
|
*/
|
||||||
final Function getFunction() {
|
final Function getFunction() {
|
||||||
result = funcIR.getFunction()
|
result = func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +102,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
|||||||
LocalScopeVariable localVar;
|
LocalScopeVariable localVar;
|
||||||
|
|
||||||
IRAutomaticUserVariable() {
|
IRAutomaticUserVariable() {
|
||||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
this = TIRAutomaticUserVariable(localVar, func) and
|
||||||
var = localVar
|
var = localVar
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +113,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
|||||||
|
|
||||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||||
IRStaticUserVariable() {
|
IRStaticUserVariable() {
|
||||||
this = TIRStaticUserVariable(var, funcIR)
|
this = TIRStaticUserVariable(var, func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +128,7 @@ class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
|||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
IRTempVariable() {
|
IRTempVariable() {
|
||||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
this = TIRTempVariable(func, ast, tag, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Type getType() {
|
override final Type getType() {
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import semmle.code.cpp.ir.implementation.Opcode
|
|||||||
private import semmle.code.cpp.ir.implementation.Opcode
|
private import semmle.code.cpp.ir.implementation.Opcode
|
||||||
private import semmle.code.cpp.ir.internal.OperandTag
|
private import semmle.code.cpp.ir.internal.OperandTag
|
||||||
|
|
||||||
class InstructionTag = Construction::InstructionTagType;
|
|
||||||
|
|
||||||
module InstructionSanity {
|
module InstructionSanity {
|
||||||
/**
|
/**
|
||||||
* Holds if the instruction `instr` should be expected to have an operand
|
* Holds if the instruction `instr` should be expected to have an operand
|
||||||
@@ -157,23 +155,60 @@ module InstructionSanity {
|
|||||||
blockCount = count(instr.getBlock()) and
|
blockCount = count(instr.getBlock()) and
|
||||||
blockCount != 1
|
blockCount != 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||||
|
b1.getASuccessor() = b2 and
|
||||||
|
not b1.getBackEdgeSuccessor(_) = b2
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||||
|
*
|
||||||
|
* This check ensures we don't have too _few_ back edges.
|
||||||
|
*/
|
||||||
|
query predicate containsLoopOfForwardEdges(FunctionIR f) {
|
||||||
|
exists(IRBlock block |
|
||||||
|
forwardEdge+(block, block) and
|
||||||
|
block.getFunctionIR() = f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `block` is reachable from its function entry point but would not
|
||||||
|
* be reachable by traversing only forward edges. This check is skipped for
|
||||||
|
* functions containing `goto` statements as the property does not generally
|
||||||
|
* hold there.
|
||||||
|
*
|
||||||
|
* This check ensures we don't have too _many_ back edges.
|
||||||
|
*/
|
||||||
|
query predicate lostReachability(IRBlock block) {
|
||||||
|
exists(FunctionIR f, IRBlock entry |
|
||||||
|
entry = f.getEntryBlock() and
|
||||||
|
entry.getASuccessor+() = block and
|
||||||
|
not forwardEdge+(entry, block) and
|
||||||
|
not exists(GotoStmt s | s.getEnclosingFunction() = f.getFunction())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the number of back edges differs between the `Instruction` graph
|
||||||
|
* and the `IRBlock` graph.
|
||||||
|
*/
|
||||||
|
query predicate backEdgeCountMismatch(Function f, int fromInstr, int fromBlock) {
|
||||||
|
fromInstr = count(Instruction i1, Instruction i2 |
|
||||||
|
i1.getFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||||
|
) and
|
||||||
|
fromBlock = count(IRBlock b1, IRBlock b2 |
|
||||||
|
b1.getFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||||
|
) and
|
||||||
|
fromInstr != fromBlock
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a single operation in the IR.
|
* Represents a single operation in the IR.
|
||||||
*/
|
*/
|
||||||
class Instruction extends Construction::TInstruction {
|
class Instruction extends Construction::TInstruction {
|
||||||
Opcode opcode;
|
|
||||||
Locatable ast;
|
|
||||||
InstructionTag instructionTag;
|
|
||||||
Type resultType;
|
|
||||||
FunctionIR funcIR;
|
|
||||||
boolean glvalue;
|
|
||||||
|
|
||||||
Instruction() {
|
|
||||||
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
|
||||||
}
|
|
||||||
|
|
||||||
final string toString() {
|
final string toString() {
|
||||||
result = getOpcode().toString() + ": " + getAST().toString()
|
result = getOpcode().toString() + ": " + getAST().toString()
|
||||||
}
|
}
|
||||||
@@ -196,9 +231,9 @@ class Instruction extends Construction::TInstruction {
|
|||||||
*/
|
*/
|
||||||
final string getOperationString() {
|
final string getOperationString() {
|
||||||
if exists(getImmediateString()) then
|
if exists(getImmediateString()) then
|
||||||
result = getOperationPrefix() + opcode.toString() + "[" + getImmediateString() + "]"
|
result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]"
|
||||||
else
|
else
|
||||||
result = getOperationPrefix() + opcode.toString()
|
result = getOperationPrefix() + getOpcode().toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -216,7 +251,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string getResultPrefix() {
|
private string getResultPrefix() {
|
||||||
if resultType instanceof VoidType then
|
if getResultType() instanceof VoidType then
|
||||||
result = "v"
|
result = "v"
|
||||||
else if hasMemoryResult() then
|
else if hasMemoryResult() then
|
||||||
if isResultModeled() then
|
if isResultModeled() then
|
||||||
@@ -261,8 +296,8 @@ class Instruction extends Construction::TInstruction {
|
|||||||
|
|
||||||
private string getResultTypeString() {
|
private string getResultTypeString() {
|
||||||
exists(string valcat |
|
exists(string valcat |
|
||||||
valcat = getValueCategoryString(resultType.toString()) and
|
valcat = getValueCategoryString(getResultType().toString()) and
|
||||||
if (resultType instanceof UnknownType and
|
if (getResultType() instanceof UnknownType and
|
||||||
not isGLValue() and
|
not isGLValue() and
|
||||||
exists(getResultSize())) then (
|
exists(getResultSize())) then (
|
||||||
result = valcat + "[" + getResultSize().toString() + "]"
|
result = valcat + "[" + getResultSize().toString() + "]"
|
||||||
@@ -330,28 +365,28 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* Gets the function that contains this instruction.
|
* Gets the function that contains this instruction.
|
||||||
*/
|
*/
|
||||||
final Function getFunction() {
|
final Function getFunction() {
|
||||||
result = funcIR.getFunction()
|
result = getFunctionIR().getFunction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the FunctionIR object that contains the IR for this instruction.
|
* Gets the FunctionIR object that contains the IR for this instruction.
|
||||||
*/
|
*/
|
||||||
final FunctionIR getFunctionIR() {
|
final FunctionIR getFunctionIR() {
|
||||||
result = funcIR
|
result = Construction::getInstructionEnclosingFunctionIR(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the AST that caused this instruction to be generated.
|
* Gets the AST that caused this instruction to be generated.
|
||||||
*/
|
*/
|
||||||
final Locatable getAST() {
|
final Locatable getAST() {
|
||||||
result = ast
|
result = Construction::getInstructionAST(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location of the source code for this instruction.
|
* Gets the location of the source code for this instruction.
|
||||||
*/
|
*/
|
||||||
final Location getLocation() {
|
final Location getLocation() {
|
||||||
result = ast.getLocation()
|
result = getAST().getLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -373,7 +408,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* instruction does not produce a result, its result type will be `VoidType`.
|
* instruction does not produce a result, its result type will be `VoidType`.
|
||||||
*/
|
*/
|
||||||
final Type getResultType() {
|
final Type getResultType() {
|
||||||
result = resultType
|
Construction::instructionHasType(this, result, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -395,7 +430,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* the integer value loaded from variable `x`.
|
* the integer value loaded from variable `x`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() {
|
final predicate isGLValue() {
|
||||||
glvalue = true
|
Construction::instructionHasType(this, _, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -412,10 +447,10 @@ class Instruction extends Construction::TInstruction {
|
|||||||
result = nullptr.getSize()
|
result = nullptr.getSize()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else if resultType instanceof UnknownType then
|
else if getResultType() instanceof UnknownType then
|
||||||
result = Construction::getInstructionResultSize(this)
|
result = Construction::getInstructionResultSize(this)
|
||||||
else (
|
else (
|
||||||
result = resultType.getSize()
|
result = getResultType().getSize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,11 +458,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* Gets the opcode that specifies the operation performed by this instruction.
|
* Gets the opcode that specifies the operation performed by this instruction.
|
||||||
*/
|
*/
|
||||||
final Opcode getOpcode() {
|
final Opcode getOpcode() {
|
||||||
result = opcode
|
result = Construction::getInstructionOpcode(this)
|
||||||
}
|
|
||||||
|
|
||||||
final InstructionTag getTag() {
|
|
||||||
result = instructionTag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -489,6 +520,24 @@ class Instruction extends Construction::TInstruction {
|
|||||||
result = Construction::getInstructionSuccessor(this, kind)
|
result = Construction::getInstructionSuccessor(this, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the a _back-edge successor_ of this instruction along the control
|
||||||
|
* flow edge specified by `kind`. A back edge in the control-flow graph is
|
||||||
|
* intuitively the edge that goes back around a loop. If all back edges are
|
||||||
|
* removed from the control-flow graph, it becomes acyclic.
|
||||||
|
*/
|
||||||
|
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
|
||||||
|
// We don't take these edges from
|
||||||
|
// `Construction::getInstructionBackEdgeSuccessor` since that relation has
|
||||||
|
// not been treated to remove any loops that might be left over due to
|
||||||
|
// flaws in the IR construction or back-edge detection.
|
||||||
|
exists(IRBlock block |
|
||||||
|
block = this.getBlock() and
|
||||||
|
this = block.getLastInstruction() and
|
||||||
|
result = block.getBackEdgeSuccessor(kind).getFirstInstruction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all direct successors of this instruction.
|
* Gets all direct successors of this instruction.
|
||||||
*/
|
*/
|
||||||
@@ -578,19 +627,19 @@ class ConstantValueInstruction extends Instruction {
|
|||||||
|
|
||||||
class EnterFunctionInstruction extends Instruction {
|
class EnterFunctionInstruction extends Instruction {
|
||||||
EnterFunctionInstruction() {
|
EnterFunctionInstruction() {
|
||||||
opcode instanceof Opcode::EnterFunction
|
getOpcode() instanceof Opcode::EnterFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VariableAddressInstruction extends VariableInstruction {
|
class VariableAddressInstruction extends VariableInstruction {
|
||||||
VariableAddressInstruction() {
|
VariableAddressInstruction() {
|
||||||
opcode instanceof Opcode::VariableAddress
|
getOpcode() instanceof Opcode::VariableAddress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InitializeParameterInstruction extends VariableInstruction {
|
class InitializeParameterInstruction extends VariableInstruction {
|
||||||
InitializeParameterInstruction() {
|
InitializeParameterInstruction() {
|
||||||
opcode instanceof Opcode::InitializeParameter
|
getOpcode() instanceof Opcode::InitializeParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
final Parameter getParameter() {
|
final Parameter getParameter() {
|
||||||
@@ -607,13 +656,13 @@ class InitializeParameterInstruction extends VariableInstruction {
|
|||||||
*/
|
*/
|
||||||
class InitializeThisInstruction extends Instruction {
|
class InitializeThisInstruction extends Instruction {
|
||||||
InitializeThisInstruction() {
|
InitializeThisInstruction() {
|
||||||
opcode instanceof Opcode::InitializeThis
|
getOpcode() instanceof Opcode::InitializeThis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldAddressInstruction extends FieldInstruction {
|
class FieldAddressInstruction extends FieldInstruction {
|
||||||
FieldAddressInstruction() {
|
FieldAddressInstruction() {
|
||||||
opcode instanceof Opcode::FieldAddress
|
getOpcode() instanceof Opcode::FieldAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getObjectAddress() {
|
final Instruction getObjectAddress() {
|
||||||
@@ -623,7 +672,7 @@ class FieldAddressInstruction extends FieldInstruction {
|
|||||||
|
|
||||||
class UninitializedInstruction extends VariableInstruction {
|
class UninitializedInstruction extends VariableInstruction {
|
||||||
UninitializedInstruction() {
|
UninitializedInstruction() {
|
||||||
opcode instanceof Opcode::Uninitialized
|
getOpcode() instanceof Opcode::Uninitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -640,25 +689,25 @@ class UninitializedInstruction extends VariableInstruction {
|
|||||||
|
|
||||||
class NoOpInstruction extends Instruction {
|
class NoOpInstruction extends Instruction {
|
||||||
NoOpInstruction() {
|
NoOpInstruction() {
|
||||||
opcode instanceof Opcode::NoOp
|
getOpcode() instanceof Opcode::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnInstruction extends Instruction {
|
class ReturnInstruction extends Instruction {
|
||||||
ReturnInstruction() {
|
ReturnInstruction() {
|
||||||
opcode instanceof ReturnOpcode
|
getOpcode() instanceof ReturnOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnVoidInstruction extends ReturnInstruction {
|
class ReturnVoidInstruction extends ReturnInstruction {
|
||||||
ReturnVoidInstruction() {
|
ReturnVoidInstruction() {
|
||||||
opcode instanceof Opcode::ReturnVoid
|
getOpcode() instanceof Opcode::ReturnVoid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnValueInstruction extends ReturnInstruction {
|
class ReturnValueInstruction extends ReturnInstruction {
|
||||||
ReturnValueInstruction() {
|
ReturnValueInstruction() {
|
||||||
opcode instanceof Opcode::ReturnValue
|
getOpcode() instanceof Opcode::ReturnValue
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getReturnValue() {
|
final Instruction getReturnValue() {
|
||||||
@@ -668,7 +717,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
|||||||
|
|
||||||
class CopyInstruction extends Instruction {
|
class CopyInstruction extends Instruction {
|
||||||
CopyInstruction() {
|
CopyInstruction() {
|
||||||
opcode instanceof CopyOpcode
|
getOpcode() instanceof CopyOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getSourceValue() {
|
final Instruction getSourceValue() {
|
||||||
@@ -678,13 +727,13 @@ class CopyInstruction extends Instruction {
|
|||||||
|
|
||||||
class CopyValueInstruction extends CopyInstruction {
|
class CopyValueInstruction extends CopyInstruction {
|
||||||
CopyValueInstruction() {
|
CopyValueInstruction() {
|
||||||
opcode instanceof Opcode::CopyValue
|
getOpcode() instanceof Opcode::CopyValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LoadInstruction extends CopyInstruction {
|
class LoadInstruction extends CopyInstruction {
|
||||||
LoadInstruction() {
|
LoadInstruction() {
|
||||||
opcode instanceof Opcode::Load
|
getOpcode() instanceof Opcode::Load
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getSourceAddress() {
|
final Instruction getSourceAddress() {
|
||||||
@@ -694,7 +743,7 @@ class LoadInstruction extends CopyInstruction {
|
|||||||
|
|
||||||
class StoreInstruction extends CopyInstruction {
|
class StoreInstruction extends CopyInstruction {
|
||||||
StoreInstruction() {
|
StoreInstruction() {
|
||||||
opcode instanceof Opcode::Store
|
getOpcode() instanceof Opcode::Store
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -708,7 +757,7 @@ class StoreInstruction extends CopyInstruction {
|
|||||||
|
|
||||||
class ConditionalBranchInstruction extends Instruction {
|
class ConditionalBranchInstruction extends Instruction {
|
||||||
ConditionalBranchInstruction() {
|
ConditionalBranchInstruction() {
|
||||||
opcode instanceof Opcode::ConditionalBranch
|
getOpcode() instanceof Opcode::ConditionalBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getCondition() {
|
final Instruction getCondition() {
|
||||||
@@ -726,25 +775,25 @@ class ConditionalBranchInstruction extends Instruction {
|
|||||||
|
|
||||||
class ExitFunctionInstruction extends Instruction {
|
class ExitFunctionInstruction extends Instruction {
|
||||||
ExitFunctionInstruction() {
|
ExitFunctionInstruction() {
|
||||||
opcode instanceof Opcode::ExitFunction
|
getOpcode() instanceof Opcode::ExitFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConstantInstruction extends ConstantValueInstruction {
|
class ConstantInstruction extends ConstantValueInstruction {
|
||||||
ConstantInstruction() {
|
ConstantInstruction() {
|
||||||
opcode instanceof Opcode::Constant
|
getOpcode() instanceof Opcode::Constant
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IntegerConstantInstruction extends ConstantInstruction {
|
class IntegerConstantInstruction extends ConstantInstruction {
|
||||||
IntegerConstantInstruction() {
|
IntegerConstantInstruction() {
|
||||||
resultType instanceof IntegralType
|
getResultType() instanceof IntegralType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FloatConstantInstruction extends ConstantInstruction {
|
class FloatConstantInstruction extends ConstantInstruction {
|
||||||
FloatConstantInstruction() {
|
FloatConstantInstruction() {
|
||||||
resultType instanceof FloatingPointType
|
getResultType() instanceof FloatingPointType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,7 +815,7 @@ class StringConstantInstruction extends Instruction {
|
|||||||
|
|
||||||
class BinaryInstruction extends Instruction {
|
class BinaryInstruction extends Instruction {
|
||||||
BinaryInstruction() {
|
BinaryInstruction() {
|
||||||
opcode instanceof BinaryOpcode
|
getOpcode() instanceof BinaryOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getLeftOperand() {
|
final Instruction getLeftOperand() {
|
||||||
@@ -789,67 +838,67 @@ class BinaryInstruction extends Instruction {
|
|||||||
|
|
||||||
class AddInstruction extends BinaryInstruction {
|
class AddInstruction extends BinaryInstruction {
|
||||||
AddInstruction() {
|
AddInstruction() {
|
||||||
opcode instanceof Opcode::Add
|
getOpcode() instanceof Opcode::Add
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubInstruction extends BinaryInstruction {
|
class SubInstruction extends BinaryInstruction {
|
||||||
SubInstruction() {
|
SubInstruction() {
|
||||||
opcode instanceof Opcode::Sub
|
getOpcode() instanceof Opcode::Sub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MulInstruction extends BinaryInstruction {
|
class MulInstruction extends BinaryInstruction {
|
||||||
MulInstruction() {
|
MulInstruction() {
|
||||||
opcode instanceof Opcode::Mul
|
getOpcode() instanceof Opcode::Mul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DivInstruction extends BinaryInstruction {
|
class DivInstruction extends BinaryInstruction {
|
||||||
DivInstruction() {
|
DivInstruction() {
|
||||||
opcode instanceof Opcode::Div
|
getOpcode() instanceof Opcode::Div
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemInstruction extends BinaryInstruction {
|
class RemInstruction extends BinaryInstruction {
|
||||||
RemInstruction() {
|
RemInstruction() {
|
||||||
opcode instanceof Opcode::Rem
|
getOpcode() instanceof Opcode::Rem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NegateInstruction extends UnaryInstruction {
|
class NegateInstruction extends UnaryInstruction {
|
||||||
NegateInstruction() {
|
NegateInstruction() {
|
||||||
opcode instanceof Opcode::Negate
|
getOpcode() instanceof Opcode::Negate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitAndInstruction extends BinaryInstruction {
|
class BitAndInstruction extends BinaryInstruction {
|
||||||
BitAndInstruction() {
|
BitAndInstruction() {
|
||||||
opcode instanceof Opcode::BitAnd
|
getOpcode() instanceof Opcode::BitAnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitOrInstruction extends BinaryInstruction {
|
class BitOrInstruction extends BinaryInstruction {
|
||||||
BitOrInstruction() {
|
BitOrInstruction() {
|
||||||
opcode instanceof Opcode::BitOr
|
getOpcode() instanceof Opcode::BitOr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitXorInstruction extends BinaryInstruction {
|
class BitXorInstruction extends BinaryInstruction {
|
||||||
BitXorInstruction() {
|
BitXorInstruction() {
|
||||||
opcode instanceof Opcode::BitXor
|
getOpcode() instanceof Opcode::BitXor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShiftLeftInstruction extends BinaryInstruction {
|
class ShiftLeftInstruction extends BinaryInstruction {
|
||||||
ShiftLeftInstruction() {
|
ShiftLeftInstruction() {
|
||||||
opcode instanceof Opcode::ShiftLeft
|
getOpcode() instanceof Opcode::ShiftLeft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShiftRightInstruction extends BinaryInstruction {
|
class ShiftRightInstruction extends BinaryInstruction {
|
||||||
ShiftRightInstruction() {
|
ShiftRightInstruction() {
|
||||||
opcode instanceof Opcode::ShiftRight
|
getOpcode() instanceof Opcode::ShiftRight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -857,7 +906,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
|||||||
int elementSize;
|
int elementSize;
|
||||||
|
|
||||||
PointerArithmeticInstruction() {
|
PointerArithmeticInstruction() {
|
||||||
opcode instanceof PointerArithmeticOpcode and
|
getOpcode() instanceof PointerArithmeticOpcode and
|
||||||
elementSize = Construction::getInstructionElementSize(this)
|
elementSize = Construction::getInstructionElementSize(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,31 +921,31 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
|||||||
|
|
||||||
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
||||||
PointerOffsetInstruction() {
|
PointerOffsetInstruction() {
|
||||||
opcode instanceof PointerOffsetOpcode
|
getOpcode() instanceof PointerOffsetOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointerAddInstruction extends PointerOffsetInstruction {
|
class PointerAddInstruction extends PointerOffsetInstruction {
|
||||||
PointerAddInstruction() {
|
PointerAddInstruction() {
|
||||||
opcode instanceof Opcode::PointerAdd
|
getOpcode() instanceof Opcode::PointerAdd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointerSubInstruction extends PointerOffsetInstruction {
|
class PointerSubInstruction extends PointerOffsetInstruction {
|
||||||
PointerSubInstruction() {
|
PointerSubInstruction() {
|
||||||
opcode instanceof Opcode::PointerSub
|
getOpcode() instanceof Opcode::PointerSub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
||||||
PointerDiffInstruction() {
|
PointerDiffInstruction() {
|
||||||
opcode instanceof Opcode::PointerDiff
|
getOpcode() instanceof Opcode::PointerDiff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnaryInstruction extends Instruction {
|
class UnaryInstruction extends Instruction {
|
||||||
UnaryInstruction() {
|
UnaryInstruction() {
|
||||||
opcode instanceof UnaryOpcode
|
getOpcode() instanceof UnaryOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getOperand() {
|
final Instruction getOperand() {
|
||||||
@@ -906,7 +955,7 @@ class UnaryInstruction extends Instruction {
|
|||||||
|
|
||||||
class ConvertInstruction extends UnaryInstruction {
|
class ConvertInstruction extends UnaryInstruction {
|
||||||
ConvertInstruction() {
|
ConvertInstruction() {
|
||||||
opcode instanceof Opcode::Convert
|
getOpcode() instanceof Opcode::Convert
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -958,7 +1007,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
|||||||
*/
|
*/
|
||||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||||
ConvertToBaseInstruction() {
|
ConvertToBaseInstruction() {
|
||||||
opcode instanceof Opcode::ConvertToBase
|
getOpcode() instanceof Opcode::ConvertToBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,7 +1017,7 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
|||||||
*/
|
*/
|
||||||
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
||||||
ConvertToVirtualBaseInstruction() {
|
ConvertToVirtualBaseInstruction() {
|
||||||
opcode instanceof Opcode::ConvertToVirtualBase
|
getOpcode() instanceof Opcode::ConvertToVirtualBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -978,37 +1027,37 @@ class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
|||||||
*/
|
*/
|
||||||
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
||||||
ConvertToDerivedInstruction() {
|
ConvertToDerivedInstruction() {
|
||||||
opcode instanceof Opcode::ConvertToDerived
|
getOpcode() instanceof Opcode::ConvertToDerived
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitComplementInstruction extends UnaryInstruction {
|
class BitComplementInstruction extends UnaryInstruction {
|
||||||
BitComplementInstruction() {
|
BitComplementInstruction() {
|
||||||
opcode instanceof Opcode::BitComplement
|
getOpcode() instanceof Opcode::BitComplement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LogicalNotInstruction extends UnaryInstruction {
|
class LogicalNotInstruction extends UnaryInstruction {
|
||||||
LogicalNotInstruction() {
|
LogicalNotInstruction() {
|
||||||
opcode instanceof Opcode::LogicalNot
|
getOpcode() instanceof Opcode::LogicalNot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompareInstruction extends BinaryInstruction {
|
class CompareInstruction extends BinaryInstruction {
|
||||||
CompareInstruction() {
|
CompareInstruction() {
|
||||||
opcode instanceof CompareOpcode
|
getOpcode() instanceof CompareOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompareEQInstruction extends CompareInstruction {
|
class CompareEQInstruction extends CompareInstruction {
|
||||||
CompareEQInstruction() {
|
CompareEQInstruction() {
|
||||||
opcode instanceof Opcode::CompareEQ
|
getOpcode() instanceof Opcode::CompareEQ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompareNEInstruction extends CompareInstruction {
|
class CompareNEInstruction extends CompareInstruction {
|
||||||
CompareNEInstruction() {
|
CompareNEInstruction() {
|
||||||
opcode instanceof Opcode::CompareNE
|
getOpcode() instanceof Opcode::CompareNE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,7 +1066,7 @@ class CompareNEInstruction extends CompareInstruction {
|
|||||||
*/
|
*/
|
||||||
class RelationalInstruction extends CompareInstruction {
|
class RelationalInstruction extends CompareInstruction {
|
||||||
RelationalInstruction() {
|
RelationalInstruction() {
|
||||||
opcode instanceof RelationalOpcode
|
getOpcode() instanceof RelationalOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1050,7 +1099,7 @@ class RelationalInstruction extends CompareInstruction {
|
|||||||
|
|
||||||
class CompareLTInstruction extends RelationalInstruction {
|
class CompareLTInstruction extends RelationalInstruction {
|
||||||
CompareLTInstruction() {
|
CompareLTInstruction() {
|
||||||
opcode instanceof Opcode::CompareLT
|
getOpcode() instanceof Opcode::CompareLT
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1068,7 +1117,7 @@ class CompareLTInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class CompareGTInstruction extends RelationalInstruction {
|
class CompareGTInstruction extends RelationalInstruction {
|
||||||
CompareGTInstruction() {
|
CompareGTInstruction() {
|
||||||
opcode instanceof Opcode::CompareGT
|
getOpcode() instanceof Opcode::CompareGT
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1086,7 +1135,7 @@ class CompareGTInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class CompareLEInstruction extends RelationalInstruction {
|
class CompareLEInstruction extends RelationalInstruction {
|
||||||
CompareLEInstruction() {
|
CompareLEInstruction() {
|
||||||
opcode instanceof Opcode::CompareLE
|
getOpcode() instanceof Opcode::CompareLE
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1104,7 +1153,7 @@ class CompareLEInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class CompareGEInstruction extends RelationalInstruction {
|
class CompareGEInstruction extends RelationalInstruction {
|
||||||
CompareGEInstruction() {
|
CompareGEInstruction() {
|
||||||
opcode instanceof Opcode::CompareGE
|
getOpcode() instanceof Opcode::CompareGE
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1122,7 +1171,7 @@ class CompareGEInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class SwitchInstruction extends Instruction {
|
class SwitchInstruction extends Instruction {
|
||||||
SwitchInstruction() {
|
SwitchInstruction() {
|
||||||
opcode instanceof Opcode::Switch
|
getOpcode() instanceof Opcode::Switch
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getExpression() {
|
final Instruction getExpression() {
|
||||||
@@ -1145,7 +1194,7 @@ class SwitchInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CallInstruction extends Instruction {
|
class CallInstruction extends Instruction {
|
||||||
CallInstruction() {
|
CallInstruction() {
|
||||||
opcode instanceof Opcode::Call
|
getOpcode() instanceof Opcode::Call
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1188,7 +1237,7 @@ class CallInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class SideEffectInstruction extends Instruction {
|
class SideEffectInstruction extends Instruction {
|
||||||
SideEffectInstruction() {
|
SideEffectInstruction() {
|
||||||
opcode instanceof SideEffectOpcode
|
getOpcode() instanceof SideEffectOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getPrimaryInstruction() {
|
final Instruction getPrimaryInstruction() {
|
||||||
@@ -1202,7 +1251,7 @@ class SideEffectInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallSideEffectInstruction() {
|
CallSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::CallSideEffect
|
getOpcode() instanceof Opcode::CallSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1216,7 +1265,7 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallReadSideEffectInstruction() {
|
CallReadSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::CallReadSideEffect
|
getOpcode() instanceof Opcode::CallReadSideEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1225,7 +1274,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
IndirectReadSideEffectInstruction() {
|
IndirectReadSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::IndirectReadSideEffect
|
getOpcode() instanceof Opcode::IndirectReadSideEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1234,7 +1283,7 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
BufferReadSideEffectInstruction() {
|
BufferReadSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::BufferReadSideEffect
|
getOpcode() instanceof Opcode::BufferReadSideEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1243,7 +1292,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
IndirectWriteSideEffectInstruction() {
|
IndirectWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::IndirectWriteSideEffect
|
getOpcode() instanceof Opcode::IndirectWriteSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1257,7 +1306,7 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
BufferWriteSideEffectInstruction() {
|
BufferWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::BufferWriteSideEffect
|
getOpcode() instanceof Opcode::BufferWriteSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1272,7 +1321,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
IndirectMayWriteSideEffectInstruction() {
|
IndirectMayWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::IndirectMayWriteSideEffect
|
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1286,7 +1335,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
BufferMayWriteSideEffectInstruction() {
|
BufferMayWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::BufferMayWriteSideEffect
|
getOpcode() instanceof Opcode::BufferMayWriteSideEffect
|
||||||
}
|
}
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
result instanceof BufferMayMemoryAccess
|
result instanceof BufferMayMemoryAccess
|
||||||
@@ -1298,7 +1347,7 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class ThrowInstruction extends Instruction {
|
class ThrowInstruction extends Instruction {
|
||||||
ThrowInstruction() {
|
ThrowInstruction() {
|
||||||
opcode instanceof ThrowOpcode
|
getOpcode() instanceof ThrowOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1307,7 +1356,7 @@ class ThrowInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class ThrowValueInstruction extends ThrowInstruction {
|
class ThrowValueInstruction extends ThrowInstruction {
|
||||||
ThrowValueInstruction() {
|
ThrowValueInstruction() {
|
||||||
opcode instanceof Opcode::ThrowValue
|
getOpcode() instanceof Opcode::ThrowValue
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1330,7 +1379,7 @@ class ThrowValueInstruction extends ThrowInstruction {
|
|||||||
*/
|
*/
|
||||||
class ReThrowInstruction extends ThrowInstruction {
|
class ReThrowInstruction extends ThrowInstruction {
|
||||||
ReThrowInstruction() {
|
ReThrowInstruction() {
|
||||||
opcode instanceof Opcode::ReThrow
|
getOpcode() instanceof Opcode::ReThrow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1339,7 +1388,7 @@ class ReThrowInstruction extends ThrowInstruction {
|
|||||||
*/
|
*/
|
||||||
class UnwindInstruction extends Instruction {
|
class UnwindInstruction extends Instruction {
|
||||||
UnwindInstruction() {
|
UnwindInstruction() {
|
||||||
opcode instanceof Opcode::Unwind
|
getOpcode() instanceof Opcode::Unwind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,7 +1397,7 @@ class UnwindInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CatchInstruction extends Instruction {
|
class CatchInstruction extends Instruction {
|
||||||
CatchInstruction() {
|
CatchInstruction() {
|
||||||
opcode instanceof CatchOpcode
|
getOpcode() instanceof CatchOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1359,7 +1408,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
|||||||
Type exceptionType;
|
Type exceptionType;
|
||||||
|
|
||||||
CatchByTypeInstruction() {
|
CatchByTypeInstruction() {
|
||||||
opcode instanceof Opcode::CatchByType and
|
getOpcode() instanceof Opcode::CatchByType and
|
||||||
exceptionType = Construction::getInstructionExceptionType(this)
|
exceptionType = Construction::getInstructionExceptionType(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,13 +1429,13 @@ class CatchByTypeInstruction extends CatchInstruction {
|
|||||||
*/
|
*/
|
||||||
class CatchAnyInstruction extends CatchInstruction {
|
class CatchAnyInstruction extends CatchInstruction {
|
||||||
CatchAnyInstruction() {
|
CatchAnyInstruction() {
|
||||||
opcode instanceof Opcode::CatchAny
|
getOpcode() instanceof Opcode::CatchAny
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnmodeledDefinitionInstruction extends Instruction {
|
class UnmodeledDefinitionInstruction extends Instruction {
|
||||||
UnmodeledDefinitionInstruction() {
|
UnmodeledDefinitionInstruction() {
|
||||||
opcode instanceof Opcode::UnmodeledDefinition
|
getOpcode() instanceof Opcode::UnmodeledDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1399,7 +1448,7 @@ class UnmodeledDefinitionInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class AliasedDefinitionInstruction extends Instruction {
|
class AliasedDefinitionInstruction extends Instruction {
|
||||||
AliasedDefinitionInstruction() {
|
AliasedDefinitionInstruction() {
|
||||||
opcode instanceof Opcode::AliasedDefinition
|
getOpcode() instanceof Opcode::AliasedDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1409,7 +1458,7 @@ class AliasedDefinitionInstruction extends Instruction {
|
|||||||
|
|
||||||
class UnmodeledUseInstruction extends Instruction {
|
class UnmodeledUseInstruction extends Instruction {
|
||||||
UnmodeledUseInstruction() {
|
UnmodeledUseInstruction() {
|
||||||
opcode instanceof Opcode::UnmodeledUse
|
getOpcode() instanceof Opcode::UnmodeledUse
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getOperandsString() {
|
override string getOperandsString() {
|
||||||
@@ -1429,7 +1478,7 @@ class UnmodeledUseInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class PhiInstruction extends Instruction {
|
class PhiInstruction extends Instruction {
|
||||||
PhiInstruction() {
|
PhiInstruction() {
|
||||||
opcode instanceof Opcode::Phi
|
getOpcode() instanceof Opcode::Phi
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1481,7 +1530,7 @@ class PhiInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class ChiInstruction extends Instruction {
|
class ChiInstruction extends Instruction {
|
||||||
ChiInstruction() {
|
ChiInstruction() {
|
||||||
opcode instanceof Opcode::Chi
|
getOpcode() instanceof Opcode::Chi
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1511,7 +1560,7 @@ class ChiInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class UnreachedInstruction extends Instruction {
|
class UnreachedInstruction extends Instruction {
|
||||||
UnreachedInstruction() {
|
UnreachedInstruction() {
|
||||||
opcode instanceof Opcode::Unreached
|
getOpcode() instanceof Opcode::Unreached
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1521,6 +1570,6 @@ class UnreachedInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class BuiltInInstruction extends Instruction {
|
class BuiltInInstruction extends Instruction {
|
||||||
BuiltInInstruction() {
|
BuiltInInstruction() {
|
||||||
opcode instanceof BuiltInOpcode
|
getOpcode() instanceof BuiltInOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,7 +287,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
|||||||
(
|
(
|
||||||
(
|
(
|
||||||
key = "semmle.label" and
|
key = "semmle.label" and
|
||||||
value = kind.toString()
|
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||||
|
then value = kind.toString() + " (back edge)"
|
||||||
|
else value = kind.toString()
|
||||||
) or
|
) or
|
||||||
(
|
(
|
||||||
key = "semmle.order" and
|
key = "semmle.order" and
|
||||||
|
|||||||
@@ -5,30 +5,15 @@ private import semmle.code.cpp.ir.internal.TempVariableTag
|
|||||||
private import InstructionTag
|
private import InstructionTag
|
||||||
private import TranslatedElement
|
private import TranslatedElement
|
||||||
private import TranslatedExpr
|
private import TranslatedExpr
|
||||||
|
private import TranslatedStmt
|
||||||
private import TranslatedFunction
|
private import TranslatedFunction
|
||||||
|
|
||||||
class InstructionTagType extends TInstructionTag {
|
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
|
||||||
final string toString() {
|
instruction = MkInstruction(result, _)
|
||||||
result = "Tag"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedElement getInstructionTranslatedElement(
|
InstructionTag getInstructionTag(Instruction instruction) {
|
||||||
Instruction instruction) {
|
instruction = MkInstruction(_, result)
|
||||||
result = getInstructionTranslatedElementAndTag(instruction, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
private TranslatedElement getInstructionTranslatedElementAndTag(
|
|
||||||
Instruction instruction, InstructionTag tag) {
|
|
||||||
result.getAST() = instruction.getAST() and
|
|
||||||
tag = instruction.getTag() and
|
|
||||||
result.hasInstruction(_, tag, _, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
private TranslatedElement getTempVariableTranslatedElement(
|
|
||||||
IRTempVariable var) {
|
|
||||||
result.getAST() = var.getAST() and
|
|
||||||
result.hasTempVariable(var.getTag(), _)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
import Cached
|
import Cached
|
||||||
@@ -38,21 +23,10 @@ cached private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached newtype TInstruction =
|
cached newtype TInstruction =
|
||||||
MkInstruction(FunctionIR funcIR, Opcode opcode, Locatable ast,
|
MkInstruction(TranslatedElement element, InstructionTag tag) {
|
||||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
element.hasInstruction(_, tag, _, _)
|
||||||
hasInstruction(funcIR.getFunction(), opcode, ast, tag,
|
|
||||||
resultType, isGLValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate hasInstruction(Function func, Opcode opcode, Locatable ast,
|
|
||||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
|
||||||
exists(TranslatedElement element |
|
|
||||||
element.getAST() = ast and
|
|
||||||
func = element.getFunction() and
|
|
||||||
element.hasInstruction(opcode, tag, resultType, isGLValue)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
||||||
Type type) {
|
Type type) {
|
||||||
exists(TranslatedElement element |
|
exists(TranslatedElement element |
|
||||||
@@ -87,7 +61,7 @@ cached private module Cached {
|
|||||||
|
|
||||||
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
|
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
|
||||||
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
|
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
|
||||||
instruction.getTag(), tag)
|
getInstructionTag(instruction), tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached Instruction getPhiInstructionOperandDefinition(Instruction instruction,
|
cached Instruction getPhiInstructionOperandDefinition(Instruction instruction,
|
||||||
@@ -101,12 +75,112 @@ cached private module Cached {
|
|||||||
|
|
||||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||||
result = getInstructionTranslatedElement(instruction).getInstructionSuccessor(
|
result = getInstructionTranslatedElement(instruction).getInstructionSuccessor(
|
||||||
instruction.getTag(), kind)
|
getInstructionTag(instruction), kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This predicate has pragma[noopt] because otherwise the `getAChild*` calls
|
||||||
|
// get joined too early. The join order for the loop cases goes like this:
|
||||||
|
// - Find all loops of that type (tens of thousands).
|
||||||
|
// - Find all edges into the start of the loop (x 2).
|
||||||
|
// - Restrict to edges that originate within the loop (/ 2).
|
||||||
|
pragma[noopt]
|
||||||
|
cached Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||||
|
// While loop:
|
||||||
|
// Any edge from within the body of the loop to the condition of the loop
|
||||||
|
// is a back edge. This includes edges from `continue` and the fall-through
|
||||||
|
// edge(s) after the last instruction(s) in the body.
|
||||||
|
exists(TranslatedWhileStmt s |
|
||||||
|
s instanceof TranslatedWhileStmt and
|
||||||
|
result = s.getFirstConditionInstruction() and
|
||||||
|
exists(TranslatedElement inBody, InstructionTag tag |
|
||||||
|
result = inBody.getInstructionSuccessor(tag, kind) and
|
||||||
|
exists(TranslatedElement body | body = s.getBody() | inBody = body.getAChild*()) and
|
||||||
|
instruction = inBody.getInstruction(tag)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Do-while loop:
|
||||||
|
// The back edge should be the edge(s) from the condition to the
|
||||||
|
// body. This ensures that it's the back edge that will be pruned in a `do
|
||||||
|
// { ... } while (0)` statement. Note that all `continue` statements in a
|
||||||
|
// do-while loop produce forward edges.
|
||||||
|
exists(TranslatedDoStmt s |
|
||||||
|
s instanceof TranslatedDoStmt and
|
||||||
|
exists(TranslatedStmt body | body = s.getBody() | result = body.getFirstInstruction()) and
|
||||||
|
exists(TranslatedElement inCondition, InstructionTag tag |
|
||||||
|
result = inCondition.getInstructionSuccessor(tag, kind) and
|
||||||
|
exists(TranslatedElement condition | condition = s.getCondition() |
|
||||||
|
inCondition = condition.getAChild*()
|
||||||
|
) and
|
||||||
|
instruction = inCondition.getInstruction(tag)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// For loop:
|
||||||
|
// Any edge from within the body or update of the loop to the condition of
|
||||||
|
// the loop is a back edge. When there is no loop update expression, this
|
||||||
|
// includes edges from `continue` and the fall-through edge(s) after the
|
||||||
|
// last instruction(s) in the body. A for loop may not have a condition, in
|
||||||
|
// which case `getFirstConditionInstruction` returns the body instead.
|
||||||
|
exists(TranslatedForStmt s |
|
||||||
|
s instanceof TranslatedForStmt and
|
||||||
|
result = s.getFirstConditionInstruction() and
|
||||||
|
exists(TranslatedElement inLoop, InstructionTag tag |
|
||||||
|
result = inLoop.getInstructionSuccessor(tag, kind) and
|
||||||
|
exists(TranslatedElement bodyOrUpdate |
|
||||||
|
bodyOrUpdate = s.getBody()
|
||||||
|
or
|
||||||
|
bodyOrUpdate = s.getUpdate()
|
||||||
|
|
|
||||||
|
inLoop = bodyOrUpdate.getAChild*()
|
||||||
|
) and
|
||||||
|
instruction = inLoop.getInstruction(tag)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Goto statement:
|
||||||
|
// As a conservative approximation, any edge out of `goto` is a back edge
|
||||||
|
// unless it goes strictly forward in the program text. A `goto` whose
|
||||||
|
// source and target are both inside a macro will be seen as having the
|
||||||
|
// same location for source and target, so we conservatively assume that
|
||||||
|
// such a `goto` creates a back edge.
|
||||||
|
exists(TranslatedElement s, GotoStmt goto |
|
||||||
|
goto instanceof GotoStmt and
|
||||||
|
not isStrictlyForwardGoto(goto) and
|
||||||
|
goto = s.getAST() and
|
||||||
|
exists(InstructionTag tag |
|
||||||
|
result = s.getInstructionSuccessor(tag, kind) and
|
||||||
|
instruction = s.getInstruction(tag)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `goto` jumps strictly forward in the program text. */
|
||||||
|
private predicate isStrictlyForwardGoto(GotoStmt goto) {
|
||||||
|
goto.getLocation().isBefore(goto.getTarget().getLocation())
|
||||||
|
}
|
||||||
|
|
||||||
|
cached Locatable getInstructionAST(Instruction instruction) {
|
||||||
|
result = getInstructionTranslatedElement(instruction).getAST()
|
||||||
|
}
|
||||||
|
|
||||||
|
cached predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
|
||||||
|
getInstructionTranslatedElement(instruction)
|
||||||
|
.hasInstruction(_, getInstructionTag(instruction), type, isGLValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached Opcode getInstructionOpcode(Instruction instruction) {
|
||||||
|
getInstructionTranslatedElement(instruction)
|
||||||
|
.hasInstruction(result, getInstructionTag(instruction), _, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached FunctionIR getInstructionEnclosingFunctionIR(Instruction instruction) {
|
||||||
|
result.getFunction() = getInstructionTranslatedElement(instruction).getFunction()
|
||||||
}
|
}
|
||||||
|
|
||||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||||
result = getInstructionTranslatedElement(instruction).getInstructionVariable(
|
result = getInstructionTranslatedElement(instruction).getInstructionVariable(
|
||||||
instruction.getTag())
|
getInstructionTag(instruction))
|
||||||
}
|
}
|
||||||
|
|
||||||
cached Field getInstructionField(Instruction instruction) {
|
cached Field getInstructionField(Instruction instruction) {
|
||||||
@@ -117,41 +191,39 @@ cached private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached Function getInstructionFunction(Instruction instruction) {
|
cached Function getInstructionFunction(Instruction instruction) {
|
||||||
exists(InstructionTag tag |
|
result = getInstructionTranslatedElement(instruction)
|
||||||
result = getInstructionTranslatedElementAndTag(instruction, tag)
|
.getInstructionFunction(getInstructionTag(instruction))
|
||||||
.getInstructionFunction(tag)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached string getInstructionConstantValue(Instruction instruction) {
|
cached string getInstructionConstantValue(Instruction instruction) {
|
||||||
result =
|
result =
|
||||||
getInstructionTranslatedElement(instruction).getInstructionConstantValue(
|
getInstructionTranslatedElement(instruction).getInstructionConstantValue(
|
||||||
instruction.getTag())
|
getInstructionTag(instruction))
|
||||||
}
|
}
|
||||||
|
|
||||||
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||||
result =
|
result =
|
||||||
getInstructionTranslatedElement(instruction).getInstructionStringLiteral(
|
getInstructionTranslatedElement(instruction).getInstructionStringLiteral(
|
||||||
instruction.getTag())
|
getInstructionTag(instruction))
|
||||||
}
|
}
|
||||||
|
|
||||||
cached Type getInstructionExceptionType(Instruction instruction) {
|
cached Type getInstructionExceptionType(Instruction instruction) {
|
||||||
result =
|
result =
|
||||||
getInstructionTranslatedElement(instruction).getInstructionExceptionType(
|
getInstructionTranslatedElement(instruction).getInstructionExceptionType(
|
||||||
instruction.getTag())
|
getInstructionTag(instruction))
|
||||||
}
|
}
|
||||||
|
|
||||||
cached predicate getInstructionInheritance(Instruction instruction,
|
cached predicate getInstructionInheritance(Instruction instruction,
|
||||||
Class baseClass, Class derivedClass) {
|
Class baseClass, Class derivedClass) {
|
||||||
getInstructionTranslatedElement(instruction).getInstructionInheritance(
|
getInstructionTranslatedElement(instruction).getInstructionInheritance(
|
||||||
instruction.getTag(), baseClass, derivedClass)
|
getInstructionTag(instruction), baseClass, derivedClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate instructionOrigin(Instruction instruction,
|
private predicate instructionOrigin(Instruction instruction,
|
||||||
TranslatedElement element, InstructionTag tag) {
|
TranslatedElement element, InstructionTag tag) {
|
||||||
element = getInstructionTranslatedElement(instruction) and
|
element = getInstructionTranslatedElement(instruction) and
|
||||||
tag = instruction.getTag()
|
tag = getInstructionTag(instruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached int getInstructionElementSize(Instruction instruction) {
|
cached int getInstructionElementSize(Instruction instruction) {
|
||||||
@@ -179,12 +251,14 @@ cached private module Cached {
|
|||||||
import CachedForDebugging
|
import CachedForDebugging
|
||||||
cached private module CachedForDebugging {
|
cached private module CachedForDebugging {
|
||||||
cached string getTempVariableUniqueId(IRTempVariable var) {
|
cached string getTempVariableUniqueId(IRTempVariable var) {
|
||||||
result = getTempVariableTranslatedElement(var).getId() + ":" +
|
exists(TranslatedElement element |
|
||||||
getTempVariableTagId(var.getTag())
|
var = element.getTempVariable(_) and
|
||||||
|
result = element.getId() + ":" + getTempVariableTagId(var.getTag())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached string getInstructionUniqueId(Instruction instruction) {
|
cached string getInstructionUniqueId(Instruction instruction) {
|
||||||
result = getInstructionTranslatedElement(instruction).getId() + ":" +
|
result = getInstructionTranslatedElement(instruction).getId() + ":" +
|
||||||
getInstructionTagId(instruction.getTag())
|
getInstructionTagId(getInstructionTag(instruction))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,12 @@ newtype TInstructionTag =
|
|||||||
elementIsInitialized(elementIndex)
|
elementIsInitialized(elementIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InstructionTag extends TInstructionTag {
|
||||||
|
final string toString() {
|
||||||
|
result = "Tag"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a unique string for the instruction tag. Primarily used for generating
|
* Gets a unique string for the instruction tag. Primarily used for generating
|
||||||
* instruction IDs to ensure stable IR dumps.
|
* instruction IDs to ensure stable IR dumps.
|
||||||
|
|||||||
@@ -255,26 +255,22 @@ abstract class TranslatedDirectCall extends TranslatedCall {
|
|||||||
*/
|
*/
|
||||||
abstract class TranslatedCallExpr extends TranslatedNonConstantExpr,
|
abstract class TranslatedCallExpr extends TranslatedNonConstantExpr,
|
||||||
TranslatedCall {
|
TranslatedCall {
|
||||||
Call call;
|
override Call expr;
|
||||||
|
|
||||||
TranslatedCallExpr() {
|
|
||||||
expr = call
|
|
||||||
}
|
|
||||||
|
|
||||||
override final Type getCallResultType() {
|
override final Type getCallResultType() {
|
||||||
result = getResultType()
|
result = getResultType()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final predicate hasArguments() {
|
override final predicate hasArguments() {
|
||||||
exists(call.getArgument(0))
|
exists(expr.getArgument(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
override final TranslatedExpr getQualifier() {
|
override final TranslatedExpr getQualifier() {
|
||||||
result = getTranslatedExpr(call.getQualifier().getFullyConverted())
|
result = getTranslatedExpr(expr.getQualifier().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
override final TranslatedExpr getArgument(int index) {
|
override final TranslatedExpr getArgument(int index) {
|
||||||
result = getTranslatedExpr(call.getArgument(index).getFullyConverted())
|
result = getTranslatedExpr(expr.getArgument(index).getFullyConverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,14 +278,11 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr,
|
|||||||
* Represents the IR translation of a call through a function pointer.
|
* Represents the IR translation of a call through a function pointer.
|
||||||
*/
|
*/
|
||||||
class TranslatedExprCall extends TranslatedCallExpr {
|
class TranslatedExprCall extends TranslatedCallExpr {
|
||||||
ExprCall exprCall;
|
override ExprCall expr;
|
||||||
|
|
||||||
TranslatedExprCall() {
|
|
||||||
expr = exprCall
|
|
||||||
}
|
|
||||||
|
|
||||||
override TranslatedExpr getCallTarget() {
|
override TranslatedExpr getCallTarget() {
|
||||||
result = getTranslatedExpr(exprCall.getExpr().getFullyConverted())
|
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,22 +290,18 @@ class TranslatedExprCall extends TranslatedCallExpr {
|
|||||||
* Represents the IR translation of a direct function call.
|
* Represents the IR translation of a direct function call.
|
||||||
*/
|
*/
|
||||||
class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
|
class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
|
||||||
FunctionCall funcCall;
|
override FunctionCall expr;
|
||||||
|
|
||||||
TranslatedFunctionCall() {
|
|
||||||
expr = funcCall
|
|
||||||
}
|
|
||||||
|
|
||||||
override Function getInstructionFunction(InstructionTag tag) {
|
override Function getInstructionFunction(InstructionTag tag) {
|
||||||
tag = CallTargetTag() and result = funcCall.getTarget()
|
tag = CallTargetTag() and result = expr.getTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasReadSideEffect() {
|
override predicate hasReadSideEffect() {
|
||||||
not funcCall.getTarget().(SideEffectFunction).neverReadsMemory()
|
not expr.getTarget().(SideEffectFunction).neverReadsMemory()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasWriteSideEffect() {
|
override predicate hasWriteSideEffect() {
|
||||||
not funcCall.getTarget().(SideEffectFunction).neverWritesMemory()
|
not expr.getTarget().(SideEffectFunction).neverWritesMemory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,8 +310,8 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
|
|||||||
*/
|
*/
|
||||||
class TranslatedStructorCall extends TranslatedFunctionCall {
|
class TranslatedStructorCall extends TranslatedFunctionCall {
|
||||||
TranslatedStructorCall() {
|
TranslatedStructorCall() {
|
||||||
funcCall instanceof ConstructorCall or
|
expr instanceof ConstructorCall or
|
||||||
funcCall instanceof DestructorCall
|
expr instanceof DestructorCall
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getQualifierResult() {
|
override Instruction getQualifierResult() {
|
||||||
|
|||||||
@@ -75,11 +75,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition,
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
||||||
ParenthesisExpr paren;
|
override ParenthesisExpr expr;
|
||||||
|
|
||||||
TranslatedParenthesisCondition() {
|
|
||||||
paren = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||||
child = getOperand() and
|
child = getOperand() and
|
||||||
@@ -92,16 +88,12 @@ class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final override TranslatedCondition getOperand() {
|
final override TranslatedCondition getOperand() {
|
||||||
result = getTranslatedCondition(paren.getExpr())
|
result = getTranslatedCondition(expr.getExpr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedNotCondition extends TranslatedFlexibleCondition {
|
class TranslatedNotCondition extends TranslatedFlexibleCondition {
|
||||||
NotExpr notExpr;
|
override NotExpr expr;
|
||||||
|
|
||||||
TranslatedNotCondition() {
|
|
||||||
notExpr = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||||
child = getOperand() and
|
child = getOperand() and
|
||||||
@@ -114,7 +106,7 @@ class TranslatedNotCondition extends TranslatedFlexibleCondition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override TranslatedCondition getOperand() {
|
override TranslatedCondition getOperand() {
|
||||||
result = getTranslatedCondition(notExpr.getOperand().getFullyConverted())
|
result = getTranslatedCondition(expr.getOperand().getFullyConverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,11 +123,7 @@ abstract class TranslatedNativeCondition extends TranslatedCondition,
|
|||||||
|
|
||||||
abstract class TranslatedBinaryLogicalOperation extends
|
abstract class TranslatedBinaryLogicalOperation extends
|
||||||
TranslatedNativeCondition, ConditionContext {
|
TranslatedNativeCondition, ConditionContext {
|
||||||
BinaryLogicalOperation op;
|
override BinaryLogicalOperation expr;
|
||||||
|
|
||||||
TranslatedBinaryLogicalOperation() {
|
|
||||||
op = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final TranslatedElement getChild(int id) {
|
override final TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = getLeftOperand() or
|
id = 0 and result = getLeftOperand() or
|
||||||
@@ -157,17 +145,17 @@ abstract class TranslatedBinaryLogicalOperation extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
final TranslatedCondition getLeftOperand() {
|
final TranslatedCondition getLeftOperand() {
|
||||||
result = getTranslatedCondition(op.getLeftOperand().getFullyConverted())
|
result = getTranslatedCondition(expr.getLeftOperand().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
final TranslatedCondition getRightOperand() {
|
final TranslatedCondition getRightOperand() {
|
||||||
result = getTranslatedCondition(op.getRightOperand().getFullyConverted())
|
result = getTranslatedCondition(expr.getRightOperand().getFullyConverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
|
class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
|
||||||
TranslatedLogicalAndExpr() {
|
TranslatedLogicalAndExpr() {
|
||||||
op instanceof LogicalAndExpr
|
expr instanceof LogicalAndExpr
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||||
@@ -188,9 +176,7 @@ class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
|
class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
|
||||||
TranslatedLogicalOrExpr() {
|
override LogicalOrExpr expr;
|
||||||
op instanceof LogicalOrExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||||
(child = getLeftOperand() or child = getRightOperand()) and
|
(child = getLeftOperand() or child = getRightOperand()) and
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ private import InstructionTag
|
|||||||
private import TranslatedCondition
|
private import TranslatedCondition
|
||||||
private import TranslatedFunction
|
private import TranslatedFunction
|
||||||
private import TranslatedStmt
|
private import TranslatedStmt
|
||||||
|
private import IRConstruction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the built-in `int` type.
|
* Gets the built-in `int` type.
|
||||||
@@ -17,53 +18,42 @@ Type getIntType() {
|
|||||||
result.(IntType).isImplicitlySigned()
|
result.(IntType).isImplicitlySigned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If `expr` is a conversion, gets the expression being converted. Otherwise,
|
|
||||||
* returns `expr`.
|
|
||||||
*/
|
|
||||||
private Expr getUnconvertedExpr(Expr expr) {
|
|
||||||
if expr instanceof Conversion then (
|
|
||||||
result = getUnconvertedExpr(expr.(Conversion).getExpr())
|
|
||||||
) else (
|
|
||||||
result = expr
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the "real" parent of `expr`. This predicate treats conversions as if
|
* Gets the "real" parent of `expr`. This predicate treats conversions as if
|
||||||
* they were explicit nodes in the expression tree, rather than as implicit
|
* they were explicit nodes in the expression tree, rather than as implicit
|
||||||
* nodes as in the regular AST representation.
|
* nodes as in the regular AST representation.
|
||||||
*/
|
*/
|
||||||
private Element getRealParent(Expr expr) {
|
private Element getRealParent(Expr expr) {
|
||||||
if expr.hasConversion() then (
|
result = expr.getParentWithConversions()
|
||||||
// The expression has a conversion, so treat that as its parent
|
or
|
||||||
result = expr.getConversion()
|
result.(Destructor).getADestruction() = expr
|
||||||
)
|
|
||||||
else (
|
|
||||||
// Either the expression is a top-level conversion, or it's not a
|
|
||||||
// conversion. The real parent is the parent of the original unconverted
|
|
||||||
// expression.
|
|
||||||
result = getUnconvertedExpr(expr).getParent() or
|
|
||||||
// The parent of a DestructorDestruction is the destructor itself.
|
|
||||||
result.(Destructor).getADestruction() = expr
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `expr` and all of its descendants should be ignored for the purposes
|
* Holds if `expr` is a constant of a type that can be replaced directly with
|
||||||
* of IR generation due to some property of `expr` itself. Unlike
|
* its value in the IR. This does not include address constants as we have no
|
||||||
* `ignoreExpr()`, this predicate does not ignore an expression solely because
|
* means to express those as QL values.
|
||||||
* it is a descendant of an ignored element.
|
*/
|
||||||
|
predicate isIRConstant(Expr expr) { exists(expr.getValue()) }
|
||||||
|
|
||||||
|
// Pulled out to work around QL-796
|
||||||
|
private predicate isOrphan(Expr expr) {
|
||||||
|
not exists(getRealParent(expr))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `expr` should be ignored for the purposes of IR generation due to
|
||||||
|
* some property of `expr` or one of its ancestors.
|
||||||
*/
|
*/
|
||||||
private predicate ignoreExprAndDescendants(Expr expr) {
|
private predicate ignoreExprAndDescendants(Expr expr) {
|
||||||
// Ignore parentless expressions
|
// Ignore parentless expressions
|
||||||
not exists(getRealParent(expr)) or
|
isOrphan(expr) or
|
||||||
// Ignore the constants in SwitchCase, since their values are embedded in the
|
// Ignore the constants in SwitchCase, since their values are embedded in the
|
||||||
// CaseEdge.
|
// CaseEdge.
|
||||||
getRealParent(expr) instanceof SwitchCase or
|
getRealParent(expr) instanceof SwitchCase or
|
||||||
// Ignore descendants of constant expressions, since we'll just substitute the
|
// Ignore descendants of constant expressions, since we'll just substitute the
|
||||||
// constant value.
|
// constant value.
|
||||||
getRealParent(expr).(Expr).isConstant() or
|
isIRConstant(getRealParent(expr)) or
|
||||||
// The `DestructorCall` node for a `DestructorFieldDestruction` has a `FieldAccess`
|
// The `DestructorCall` node for a `DestructorFieldDestruction` has a `FieldAccess`
|
||||||
// node as its qualifier, but that `FieldAccess` does not have a child of its own.
|
// node as its qualifier, but that `FieldAccess` does not have a child of its own.
|
||||||
// We'll ignore that `FieldAccess`, and supply the receiver as part of the calling
|
// We'll ignore that `FieldAccess`, and supply the receiver as part of the calling
|
||||||
@@ -73,7 +63,8 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
|||||||
// REVIEW: Ignore initializers for `NewArrayExpr` until we determine how to
|
// REVIEW: Ignore initializers for `NewArrayExpr` until we determine how to
|
||||||
// represent them.
|
// represent them.
|
||||||
newExpr.getInitializer().getFullyConverted() = expr
|
newExpr.getInitializer().getFullyConverted() = expr
|
||||||
)
|
) or
|
||||||
|
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,7 +85,7 @@ private predicate ignoreExprOnly(Expr expr) {
|
|||||||
*/
|
*/
|
||||||
private predicate ignoreExpr(Expr expr) {
|
private predicate ignoreExpr(Expr expr) {
|
||||||
ignoreExprOnly(expr) or
|
ignoreExprOnly(expr) or
|
||||||
ignoreExprAndDescendants(getRealParent*(expr))
|
ignoreExprAndDescendants(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,7 +137,7 @@ private predicate translateStmt(Stmt stmt) {
|
|||||||
*/
|
*/
|
||||||
private predicate isNativeCondition(Expr expr) {
|
private predicate isNativeCondition(Expr expr) {
|
||||||
expr instanceof BinaryLogicalOperation and
|
expr instanceof BinaryLogicalOperation and
|
||||||
not expr.isConstant()
|
not isIRConstant(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,7 +150,7 @@ private predicate isFlexibleCondition(Expr expr) {
|
|||||||
expr instanceof NotExpr
|
expr instanceof NotExpr
|
||||||
) and
|
) and
|
||||||
usedAsCondition(expr) and
|
usedAsCondition(expr) and
|
||||||
not expr.isConstant()
|
not isIRConstant(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -637,8 +628,8 @@ abstract class TranslatedElement extends TTranslatedElement {
|
|||||||
* Gets the instruction generated by this element with tag `tag`.
|
* Gets the instruction generated by this element with tag `tag`.
|
||||||
*/
|
*/
|
||||||
final Instruction getInstruction(InstructionTag tag) {
|
final Instruction getInstruction(InstructionTag tag) {
|
||||||
result.getAST() = getAST() and
|
getInstructionTranslatedElement(result) = this and
|
||||||
result.getTag() = tag
|
getInstructionTag(result) = tag
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -646,7 +637,8 @@ abstract class TranslatedElement extends TTranslatedElement {
|
|||||||
*/
|
*/
|
||||||
final IRTempVariable getTempVariable(TempVariableTag tag) {
|
final IRTempVariable getTempVariable(TempVariableTag tag) {
|
||||||
result.getAST() = getAST() and
|
result.getAST() = getAST() and
|
||||||
result.getTag() = tag
|
result.getTag() = tag and
|
||||||
|
hasTempVariable(tag, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -369,11 +369,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedCommaExpr extends TranslatedNonConstantExpr {
|
class TranslatedCommaExpr extends TranslatedNonConstantExpr {
|
||||||
CommaExpr comma;
|
override CommaExpr expr;
|
||||||
|
|
||||||
TranslatedCommaExpr() {
|
|
||||||
comma = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getFirstInstruction() {
|
override Instruction getFirstInstruction() {
|
||||||
result = getLeftOperand().getFirstInstruction()
|
result = getLeftOperand().getFirstInstruction()
|
||||||
@@ -412,20 +408,16 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getLeftOperand() {
|
private TranslatedExpr getLeftOperand() {
|
||||||
result = getTranslatedExpr(comma.getLeftOperand().getFullyConverted())
|
result = getTranslatedExpr(expr.getLeftOperand().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getRightOperand() {
|
private TranslatedExpr getRightOperand() {
|
||||||
result = getTranslatedExpr(comma.getRightOperand().getFullyConverted())
|
result = getTranslatedExpr(expr.getRightOperand().getFullyConverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||||
CrementOperation op;
|
override CrementOperation expr;
|
||||||
|
|
||||||
TranslatedCrementOperation() {
|
|
||||||
op = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final TranslatedElement getChild(int id) {
|
override final TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = getOperand()
|
id = 0 and result = getOperand()
|
||||||
@@ -564,7 +556,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final TranslatedExpr getOperand() {
|
final TranslatedExpr getOperand() {
|
||||||
result = getTranslatedExpr(op.getOperand().getFullyConverted())
|
result = getTranslatedExpr(expr.getOperand().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
final Opcode getOpcode() {
|
final Opcode getOpcode() {
|
||||||
@@ -572,14 +564,14 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
|||||||
resultType = getResultType() and
|
resultType = getResultType() and
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
op instanceof IncrementOperation and
|
expr instanceof IncrementOperation and
|
||||||
if resultType instanceof PointerType then
|
if resultType instanceof PointerType then
|
||||||
result instanceof Opcode::PointerAdd
|
result instanceof Opcode::PointerAdd
|
||||||
else
|
else
|
||||||
result instanceof Opcode::Add
|
result instanceof Opcode::Add
|
||||||
) or
|
) or
|
||||||
(
|
(
|
||||||
op instanceof DecrementOperation and
|
expr instanceof DecrementOperation and
|
||||||
if resultType instanceof PointerType then
|
if resultType instanceof PointerType then
|
||||||
result instanceof Opcode::PointerSub
|
result instanceof Opcode::PointerSub
|
||||||
else
|
else
|
||||||
@@ -591,9 +583,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedPrefixCrementOperation extends TranslatedCrementOperation {
|
class TranslatedPrefixCrementOperation extends TranslatedCrementOperation {
|
||||||
TranslatedPrefixCrementOperation() {
|
override PrefixCrementOperation expr;
|
||||||
op instanceof PrefixCrementOperation
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getResult() {
|
override Instruction getResult() {
|
||||||
if expr.isPRValueCategory() then (
|
if expr.isPRValueCategory() then (
|
||||||
@@ -612,9 +602,7 @@ class TranslatedPrefixCrementOperation extends TranslatedCrementOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedPostfixCrementOperation extends TranslatedCrementOperation {
|
class TranslatedPostfixCrementOperation extends TranslatedCrementOperation {
|
||||||
TranslatedPostfixCrementOperation() {
|
override PostfixCrementOperation expr;
|
||||||
op instanceof PostfixCrementOperation
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getResult() {
|
override Instruction getResult() {
|
||||||
// The result is a prvalue copy of the original value
|
// The result is a prvalue copy of the original value
|
||||||
@@ -623,11 +611,7 @@ class TranslatedPostfixCrementOperation extends TranslatedCrementOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
||||||
ArrayExpr arrayExpr;
|
override ArrayExpr expr;
|
||||||
|
|
||||||
TranslatedArrayExpr() {
|
|
||||||
arrayExpr = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getFirstInstruction() {
|
override Instruction getFirstInstruction() {
|
||||||
result = getBaseOperand().getFirstInstruction()
|
result = getBaseOperand().getFirstInstruction()
|
||||||
@@ -689,11 +673,11 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getBaseOperand() {
|
private TranslatedExpr getBaseOperand() {
|
||||||
result = getTranslatedExpr(arrayExpr.getArrayBase().getFullyConverted())
|
result = getTranslatedExpr(expr.getArrayBase().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getOffsetOperand() {
|
private TranslatedExpr getOffsetOperand() {
|
||||||
result = getTranslatedExpr(arrayExpr.getArrayOffset().getFullyConverted())
|
result = getTranslatedExpr(expr.getArrayOffset().getFullyConverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,10 +717,9 @@ abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedTransparentUnaryOperation extends TranslatedTransparentExpr {
|
class TranslatedTransparentUnaryOperation extends TranslatedTransparentExpr {
|
||||||
UnaryOperation op;
|
override UnaryOperation expr;
|
||||||
|
|
||||||
TranslatedTransparentUnaryOperation() {
|
TranslatedTransparentUnaryOperation() {
|
||||||
op = expr and
|
|
||||||
(
|
(
|
||||||
// *p is the same as p until the result is loaded.
|
// *p is the same as p until the result is loaded.
|
||||||
expr instanceof PointerDereferenceExpr or
|
expr instanceof PointerDereferenceExpr or
|
||||||
@@ -747,31 +730,28 @@ class TranslatedTransparentUnaryOperation extends TranslatedTransparentExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override TranslatedExpr getOperand() {
|
override TranslatedExpr getOperand() {
|
||||||
result = getTranslatedExpr(op.getOperand().getFullyConverted())
|
result = getTranslatedExpr(expr.getOperand().getFullyConverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedTransparentConversion extends TranslatedTransparentExpr {
|
class TranslatedTransparentConversion extends TranslatedTransparentExpr {
|
||||||
Conversion conv;
|
override Conversion expr;
|
||||||
|
|
||||||
TranslatedTransparentConversion() {
|
TranslatedTransparentConversion() {
|
||||||
conv = expr and
|
|
||||||
(
|
(
|
||||||
conv instanceof ParenthesisExpr or
|
expr instanceof ParenthesisExpr or
|
||||||
conv instanceof ReferenceDereferenceExpr or
|
expr instanceof ReferenceDereferenceExpr or
|
||||||
conv instanceof ReferenceToExpr
|
expr instanceof ReferenceToExpr
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override TranslatedExpr getOperand() {
|
override TranslatedExpr getOperand() {
|
||||||
result = getTranslatedExpr(conv.getExpr())
|
result = getTranslatedExpr(expr.getExpr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedThisExpr extends TranslatedNonConstantExpr {
|
class TranslatedThisExpr extends TranslatedNonConstantExpr {
|
||||||
TranslatedThisExpr() {
|
override ThisExpr expr;
|
||||||
expr instanceof ThisExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final TranslatedElement getChild(int id) {
|
override final TranslatedElement getChild(int id) {
|
||||||
none()
|
none()
|
||||||
@@ -817,18 +797,14 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr {
|
abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr {
|
||||||
VariableAccess access;
|
override VariableAccess expr;
|
||||||
|
|
||||||
TranslatedVariableAccess() {
|
|
||||||
access = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final TranslatedElement getChild(int id) {
|
override final TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = getQualifier() // Might not exist
|
id = 0 and result = getQualifier() // Might not exist
|
||||||
}
|
}
|
||||||
|
|
||||||
final TranslatedExpr getQualifier() {
|
final TranslatedExpr getQualifier() {
|
||||||
result = getTranslatedExpr(access.getQualifier().getFullyConverted())
|
result = getTranslatedExpr(expr.getQualifier().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getResult() {
|
override Instruction getResult() {
|
||||||
@@ -874,18 +850,13 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
|
|||||||
|
|
||||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
result = getIRUserVariable(access.getEnclosingFunction(),
|
result = getIRUserVariable(expr.getEnclosingFunction(),
|
||||||
access.getTarget())
|
expr.getTarget())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedFieldAccess extends TranslatedVariableAccess {
|
class TranslatedFieldAccess extends TranslatedVariableAccess {
|
||||||
FieldAccess fieldAccess;
|
override FieldAccess expr;
|
||||||
|
|
||||||
TranslatedFieldAccess() {
|
|
||||||
//REVIEW: Implicit 'this'?
|
|
||||||
fieldAccess = access
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getFirstInstruction() {
|
override Instruction getFirstInstruction() {
|
||||||
result = getQualifier().getFirstInstruction()
|
result = getQualifier().getFirstInstruction()
|
||||||
@@ -908,16 +879,12 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
|
|||||||
|
|
||||||
override Field getInstructionField(InstructionTag tag) {
|
override Field getInstructionField(InstructionTag tag) {
|
||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
result = access.getTarget()
|
result = expr.getTarget()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
||||||
FunctionAccess access;
|
override FunctionAccess expr;
|
||||||
|
|
||||||
TranslatedFunctionAccess() {
|
|
||||||
access = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) {
|
||||||
none()
|
none()
|
||||||
@@ -942,13 +909,13 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
|||||||
Type resultType, boolean isGLValue) {
|
Type resultType, boolean isGLValue) {
|
||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
opcode instanceof Opcode::FunctionAddress and
|
opcode instanceof Opcode::FunctionAddress and
|
||||||
resultType = access.getType().getUnspecifiedType() and
|
resultType = expr.getType().getUnspecifiedType() and
|
||||||
isGLValue = true
|
isGLValue = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override Function getInstructionFunction(InstructionTag tag) {
|
override Function getInstructionFunction(InstructionTag tag) {
|
||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
result = access.getTarget()
|
result = expr.getTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||||
@@ -962,7 +929,7 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
|||||||
abstract class TranslatedNonConstantExpr extends TranslatedCoreExpr, TTranslatedValueExpr {
|
abstract class TranslatedNonConstantExpr extends TranslatedCoreExpr, TTranslatedValueExpr {
|
||||||
TranslatedNonConstantExpr() {
|
TranslatedNonConstantExpr() {
|
||||||
this = TTranslatedValueExpr(expr) and
|
this = TTranslatedValueExpr(expr) and
|
||||||
not expr.isConstant()
|
not isIRConstant(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -974,7 +941,7 @@ abstract class TranslatedNonConstantExpr extends TranslatedCoreExpr, TTranslated
|
|||||||
abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedValueExpr {
|
abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedValueExpr {
|
||||||
TranslatedConstantExpr() {
|
TranslatedConstantExpr() {
|
||||||
this = TTranslatedValueExpr(expr) and
|
this = TTranslatedValueExpr(expr) and
|
||||||
expr.isConstant()
|
isIRConstant(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Instruction getFirstInstruction() {
|
override final Instruction getFirstInstruction() {
|
||||||
@@ -1035,15 +1002,11 @@ class TranslatedArithmeticLiteral extends TranslatedConstantExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedStringLiteral extends TranslatedConstantExpr {
|
class TranslatedStringLiteral extends TranslatedConstantExpr {
|
||||||
StringLiteral stringLiteral;
|
override StringLiteral expr;
|
||||||
|
|
||||||
TranslatedStringLiteral() {
|
|
||||||
stringLiteral = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override StringLiteral getInstructionStringLiteral(InstructionTag tag) {
|
override StringLiteral getInstructionStringLiteral(InstructionTag tag) {
|
||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
result = stringLiteral
|
result = expr
|
||||||
}
|
}
|
||||||
|
|
||||||
override Opcode getOpcode() {
|
override Opcode getOpcode() {
|
||||||
@@ -1127,11 +1090,7 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class TranslatedConversion extends TranslatedNonConstantExpr {
|
abstract class TranslatedConversion extends TranslatedNonConstantExpr {
|
||||||
Conversion conv;
|
override Conversion expr;
|
||||||
|
|
||||||
TranslatedConversion() {
|
|
||||||
conv = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getFirstInstruction() {
|
override Instruction getFirstInstruction() {
|
||||||
result = getOperand().getFirstInstruction()
|
result = getOperand().getFirstInstruction()
|
||||||
@@ -1193,15 +1152,15 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
|
|||||||
*/
|
*/
|
||||||
class TranslatedSimpleConversion extends TranslatedSingleInstructionConversion {
|
class TranslatedSimpleConversion extends TranslatedSingleInstructionConversion {
|
||||||
TranslatedSimpleConversion() {
|
TranslatedSimpleConversion() {
|
||||||
conv instanceof ArithmeticConversion or
|
expr instanceof ArithmeticConversion or
|
||||||
conv instanceof PointerConversion or
|
expr instanceof PointerConversion or
|
||||||
conv instanceof PointerToMemberConversion or
|
expr instanceof PointerToMemberConversion or
|
||||||
conv instanceof PointerToIntegralConversion or
|
expr instanceof PointerToIntegralConversion or
|
||||||
conv instanceof IntegralToPointerConversion or
|
expr instanceof IntegralToPointerConversion or
|
||||||
conv instanceof GlvalueConversion or
|
expr instanceof GlvalueConversion or
|
||||||
conv instanceof ArrayToPointerConversion or
|
expr instanceof ArrayToPointerConversion or
|
||||||
conv instanceof PrvalueAdjustmentConversion or
|
expr instanceof PrvalueAdjustmentConversion or
|
||||||
conv instanceof VoidConversion
|
expr instanceof VoidConversion
|
||||||
}
|
}
|
||||||
|
|
||||||
override Opcode getOpcode() {
|
override Opcode getOpcode() {
|
||||||
@@ -1214,7 +1173,7 @@ class TranslatedSimpleConversion extends TranslatedSingleInstructionConversion {
|
|||||||
*/
|
*/
|
||||||
class TranslatedDynamicCast extends TranslatedSingleInstructionConversion {
|
class TranslatedDynamicCast extends TranslatedSingleInstructionConversion {
|
||||||
TranslatedDynamicCast() {
|
TranslatedDynamicCast() {
|
||||||
conv instanceof DynamicCast
|
expr instanceof DynamicCast
|
||||||
}
|
}
|
||||||
|
|
||||||
override Opcode getOpcode() {
|
override Opcode getOpcode() {
|
||||||
@@ -1237,22 +1196,19 @@ class TranslatedDynamicCast extends TranslatedSingleInstructionConversion {
|
|||||||
* expression.
|
* expression.
|
||||||
*/
|
*/
|
||||||
class TranslatedInheritanceConversion extends TranslatedSingleInstructionConversion {
|
class TranslatedInheritanceConversion extends TranslatedSingleInstructionConversion {
|
||||||
InheritanceConversion inheritanceConv;
|
override InheritanceConversion expr;
|
||||||
|
|
||||||
TranslatedInheritanceConversion() {
|
|
||||||
inheritanceConv = conv
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate getInstructionInheritance(InstructionTag tag, Class baseClass,
|
override predicate getInstructionInheritance(InstructionTag tag, Class baseClass,
|
||||||
Class derivedClass) {
|
Class derivedClass) {
|
||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
baseClass = inheritanceConv.getBaseClass() and
|
baseClass = expr.getBaseClass() and
|
||||||
derivedClass = inheritanceConv.getDerivedClass()
|
derivedClass = expr.getDerivedClass()
|
||||||
}
|
}
|
||||||
|
|
||||||
override Opcode getOpcode() {
|
override Opcode getOpcode() {
|
||||||
if inheritanceConv instanceof BaseClassConversion then (
|
if expr instanceof BaseClassConversion then (
|
||||||
if inheritanceConv.(BaseClassConversion).isVirtual() then
|
if expr.(BaseClassConversion).isVirtual() then
|
||||||
result instanceof Opcode::ConvertToVirtualBase
|
result instanceof Opcode::ConvertToVirtualBase
|
||||||
else
|
else
|
||||||
result instanceof Opcode::ConvertToBase
|
result instanceof Opcode::ConvertToBase
|
||||||
@@ -1267,9 +1223,7 @@ class TranslatedInheritanceConversion extends TranslatedSingleInstructionConvers
|
|||||||
* a comparison with zero.
|
* a comparison with zero.
|
||||||
*/
|
*/
|
||||||
class TranslatedBoolConversion extends TranslatedConversion {
|
class TranslatedBoolConversion extends TranslatedConversion {
|
||||||
TranslatedBoolConversion() {
|
override BoolConversion expr;
|
||||||
conv instanceof BoolConversion
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||||
EdgeKind kind) {
|
EdgeKind kind) {
|
||||||
@@ -1471,11 +1425,7 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class TranslatedAssignment extends TranslatedNonConstantExpr {
|
abstract class TranslatedAssignment extends TranslatedNonConstantExpr {
|
||||||
Assignment assign;
|
override Assignment expr;
|
||||||
|
|
||||||
TranslatedAssignment() {
|
|
||||||
expr = assign
|
|
||||||
}
|
|
||||||
|
|
||||||
override final TranslatedElement getChild(int id) {
|
override final TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = getLeftOperand() or
|
id = 0 and result = getLeftOperand() or
|
||||||
@@ -1506,20 +1456,20 @@ abstract class TranslatedAssignment extends TranslatedNonConstantExpr {
|
|||||||
|
|
||||||
final TranslatedExpr getLeftOperand() {
|
final TranslatedExpr getLeftOperand() {
|
||||||
result = getTranslatedExpr(
|
result = getTranslatedExpr(
|
||||||
assign.getLValue().getFullyConverted()
|
expr.getLValue().getFullyConverted()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
final TranslatedExpr getRightOperand() {
|
final TranslatedExpr getRightOperand() {
|
||||||
result = getTranslatedExpr(
|
result = getTranslatedExpr(
|
||||||
assign.getRValue().getFullyConverted()
|
expr.getRValue().getFullyConverted()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedAssignExpr extends TranslatedAssignment {
|
class TranslatedAssignExpr extends TranslatedAssignment {
|
||||||
TranslatedAssignExpr() {
|
TranslatedAssignExpr() {
|
||||||
assign instanceof AssignExpr
|
expr instanceof AssignExpr
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||||
@@ -1570,11 +1520,7 @@ class TranslatedAssignExpr extends TranslatedAssignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedAssignOperation extends TranslatedAssignment {
|
class TranslatedAssignOperation extends TranslatedAssignment {
|
||||||
AssignOperation assignOp;
|
override AssignOperation expr;
|
||||||
|
|
||||||
TranslatedAssignOperation() {
|
|
||||||
expr = assignOp
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||||
EdgeKind kind) {
|
EdgeKind kind) {
|
||||||
@@ -1629,10 +1575,10 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Type getConvertedLeftOperandType() {
|
private Type getConvertedLeftOperandType() {
|
||||||
if(assignOp instanceof AssignLShiftExpr or
|
if(expr instanceof AssignLShiftExpr or
|
||||||
assignOp instanceof AssignRShiftExpr or
|
expr instanceof AssignRShiftExpr or
|
||||||
assignOp instanceof AssignPointerAddExpr or
|
expr instanceof AssignPointerAddExpr or
|
||||||
assignOp instanceof AssignPointerSubExpr) then (
|
expr instanceof AssignPointerSubExpr) then (
|
||||||
// No need to convert for a shift. Technically, the left side should
|
// No need to convert for a shift. Technically, the left side should
|
||||||
// undergo integral promotion, and then the result would be converted back
|
// undergo integral promotion, and then the result would be converted back
|
||||||
// to the destination type. There's not much point to this, though,
|
// to the destination type. There's not much point to this, though,
|
||||||
@@ -1652,18 +1598,18 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Opcode getOpcode() {
|
private Opcode getOpcode() {
|
||||||
assignOp instanceof AssignAddExpr and result instanceof Opcode::Add or
|
expr instanceof AssignAddExpr and result instanceof Opcode::Add or
|
||||||
assignOp instanceof AssignSubExpr and result instanceof Opcode::Sub or
|
expr instanceof AssignSubExpr and result instanceof Opcode::Sub or
|
||||||
assignOp instanceof AssignMulExpr and result instanceof Opcode::Mul or
|
expr instanceof AssignMulExpr and result instanceof Opcode::Mul or
|
||||||
assignOp instanceof AssignDivExpr and result instanceof Opcode::Div or
|
expr instanceof AssignDivExpr and result instanceof Opcode::Div or
|
||||||
assignOp instanceof AssignRemExpr and result instanceof Opcode::Rem or
|
expr instanceof AssignRemExpr and result instanceof Opcode::Rem or
|
||||||
assignOp instanceof AssignAndExpr and result instanceof Opcode::BitAnd or
|
expr instanceof AssignAndExpr and result instanceof Opcode::BitAnd or
|
||||||
assignOp instanceof AssignOrExpr and result instanceof Opcode::BitOr or
|
expr instanceof AssignOrExpr and result instanceof Opcode::BitOr or
|
||||||
assignOp instanceof AssignXorExpr and result instanceof Opcode::BitXor or
|
expr instanceof AssignXorExpr and result instanceof Opcode::BitXor or
|
||||||
assignOp instanceof AssignLShiftExpr and result instanceof Opcode::ShiftLeft or
|
expr instanceof AssignLShiftExpr and result instanceof Opcode::ShiftLeft or
|
||||||
assignOp instanceof AssignRShiftExpr and result instanceof Opcode::ShiftRight or
|
expr instanceof AssignRShiftExpr and result instanceof Opcode::ShiftRight or
|
||||||
assignOp instanceof AssignPointerAddExpr and result instanceof Opcode::PointerAdd or
|
expr instanceof AssignPointerAddExpr and result instanceof Opcode::PointerAdd or
|
||||||
assignOp instanceof AssignPointerSubExpr and result instanceof Opcode::PointerSub
|
expr instanceof AssignPointerSubExpr and result instanceof Opcode::PointerSub
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||||
@@ -1779,15 +1725,14 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
|||||||
*/
|
*/
|
||||||
abstract class TranslatedAllocationSize extends TranslatedExpr,
|
abstract class TranslatedAllocationSize extends TranslatedExpr,
|
||||||
TTranslatedAllocationSize {
|
TTranslatedAllocationSize {
|
||||||
NewOrNewArrayExpr newExpr;
|
override NewOrNewArrayExpr expr;
|
||||||
|
|
||||||
TranslatedAllocationSize() {
|
TranslatedAllocationSize() {
|
||||||
this = TTranslatedAllocationSize(newExpr) and
|
this = TTranslatedAllocationSize(expr)
|
||||||
expr = newExpr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string toString() {
|
||||||
result = "Allocation size for " + newExpr.toString()
|
result = "Allocation size for " + expr.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final predicate producesExprResult() {
|
override final predicate producesExprResult() {
|
||||||
@@ -1812,7 +1757,7 @@ TranslatedAllocationSize getTranslatedAllocationSize(NewOrNewArrayExpr newExpr)
|
|||||||
*/
|
*/
|
||||||
class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
||||||
TranslatedConstantAllocationSize() {
|
TranslatedConstantAllocationSize() {
|
||||||
not exists(newExpr.(NewArrayExpr).getExtent())
|
not exists(expr.(NewArrayExpr).getExtent())
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Instruction getFirstInstruction() {
|
override final Instruction getFirstInstruction() {
|
||||||
@@ -1823,7 +1768,7 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
|||||||
Type resultType, boolean isGLValue) {
|
Type resultType, boolean isGLValue) {
|
||||||
tag = AllocationSizeTag() and
|
tag = AllocationSizeTag() and
|
||||||
opcode instanceof Opcode::Constant and
|
opcode instanceof Opcode::Constant and
|
||||||
resultType = newExpr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
|
resultType = expr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
|
||||||
isGLValue = false
|
isGLValue = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1844,7 +1789,7 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
|||||||
|
|
||||||
override final string getInstructionConstantValue(InstructionTag tag) {
|
override final string getInstructionConstantValue(InstructionTag tag) {
|
||||||
tag = AllocationSizeTag() and
|
tag = AllocationSizeTag() and
|
||||||
result = newExpr.getAllocatedType().getSize().toString()
|
result = expr.getAllocatedType().getSize().toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1856,11 +1801,10 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
|||||||
* the extent by the element size.
|
* the extent by the element size.
|
||||||
*/
|
*/
|
||||||
class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
||||||
NewArrayExpr newArrayExpr;
|
override NewArrayExpr expr;
|
||||||
|
|
||||||
TranslatedNonConstantAllocationSize() {
|
TranslatedNonConstantAllocationSize() {
|
||||||
newArrayExpr = newExpr and
|
exists(expr.getExtent())
|
||||||
exists(newArrayExpr.getExtent())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Instruction getFirstInstruction() {
|
override final Instruction getFirstInstruction() {
|
||||||
@@ -1870,7 +1814,7 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
|||||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||||
Type resultType, boolean isGLValue) {
|
Type resultType, boolean isGLValue) {
|
||||||
isGLValue = false and
|
isGLValue = false and
|
||||||
resultType = newExpr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
|
resultType = expr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
|
||||||
(
|
(
|
||||||
// Convert the extent to `size_t`, because the AST doesn't do this already.
|
// Convert the extent to `size_t`, because the AST doesn't do this already.
|
||||||
tag = AllocationExtentConvertTag() and opcode instanceof Opcode::Convert or
|
tag = AllocationExtentConvertTag() and opcode instanceof Opcode::Convert or
|
||||||
@@ -1909,7 +1853,7 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
|||||||
|
|
||||||
override final string getInstructionConstantValue(InstructionTag tag) {
|
override final string getInstructionConstantValue(InstructionTag tag) {
|
||||||
tag = AllocationElementSizeTag() and
|
tag = AllocationElementSizeTag() and
|
||||||
result = newArrayExpr.getAllocatedElementType().getSize().toString()
|
result = expr.getAllocatedElementType().getSize().toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||||
@@ -1929,7 +1873,7 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getExtent() {
|
private TranslatedExpr getExtent() {
|
||||||
result = getTranslatedExpr(newArrayExpr.getExtent().getFullyConverted())
|
result = getTranslatedExpr(expr.getExtent().getFullyConverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1939,15 +1883,14 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
|||||||
*/
|
*/
|
||||||
class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
|
class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
|
||||||
TranslatedDirectCall {
|
TranslatedDirectCall {
|
||||||
NewOrNewArrayExpr newExpr;
|
override NewOrNewArrayExpr expr;
|
||||||
|
|
||||||
TranslatedAllocatorCall() {
|
TranslatedAllocatorCall() {
|
||||||
this = TTranslatedAllocatorCall(newExpr) and
|
this = TTranslatedAllocatorCall(expr)
|
||||||
expr = newExpr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string toString() {
|
||||||
result = "Allocator call for " + newExpr.toString()
|
result = "Allocator call for " + expr.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final predicate producesExprResult() {
|
override final predicate producesExprResult() {
|
||||||
@@ -1955,11 +1898,11 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override Function getInstructionFunction(InstructionTag tag) {
|
override Function getInstructionFunction(InstructionTag tag) {
|
||||||
tag = CallTargetTag() and result = newExpr.getAllocator()
|
tag = CallTargetTag() and result = expr.getAllocator()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Type getCallResultType() {
|
override final Type getCallResultType() {
|
||||||
result = newExpr.getAllocator().getType().getUnspecifiedType()
|
result = expr.getAllocator().getType().getUnspecifiedType()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final TranslatedExpr getQualifier() {
|
override final TranslatedExpr getQualifier() {
|
||||||
@@ -1979,11 +1922,11 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
|
|||||||
// an error node, so we need to provide the correct size argument in any
|
// an error node, so we need to provide the correct size argument in any
|
||||||
// case.
|
// case.
|
||||||
if index = 0 then
|
if index = 0 then
|
||||||
result = getTranslatedAllocationSize(newExpr)
|
result = getTranslatedAllocationSize(expr)
|
||||||
else if(index = 1 and newExpr.hasAlignedAllocation()) then
|
else if(index = 1 and expr.hasAlignedAllocation()) then
|
||||||
result = getTranslatedExpr(newExpr.getAlignmentArgument())
|
result = getTranslatedExpr(expr.getAlignmentArgument())
|
||||||
else
|
else
|
||||||
result = getTranslatedExpr(newExpr.getAllocatorCall().getArgument(index))
|
result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2009,11 +1952,7 @@ abstract class StructorCallContext extends TranslatedElement {
|
|||||||
*/
|
*/
|
||||||
class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
|
class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
|
||||||
StructorCallContext {
|
StructorCallContext {
|
||||||
DestructorFieldDestruction destruction;
|
override DestructorFieldDestruction expr;
|
||||||
|
|
||||||
TranslatedDestructorFieldDestruction() {
|
|
||||||
destruction = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final TranslatedElement getChild(int id) {
|
override final TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = getDestructorCall()
|
id = 0 and result = getDestructorCall()
|
||||||
@@ -2023,7 +1962,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
|
|||||||
Type resultType, boolean isGLValue) {
|
Type resultType, boolean isGLValue) {
|
||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
opcode instanceof Opcode::FieldAddress and
|
opcode instanceof Opcode::FieldAddress and
|
||||||
resultType = destruction.getTarget().getType().getUnspecifiedType() and
|
resultType = expr.getTarget().getType().getUnspecifiedType() and
|
||||||
isGLValue = true
|
isGLValue = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2050,12 +1989,12 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
|
|||||||
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
operandTag instanceof UnaryOperandTag and
|
operandTag instanceof UnaryOperandTag and
|
||||||
result = getTranslatedFunction(destruction.getEnclosingFunction()).getInitializeThisInstruction()
|
result = getTranslatedFunction(expr.getEnclosingFunction()).getInitializeThisInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Field getInstructionField(InstructionTag tag) {
|
override final Field getInstructionField(InstructionTag tag) {
|
||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
result = destruction.getTarget()
|
result = expr.getTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Instruction getReceiver() {
|
override final Instruction getReceiver() {
|
||||||
@@ -2063,17 +2002,13 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getDestructorCall() {
|
private TranslatedExpr getDestructorCall() {
|
||||||
result = getTranslatedExpr(destruction.getExpr())
|
result = getTranslatedExpr(expr.getExpr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||||
ConditionContext {
|
ConditionContext {
|
||||||
ConditionalExpr condExpr;
|
override ConditionalExpr expr;
|
||||||
|
|
||||||
TranslatedConditionalExpr() {
|
|
||||||
condExpr = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final TranslatedElement getChild(int id) {
|
override final TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = getCondition() or
|
id = 0 and result = getCondition() or
|
||||||
@@ -2256,29 +2191,29 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedCondition getCondition() {
|
private TranslatedCondition getCondition() {
|
||||||
result = getTranslatedCondition(condExpr.getCondition().getFullyConverted())
|
result = getTranslatedCondition(expr.getCondition().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getThen() {
|
private TranslatedExpr getThen() {
|
||||||
result = getTranslatedExpr(condExpr.getThen().getFullyConverted())
|
result = getTranslatedExpr(expr.getThen().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getElse() {
|
private TranslatedExpr getElse() {
|
||||||
result = getTranslatedExpr(condExpr.getElse().getFullyConverted())
|
result = getTranslatedExpr(expr.getElse().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate thenIsVoid() {
|
private predicate thenIsVoid() {
|
||||||
getThen().getResultType() instanceof VoidType or
|
getThen().getResultType() instanceof VoidType or
|
||||||
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
|
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
|
||||||
// thrown, rather than `void`. Handle that case here.
|
// thrown, rather than `void`. Handle that case here.
|
||||||
condExpr.getThen() instanceof ThrowExpr
|
expr.getThen() instanceof ThrowExpr
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate elseIsVoid() {
|
private predicate elseIsVoid() {
|
||||||
getElse().getResultType() instanceof VoidType or
|
getElse().getResultType() instanceof VoidType or
|
||||||
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
|
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
|
||||||
// thrown, rather than `void`. Handle that case here.
|
// thrown, rather than `void`. Handle that case here.
|
||||||
condExpr.getElse() instanceof ThrowExpr
|
expr.getElse() instanceof ThrowExpr
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate resultIsVoid() {
|
private predicate resultIsVoid() {
|
||||||
@@ -2290,11 +2225,8 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
|||||||
* IR translation of a `throw` expression.
|
* IR translation of a `throw` expression.
|
||||||
*/
|
*/
|
||||||
abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
||||||
ThrowExpr throw;
|
override ThrowExpr expr;
|
||||||
|
|
||||||
TranslatedThrowExpr() {
|
|
||||||
throw = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||||
Type resultType, boolean isGLValue) {
|
Type resultType, boolean isGLValue) {
|
||||||
@@ -2325,7 +2257,7 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
|||||||
class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
||||||
InitializationContext {
|
InitializationContext {
|
||||||
TranslatedThrowValueExpr() {
|
TranslatedThrowValueExpr() {
|
||||||
not throw instanceof ReThrowExpr
|
not expr instanceof ReThrowExpr
|
||||||
}
|
}
|
||||||
|
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) {
|
||||||
@@ -2362,7 +2294,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
|||||||
|
|
||||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||||
tag = InitializerVariableAddressTag() and
|
tag = InitializerVariableAddressTag() and
|
||||||
result = getIRTempVariable(throw, ThrowTempVar())
|
result = getIRTempVariable(expr, ThrowTempVar())
|
||||||
}
|
}
|
||||||
|
|
||||||
override final predicate hasTempVariable(TempVariableTag tag, Type type) {
|
override final predicate hasTempVariable(TempVariableTag tag, Type type) {
|
||||||
@@ -2395,7 +2327,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
|||||||
|
|
||||||
TranslatedInitialization getInitialization() {
|
TranslatedInitialization getInitialization() {
|
||||||
result = getTranslatedInitialization(
|
result = getTranslatedInitialization(
|
||||||
throw.getExpr().getFullyConverted())
|
expr.getExpr().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Opcode getThrowOpcode() {
|
override final Opcode getThrowOpcode() {
|
||||||
@@ -2403,7 +2335,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Type getExceptionType() {
|
private Type getExceptionType() {
|
||||||
result = throw.getType().getUnspecifiedType()
|
result = expr.getType().getUnspecifiedType()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2411,9 +2343,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
|||||||
* IR translation of a `throw` expression with no argument (e.g. `throw;`).
|
* IR translation of a `throw` expression with no argument (e.g. `throw;`).
|
||||||
*/
|
*/
|
||||||
class TranslatedReThrowExpr extends TranslatedThrowExpr {
|
class TranslatedReThrowExpr extends TranslatedThrowExpr {
|
||||||
TranslatedReThrowExpr() {
|
override ReThrowExpr expr;
|
||||||
throw instanceof ReThrowExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) {
|
||||||
none()
|
none()
|
||||||
@@ -2493,9 +2423,7 @@ abstract class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
|||||||
* The IR translation of a `BuiltInVarArgsStart` expression.
|
* The IR translation of a `BuiltInVarArgsStart` expression.
|
||||||
*/
|
*/
|
||||||
class TranslatedVarArgsStart extends TranslatedBuiltInOperation {
|
class TranslatedVarArgsStart extends TranslatedBuiltInOperation {
|
||||||
TranslatedVarArgsStart() {
|
override BuiltInVarArgsStart expr;
|
||||||
expr instanceof BuiltInVarArgsStart
|
|
||||||
}
|
|
||||||
|
|
||||||
override final Opcode getOpcode() {
|
override final Opcode getOpcode() {
|
||||||
result instanceof Opcode::VarArgsStart
|
result instanceof Opcode::VarArgsStart
|
||||||
@@ -2506,9 +2434,7 @@ class TranslatedVarArgsStart extends TranslatedBuiltInOperation {
|
|||||||
* The IR translation of a `BuiltInVarArgsEnd` expression.
|
* The IR translation of a `BuiltInVarArgsEnd` expression.
|
||||||
*/
|
*/
|
||||||
class TranslatedVarArgsEnd extends TranslatedBuiltInOperation {
|
class TranslatedVarArgsEnd extends TranslatedBuiltInOperation {
|
||||||
TranslatedVarArgsEnd() {
|
override BuiltInVarArgsEnd expr;
|
||||||
expr instanceof BuiltInVarArgsEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
override final Opcode getOpcode() {
|
override final Opcode getOpcode() {
|
||||||
result instanceof Opcode::VarArgsEnd
|
result instanceof Opcode::VarArgsEnd
|
||||||
@@ -2519,9 +2445,7 @@ class TranslatedVarArgsEnd extends TranslatedBuiltInOperation {
|
|||||||
* The IR translation of a `BuiltInVarArg` expression.
|
* The IR translation of a `BuiltInVarArg` expression.
|
||||||
*/
|
*/
|
||||||
class TranslatedVarArg extends TranslatedBuiltInOperation {
|
class TranslatedVarArg extends TranslatedBuiltInOperation {
|
||||||
TranslatedVarArg() {
|
override BuiltInVarArg expr;
|
||||||
expr instanceof BuiltInVarArg
|
|
||||||
}
|
|
||||||
|
|
||||||
override final Opcode getOpcode() {
|
override final Opcode getOpcode() {
|
||||||
result instanceof Opcode::VarArg
|
result instanceof Opcode::VarArg
|
||||||
@@ -2532,9 +2456,7 @@ class TranslatedVarArg extends TranslatedBuiltInOperation {
|
|||||||
* The IR translation of a `BuiltInVarArgCopy` expression.
|
* The IR translation of a `BuiltInVarArgCopy` expression.
|
||||||
*/
|
*/
|
||||||
class TranslatedVarArgCopy extends TranslatedBuiltInOperation {
|
class TranslatedVarArgCopy extends TranslatedBuiltInOperation {
|
||||||
TranslatedVarArgCopy() {
|
override BuiltInVarArgCopy expr;
|
||||||
expr instanceof BuiltInVarArgCopy
|
|
||||||
}
|
|
||||||
|
|
||||||
override final Opcode getOpcode() {
|
override final Opcode getOpcode() {
|
||||||
result instanceof Opcode::VarArgCopy
|
result instanceof Opcode::VarArgCopy
|
||||||
@@ -2546,11 +2468,7 @@ class TranslatedVarArgCopy extends TranslatedBuiltInOperation {
|
|||||||
*/
|
*/
|
||||||
abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
|
abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
|
||||||
InitializationContext {
|
InitializationContext {
|
||||||
NewOrNewArrayExpr newExpr;
|
override NewOrNewArrayExpr expr;
|
||||||
|
|
||||||
TranslatedNewOrNewArrayExpr() {
|
|
||||||
expr = newExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final TranslatedElement getChild(int id) {
|
override final TranslatedElement getChild(int id) {
|
||||||
id = 0 and result = getAllocatorCall() or
|
id = 0 and result = getAllocatorCall() or
|
||||||
@@ -2600,7 +2518,7 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedAllocatorCall getAllocatorCall() {
|
private TranslatedAllocatorCall getAllocatorCall() {
|
||||||
result = getTranslatedAllocatorCall(newExpr)
|
result = getTranslatedAllocatorCall(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract TranslatedInitialization getInitialization();
|
abstract TranslatedInitialization getInitialization();
|
||||||
@@ -2610,16 +2528,14 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
|
|||||||
* The IR translation of a `new` expression.
|
* The IR translation of a `new` expression.
|
||||||
*/
|
*/
|
||||||
class TranslatedNewExpr extends TranslatedNewOrNewArrayExpr {
|
class TranslatedNewExpr extends TranslatedNewOrNewArrayExpr {
|
||||||
TranslatedNewExpr() {
|
override NewExpr expr;
|
||||||
newExpr instanceof NewExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final Type getTargetType() {
|
override final Type getTargetType() {
|
||||||
result = newExpr.getAllocatedType().getUnspecifiedType()
|
result = expr.getAllocatedType().getUnspecifiedType()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final TranslatedInitialization getInitialization() {
|
override final TranslatedInitialization getInitialization() {
|
||||||
result = getTranslatedInitialization(newExpr.(NewExpr).getInitializer())
|
result = getTranslatedInitialization(expr.getInitializer())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2627,12 +2543,10 @@ class TranslatedNewExpr extends TranslatedNewOrNewArrayExpr {
|
|||||||
* The IR translation of a `new[]` expression.
|
* The IR translation of a `new[]` expression.
|
||||||
*/
|
*/
|
||||||
class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
|
class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
|
||||||
TranslatedNewArrayExpr() {
|
override NewArrayExpr expr;
|
||||||
newExpr instanceof NewArrayExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final Type getTargetType() {
|
override final Type getTargetType() {
|
||||||
result = newExpr.getAllocatedType().getUnspecifiedType()
|
result = expr.getAllocatedType().getUnspecifiedType()
|
||||||
}
|
}
|
||||||
|
|
||||||
override final TranslatedInitialization getInitialization() {
|
override final TranslatedInitialization getInitialization() {
|
||||||
@@ -2650,11 +2564,7 @@ class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr {
|
class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr {
|
||||||
ConditionDeclExpr condDeclExpr;
|
override ConditionDeclExpr expr;
|
||||||
|
|
||||||
TranslatedConditionDeclExpr() {
|
|
||||||
condDeclExpr = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override final Instruction getFirstInstruction() {
|
override final Instruction getFirstInstruction() {
|
||||||
result = getDecl().getFirstInstruction()
|
result = getDecl().getFirstInstruction()
|
||||||
@@ -2687,10 +2597,10 @@ class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedConditionDecl getDecl() {
|
private TranslatedConditionDecl getDecl() {
|
||||||
result = getTranslatedConditionDecl(condDeclExpr)
|
result = getTranslatedConditionDecl(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getConditionExpr() {
|
private TranslatedExpr getConditionExpr() {
|
||||||
result = getTranslatedExpr(condDeclExpr.getVariableAccess().getFullyConverted())
|
result = getTranslatedExpr(expr.getVariableAccess().getFullyConverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,16 +120,12 @@ abstract class TranslatedListInitialization extends TranslatedInitialization,
|
|||||||
class TranslatedClassListInitialization extends
|
class TranslatedClassListInitialization extends
|
||||||
TranslatedListInitialization
|
TranslatedListInitialization
|
||||||
{
|
{
|
||||||
ClassAggregateLiteral initList;
|
override ClassAggregateLiteral expr;
|
||||||
|
|
||||||
TranslatedClassListInitialization() {
|
|
||||||
initList = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) {
|
||||||
exists(TranslatedFieldInitialization fieldInit |
|
exists(TranslatedFieldInitialization fieldInit |
|
||||||
result = fieldInit and
|
result = fieldInit and
|
||||||
fieldInit = getTranslatedFieldInitialization(initList, _) and
|
fieldInit = getTranslatedFieldInitialization(expr, _) and
|
||||||
fieldInit.getOrder() = id
|
fieldInit.getOrder() = id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -141,16 +137,12 @@ class TranslatedClassListInitialization extends
|
|||||||
*/
|
*/
|
||||||
class TranslatedArrayListInitialization extends
|
class TranslatedArrayListInitialization extends
|
||||||
TranslatedListInitialization {
|
TranslatedListInitialization {
|
||||||
ArrayAggregateLiteral initList;
|
override ArrayAggregateLiteral expr;
|
||||||
|
|
||||||
TranslatedArrayListInitialization() {
|
|
||||||
initList = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override TranslatedElement getChild(int id) {
|
override TranslatedElement getChild(int id) {
|
||||||
// The children are in initialization order
|
// The children are in initialization order
|
||||||
result = rank[id + 1](TranslatedElementInitialization init |
|
result = rank[id + 1](TranslatedElementInitialization init |
|
||||||
init.getInitList() = initList |
|
init.getInitList() = expr |
|
||||||
init order by init.getElementIndex()
|
init order by init.getElementIndex()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -231,9 +223,7 @@ class TranslatedSimpleDirectInitialization extends
|
|||||||
*/
|
*/
|
||||||
class TranslatedStringLiteralInitialization extends
|
class TranslatedStringLiteralInitialization extends
|
||||||
TranslatedDirectInitialization {
|
TranslatedDirectInitialization {
|
||||||
TranslatedStringLiteralInitialization() {
|
override StringLiteral expr;
|
||||||
expr instanceof StringLiteral
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||||
Type resultType, boolean isGLValue) {
|
Type resultType, boolean isGLValue) {
|
||||||
@@ -434,11 +424,7 @@ class TranslatedStringLiteralInitialization extends
|
|||||||
|
|
||||||
class TranslatedConstructorInitialization extends
|
class TranslatedConstructorInitialization extends
|
||||||
TranslatedDirectInitialization, StructorCallContext {
|
TranslatedDirectInitialization, StructorCallContext {
|
||||||
ConstructorCall ctorCall;
|
override ConstructorCall expr;
|
||||||
|
|
||||||
TranslatedConstructorInitialization() {
|
|
||||||
ctorCall = expr
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||||
Type resultType, boolean isGLValue) {
|
Type resultType, boolean isGLValue) {
|
||||||
@@ -1008,9 +994,7 @@ TranslatedConstructorCallFromConstructor getTranslatedConstructorBaseInit(Constr
|
|||||||
* Represents the IR translation of a delegating constructor call from within a constructor.
|
* Represents the IR translation of a delegating constructor call from within a constructor.
|
||||||
*/
|
*/
|
||||||
class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromConstructor {
|
class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromConstructor {
|
||||||
TranslatedConstructorDelegationInit() {
|
override ConstructorDelegationInit call;
|
||||||
call instanceof ConstructorDelegationInit
|
|
||||||
}
|
|
||||||
|
|
||||||
override final string toString() {
|
override final string toString() {
|
||||||
result = "delegation construct: " + call.toString()
|
result = "delegation construct: " + call.toString()
|
||||||
|
|||||||
@@ -632,7 +632,7 @@ class TranslatedForStmt extends TranslatedLoop {
|
|||||||
exists(forStmt.getInitialization())
|
exists(forStmt.getInitialization())
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedExpr getUpdate() {
|
TranslatedExpr getUpdate() {
|
||||||
result = getTranslatedExpr(forStmt.getUpdate().getFullyConverted())
|
result = getTranslatedExpr(forStmt.getUpdate().getFullyConverted())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ class FunctionIR extends TFunctionIR {
|
|||||||
result.getFunctionIR() = this
|
result.getFunctionIR() = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
final UnmodeledUseInstruction getUnmodeledUseInstruction() {
|
||||||
|
result.getFunctionIR() = this
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the single return instruction for this function.
|
* Gets the single return instruction for this function.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
|
|||||||
blockSuccessor(this, result, kind)
|
blockSuccessor(this, result, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||||
|
backEdgeSuccessor(this, result, kind)
|
||||||
|
}
|
||||||
|
|
||||||
final predicate immediatelyDominates(IRBlock block) {
|
final predicate immediatelyDominates(IRBlock block) {
|
||||||
blockImmediatelyDominates(this, block)
|
blockImmediatelyDominates(this, block)
|
||||||
}
|
}
|
||||||
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
|
|||||||
exists(Instruction predecessor, EdgeKind kind |
|
exists(Instruction predecessor, EdgeKind kind |
|
||||||
instr = predecessor.getSuccessor(kind) and
|
instr = predecessor.getSuccessor(kind) and
|
||||||
not kind instanceof GotoEdge
|
not kind instanceof GotoEdge
|
||||||
) // Incoming edge is not a GotoEdge
|
) or // Incoming edge is not a GotoEdge
|
||||||
|
exists(Instruction predecessor |
|
||||||
|
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
|
||||||
|
) // A back edge enters this instruction
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,24 +159,13 @@ private cached module Cached {
|
|||||||
not startsBasicBlock(i2)
|
not startsBasicBlock(i2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the index of `i` in its `IRBlock`. */
|
/** Holds if `i` is the `index`th instruction the block starting with `first`. */
|
||||||
private int getMemberIndex(Instruction i) {
|
private Instruction getInstructionFromFirst(Instruction first, int index) =
|
||||||
startsBasicBlock(i) and
|
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
|
||||||
result = 0
|
|
||||||
or
|
|
||||||
exists(Instruction iPrev |
|
|
||||||
adjacentInBlock(iPrev, i) and
|
|
||||||
result = getMemberIndex(iPrev) + 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `i` is the `index`th instruction in `block`. */
|
/** Holds if `i` is the `index`th instruction in `block`. */
|
||||||
cached Instruction getInstruction(TIRBlock block, int index) {
|
cached Instruction getInstruction(TIRBlock block, int index) {
|
||||||
exists(Instruction first |
|
result = getInstructionFromFirst(getFirstInstruction(block), index)
|
||||||
block = MkIRBlock(first) and
|
|
||||||
index = getMemberIndex(result) and
|
|
||||||
adjacentInBlock*(first, result)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached int getInstructionCount(TIRBlock block) {
|
cached int getInstructionCount(TIRBlock block) {
|
||||||
@@ -184,6 +180,41 @@ private cached module Cached {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||||
|
backEdgeSuccessorRaw(pred, succ, kind)
|
||||||
|
or
|
||||||
|
forwardEdgeRaw+(pred, pred) and
|
||||||
|
blockSuccessor(pred, succ, kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
|
||||||
|
*/
|
||||||
|
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
|
||||||
|
exists(EdgeKind kind |
|
||||||
|
blockSuccessor(pred, succ, kind) and
|
||||||
|
not backEdgeSuccessorRaw(pred, succ, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
|
||||||
|
* `Construction`.
|
||||||
|
*
|
||||||
|
* There could be loops of non-back-edges if there is a flaw in the IR
|
||||||
|
* construction or back-edge detection, and this could cause non-termination
|
||||||
|
* of subsequent analysis. To prevent that, a subsequent predicate further
|
||||||
|
* classifies all edges as back edges if they are involved in a loop of
|
||||||
|
* non-back-edges.
|
||||||
|
*/
|
||||||
|
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
|
||||||
|
exists(Instruction predLast, Instruction succFirst |
|
||||||
|
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
|
||||||
|
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
|
||||||
|
succ = MkIRBlock(succFirst)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
cached predicate blockSuccessor(TIRBlock pred, TIRBlock succ) {
|
||||||
blockSuccessor(pred, succ, _)
|
blockSuccessor(pred, succ, _)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,31 +3,7 @@ import FunctionIR
|
|||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.ir.implementation.TempVariableTag
|
import semmle.code.cpp.ir.implementation.TempVariableTag
|
||||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||||
|
private import semmle.code.cpp.ir.internal.TIRVariable
|
||||||
private newtype TIRVariable =
|
|
||||||
TIRAutomaticUserVariable(LocalScopeVariable var, FunctionIR funcIR) {
|
|
||||||
exists(Function func |
|
|
||||||
func = funcIR.getFunction() and
|
|
||||||
(
|
|
||||||
var.getFunction() = func or
|
|
||||||
var.(Parameter).getCatchBlock().getEnclosingFunction() = func
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} or
|
|
||||||
TIRStaticUserVariable(Variable var, FunctionIR funcIR) {
|
|
||||||
(
|
|
||||||
var instanceof GlobalOrNamespaceVariable or
|
|
||||||
var instanceof MemberVariable and not var instanceof Field
|
|
||||||
) and
|
|
||||||
exists(VariableAccess access |
|
|
||||||
access.getTarget() = var and
|
|
||||||
access.getEnclosingFunction() = funcIR.getFunction()
|
|
||||||
)
|
|
||||||
} or
|
|
||||||
TIRTempVariable(FunctionIR funcIR, Locatable ast, TempVariableTag tag,
|
|
||||||
Type type) {
|
|
||||||
Construction::hasTempVariable(funcIR.getFunction(), ast, tag, type)
|
|
||||||
}
|
|
||||||
|
|
||||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||||
result.getVariable() = var and
|
result.getVariable() = var and
|
||||||
@@ -40,7 +16,7 @@ IRUserVariable getIRUserVariable(Function func, Variable var) {
|
|||||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||||
*/
|
*/
|
||||||
abstract class IRVariable extends TIRVariable {
|
abstract class IRVariable extends TIRVariable {
|
||||||
FunctionIR funcIR;
|
Function func;
|
||||||
|
|
||||||
abstract string toString();
|
abstract string toString();
|
||||||
|
|
||||||
@@ -72,14 +48,14 @@ abstract class IRVariable extends TIRVariable {
|
|||||||
* Gets the IR for the function that references this variable.
|
* Gets the IR for the function that references this variable.
|
||||||
*/
|
*/
|
||||||
final FunctionIR getFunctionIR() {
|
final FunctionIR getFunctionIR() {
|
||||||
result = funcIR
|
result.getFunction() = func
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the function that references this variable.
|
* Gets the function that references this variable.
|
||||||
*/
|
*/
|
||||||
final Function getFunction() {
|
final Function getFunction() {
|
||||||
result = funcIR.getFunction()
|
result = func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +102,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
|||||||
LocalScopeVariable localVar;
|
LocalScopeVariable localVar;
|
||||||
|
|
||||||
IRAutomaticUserVariable() {
|
IRAutomaticUserVariable() {
|
||||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
this = TIRAutomaticUserVariable(localVar, func) and
|
||||||
var = localVar
|
var = localVar
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +113,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
|||||||
|
|
||||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||||
IRStaticUserVariable() {
|
IRStaticUserVariable() {
|
||||||
this = TIRStaticUserVariable(var, funcIR)
|
this = TIRStaticUserVariable(var, func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +128,7 @@ class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
|||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
IRTempVariable() {
|
IRTempVariable() {
|
||||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
this = TIRTempVariable(func, ast, tag, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final Type getType() {
|
override final Type getType() {
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import semmle.code.cpp.ir.implementation.Opcode
|
|||||||
private import semmle.code.cpp.ir.implementation.Opcode
|
private import semmle.code.cpp.ir.implementation.Opcode
|
||||||
private import semmle.code.cpp.ir.internal.OperandTag
|
private import semmle.code.cpp.ir.internal.OperandTag
|
||||||
|
|
||||||
class InstructionTag = Construction::InstructionTagType;
|
|
||||||
|
|
||||||
module InstructionSanity {
|
module InstructionSanity {
|
||||||
/**
|
/**
|
||||||
* Holds if the instruction `instr` should be expected to have an operand
|
* Holds if the instruction `instr` should be expected to have an operand
|
||||||
@@ -157,23 +155,60 @@ module InstructionSanity {
|
|||||||
blockCount = count(instr.getBlock()) and
|
blockCount = count(instr.getBlock()) and
|
||||||
blockCount != 1
|
blockCount != 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||||
|
b1.getASuccessor() = b2 and
|
||||||
|
not b1.getBackEdgeSuccessor(_) = b2
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||||
|
*
|
||||||
|
* This check ensures we don't have too _few_ back edges.
|
||||||
|
*/
|
||||||
|
query predicate containsLoopOfForwardEdges(FunctionIR f) {
|
||||||
|
exists(IRBlock block |
|
||||||
|
forwardEdge+(block, block) and
|
||||||
|
block.getFunctionIR() = f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `block` is reachable from its function entry point but would not
|
||||||
|
* be reachable by traversing only forward edges. This check is skipped for
|
||||||
|
* functions containing `goto` statements as the property does not generally
|
||||||
|
* hold there.
|
||||||
|
*
|
||||||
|
* This check ensures we don't have too _many_ back edges.
|
||||||
|
*/
|
||||||
|
query predicate lostReachability(IRBlock block) {
|
||||||
|
exists(FunctionIR f, IRBlock entry |
|
||||||
|
entry = f.getEntryBlock() and
|
||||||
|
entry.getASuccessor+() = block and
|
||||||
|
not forwardEdge+(entry, block) and
|
||||||
|
not exists(GotoStmt s | s.getEnclosingFunction() = f.getFunction())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the number of back edges differs between the `Instruction` graph
|
||||||
|
* and the `IRBlock` graph.
|
||||||
|
*/
|
||||||
|
query predicate backEdgeCountMismatch(Function f, int fromInstr, int fromBlock) {
|
||||||
|
fromInstr = count(Instruction i1, Instruction i2 |
|
||||||
|
i1.getFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||||
|
) and
|
||||||
|
fromBlock = count(IRBlock b1, IRBlock b2 |
|
||||||
|
b1.getFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||||
|
) and
|
||||||
|
fromInstr != fromBlock
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a single operation in the IR.
|
* Represents a single operation in the IR.
|
||||||
*/
|
*/
|
||||||
class Instruction extends Construction::TInstruction {
|
class Instruction extends Construction::TInstruction {
|
||||||
Opcode opcode;
|
|
||||||
Locatable ast;
|
|
||||||
InstructionTag instructionTag;
|
|
||||||
Type resultType;
|
|
||||||
FunctionIR funcIR;
|
|
||||||
boolean glvalue;
|
|
||||||
|
|
||||||
Instruction() {
|
|
||||||
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
|
||||||
}
|
|
||||||
|
|
||||||
final string toString() {
|
final string toString() {
|
||||||
result = getOpcode().toString() + ": " + getAST().toString()
|
result = getOpcode().toString() + ": " + getAST().toString()
|
||||||
}
|
}
|
||||||
@@ -196,9 +231,9 @@ class Instruction extends Construction::TInstruction {
|
|||||||
*/
|
*/
|
||||||
final string getOperationString() {
|
final string getOperationString() {
|
||||||
if exists(getImmediateString()) then
|
if exists(getImmediateString()) then
|
||||||
result = getOperationPrefix() + opcode.toString() + "[" + getImmediateString() + "]"
|
result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]"
|
||||||
else
|
else
|
||||||
result = getOperationPrefix() + opcode.toString()
|
result = getOperationPrefix() + getOpcode().toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -216,7 +251,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string getResultPrefix() {
|
private string getResultPrefix() {
|
||||||
if resultType instanceof VoidType then
|
if getResultType() instanceof VoidType then
|
||||||
result = "v"
|
result = "v"
|
||||||
else if hasMemoryResult() then
|
else if hasMemoryResult() then
|
||||||
if isResultModeled() then
|
if isResultModeled() then
|
||||||
@@ -261,8 +296,8 @@ class Instruction extends Construction::TInstruction {
|
|||||||
|
|
||||||
private string getResultTypeString() {
|
private string getResultTypeString() {
|
||||||
exists(string valcat |
|
exists(string valcat |
|
||||||
valcat = getValueCategoryString(resultType.toString()) and
|
valcat = getValueCategoryString(getResultType().toString()) and
|
||||||
if (resultType instanceof UnknownType and
|
if (getResultType() instanceof UnknownType and
|
||||||
not isGLValue() and
|
not isGLValue() and
|
||||||
exists(getResultSize())) then (
|
exists(getResultSize())) then (
|
||||||
result = valcat + "[" + getResultSize().toString() + "]"
|
result = valcat + "[" + getResultSize().toString() + "]"
|
||||||
@@ -330,28 +365,28 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* Gets the function that contains this instruction.
|
* Gets the function that contains this instruction.
|
||||||
*/
|
*/
|
||||||
final Function getFunction() {
|
final Function getFunction() {
|
||||||
result = funcIR.getFunction()
|
result = getFunctionIR().getFunction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the FunctionIR object that contains the IR for this instruction.
|
* Gets the FunctionIR object that contains the IR for this instruction.
|
||||||
*/
|
*/
|
||||||
final FunctionIR getFunctionIR() {
|
final FunctionIR getFunctionIR() {
|
||||||
result = funcIR
|
result = Construction::getInstructionEnclosingFunctionIR(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the AST that caused this instruction to be generated.
|
* Gets the AST that caused this instruction to be generated.
|
||||||
*/
|
*/
|
||||||
final Locatable getAST() {
|
final Locatable getAST() {
|
||||||
result = ast
|
result = Construction::getInstructionAST(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location of the source code for this instruction.
|
* Gets the location of the source code for this instruction.
|
||||||
*/
|
*/
|
||||||
final Location getLocation() {
|
final Location getLocation() {
|
||||||
result = ast.getLocation()
|
result = getAST().getLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -373,7 +408,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* instruction does not produce a result, its result type will be `VoidType`.
|
* instruction does not produce a result, its result type will be `VoidType`.
|
||||||
*/
|
*/
|
||||||
final Type getResultType() {
|
final Type getResultType() {
|
||||||
result = resultType
|
Construction::instructionHasType(this, result, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -395,7 +430,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* the integer value loaded from variable `x`.
|
* the integer value loaded from variable `x`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() {
|
final predicate isGLValue() {
|
||||||
glvalue = true
|
Construction::instructionHasType(this, _, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -412,10 +447,10 @@ class Instruction extends Construction::TInstruction {
|
|||||||
result = nullptr.getSize()
|
result = nullptr.getSize()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else if resultType instanceof UnknownType then
|
else if getResultType() instanceof UnknownType then
|
||||||
result = Construction::getInstructionResultSize(this)
|
result = Construction::getInstructionResultSize(this)
|
||||||
else (
|
else (
|
||||||
result = resultType.getSize()
|
result = getResultType().getSize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,11 +458,7 @@ class Instruction extends Construction::TInstruction {
|
|||||||
* Gets the opcode that specifies the operation performed by this instruction.
|
* Gets the opcode that specifies the operation performed by this instruction.
|
||||||
*/
|
*/
|
||||||
final Opcode getOpcode() {
|
final Opcode getOpcode() {
|
||||||
result = opcode
|
result = Construction::getInstructionOpcode(this)
|
||||||
}
|
|
||||||
|
|
||||||
final InstructionTag getTag() {
|
|
||||||
result = instructionTag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -489,6 +520,24 @@ class Instruction extends Construction::TInstruction {
|
|||||||
result = Construction::getInstructionSuccessor(this, kind)
|
result = Construction::getInstructionSuccessor(this, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the a _back-edge successor_ of this instruction along the control
|
||||||
|
* flow edge specified by `kind`. A back edge in the control-flow graph is
|
||||||
|
* intuitively the edge that goes back around a loop. If all back edges are
|
||||||
|
* removed from the control-flow graph, it becomes acyclic.
|
||||||
|
*/
|
||||||
|
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
|
||||||
|
// We don't take these edges from
|
||||||
|
// `Construction::getInstructionBackEdgeSuccessor` since that relation has
|
||||||
|
// not been treated to remove any loops that might be left over due to
|
||||||
|
// flaws in the IR construction or back-edge detection.
|
||||||
|
exists(IRBlock block |
|
||||||
|
block = this.getBlock() and
|
||||||
|
this = block.getLastInstruction() and
|
||||||
|
result = block.getBackEdgeSuccessor(kind).getFirstInstruction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all direct successors of this instruction.
|
* Gets all direct successors of this instruction.
|
||||||
*/
|
*/
|
||||||
@@ -578,19 +627,19 @@ class ConstantValueInstruction extends Instruction {
|
|||||||
|
|
||||||
class EnterFunctionInstruction extends Instruction {
|
class EnterFunctionInstruction extends Instruction {
|
||||||
EnterFunctionInstruction() {
|
EnterFunctionInstruction() {
|
||||||
opcode instanceof Opcode::EnterFunction
|
getOpcode() instanceof Opcode::EnterFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VariableAddressInstruction extends VariableInstruction {
|
class VariableAddressInstruction extends VariableInstruction {
|
||||||
VariableAddressInstruction() {
|
VariableAddressInstruction() {
|
||||||
opcode instanceof Opcode::VariableAddress
|
getOpcode() instanceof Opcode::VariableAddress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InitializeParameterInstruction extends VariableInstruction {
|
class InitializeParameterInstruction extends VariableInstruction {
|
||||||
InitializeParameterInstruction() {
|
InitializeParameterInstruction() {
|
||||||
opcode instanceof Opcode::InitializeParameter
|
getOpcode() instanceof Opcode::InitializeParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
final Parameter getParameter() {
|
final Parameter getParameter() {
|
||||||
@@ -607,13 +656,13 @@ class InitializeParameterInstruction extends VariableInstruction {
|
|||||||
*/
|
*/
|
||||||
class InitializeThisInstruction extends Instruction {
|
class InitializeThisInstruction extends Instruction {
|
||||||
InitializeThisInstruction() {
|
InitializeThisInstruction() {
|
||||||
opcode instanceof Opcode::InitializeThis
|
getOpcode() instanceof Opcode::InitializeThis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldAddressInstruction extends FieldInstruction {
|
class FieldAddressInstruction extends FieldInstruction {
|
||||||
FieldAddressInstruction() {
|
FieldAddressInstruction() {
|
||||||
opcode instanceof Opcode::FieldAddress
|
getOpcode() instanceof Opcode::FieldAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getObjectAddress() {
|
final Instruction getObjectAddress() {
|
||||||
@@ -623,7 +672,7 @@ class FieldAddressInstruction extends FieldInstruction {
|
|||||||
|
|
||||||
class UninitializedInstruction extends VariableInstruction {
|
class UninitializedInstruction extends VariableInstruction {
|
||||||
UninitializedInstruction() {
|
UninitializedInstruction() {
|
||||||
opcode instanceof Opcode::Uninitialized
|
getOpcode() instanceof Opcode::Uninitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -640,25 +689,25 @@ class UninitializedInstruction extends VariableInstruction {
|
|||||||
|
|
||||||
class NoOpInstruction extends Instruction {
|
class NoOpInstruction extends Instruction {
|
||||||
NoOpInstruction() {
|
NoOpInstruction() {
|
||||||
opcode instanceof Opcode::NoOp
|
getOpcode() instanceof Opcode::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnInstruction extends Instruction {
|
class ReturnInstruction extends Instruction {
|
||||||
ReturnInstruction() {
|
ReturnInstruction() {
|
||||||
opcode instanceof ReturnOpcode
|
getOpcode() instanceof ReturnOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnVoidInstruction extends ReturnInstruction {
|
class ReturnVoidInstruction extends ReturnInstruction {
|
||||||
ReturnVoidInstruction() {
|
ReturnVoidInstruction() {
|
||||||
opcode instanceof Opcode::ReturnVoid
|
getOpcode() instanceof Opcode::ReturnVoid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReturnValueInstruction extends ReturnInstruction {
|
class ReturnValueInstruction extends ReturnInstruction {
|
||||||
ReturnValueInstruction() {
|
ReturnValueInstruction() {
|
||||||
opcode instanceof Opcode::ReturnValue
|
getOpcode() instanceof Opcode::ReturnValue
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getReturnValue() {
|
final Instruction getReturnValue() {
|
||||||
@@ -668,7 +717,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
|||||||
|
|
||||||
class CopyInstruction extends Instruction {
|
class CopyInstruction extends Instruction {
|
||||||
CopyInstruction() {
|
CopyInstruction() {
|
||||||
opcode instanceof CopyOpcode
|
getOpcode() instanceof CopyOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getSourceValue() {
|
final Instruction getSourceValue() {
|
||||||
@@ -678,13 +727,13 @@ class CopyInstruction extends Instruction {
|
|||||||
|
|
||||||
class CopyValueInstruction extends CopyInstruction {
|
class CopyValueInstruction extends CopyInstruction {
|
||||||
CopyValueInstruction() {
|
CopyValueInstruction() {
|
||||||
opcode instanceof Opcode::CopyValue
|
getOpcode() instanceof Opcode::CopyValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LoadInstruction extends CopyInstruction {
|
class LoadInstruction extends CopyInstruction {
|
||||||
LoadInstruction() {
|
LoadInstruction() {
|
||||||
opcode instanceof Opcode::Load
|
getOpcode() instanceof Opcode::Load
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getSourceAddress() {
|
final Instruction getSourceAddress() {
|
||||||
@@ -694,7 +743,7 @@ class LoadInstruction extends CopyInstruction {
|
|||||||
|
|
||||||
class StoreInstruction extends CopyInstruction {
|
class StoreInstruction extends CopyInstruction {
|
||||||
StoreInstruction() {
|
StoreInstruction() {
|
||||||
opcode instanceof Opcode::Store
|
getOpcode() instanceof Opcode::Store
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -708,7 +757,7 @@ class StoreInstruction extends CopyInstruction {
|
|||||||
|
|
||||||
class ConditionalBranchInstruction extends Instruction {
|
class ConditionalBranchInstruction extends Instruction {
|
||||||
ConditionalBranchInstruction() {
|
ConditionalBranchInstruction() {
|
||||||
opcode instanceof Opcode::ConditionalBranch
|
getOpcode() instanceof Opcode::ConditionalBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getCondition() {
|
final Instruction getCondition() {
|
||||||
@@ -726,25 +775,25 @@ class ConditionalBranchInstruction extends Instruction {
|
|||||||
|
|
||||||
class ExitFunctionInstruction extends Instruction {
|
class ExitFunctionInstruction extends Instruction {
|
||||||
ExitFunctionInstruction() {
|
ExitFunctionInstruction() {
|
||||||
opcode instanceof Opcode::ExitFunction
|
getOpcode() instanceof Opcode::ExitFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConstantInstruction extends ConstantValueInstruction {
|
class ConstantInstruction extends ConstantValueInstruction {
|
||||||
ConstantInstruction() {
|
ConstantInstruction() {
|
||||||
opcode instanceof Opcode::Constant
|
getOpcode() instanceof Opcode::Constant
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IntegerConstantInstruction extends ConstantInstruction {
|
class IntegerConstantInstruction extends ConstantInstruction {
|
||||||
IntegerConstantInstruction() {
|
IntegerConstantInstruction() {
|
||||||
resultType instanceof IntegralType
|
getResultType() instanceof IntegralType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FloatConstantInstruction extends ConstantInstruction {
|
class FloatConstantInstruction extends ConstantInstruction {
|
||||||
FloatConstantInstruction() {
|
FloatConstantInstruction() {
|
||||||
resultType instanceof FloatingPointType
|
getResultType() instanceof FloatingPointType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,7 +815,7 @@ class StringConstantInstruction extends Instruction {
|
|||||||
|
|
||||||
class BinaryInstruction extends Instruction {
|
class BinaryInstruction extends Instruction {
|
||||||
BinaryInstruction() {
|
BinaryInstruction() {
|
||||||
opcode instanceof BinaryOpcode
|
getOpcode() instanceof BinaryOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getLeftOperand() {
|
final Instruction getLeftOperand() {
|
||||||
@@ -789,67 +838,67 @@ class BinaryInstruction extends Instruction {
|
|||||||
|
|
||||||
class AddInstruction extends BinaryInstruction {
|
class AddInstruction extends BinaryInstruction {
|
||||||
AddInstruction() {
|
AddInstruction() {
|
||||||
opcode instanceof Opcode::Add
|
getOpcode() instanceof Opcode::Add
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubInstruction extends BinaryInstruction {
|
class SubInstruction extends BinaryInstruction {
|
||||||
SubInstruction() {
|
SubInstruction() {
|
||||||
opcode instanceof Opcode::Sub
|
getOpcode() instanceof Opcode::Sub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MulInstruction extends BinaryInstruction {
|
class MulInstruction extends BinaryInstruction {
|
||||||
MulInstruction() {
|
MulInstruction() {
|
||||||
opcode instanceof Opcode::Mul
|
getOpcode() instanceof Opcode::Mul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DivInstruction extends BinaryInstruction {
|
class DivInstruction extends BinaryInstruction {
|
||||||
DivInstruction() {
|
DivInstruction() {
|
||||||
opcode instanceof Opcode::Div
|
getOpcode() instanceof Opcode::Div
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemInstruction extends BinaryInstruction {
|
class RemInstruction extends BinaryInstruction {
|
||||||
RemInstruction() {
|
RemInstruction() {
|
||||||
opcode instanceof Opcode::Rem
|
getOpcode() instanceof Opcode::Rem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NegateInstruction extends UnaryInstruction {
|
class NegateInstruction extends UnaryInstruction {
|
||||||
NegateInstruction() {
|
NegateInstruction() {
|
||||||
opcode instanceof Opcode::Negate
|
getOpcode() instanceof Opcode::Negate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitAndInstruction extends BinaryInstruction {
|
class BitAndInstruction extends BinaryInstruction {
|
||||||
BitAndInstruction() {
|
BitAndInstruction() {
|
||||||
opcode instanceof Opcode::BitAnd
|
getOpcode() instanceof Opcode::BitAnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitOrInstruction extends BinaryInstruction {
|
class BitOrInstruction extends BinaryInstruction {
|
||||||
BitOrInstruction() {
|
BitOrInstruction() {
|
||||||
opcode instanceof Opcode::BitOr
|
getOpcode() instanceof Opcode::BitOr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitXorInstruction extends BinaryInstruction {
|
class BitXorInstruction extends BinaryInstruction {
|
||||||
BitXorInstruction() {
|
BitXorInstruction() {
|
||||||
opcode instanceof Opcode::BitXor
|
getOpcode() instanceof Opcode::BitXor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShiftLeftInstruction extends BinaryInstruction {
|
class ShiftLeftInstruction extends BinaryInstruction {
|
||||||
ShiftLeftInstruction() {
|
ShiftLeftInstruction() {
|
||||||
opcode instanceof Opcode::ShiftLeft
|
getOpcode() instanceof Opcode::ShiftLeft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShiftRightInstruction extends BinaryInstruction {
|
class ShiftRightInstruction extends BinaryInstruction {
|
||||||
ShiftRightInstruction() {
|
ShiftRightInstruction() {
|
||||||
opcode instanceof Opcode::ShiftRight
|
getOpcode() instanceof Opcode::ShiftRight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -857,7 +906,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
|||||||
int elementSize;
|
int elementSize;
|
||||||
|
|
||||||
PointerArithmeticInstruction() {
|
PointerArithmeticInstruction() {
|
||||||
opcode instanceof PointerArithmeticOpcode and
|
getOpcode() instanceof PointerArithmeticOpcode and
|
||||||
elementSize = Construction::getInstructionElementSize(this)
|
elementSize = Construction::getInstructionElementSize(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,31 +921,31 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
|||||||
|
|
||||||
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
||||||
PointerOffsetInstruction() {
|
PointerOffsetInstruction() {
|
||||||
opcode instanceof PointerOffsetOpcode
|
getOpcode() instanceof PointerOffsetOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointerAddInstruction extends PointerOffsetInstruction {
|
class PointerAddInstruction extends PointerOffsetInstruction {
|
||||||
PointerAddInstruction() {
|
PointerAddInstruction() {
|
||||||
opcode instanceof Opcode::PointerAdd
|
getOpcode() instanceof Opcode::PointerAdd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointerSubInstruction extends PointerOffsetInstruction {
|
class PointerSubInstruction extends PointerOffsetInstruction {
|
||||||
PointerSubInstruction() {
|
PointerSubInstruction() {
|
||||||
opcode instanceof Opcode::PointerSub
|
getOpcode() instanceof Opcode::PointerSub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
||||||
PointerDiffInstruction() {
|
PointerDiffInstruction() {
|
||||||
opcode instanceof Opcode::PointerDiff
|
getOpcode() instanceof Opcode::PointerDiff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnaryInstruction extends Instruction {
|
class UnaryInstruction extends Instruction {
|
||||||
UnaryInstruction() {
|
UnaryInstruction() {
|
||||||
opcode instanceof UnaryOpcode
|
getOpcode() instanceof UnaryOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getOperand() {
|
final Instruction getOperand() {
|
||||||
@@ -906,7 +955,7 @@ class UnaryInstruction extends Instruction {
|
|||||||
|
|
||||||
class ConvertInstruction extends UnaryInstruction {
|
class ConvertInstruction extends UnaryInstruction {
|
||||||
ConvertInstruction() {
|
ConvertInstruction() {
|
||||||
opcode instanceof Opcode::Convert
|
getOpcode() instanceof Opcode::Convert
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -958,7 +1007,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
|||||||
*/
|
*/
|
||||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||||
ConvertToBaseInstruction() {
|
ConvertToBaseInstruction() {
|
||||||
opcode instanceof Opcode::ConvertToBase
|
getOpcode() instanceof Opcode::ConvertToBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,7 +1017,7 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
|||||||
*/
|
*/
|
||||||
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
||||||
ConvertToVirtualBaseInstruction() {
|
ConvertToVirtualBaseInstruction() {
|
||||||
opcode instanceof Opcode::ConvertToVirtualBase
|
getOpcode() instanceof Opcode::ConvertToVirtualBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -978,37 +1027,37 @@ class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
|||||||
*/
|
*/
|
||||||
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
||||||
ConvertToDerivedInstruction() {
|
ConvertToDerivedInstruction() {
|
||||||
opcode instanceof Opcode::ConvertToDerived
|
getOpcode() instanceof Opcode::ConvertToDerived
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitComplementInstruction extends UnaryInstruction {
|
class BitComplementInstruction extends UnaryInstruction {
|
||||||
BitComplementInstruction() {
|
BitComplementInstruction() {
|
||||||
opcode instanceof Opcode::BitComplement
|
getOpcode() instanceof Opcode::BitComplement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LogicalNotInstruction extends UnaryInstruction {
|
class LogicalNotInstruction extends UnaryInstruction {
|
||||||
LogicalNotInstruction() {
|
LogicalNotInstruction() {
|
||||||
opcode instanceof Opcode::LogicalNot
|
getOpcode() instanceof Opcode::LogicalNot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompareInstruction extends BinaryInstruction {
|
class CompareInstruction extends BinaryInstruction {
|
||||||
CompareInstruction() {
|
CompareInstruction() {
|
||||||
opcode instanceof CompareOpcode
|
getOpcode() instanceof CompareOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompareEQInstruction extends CompareInstruction {
|
class CompareEQInstruction extends CompareInstruction {
|
||||||
CompareEQInstruction() {
|
CompareEQInstruction() {
|
||||||
opcode instanceof Opcode::CompareEQ
|
getOpcode() instanceof Opcode::CompareEQ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompareNEInstruction extends CompareInstruction {
|
class CompareNEInstruction extends CompareInstruction {
|
||||||
CompareNEInstruction() {
|
CompareNEInstruction() {
|
||||||
opcode instanceof Opcode::CompareNE
|
getOpcode() instanceof Opcode::CompareNE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,7 +1066,7 @@ class CompareNEInstruction extends CompareInstruction {
|
|||||||
*/
|
*/
|
||||||
class RelationalInstruction extends CompareInstruction {
|
class RelationalInstruction extends CompareInstruction {
|
||||||
RelationalInstruction() {
|
RelationalInstruction() {
|
||||||
opcode instanceof RelationalOpcode
|
getOpcode() instanceof RelationalOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1050,7 +1099,7 @@ class RelationalInstruction extends CompareInstruction {
|
|||||||
|
|
||||||
class CompareLTInstruction extends RelationalInstruction {
|
class CompareLTInstruction extends RelationalInstruction {
|
||||||
CompareLTInstruction() {
|
CompareLTInstruction() {
|
||||||
opcode instanceof Opcode::CompareLT
|
getOpcode() instanceof Opcode::CompareLT
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1068,7 +1117,7 @@ class CompareLTInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class CompareGTInstruction extends RelationalInstruction {
|
class CompareGTInstruction extends RelationalInstruction {
|
||||||
CompareGTInstruction() {
|
CompareGTInstruction() {
|
||||||
opcode instanceof Opcode::CompareGT
|
getOpcode() instanceof Opcode::CompareGT
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1086,7 +1135,7 @@ class CompareGTInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class CompareLEInstruction extends RelationalInstruction {
|
class CompareLEInstruction extends RelationalInstruction {
|
||||||
CompareLEInstruction() {
|
CompareLEInstruction() {
|
||||||
opcode instanceof Opcode::CompareLE
|
getOpcode() instanceof Opcode::CompareLE
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1104,7 +1153,7 @@ class CompareLEInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class CompareGEInstruction extends RelationalInstruction {
|
class CompareGEInstruction extends RelationalInstruction {
|
||||||
CompareGEInstruction() {
|
CompareGEInstruction() {
|
||||||
opcode instanceof Opcode::CompareGE
|
getOpcode() instanceof Opcode::CompareGE
|
||||||
}
|
}
|
||||||
|
|
||||||
override Instruction getLesserOperand() {
|
override Instruction getLesserOperand() {
|
||||||
@@ -1122,7 +1171,7 @@ class CompareGEInstruction extends RelationalInstruction {
|
|||||||
|
|
||||||
class SwitchInstruction extends Instruction {
|
class SwitchInstruction extends Instruction {
|
||||||
SwitchInstruction() {
|
SwitchInstruction() {
|
||||||
opcode instanceof Opcode::Switch
|
getOpcode() instanceof Opcode::Switch
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getExpression() {
|
final Instruction getExpression() {
|
||||||
@@ -1145,7 +1194,7 @@ class SwitchInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CallInstruction extends Instruction {
|
class CallInstruction extends Instruction {
|
||||||
CallInstruction() {
|
CallInstruction() {
|
||||||
opcode instanceof Opcode::Call
|
getOpcode() instanceof Opcode::Call
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1188,7 +1237,7 @@ class CallInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class SideEffectInstruction extends Instruction {
|
class SideEffectInstruction extends Instruction {
|
||||||
SideEffectInstruction() {
|
SideEffectInstruction() {
|
||||||
opcode instanceof SideEffectOpcode
|
getOpcode() instanceof SideEffectOpcode
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getPrimaryInstruction() {
|
final Instruction getPrimaryInstruction() {
|
||||||
@@ -1202,7 +1251,7 @@ class SideEffectInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallSideEffectInstruction() {
|
CallSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::CallSideEffect
|
getOpcode() instanceof Opcode::CallSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1216,7 +1265,7 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallReadSideEffectInstruction() {
|
CallReadSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::CallReadSideEffect
|
getOpcode() instanceof Opcode::CallReadSideEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1225,7 +1274,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
IndirectReadSideEffectInstruction() {
|
IndirectReadSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::IndirectReadSideEffect
|
getOpcode() instanceof Opcode::IndirectReadSideEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1234,7 +1283,7 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
BufferReadSideEffectInstruction() {
|
BufferReadSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::BufferReadSideEffect
|
getOpcode() instanceof Opcode::BufferReadSideEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1243,7 +1292,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
IndirectWriteSideEffectInstruction() {
|
IndirectWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::IndirectWriteSideEffect
|
getOpcode() instanceof Opcode::IndirectWriteSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1257,7 +1306,7 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
BufferWriteSideEffectInstruction() {
|
BufferWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::BufferWriteSideEffect
|
getOpcode() instanceof Opcode::BufferWriteSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1272,7 +1321,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
IndirectMayWriteSideEffectInstruction() {
|
IndirectMayWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::IndirectMayWriteSideEffect
|
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1286,7 +1335,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||||
BufferMayWriteSideEffectInstruction() {
|
BufferMayWriteSideEffectInstruction() {
|
||||||
opcode instanceof Opcode::BufferMayWriteSideEffect
|
getOpcode() instanceof Opcode::BufferMayWriteSideEffect
|
||||||
}
|
}
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
result instanceof BufferMayMemoryAccess
|
result instanceof BufferMayMemoryAccess
|
||||||
@@ -1298,7 +1347,7 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class ThrowInstruction extends Instruction {
|
class ThrowInstruction extends Instruction {
|
||||||
ThrowInstruction() {
|
ThrowInstruction() {
|
||||||
opcode instanceof ThrowOpcode
|
getOpcode() instanceof ThrowOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1307,7 +1356,7 @@ class ThrowInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class ThrowValueInstruction extends ThrowInstruction {
|
class ThrowValueInstruction extends ThrowInstruction {
|
||||||
ThrowValueInstruction() {
|
ThrowValueInstruction() {
|
||||||
opcode instanceof Opcode::ThrowValue
|
getOpcode() instanceof Opcode::ThrowValue
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1330,7 +1379,7 @@ class ThrowValueInstruction extends ThrowInstruction {
|
|||||||
*/
|
*/
|
||||||
class ReThrowInstruction extends ThrowInstruction {
|
class ReThrowInstruction extends ThrowInstruction {
|
||||||
ReThrowInstruction() {
|
ReThrowInstruction() {
|
||||||
opcode instanceof Opcode::ReThrow
|
getOpcode() instanceof Opcode::ReThrow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1339,7 +1388,7 @@ class ReThrowInstruction extends ThrowInstruction {
|
|||||||
*/
|
*/
|
||||||
class UnwindInstruction extends Instruction {
|
class UnwindInstruction extends Instruction {
|
||||||
UnwindInstruction() {
|
UnwindInstruction() {
|
||||||
opcode instanceof Opcode::Unwind
|
getOpcode() instanceof Opcode::Unwind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,7 +1397,7 @@ class UnwindInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CatchInstruction extends Instruction {
|
class CatchInstruction extends Instruction {
|
||||||
CatchInstruction() {
|
CatchInstruction() {
|
||||||
opcode instanceof CatchOpcode
|
getOpcode() instanceof CatchOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1359,7 +1408,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
|||||||
Type exceptionType;
|
Type exceptionType;
|
||||||
|
|
||||||
CatchByTypeInstruction() {
|
CatchByTypeInstruction() {
|
||||||
opcode instanceof Opcode::CatchByType and
|
getOpcode() instanceof Opcode::CatchByType and
|
||||||
exceptionType = Construction::getInstructionExceptionType(this)
|
exceptionType = Construction::getInstructionExceptionType(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,13 +1429,13 @@ class CatchByTypeInstruction extends CatchInstruction {
|
|||||||
*/
|
*/
|
||||||
class CatchAnyInstruction extends CatchInstruction {
|
class CatchAnyInstruction extends CatchInstruction {
|
||||||
CatchAnyInstruction() {
|
CatchAnyInstruction() {
|
||||||
opcode instanceof Opcode::CatchAny
|
getOpcode() instanceof Opcode::CatchAny
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnmodeledDefinitionInstruction extends Instruction {
|
class UnmodeledDefinitionInstruction extends Instruction {
|
||||||
UnmodeledDefinitionInstruction() {
|
UnmodeledDefinitionInstruction() {
|
||||||
opcode instanceof Opcode::UnmodeledDefinition
|
getOpcode() instanceof Opcode::UnmodeledDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1399,7 +1448,7 @@ class UnmodeledDefinitionInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class AliasedDefinitionInstruction extends Instruction {
|
class AliasedDefinitionInstruction extends Instruction {
|
||||||
AliasedDefinitionInstruction() {
|
AliasedDefinitionInstruction() {
|
||||||
opcode instanceof Opcode::AliasedDefinition
|
getOpcode() instanceof Opcode::AliasedDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1409,7 +1458,7 @@ class AliasedDefinitionInstruction extends Instruction {
|
|||||||
|
|
||||||
class UnmodeledUseInstruction extends Instruction {
|
class UnmodeledUseInstruction extends Instruction {
|
||||||
UnmodeledUseInstruction() {
|
UnmodeledUseInstruction() {
|
||||||
opcode instanceof Opcode::UnmodeledUse
|
getOpcode() instanceof Opcode::UnmodeledUse
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getOperandsString() {
|
override string getOperandsString() {
|
||||||
@@ -1429,7 +1478,7 @@ class UnmodeledUseInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class PhiInstruction extends Instruction {
|
class PhiInstruction extends Instruction {
|
||||||
PhiInstruction() {
|
PhiInstruction() {
|
||||||
opcode instanceof Opcode::Phi
|
getOpcode() instanceof Opcode::Phi
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1481,7 +1530,7 @@ class PhiInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class ChiInstruction extends Instruction {
|
class ChiInstruction extends Instruction {
|
||||||
ChiInstruction() {
|
ChiInstruction() {
|
||||||
opcode instanceof Opcode::Chi
|
getOpcode() instanceof Opcode::Chi
|
||||||
}
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getResultMemoryAccess() {
|
override final MemoryAccessKind getResultMemoryAccess() {
|
||||||
@@ -1511,7 +1560,7 @@ class ChiInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class UnreachedInstruction extends Instruction {
|
class UnreachedInstruction extends Instruction {
|
||||||
UnreachedInstruction() {
|
UnreachedInstruction() {
|
||||||
opcode instanceof Opcode::Unreached
|
getOpcode() instanceof Opcode::Unreached
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1521,6 +1570,6 @@ class UnreachedInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class BuiltInInstruction extends Instruction {
|
class BuiltInInstruction extends Instruction {
|
||||||
BuiltInInstruction() {
|
BuiltInInstruction() {
|
||||||
opcode instanceof BuiltInOpcode
|
getOpcode() instanceof BuiltInOpcode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,7 +287,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
|||||||
(
|
(
|
||||||
(
|
(
|
||||||
key = "semmle.label" and
|
key = "semmle.label" and
|
||||||
value = kind.toString()
|
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||||
|
then value = kind.toString() + " (back edge)"
|
||||||
|
else value = kind.toString()
|
||||||
) or
|
) or
|
||||||
(
|
(
|
||||||
key = "semmle.order" and
|
key = "semmle.order" and
|
||||||
|
|||||||
@@ -14,25 +14,6 @@ cached private module Cached {
|
|||||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
}
|
}
|
||||||
|
|
||||||
cached newtype TInstructionTag =
|
|
||||||
WrappedInstructionTag(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction
|
|
||||||
} or
|
|
||||||
PhiTag(Alias::VirtualVariable vvar, OldBlock block) {
|
|
||||||
hasPhiNode(vvar, block)
|
|
||||||
} or
|
|
||||||
ChiTag(OldInstruction oldInstruction) {
|
|
||||||
not oldInstruction instanceof OldIR::PhiInstruction and
|
|
||||||
hasChiNode(_, oldInstruction)
|
|
||||||
} or
|
|
||||||
UnreachedTag()
|
|
||||||
|
|
||||||
cached class InstructionTagType extends TInstructionTag {
|
|
||||||
cached final string toString() {
|
|
||||||
result = "Tag"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cached predicate functionHasIR(Function func) {
|
cached predicate functionHasIR(Function func) {
|
||||||
exists(OldIR::FunctionIR funcIR |
|
exists(OldIR::FunctionIR funcIR |
|
||||||
funcIR.getFunction() = func
|
funcIR.getFunction() = func
|
||||||
@@ -40,7 +21,7 @@ cached private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached OldInstruction getOldInstruction(Instruction instr) {
|
cached OldInstruction getOldInstruction(Instruction instr) {
|
||||||
instr.getTag() = WrappedInstructionTag(result)
|
instr = WrappedInstruction(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
private Instruction getNewInstruction(OldInstruction instr) {
|
private Instruction getNewInstruction(OldInstruction instr) {
|
||||||
@@ -52,90 +33,35 @@ cached private module Cached {
|
|||||||
* corresponding to `instr` if there is no `Chi` node.
|
* corresponding to `instr` if there is no `Chi` node.
|
||||||
*/
|
*/
|
||||||
private Instruction getNewFinalInstruction(OldInstruction instr) {
|
private Instruction getNewFinalInstruction(OldInstruction instr) {
|
||||||
result = getChiInstruction(instr)
|
result = Chi(instr)
|
||||||
or
|
or
|
||||||
not exists(getChiInstruction(instr)) and
|
not exists(Chi(instr)) and
|
||||||
result = getNewInstruction(instr)
|
result = getNewInstruction(instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
private PhiInstruction getPhiInstruction(Function func, OldBlock oldBlock,
|
|
||||||
Alias::VirtualVariable vvar) {
|
|
||||||
result.getFunction() = func and
|
|
||||||
result.getAST() = oldBlock.getFirstInstruction().getAST() and
|
|
||||||
result.getTag() = PhiTag(vvar, oldBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChiInstruction getChiInstruction (OldInstruction instr) {
|
|
||||||
hasChiNode(_, instr) and
|
|
||||||
result.getTag() = ChiTag(instr)
|
|
||||||
}
|
|
||||||
|
|
||||||
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
private IRVariable getNewIRVariable(OldIR::IRVariable var) {
|
||||||
result.getFunction() = var.getFunction() and
|
// This is just a type cast. Both classes derive from the same newtype.
|
||||||
(
|
result = var
|
||||||
exists(OldIR::IRUserVariable userVar, IRUserVariable newUserVar |
|
|
||||||
userVar = var and
|
|
||||||
newUserVar.getVariable() = userVar.getVariable() and
|
|
||||||
result = newUserVar
|
|
||||||
) or
|
|
||||||
exists(OldIR::IRTempVariable tempVar, IRTempVariable newTempVar |
|
|
||||||
tempVar = var and
|
|
||||||
newTempVar.getAST() = tempVar.getAST() and
|
|
||||||
newTempVar.getTag() = tempVar.getTag() and
|
|
||||||
result = newTempVar
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached newtype TInstruction =
|
cached newtype TInstruction =
|
||||||
MkInstruction(FunctionIR funcIR, Opcode opcode, Locatable ast,
|
WrappedInstruction(OldInstruction oldInstruction) {
|
||||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
not oldInstruction instanceof OldIR::PhiInstruction
|
||||||
hasInstruction(funcIR.getFunction(), opcode, ast, tag,
|
} or
|
||||||
resultType, isGLValue)
|
Phi(OldBlock block, Alias::VirtualVariable vvar) {
|
||||||
|
hasPhiNode(vvar, block)
|
||||||
|
} or
|
||||||
|
Chi(OldInstruction oldInstruction) {
|
||||||
|
not oldInstruction instanceof OldIR::PhiInstruction and
|
||||||
|
hasChiNode(_, oldInstruction)
|
||||||
|
} or
|
||||||
|
Unreached(Function function) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
function = oldInstruction.getFunction() and
|
||||||
|
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate hasInstruction(Function func, Opcode opcode, Locatable ast,
|
|
||||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
|
||||||
exists(OldInstruction instr |
|
|
||||||
instr.getFunction() = func and
|
|
||||||
instr.getOpcode() = opcode and
|
|
||||||
instr.getAST() = ast and
|
|
||||||
WrappedInstructionTag(instr) = tag and
|
|
||||||
instr.getResultType() = resultType and
|
|
||||||
if instr.isGLValue() then
|
|
||||||
isGLValue = true
|
|
||||||
else
|
|
||||||
isGLValue = false
|
|
||||||
) or
|
|
||||||
exists(OldBlock block, Alias::VirtualVariable vvar |
|
|
||||||
hasPhiNode(vvar, block) and
|
|
||||||
block.getFunction() = func and
|
|
||||||
opcode instanceof Opcode::Phi and
|
|
||||||
ast = block.getFirstInstruction().getAST() and
|
|
||||||
tag = PhiTag(vvar, block) and
|
|
||||||
resultType = vvar.getType() and
|
|
||||||
isGLValue = false
|
|
||||||
) or
|
|
||||||
exists(OldInstruction instr, Alias::VirtualVariable vvar |
|
|
||||||
hasChiNode(vvar, instr) and
|
|
||||||
instr.getFunction() = func and
|
|
||||||
opcode instanceof Opcode::Chi and
|
|
||||||
ast = instr.getAST() and
|
|
||||||
tag = ChiTag(instr) and
|
|
||||||
resultType = vvar.getType() and
|
|
||||||
isGLValue = false
|
|
||||||
) or
|
|
||||||
exists(OldInstruction oldInstruction |
|
|
||||||
func = oldInstruction.getFunction() and
|
|
||||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) and
|
|
||||||
tag = UnreachedTag() and
|
|
||||||
opcode instanceof Opcode::Unreached and
|
|
||||||
ast = func and
|
|
||||||
resultType instanceof VoidType and
|
|
||||||
isGLValue = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
||||||
Type type) {
|
Type type) {
|
||||||
exists(OldIR::IRTempVariable var |
|
exists(OldIR::IRTempVariable var |
|
||||||
@@ -169,7 +95,7 @@ cached private module Cached {
|
|||||||
if defIndex >= 0 then
|
if defIndex >= 0 then
|
||||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||||
else
|
else
|
||||||
result = getPhiInstruction(instruction.getFunction(), defBlock, vvar)
|
result = Phi(defBlock, vvar)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else (
|
else (
|
||||||
@@ -189,13 +115,14 @@ cached private module Cached {
|
|||||||
else
|
else
|
||||||
result = getNewInstruction(oldOperand.getDefinitionInstruction())
|
result = getNewInstruction(oldOperand.getDefinitionInstruction())
|
||||||
) or
|
) or
|
||||||
instruction.getTag() = ChiTag(getOldInstruction(result)) and
|
instruction = Chi(getOldInstruction(result)) and
|
||||||
tag instanceof ChiPartialOperandTag
|
tag instanceof ChiPartialOperandTag
|
||||||
or
|
or
|
||||||
instruction instanceof UnmodeledUseInstruction and
|
exists(FunctionIR f |
|
||||||
tag instanceof UnmodeledUseOperandTag and
|
tag instanceof UnmodeledUseOperandTag and
|
||||||
result instanceof UnmodeledDefinitionInstruction and
|
result = f.getUnmodeledDefinitionInstruction() and
|
||||||
instruction.getFunction() = result.getFunction()
|
instruction = f.getUnmodeledUseInstruction()
|
||||||
|
)
|
||||||
or
|
or
|
||||||
tag instanceof ChiTotalOperandTag and
|
tag instanceof ChiTotalOperandTag and
|
||||||
result = getChiInstructionTotalOperand(instruction)
|
result = getChiInstructionTotalOperand(instruction)
|
||||||
@@ -207,21 +134,21 @@ cached private module Cached {
|
|||||||
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
|
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
|
||||||
hasPhiNode(vvar, phiBlock) and
|
hasPhiNode(vvar, phiBlock) and
|
||||||
predBlock = phiBlock.getAFeasiblePredecessor() and
|
predBlock = phiBlock.getAFeasiblePredecessor() and
|
||||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
instr = Phi(phiBlock, vvar) and
|
||||||
newPredecessorBlock = getNewBlock(predBlock) and
|
newPredecessorBlock = getNewBlock(predBlock) and
|
||||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||||
if defIndex >= 0 then
|
if defIndex >= 0 then
|
||||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||||
else
|
else
|
||||||
result = getPhiInstruction(instr.getFunction(), defBlock, vvar)
|
result = Phi(defBlock, vvar)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
|
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
|
||||||
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
|
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
|
||||||
int defRank, int defIndex, OldBlock useBlock, int useRank |
|
int defRank, int defIndex, OldBlock useBlock, int useRank |
|
||||||
ChiTag(oldInstr) = chiInstr.getTag() and
|
chiInstr = Chi(oldInstr) and
|
||||||
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
|
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
|
||||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||||
@@ -229,13 +156,13 @@ cached private module Cached {
|
|||||||
if defIndex >= 0 then
|
if defIndex >= 0 then
|
||||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||||
else
|
else
|
||||||
result = getPhiInstruction(chiInstr.getFunction(), defBlock, vvar)
|
result = Phi(defBlock, vvar)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||||
exists(OldBlock oldBlock |
|
exists(OldBlock oldBlock |
|
||||||
instr.getTag() = PhiTag(_, oldBlock) and
|
instr = Phi(oldBlock, _) and
|
||||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -256,15 +183,14 @@ cached private module Cached {
|
|||||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||||
if(hasChiNode(_, getOldInstruction(instruction)))
|
if(hasChiNode(_, getOldInstruction(instruction)))
|
||||||
then
|
then
|
||||||
result = getChiInstruction(getOldInstruction(instruction)) and
|
result = Chi(getOldInstruction(instruction)) and
|
||||||
kind instanceof GotoEdge
|
kind instanceof GotoEdge
|
||||||
else (
|
else (
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
oldInstruction = getOldInstruction(instruction) and
|
oldInstruction = getOldInstruction(instruction) and
|
||||||
(
|
(
|
||||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) then (
|
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) then (
|
||||||
result.getTag() = UnreachedTag() and
|
result = Unreached(instruction.getFunction())
|
||||||
result.getFunction() = instruction.getFunction()
|
|
||||||
)
|
)
|
||||||
else (
|
else (
|
||||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
@@ -272,12 +198,106 @@ cached private module Cached {
|
|||||||
)
|
)
|
||||||
) or
|
) or
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
instruction = getChiInstruction(oldInstruction) and
|
instruction = Chi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
result = getNewInstruction(oldInstruction.getSuccessor(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
|
||||||
|
// SSA construction never inserts extra instructions _before_ an existing
|
||||||
|
// instruction.
|
||||||
|
getOldInstruction(result) = oldInstruction.getBackEdgeSuccessor(kind) and
|
||||||
|
// There are two cases for the translation into `instruction` because the
|
||||||
|
// SSA construction might have inserted a chi node _after_
|
||||||
|
// `oldInstruction`, in which case the back edge should come out of the
|
||||||
|
// chi node instead.
|
||||||
|
if hasChiNode(_, oldInstruction)
|
||||||
|
then instruction = Chi(oldInstruction)
|
||||||
|
else instruction = getNewInstruction(oldInstruction)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached Locatable getInstructionAST(Instruction instruction) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
instruction = WrappedInstruction(oldInstruction)
|
||||||
|
or
|
||||||
|
instruction = Chi(oldInstruction)
|
||||||
|
|
|
||||||
|
result = oldInstruction.getAST()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(OldBlock block |
|
||||||
|
instruction = Phi(block, _) and
|
||||||
|
result = block.getFirstInstruction().getAST()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
instruction = Unreached(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
|
||||||
|
instruction = Chi(oldInstruction) and
|
||||||
|
hasChiNode(vvar, oldInstruction) and
|
||||||
|
type = vvar.getType() and
|
||||||
|
isGLValue = false
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(Alias::VirtualVariable vvar |
|
||||||
|
instruction = Phi(_, vvar) and
|
||||||
|
type = vvar.getType() and
|
||||||
|
isGLValue = false
|
||||||
|
)
|
||||||
|
or
|
||||||
|
instruction = Unreached(_) and
|
||||||
|
type instanceof VoidType and
|
||||||
|
isGLValue = false
|
||||||
|
}
|
||||||
|
|
||||||
|
cached Opcode getInstructionOpcode(Instruction instruction) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
instruction = WrappedInstruction(oldInstruction) and
|
||||||
|
result = oldInstruction.getOpcode()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
instruction instanceof Chi and
|
||||||
|
result instanceof Opcode::Chi
|
||||||
|
or
|
||||||
|
instruction instanceof Phi and
|
||||||
|
result instanceof Opcode::Phi
|
||||||
|
or
|
||||||
|
instruction instanceof Unreached and
|
||||||
|
result instanceof Opcode::Unreached
|
||||||
|
}
|
||||||
|
|
||||||
|
cached FunctionIR getInstructionEnclosingFunctionIR(Instruction instruction) {
|
||||||
|
exists(OldInstruction oldInstruction |
|
||||||
|
instruction = WrappedInstruction(oldInstruction)
|
||||||
|
or
|
||||||
|
instruction = Chi(oldInstruction)
|
||||||
|
|
|
||||||
|
result.getFunction() = oldInstruction.getFunction()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(OldBlock block |
|
||||||
|
instruction = Phi(block, _) and
|
||||||
|
result.getFunction() = block.getFunction()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
instruction = Unreached(result.getFunction())
|
||||||
|
}
|
||||||
|
|
||||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||||
}
|
}
|
||||||
@@ -328,13 +348,13 @@ cached private module Cached {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldIR::Instruction oldInstruction |
|
exists(OldIR::Instruction oldInstruction |
|
||||||
instruction.getTag() = ChiTag(oldInstruction) and
|
instruction = Chi(oldInstruction) and
|
||||||
result = getNewInstruction(oldInstruction)
|
result = getNewInstruction(oldInstruction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||||
OldInstruction instr, OldBlock block, int index) {
|
OldBlock block, int index, OldInstruction instr) {
|
||||||
block.getInstruction(index) = instr and
|
block.getInstruction(index) = instr and
|
||||||
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
|
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
|
||||||
}
|
}
|
||||||
@@ -352,11 +372,11 @@ cached private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate defUseRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex, int index) {
|
private predicate defUseRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex, int index) {
|
||||||
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
|
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, block, j, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate hasUse(Alias::VirtualVariable vvar, OldInstruction use, OldBlock block,
|
private predicate hasUse(Alias::VirtualVariable vvar, OldBlock block, int index,
|
||||||
int index) {
|
OldInstruction use) {
|
||||||
exists(Alias::MemoryAccess access |
|
exists(Alias::MemoryAccess access |
|
||||||
(
|
(
|
||||||
access = Alias::getOperandMemoryAccess(use.getAnOperand())
|
access = Alias::getOperandMemoryAccess(use.getAnOperand())
|
||||||
@@ -374,10 +394,16 @@ cached private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
|
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
|
||||||
exists (int index | hasUse(vvar, _, block, index) |
|
exists(int firstAccess |
|
||||||
not exists (int j | ssa_variableUpdate(vvar, _, block, j) | j < index)
|
hasUse(vvar, block, firstAccess, _) and
|
||||||
) or
|
firstAccess = min(int index |
|
||||||
(variableLiveOnExitFromBlock(vvar, block) and not ssa_variableUpdate(vvar, _, block, _))
|
hasUse(vvar, block, index, _)
|
||||||
|
or
|
||||||
|
ssa_variableUpdate(vvar, block, index, _)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
(variableLiveOnExitFromBlock(vvar, block) and not ssa_variableUpdate(vvar, block, _, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
@@ -404,7 +430,7 @@ cached private module Cached {
|
|||||||
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
|
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
|
||||||
OldInstruction use) {
|
OldInstruction use) {
|
||||||
exists(int index |
|
exists(int index |
|
||||||
hasUse(vvar, use, block, index) and
|
hasUse(vvar, block, index, use) and
|
||||||
defUseRank(vvar, block, rankIndex, index)
|
defUseRank(vvar, block, rankIndex, index)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -517,11 +543,11 @@ cached private module CachedForDebugging {
|
|||||||
result = "NonSSA: " + oldInstr.getUniqueId()
|
result = "NonSSA: " + oldInstr.getUniqueId()
|
||||||
) or
|
) or
|
||||||
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
|
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
|
||||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
instr = Phi(phiBlock, vvar) and
|
||||||
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
||||||
) or
|
) or
|
||||||
(
|
(
|
||||||
instr.getTag() = UnreachedTag() and
|
instr = Unreached(_) and
|
||||||
result = "Unreached"
|
result = "Unreached"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
25
cpp/ql/src/semmle/code/cpp/ir/internal/TIRVariable.qll
Normal file
25
cpp/ql/src/semmle/code/cpp/ir/internal/TIRVariable.qll
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
private import cpp
|
||||||
|
private import semmle.code.cpp.ir.implementation.TempVariableTag
|
||||||
|
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as Construction
|
||||||
|
|
||||||
|
newtype TIRVariable =
|
||||||
|
TIRAutomaticUserVariable(LocalScopeVariable var, Function func) {
|
||||||
|
Construction::functionHasIR(func) and
|
||||||
|
var.getFunction() = func or
|
||||||
|
var.(Parameter).getCatchBlock().getEnclosingFunction() = func
|
||||||
|
} or
|
||||||
|
TIRStaticUserVariable(Variable var, Function func) {
|
||||||
|
Construction::functionHasIR(func) and
|
||||||
|
(
|
||||||
|
var instanceof GlobalOrNamespaceVariable or
|
||||||
|
var instanceof MemberVariable and not var instanceof Field
|
||||||
|
) and
|
||||||
|
exists(VariableAccess access |
|
||||||
|
access.getTarget() = var and
|
||||||
|
access.getEnclosingFunction() = func
|
||||||
|
)
|
||||||
|
} or
|
||||||
|
TIRTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) {
|
||||||
|
Construction::hasTempVariable(func, ast, tag, type)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -559,47 +559,44 @@ private predicate boundedCastExpr(
|
|||||||
private predicate boundedInstruction(
|
private predicate boundedInstruction(
|
||||||
Instruction i, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, Reason reason
|
Instruction i, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, Reason reason
|
||||||
) {
|
) {
|
||||||
isReducibleCFG(i.getFunction()) and
|
i instanceof PhiInstruction and
|
||||||
(
|
forex(PhiOperand op | op = i.getAnOperand() |
|
||||||
i instanceof PhiInstruction and
|
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
|
||||||
forex(PhiOperand op | op = i.getAnOperand() |
|
)
|
||||||
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
|
or
|
||||||
)
|
i = b.getInstruction(delta) and
|
||||||
or
|
(upper = true or upper = false) and
|
||||||
i = b.getInstruction(delta) and
|
fromBackEdge = false and
|
||||||
(upper = true or upper = false) and
|
origdelta = delta and
|
||||||
fromBackEdge = false and
|
reason = TNoReason()
|
||||||
origdelta = delta and
|
or
|
||||||
reason = TNoReason()
|
exists(Operand mid, int d1, int d2 |
|
||||||
or
|
boundFlowStep(i, mid, d1, upper) and
|
||||||
exists(Operand mid, int d1, int d2 |
|
boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
|
||||||
boundFlowStep(i, mid, d1, upper) and
|
delta = d1 + d2 and
|
||||||
boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
|
not exists(getValue(getConstantValue(i)))
|
||||||
delta = d1 + d2 and
|
)
|
||||||
not exists(getValue(getConstantValue(i)))
|
or
|
||||||
)
|
exists(Operand mid, int factor, int d |
|
||||||
or
|
boundFlowStepMul(i, mid, factor) and
|
||||||
exists(Operand mid, int factor, int d |
|
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||||
boundFlowStepMul(i, mid, factor) and
|
b instanceof ZeroBound and
|
||||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
delta = d*factor and
|
||||||
b instanceof ZeroBound and
|
not exists(getValue(getConstantValue(i)))
|
||||||
delta = d*factor and
|
)
|
||||||
not exists(getValue(getConstantValue(i)))
|
or
|
||||||
)
|
exists(Operand mid, int factor, int d |
|
||||||
or
|
boundFlowStepDiv(i, mid, factor) and
|
||||||
exists(Operand mid, int factor, int d |
|
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||||
boundFlowStepDiv(i, mid, factor) and
|
d >= 0 and
|
||||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
b instanceof ZeroBound and
|
||||||
d >= 0 and
|
delta = d / factor and
|
||||||
b instanceof ZeroBound and
|
not exists(getValue(getConstantValue(i)))
|
||||||
delta = d / factor and
|
)
|
||||||
not exists(getValue(getConstantValue(i)))
|
or
|
||||||
)
|
exists(NarrowingCastInstruction cast |
|
||||||
or
|
cast = i and
|
||||||
exists(NarrowingCastInstruction cast |
|
safeNarrowingCast(cast, upper.booleanNot()) and
|
||||||
cast = i and
|
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
|
||||||
safeNarrowingCast(cast, upper.booleanNot()) and
|
|
||||||
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,24 +63,7 @@ predicate valueFlowStep(Instruction i, Operand op, int delta) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isReducibleCFG(Function f) {
|
|
||||||
not exists(LabelStmt l, GotoStmt goto |
|
|
||||||
goto.getTarget() = l and
|
|
||||||
l.getLocation().isBefore(goto.getLocation()) and
|
|
||||||
l.getEnclosingFunction() = f
|
|
||||||
) and
|
|
||||||
not exists(LabelStmt ls, Loop l |
|
|
||||||
ls.getParent*() = l and
|
|
||||||
l.getEnclosingFunction() = f
|
|
||||||
) and
|
|
||||||
not exists(SwitchCase cs |
|
|
||||||
cs.getSwitchStmt().getStmt() != cs.getParentStmt() and
|
|
||||||
cs.getEnclosingFunction() = f
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate backEdge(PhiInstruction phi, PhiOperand op) {
|
predicate backEdge(PhiInstruction phi, PhiOperand op) {
|
||||||
phi.getAnOperand() = op and
|
phi.getAnOperand() = op and
|
||||||
phi.getBlock().dominates(op.getPredecessorBlock())
|
phi.getBlock() = op.getPredecessorBlock().getBackEdgeSuccessor(_)
|
||||||
// TODO: identify backedges during IR construction
|
}
|
||||||
}
|
|
||||||
|
|||||||
86
cpp/ql/test/library-tests/constants/addresses/addresses.cpp
Normal file
86
cpp/ql/test/library-tests/constants/addresses/addresses.cpp
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// semmle-extractor-options: --c++14
|
||||||
|
|
||||||
|
const int int_const = 1;
|
||||||
|
extern const int extern_int_const = 1;
|
||||||
|
extern const int extern_int_const_noinit;
|
||||||
|
|
||||||
|
int int_var;
|
||||||
|
int int_arr[4];
|
||||||
|
int int_arr_arr[4][4];
|
||||||
|
|
||||||
|
int *const const_ptr = &int_var;
|
||||||
|
|
||||||
|
void sideEffect();
|
||||||
|
using fptr = void (*)();
|
||||||
|
using fref = void (&)();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// All variables in this function are initialized to constants, as witnessed by
|
||||||
|
// the `constexpr` annotation that compiles under C++14.
|
||||||
|
void constantAddresses(int param) {
|
||||||
|
constexpr int *ptr_int = &int_var;
|
||||||
|
constexpr int *ptr_deref_chain = &*&int_var;
|
||||||
|
constexpr int *ptr_array = &int_arr[1] + 1;
|
||||||
|
constexpr int (*ptr_to_array)[4] = &int_arr_arr[1] + 1;
|
||||||
|
constexpr int *array2d = &int_arr_arr[1][1] + 1;
|
||||||
|
constexpr int *const_ints = &int_arr_arr[int_const][extern_int_const];
|
||||||
|
|
||||||
|
// Commented out because clang and EDG disagree on whether this is
|
||||||
|
// constant.
|
||||||
|
//constexpr int *stmtexpr_int = &int_arr[ ({ 1; }) ];
|
||||||
|
|
||||||
|
constexpr int *comma_int = &int_arr[ ((void)0, 1) ];
|
||||||
|
constexpr int *comma_addr = ((void)0, &int_var);
|
||||||
|
constexpr int *ternary_true = int_const ? &int_var : ¶m;
|
||||||
|
constexpr int *ternary_false = !int_const ? ¶m : &int_var;
|
||||||
|
constexpr int *ternary_overflow = (unsigned char)256 ? ¶m : &int_var;
|
||||||
|
constexpr int *ternary_ptr_cond = (&int_arr+1) ? &int_var : ¶m;;
|
||||||
|
constexpr int *ptr_subtract = &int_arr[&int_arr[1] - &int_arr[0]];
|
||||||
|
|
||||||
|
constexpr int *constexpr_va = ptr_subtract + 1;
|
||||||
|
|
||||||
|
constexpr int &ref_int = int_var;
|
||||||
|
constexpr int &ref_array2d = int_arr_arr[1][1];
|
||||||
|
constexpr int &ref_va = ref_array2d;
|
||||||
|
constexpr int &ref_va_arith = *(&ref_array2d + 1);
|
||||||
|
|
||||||
|
constexpr fptr fp_implicit = sideEffect;
|
||||||
|
constexpr fptr fp_explicit = &sideEffect;
|
||||||
|
constexpr fptr fp_chain_addressof = &**&**sideEffect;
|
||||||
|
constexpr fptr fp_chain_deref = **&**&**sideEffect;
|
||||||
|
constexpr fptr fp_shortchain_deref = *&sideEffect;
|
||||||
|
|
||||||
|
constexpr fref fr_int = sideEffect;
|
||||||
|
constexpr fref fr_deref = *&sideEffect;
|
||||||
|
constexpr fref fr_2deref = **sideEffect;
|
||||||
|
constexpr fref fr_va = fr_int;
|
||||||
|
|
||||||
|
constexpr const char *char_ptr = "str";
|
||||||
|
constexpr const char *char_ptr_1 = "str" + 1;
|
||||||
|
constexpr char char_arr[] = "str";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// All variables in this function are initialized to non-const values. Writing
|
||||||
|
// `constexpr` in front of any of the variables will be a compile error
|
||||||
|
// (C++14).
|
||||||
|
void nonConstantAddresses(const int param, int *const pparam, int &rparam, fref frparam) {
|
||||||
|
int *int_param = &int_arr[param];
|
||||||
|
int *int_noinit = &int_arr[extern_int_const_noinit];
|
||||||
|
|
||||||
|
int *side_effect_stmtexpr = &int_arr[ ({ sideEffect(); 1; }) ];
|
||||||
|
int *side_effect_comma_int = &int_arr[ (sideEffect(), 1) ];
|
||||||
|
int *side_effect_comma_addr = (sideEffect(), &int_var);
|
||||||
|
int *side_effect_comma_addr2 = ((void)(sideEffect(), 1), &int_var);
|
||||||
|
int *ternary_int = &int_arr[int_const ? param : 1];
|
||||||
|
const int *ternary_addr = int_const ? ¶m : &int_var;
|
||||||
|
int *va_non_constexpr = pparam;
|
||||||
|
|
||||||
|
int *&&ref_to_temporary = &int_var; // reference to temporary is not a const
|
||||||
|
int &ref_param = rparam;
|
||||||
|
|
||||||
|
fref fr_param = frparam;
|
||||||
|
}
|
||||||
16
cpp/ql/test/library-tests/constants/addresses/addresses.ql
Normal file
16
cpp/ql/test/library-tests/constants/addresses/addresses.ql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import cpp
|
||||||
|
|
||||||
|
from Expr e, string msg, LocalVariable var, Function f
|
||||||
|
where
|
||||||
|
e = var.getInitializer().getExpr().getFullyConverted() and
|
||||||
|
var.getFunction() = f and
|
||||||
|
(
|
||||||
|
e.isConstant() and
|
||||||
|
f.getName() = "nonConstantAddresses" and
|
||||||
|
msg = "misclassified as constant"
|
||||||
|
or
|
||||||
|
not e.isConstant() and
|
||||||
|
f.getName() = "constantAddresses" and
|
||||||
|
msg = "misclassified as NOT constant"
|
||||||
|
)
|
||||||
|
select e, var.getName(), msg
|
||||||
@@ -6782,3 +6782,47 @@ ir.cpp:
|
|||||||
# 1055| 0: i
|
# 1055| 0: i
|
||||||
# 1055| Type = int
|
# 1055| Type = int
|
||||||
# 1055| ValueCategory = prvalue(load)
|
# 1055| ValueCategory = prvalue(load)
|
||||||
|
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||||
|
# 1058| params:
|
||||||
|
# 1058| 0: n
|
||||||
|
# 1058| Type = int
|
||||||
|
# 1058| 1: p
|
||||||
|
# 1058| Type = char *
|
||||||
|
# 1058| body: { ... }
|
||||||
|
# 1059| 0: while (...) ...
|
||||||
|
# 1059| 0: ... > ...
|
||||||
|
# 1059| Type = bool
|
||||||
|
# 1059| ValueCategory = prvalue
|
||||||
|
# 1059| 0: ... --
|
||||||
|
# 1059| Type = int
|
||||||
|
# 1059| ValueCategory = prvalue
|
||||||
|
# 1059| 0: n
|
||||||
|
# 1059| Type = int
|
||||||
|
# 1059| ValueCategory = lvalue
|
||||||
|
# 1059| 1: 0
|
||||||
|
# 1059| Type = int
|
||||||
|
# 1059| Value = 0
|
||||||
|
# 1059| ValueCategory = prvalue
|
||||||
|
# 1060| 1: ExprStmt
|
||||||
|
# 1060| 0: ... = ...
|
||||||
|
# 1060| Type = char
|
||||||
|
# 1060| ValueCategory = lvalue
|
||||||
|
# 1060| 0: * ...
|
||||||
|
# 1060| Type = char
|
||||||
|
# 1060| ValueCategory = lvalue
|
||||||
|
# 1060| 0: ... ++
|
||||||
|
# 1060| Type = char *
|
||||||
|
# 1060| ValueCategory = prvalue
|
||||||
|
# 1060| 0: p
|
||||||
|
# 1060| Type = char *
|
||||||
|
# 1060| ValueCategory = lvalue
|
||||||
|
# 1060| 1: (char)...
|
||||||
|
# 1060| Conversion = integral conversion
|
||||||
|
# 1060| Type = char
|
||||||
|
# 1060| Value = 0
|
||||||
|
# 1060| ValueCategory = prvalue
|
||||||
|
# 1060| expr: 0
|
||||||
|
# 1060| Type = int
|
||||||
|
# 1060| Value = 0
|
||||||
|
# 1060| ValueCategory = prvalue
|
||||||
|
# 1061| 1: return ...
|
||||||
|
|||||||
@@ -1116,7 +1116,7 @@ ir.cpp:
|
|||||||
# 255| r1_2(int) = Load : r1_1, m3_0
|
# 255| r1_2(int) = Load : r1_1, m3_0
|
||||||
# 255| r1_3(int) = Sub : r1_2, r1_0
|
# 255| r1_3(int) = Sub : r1_2, r1_0
|
||||||
# 255| m1_4(int) = Store : r1_1, r1_3
|
# 255| m1_4(int) = Store : r1_1, r1_3
|
||||||
#-----| Goto -> Block 3
|
#-----| Goto (back edge) -> Block 3
|
||||||
|
|
||||||
# 257| Block 2
|
# 257| Block 2
|
||||||
# 257| v2_0(void) = NoOp :
|
# 257| v2_0(void) = NoOp :
|
||||||
@@ -1156,7 +1156,7 @@ ir.cpp:
|
|||||||
# 262| r1_9(bool) = CompareGT : r1_7, r1_8
|
# 262| r1_9(bool) = CompareGT : r1_7, r1_8
|
||||||
# 262| v1_10(void) = ConditionalBranch : r1_9
|
# 262| v1_10(void) = ConditionalBranch : r1_9
|
||||||
#-----| False -> Block 2
|
#-----| False -> Block 2
|
||||||
#-----| True -> Block 1
|
#-----| True (back edge) -> Block 1
|
||||||
|
|
||||||
# 263| Block 2
|
# 263| Block 2
|
||||||
# 263| v2_0(void) = NoOp :
|
# 263| v2_0(void) = NoOp :
|
||||||
@@ -1175,7 +1175,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 268| Block 1
|
# 268| Block 1
|
||||||
# 268| v1_0(void) = NoOp :
|
# 268| v1_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 272| For_Init() -> void
|
# 272| For_Init() -> void
|
||||||
# 272| Block 0
|
# 272| Block 0
|
||||||
@@ -1189,7 +1189,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 274| Block 1
|
# 274| Block 1
|
||||||
# 274| v1_0(void) = NoOp :
|
# 274| v1_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 278| For_Condition() -> void
|
# 278| For_Condition() -> void
|
||||||
# 278| Block 0
|
# 278| Block 0
|
||||||
@@ -1212,7 +1212,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 281| Block 2
|
# 281| Block 2
|
||||||
# 281| v2_0(void) = NoOp :
|
# 281| v2_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 278| Block 3
|
# 278| Block 3
|
||||||
# 278| v3_0(void) = Unreached :
|
# 278| v3_0(void) = Unreached :
|
||||||
@@ -1235,7 +1235,7 @@ ir.cpp:
|
|||||||
# 287| r1_4(int) = Load : r1_3, m1_0
|
# 287| r1_4(int) = Load : r1_3, m1_0
|
||||||
# 287| r1_5(int) = Add : r1_4, r1_2
|
# 287| r1_5(int) = Add : r1_4, r1_2
|
||||||
# 287| m1_6(int) = Store : r1_3, r1_5
|
# 287| m1_6(int) = Store : r1_3, r1_5
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 292| For_InitCondition() -> void
|
# 292| For_InitCondition() -> void
|
||||||
# 292| Block 0
|
# 292| Block 0
|
||||||
@@ -1258,7 +1258,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 294| Block 2
|
# 294| Block 2
|
||||||
# 294| v2_0(void) = NoOp :
|
# 294| v2_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 292| Block 3
|
# 292| Block 3
|
||||||
# 292| v3_0(void) = Unreached :
|
# 292| v3_0(void) = Unreached :
|
||||||
@@ -1281,7 +1281,7 @@ ir.cpp:
|
|||||||
# 299| r1_4(int) = Load : r1_3, m1_0
|
# 299| r1_4(int) = Load : r1_3, m1_0
|
||||||
# 299| r1_5(int) = Add : r1_4, r1_2
|
# 299| r1_5(int) = Add : r1_4, r1_2
|
||||||
# 299| m1_6(int) = Store : r1_3, r1_5
|
# 299| m1_6(int) = Store : r1_3, r1_5
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 304| For_ConditionUpdate() -> void
|
# 304| For_ConditionUpdate() -> void
|
||||||
# 304| Block 0
|
# 304| Block 0
|
||||||
@@ -1310,7 +1310,7 @@ ir.cpp:
|
|||||||
# 306| r2_3(int) = Load : r2_2, m1_0
|
# 306| r2_3(int) = Load : r2_2, m1_0
|
||||||
# 306| r2_4(int) = Add : r2_3, r2_1
|
# 306| r2_4(int) = Add : r2_3, r2_1
|
||||||
# 306| m2_5(int) = Store : r2_2, r2_4
|
# 306| m2_5(int) = Store : r2_2, r2_4
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 309| Block 3
|
# 309| Block 3
|
||||||
# 309| v3_0(void) = NoOp :
|
# 309| v3_0(void) = NoOp :
|
||||||
@@ -1345,7 +1345,7 @@ ir.cpp:
|
|||||||
# 312| r2_3(int) = Load : r2_2, m1_0
|
# 312| r2_3(int) = Load : r2_2, m1_0
|
||||||
# 312| r2_4(int) = Add : r2_3, r2_1
|
# 312| r2_4(int) = Add : r2_3, r2_1
|
||||||
# 312| m2_5(int) = Store : r2_2, r2_4
|
# 312| m2_5(int) = Store : r2_2, r2_4
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 315| Block 3
|
# 315| Block 3
|
||||||
# 315| v3_0(void) = NoOp :
|
# 315| v3_0(void) = NoOp :
|
||||||
@@ -1379,7 +1379,7 @@ ir.cpp:
|
|||||||
# 318| r2_2(int) = Load : r2_1, m1_0
|
# 318| r2_2(int) = Load : r2_1, m1_0
|
||||||
# 318| r2_3(int) = Add : r2_2, r2_0
|
# 318| r2_3(int) = Add : r2_2, r2_0
|
||||||
# 318| m2_4(int) = Store : r2_1, r2_3
|
# 318| m2_4(int) = Store : r2_1, r2_3
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 319| Block 3
|
# 319| Block 3
|
||||||
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
||||||
@@ -1441,7 +1441,7 @@ ir.cpp:
|
|||||||
# 326| r4_3(int) = Load : r4_2, m1_0
|
# 326| r4_3(int) = Load : r4_2, m1_0
|
||||||
# 326| r4_4(int) = Add : r4_3, r4_1
|
# 326| r4_4(int) = Add : r4_3, r4_1
|
||||||
# 326| m4_5(int) = Store : r4_2, r4_4
|
# 326| m4_5(int) = Store : r4_2, r4_4
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 331| Block 5
|
# 331| Block 5
|
||||||
# 331| v5_0(void) = NoOp :
|
# 331| v5_0(void) = NoOp :
|
||||||
@@ -1479,7 +1479,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 334| Block 3
|
# 334| Block 3
|
||||||
# 334| v3_0(void) = NoOp :
|
# 334| v3_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 333| Block 4
|
# 333| Block 4
|
||||||
# 333| v4_0(void) = Unreached :
|
# 333| v4_0(void) = Unreached :
|
||||||
@@ -1547,7 +1547,7 @@ ir.cpp:
|
|||||||
# 356| r3_2(int) = Load : r3_1, m5_0
|
# 356| r3_2(int) = Load : r3_1, m5_0
|
||||||
# 356| r3_3(int) = Sub : r3_2, r3_0
|
# 356| r3_3(int) = Sub : r3_2, r3_0
|
||||||
# 356| m3_4(int) = Store : r3_1, r3_3
|
# 356| m3_4(int) = Store : r3_1, r3_3
|
||||||
#-----| Goto -> Block 5
|
#-----| Goto (back edge) -> Block 5
|
||||||
|
|
||||||
# 357| Block 4
|
# 357| Block 4
|
||||||
# 357| v4_0(void) = NoOp :
|
# 357| v4_0(void) = NoOp :
|
||||||
@@ -1606,7 +1606,7 @@ ir.cpp:
|
|||||||
# 366| r4_5(bool) = CompareGT : r4_3, r4_4
|
# 366| r4_5(bool) = CompareGT : r4_3, r4_4
|
||||||
# 366| v4_6(void) = ConditionalBranch : r4_5
|
# 366| v4_6(void) = ConditionalBranch : r4_5
|
||||||
#-----| False -> Block 5
|
#-----| False -> Block 5
|
||||||
#-----| True -> Block 1
|
#-----| True (back edge) -> Block 1
|
||||||
|
|
||||||
# 367| Block 5
|
# 367| Block 5
|
||||||
# 367| v5_0(void) = NoOp :
|
# 367| v5_0(void) = NoOp :
|
||||||
@@ -4395,7 +4395,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 979| Block 1
|
# 979| Block 1
|
||||||
# 979| v1_0(void) = NoOp :
|
# 979| v1_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 7
|
#-----| Goto (back edge) -> Block 7
|
||||||
|
|
||||||
# 981| Block 2
|
# 981| Block 2
|
||||||
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
||||||
@@ -4415,7 +4415,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 981| Block 3
|
# 981| Block 3
|
||||||
# 981| v3_0(void) = NoOp :
|
# 981| v3_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 2
|
#-----| Goto (back edge) -> Block 2
|
||||||
|
|
||||||
# 983| Block 4
|
# 983| Block 4
|
||||||
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
||||||
@@ -4431,7 +4431,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 983| Block 5
|
# 983| Block 5
|
||||||
# 983| v5_0(void) = NoOp :
|
# 983| v5_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 4
|
#-----| Goto (back edge) -> Block 4
|
||||||
|
|
||||||
# 985| Block 6
|
# 985| Block 6
|
||||||
# 985| v6_0(void) = NoOp :
|
# 985| v6_0(void) = NoOp :
|
||||||
@@ -4646,3 +4646,46 @@ ir.cpp:
|
|||||||
|
|
||||||
# 1049| Block 2
|
# 1049| Block 2
|
||||||
# 1049| v2_0(void) = Unreached :
|
# 1049| v2_0(void) = Unreached :
|
||||||
|
|
||||||
|
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||||
|
# 1058| Block 0
|
||||||
|
# 1058| v0_0(void) = EnterFunction :
|
||||||
|
# 1058| m0_1(unknown) = AliasedDefinition :
|
||||||
|
# 1058| mu0_2(unknown) = UnmodeledDefinition :
|
||||||
|
# 1058| r0_3(glval<int>) = VariableAddress[n] :
|
||||||
|
# 1058| m0_4(int) = InitializeParameter[n] : r0_3
|
||||||
|
# 1058| r0_5(glval<char *>) = VariableAddress[p] :
|
||||||
|
# 1058| m0_6(char *) = InitializeParameter[p] : r0_5
|
||||||
|
#-----| Goto -> Block 3
|
||||||
|
|
||||||
|
# 1060| Block 1
|
||||||
|
# 1060| r1_0(char) = Constant[0] :
|
||||||
|
# 1060| r1_1(glval<char *>) = VariableAddress[p] :
|
||||||
|
# 1060| r1_2(char *) = Load : r1_1, m3_2
|
||||||
|
# 1060| r1_3(int) = Constant[1] :
|
||||||
|
# 1060| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
|
||||||
|
# 1060| m1_5(char *) = Store : r1_1, r1_4
|
||||||
|
# 1060| m1_6(char) = Store : r1_2, r1_0
|
||||||
|
# 1060| m1_7(unknown) = Chi : m3_0, m1_6
|
||||||
|
#-----| Goto (back edge) -> Block 3
|
||||||
|
|
||||||
|
# 1061| Block 2
|
||||||
|
# 1061| v2_0(void) = NoOp :
|
||||||
|
# 1058| v2_1(void) = ReturnVoid :
|
||||||
|
# 1058| v2_2(void) = UnmodeledUse : mu*
|
||||||
|
# 1058| v2_3(void) = ExitFunction :
|
||||||
|
|
||||||
|
# 1059| Block 3
|
||||||
|
# 1059| m3_0(unknown) = Phi : from 0:m0_1, from 1:m1_7
|
||||||
|
# 1059| m3_1(int) = Phi : from 0:m0_4, from 1:m3_7
|
||||||
|
# 1059| m3_2(char *) = Phi : from 0:m0_6, from 1:m1_5
|
||||||
|
# 1059| r3_3(glval<int>) = VariableAddress[n] :
|
||||||
|
# 1059| r3_4(int) = Load : r3_3, m3_1
|
||||||
|
# 1059| r3_5(int) = Constant[1] :
|
||||||
|
# 1059| r3_6(int) = Sub : r3_4, r3_5
|
||||||
|
# 1059| m3_7(int) = Store : r3_3, r3_6
|
||||||
|
# 1059| r3_8(int) = Constant[0] :
|
||||||
|
# 1059| r3_9(bool) = CompareGT : r3_4, r3_8
|
||||||
|
# 1059| v3_10(void) = ConditionalBranch : r3_9
|
||||||
|
#-----| False -> Block 2
|
||||||
|
#-----| True -> Block 1
|
||||||
|
|||||||
@@ -8,3 +8,6 @@ unexplainedLoop
|
|||||||
unnecessaryPhiInstruction
|
unnecessaryPhiInstruction
|
||||||
operandAcrossFunctions
|
operandAcrossFunctions
|
||||||
instructionWithoutUniqueBlock
|
instructionWithoutUniqueBlock
|
||||||
|
containsLoopOfForwardEdges
|
||||||
|
lostReachability
|
||||||
|
backEdgeCountMismatch
|
||||||
|
|||||||
@@ -1055,4 +1055,9 @@ int DoWhileFalse() {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void chiNodeAtEndOfLoop(int n, char *p) {
|
||||||
|
while (n-- > 0)
|
||||||
|
*p++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// semmle-extractor-options: -std=c++17
|
// semmle-extractor-options: -std=c++17
|
||||||
|
|||||||
@@ -1108,7 +1108,7 @@ ir.cpp:
|
|||||||
# 255| r1_2(int) = Load : r1_1, mu0_2
|
# 255| r1_2(int) = Load : r1_1, mu0_2
|
||||||
# 255| r1_3(int) = Sub : r1_2, r1_0
|
# 255| r1_3(int) = Sub : r1_2, r1_0
|
||||||
# 255| mu1_4(int) = Store : r1_1, r1_3
|
# 255| mu1_4(int) = Store : r1_1, r1_3
|
||||||
#-----| Goto -> Block 3
|
#-----| Goto (back edge) -> Block 3
|
||||||
|
|
||||||
# 257| Block 2
|
# 257| Block 2
|
||||||
# 257| v2_0(void) = NoOp :
|
# 257| v2_0(void) = NoOp :
|
||||||
@@ -1146,7 +1146,7 @@ ir.cpp:
|
|||||||
# 262| r1_8(bool) = CompareGT : r1_6, r1_7
|
# 262| r1_8(bool) = CompareGT : r1_6, r1_7
|
||||||
# 262| v1_9(void) = ConditionalBranch : r1_8
|
# 262| v1_9(void) = ConditionalBranch : r1_8
|
||||||
#-----| False -> Block 2
|
#-----| False -> Block 2
|
||||||
#-----| True -> Block 1
|
#-----| True (back edge) -> Block 1
|
||||||
|
|
||||||
# 263| Block 2
|
# 263| Block 2
|
||||||
# 263| v2_0(void) = NoOp :
|
# 263| v2_0(void) = NoOp :
|
||||||
@@ -1170,7 +1170,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 268| Block 2
|
# 268| Block 2
|
||||||
# 268| v2_0(void) = NoOp :
|
# 268| v2_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 2
|
#-----| Goto (back edge) -> Block 2
|
||||||
|
|
||||||
# 272| For_Init() -> void
|
# 272| For_Init() -> void
|
||||||
# 272| Block 0
|
# 272| Block 0
|
||||||
@@ -1189,7 +1189,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 274| Block 2
|
# 274| Block 2
|
||||||
# 274| v2_0(void) = NoOp :
|
# 274| v2_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 2
|
#-----| Goto (back edge) -> Block 2
|
||||||
|
|
||||||
# 278| For_Condition() -> void
|
# 278| For_Condition() -> void
|
||||||
# 278| Block 0
|
# 278| Block 0
|
||||||
@@ -1212,7 +1212,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 281| Block 2
|
# 281| Block 2
|
||||||
# 281| v2_0(void) = NoOp :
|
# 281| v2_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 283| Block 3
|
# 283| Block 3
|
||||||
# 283| v3_0(void) = NoOp :
|
# 283| v3_0(void) = NoOp :
|
||||||
@@ -1242,7 +1242,7 @@ ir.cpp:
|
|||||||
# 287| r2_3(int) = Load : r2_2, mu0_2
|
# 287| r2_3(int) = Load : r2_2, mu0_2
|
||||||
# 287| r2_4(int) = Add : r2_3, r2_1
|
# 287| r2_4(int) = Add : r2_3, r2_1
|
||||||
# 287| mu2_5(int) = Store : r2_2, r2_4
|
# 287| mu2_5(int) = Store : r2_2, r2_4
|
||||||
#-----| Goto -> Block 2
|
#-----| Goto (back edge) -> Block 2
|
||||||
|
|
||||||
# 292| For_InitCondition() -> void
|
# 292| For_InitCondition() -> void
|
||||||
# 292| Block 0
|
# 292| Block 0
|
||||||
@@ -1265,7 +1265,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 294| Block 2
|
# 294| Block 2
|
||||||
# 294| v2_0(void) = NoOp :
|
# 294| v2_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 296| Block 3
|
# 296| Block 3
|
||||||
# 296| v3_0(void) = NoOp :
|
# 296| v3_0(void) = NoOp :
|
||||||
@@ -1295,7 +1295,7 @@ ir.cpp:
|
|||||||
# 299| r2_3(int) = Load : r2_2, mu0_2
|
# 299| r2_3(int) = Load : r2_2, mu0_2
|
||||||
# 299| r2_4(int) = Add : r2_3, r2_1
|
# 299| r2_4(int) = Add : r2_3, r2_1
|
||||||
# 299| mu2_5(int) = Store : r2_2, r2_4
|
# 299| mu2_5(int) = Store : r2_2, r2_4
|
||||||
#-----| Goto -> Block 2
|
#-----| Goto (back edge) -> Block 2
|
||||||
|
|
||||||
# 304| For_ConditionUpdate() -> void
|
# 304| For_ConditionUpdate() -> void
|
||||||
# 304| Block 0
|
# 304| Block 0
|
||||||
@@ -1323,7 +1323,7 @@ ir.cpp:
|
|||||||
# 306| r2_3(int) = Load : r2_2, mu0_2
|
# 306| r2_3(int) = Load : r2_2, mu0_2
|
||||||
# 306| r2_4(int) = Add : r2_3, r2_1
|
# 306| r2_4(int) = Add : r2_3, r2_1
|
||||||
# 306| mu2_5(int) = Store : r2_2, r2_4
|
# 306| mu2_5(int) = Store : r2_2, r2_4
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 309| Block 3
|
# 309| Block 3
|
||||||
# 309| v3_0(void) = NoOp :
|
# 309| v3_0(void) = NoOp :
|
||||||
@@ -1357,7 +1357,7 @@ ir.cpp:
|
|||||||
# 312| r2_3(int) = Load : r2_2, mu0_2
|
# 312| r2_3(int) = Load : r2_2, mu0_2
|
||||||
# 312| r2_4(int) = Add : r2_3, r2_1
|
# 312| r2_4(int) = Add : r2_3, r2_1
|
||||||
# 312| mu2_5(int) = Store : r2_2, r2_4
|
# 312| mu2_5(int) = Store : r2_2, r2_4
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 315| Block 3
|
# 315| Block 3
|
||||||
# 315| v3_0(void) = NoOp :
|
# 315| v3_0(void) = NoOp :
|
||||||
@@ -1390,7 +1390,7 @@ ir.cpp:
|
|||||||
# 318| r2_2(int) = Load : r2_1, mu0_2
|
# 318| r2_2(int) = Load : r2_1, mu0_2
|
||||||
# 318| r2_3(int) = Add : r2_2, r2_0
|
# 318| r2_3(int) = Add : r2_2, r2_0
|
||||||
# 318| mu2_4(int) = Store : r2_1, r2_3
|
# 318| mu2_4(int) = Store : r2_1, r2_3
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 319| Block 3
|
# 319| Block 3
|
||||||
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
||||||
@@ -1451,7 +1451,7 @@ ir.cpp:
|
|||||||
# 326| r4_3(int) = Load : r4_2, mu0_2
|
# 326| r4_3(int) = Load : r4_2, mu0_2
|
||||||
# 326| r4_4(int) = Add : r4_3, r4_1
|
# 326| r4_4(int) = Add : r4_3, r4_1
|
||||||
# 326| mu4_5(int) = Store : r4_2, r4_4
|
# 326| mu4_5(int) = Store : r4_2, r4_4
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 331| Block 5
|
# 331| Block 5
|
||||||
# 331| v5_0(void) = NoOp :
|
# 331| v5_0(void) = NoOp :
|
||||||
@@ -1493,7 +1493,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 334| Block 4
|
# 334| Block 4
|
||||||
# 334| v4_0(void) = NoOp :
|
# 334| v4_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 339| Block 5
|
# 339| Block 5
|
||||||
# 339| v5_0(void) = NoOp :
|
# 339| v5_0(void) = NoOp :
|
||||||
@@ -1563,7 +1563,7 @@ ir.cpp:
|
|||||||
# 356| r3_2(int) = Load : r3_1, mu0_2
|
# 356| r3_2(int) = Load : r3_1, mu0_2
|
||||||
# 356| r3_3(int) = Sub : r3_2, r3_0
|
# 356| r3_3(int) = Sub : r3_2, r3_0
|
||||||
# 356| mu3_4(int) = Store : r3_1, r3_3
|
# 356| mu3_4(int) = Store : r3_1, r3_3
|
||||||
#-----| Goto -> Block 5
|
#-----| Goto (back edge) -> Block 5
|
||||||
|
|
||||||
# 357| Block 4
|
# 357| Block 4
|
||||||
# 357| v4_0(void) = NoOp :
|
# 357| v4_0(void) = NoOp :
|
||||||
@@ -1619,7 +1619,7 @@ ir.cpp:
|
|||||||
# 366| r4_4(bool) = CompareGT : r4_2, r4_3
|
# 366| r4_4(bool) = CompareGT : r4_2, r4_3
|
||||||
# 366| v4_5(void) = ConditionalBranch : r4_4
|
# 366| v4_5(void) = ConditionalBranch : r4_4
|
||||||
#-----| False -> Block 5
|
#-----| False -> Block 5
|
||||||
#-----| True -> Block 1
|
#-----| True (back edge) -> Block 1
|
||||||
|
|
||||||
# 367| Block 5
|
# 367| Block 5
|
||||||
# 367| v5_0(void) = NoOp :
|
# 367| v5_0(void) = NoOp :
|
||||||
@@ -4282,7 +4282,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 979| Block 1
|
# 979| Block 1
|
||||||
# 979| v1_0(void) = NoOp :
|
# 979| v1_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 7
|
#-----| Goto (back edge) -> Block 7
|
||||||
|
|
||||||
# 981| Block 2
|
# 981| Block 2
|
||||||
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
||||||
@@ -4302,7 +4302,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 981| Block 3
|
# 981| Block 3
|
||||||
# 981| v3_0(void) = NoOp :
|
# 981| v3_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 2
|
#-----| Goto (back edge) -> Block 2
|
||||||
|
|
||||||
# 983| Block 4
|
# 983| Block 4
|
||||||
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
||||||
@@ -4318,7 +4318,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 983| Block 5
|
# 983| Block 5
|
||||||
# 983| v5_0(void) = NoOp :
|
# 983| v5_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 4
|
#-----| Goto (back edge) -> Block 4
|
||||||
|
|
||||||
# 985| Block 6
|
# 985| Block 6
|
||||||
# 985| v6_0(void) = NoOp :
|
# 985| v6_0(void) = NoOp :
|
||||||
@@ -4533,7 +4533,7 @@ ir.cpp:
|
|||||||
# 1053| r1_5(bool) = Constant[0] :
|
# 1053| r1_5(bool) = Constant[0] :
|
||||||
# 1053| v1_6(void) = ConditionalBranch : r1_5
|
# 1053| v1_6(void) = ConditionalBranch : r1_5
|
||||||
#-----| False -> Block 2
|
#-----| False -> Block 2
|
||||||
#-----| True -> Block 1
|
#-----| True (back edge) -> Block 1
|
||||||
|
|
||||||
# 1055| Block 2
|
# 1055| Block 2
|
||||||
# 1055| r2_0(glval<int>) = VariableAddress[#return] :
|
# 1055| r2_0(glval<int>) = VariableAddress[#return] :
|
||||||
@@ -4544,3 +4544,42 @@ ir.cpp:
|
|||||||
# 1049| v2_5(void) = ReturnValue : r2_4, mu0_2
|
# 1049| v2_5(void) = ReturnValue : r2_4, mu0_2
|
||||||
# 1049| v2_6(void) = UnmodeledUse : mu*
|
# 1049| v2_6(void) = UnmodeledUse : mu*
|
||||||
# 1049| v2_7(void) = ExitFunction :
|
# 1049| v2_7(void) = ExitFunction :
|
||||||
|
|
||||||
|
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||||
|
# 1058| Block 0
|
||||||
|
# 1058| v0_0(void) = EnterFunction :
|
||||||
|
# 1058| mu0_1(unknown) = AliasedDefinition :
|
||||||
|
# 1058| mu0_2(unknown) = UnmodeledDefinition :
|
||||||
|
# 1058| r0_3(glval<int>) = VariableAddress[n] :
|
||||||
|
# 1058| mu0_4(int) = InitializeParameter[n] : r0_3
|
||||||
|
# 1058| r0_5(glval<char *>) = VariableAddress[p] :
|
||||||
|
# 1058| mu0_6(char *) = InitializeParameter[p] : r0_5
|
||||||
|
#-----| Goto -> Block 3
|
||||||
|
|
||||||
|
# 1060| Block 1
|
||||||
|
# 1060| r1_0(char) = Constant[0] :
|
||||||
|
# 1060| r1_1(glval<char *>) = VariableAddress[p] :
|
||||||
|
# 1060| r1_2(char *) = Load : r1_1, mu0_2
|
||||||
|
# 1060| r1_3(int) = Constant[1] :
|
||||||
|
# 1060| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
|
||||||
|
# 1060| mu1_5(char *) = Store : r1_1, r1_4
|
||||||
|
# 1060| mu1_6(char) = Store : r1_2, r1_0
|
||||||
|
#-----| Goto (back edge) -> Block 3
|
||||||
|
|
||||||
|
# 1061| Block 2
|
||||||
|
# 1061| v2_0(void) = NoOp :
|
||||||
|
# 1058| v2_1(void) = ReturnVoid :
|
||||||
|
# 1058| v2_2(void) = UnmodeledUse : mu*
|
||||||
|
# 1058| v2_3(void) = ExitFunction :
|
||||||
|
|
||||||
|
# 1059| Block 3
|
||||||
|
# 1059| r3_0(glval<int>) = VariableAddress[n] :
|
||||||
|
# 1059| r3_1(int) = Load : r3_0, mu0_2
|
||||||
|
# 1059| r3_2(int) = Constant[1] :
|
||||||
|
# 1059| r3_3(int) = Sub : r3_1, r3_2
|
||||||
|
# 1059| mu3_4(int) = Store : r3_0, r3_3
|
||||||
|
# 1059| r3_5(int) = Constant[0] :
|
||||||
|
# 1059| r3_6(bool) = CompareGT : r3_1, r3_5
|
||||||
|
# 1059| v3_7(void) = ConditionalBranch : r3_6
|
||||||
|
#-----| False -> Block 2
|
||||||
|
#-----| True -> Block 1
|
||||||
|
|||||||
@@ -8,3 +8,6 @@ unexplainedLoop
|
|||||||
unnecessaryPhiInstruction
|
unnecessaryPhiInstruction
|
||||||
operandAcrossFunctions
|
operandAcrossFunctions
|
||||||
instructionWithoutUniqueBlock
|
instructionWithoutUniqueBlock
|
||||||
|
containsLoopOfForwardEdges
|
||||||
|
lostReachability
|
||||||
|
backEdgeCountMismatch
|
||||||
|
|||||||
@@ -101,6 +101,7 @@
|
|||||||
| IR: VirtualMemberFunction | 1 |
|
| IR: VirtualMemberFunction | 1 |
|
||||||
| IR: WhileStatements | 4 |
|
| IR: WhileStatements | 4 |
|
||||||
| IR: WhileStmtWithDeclaration | 8 |
|
| IR: WhileStmtWithDeclaration | 8 |
|
||||||
|
| IR: chiNodeAtEndOfLoop | 4 |
|
||||||
| IR: designatedInit | 1 |
|
| IR: designatedInit | 1 |
|
||||||
| IR: min | 4 |
|
| IR: min | 4 |
|
||||||
| IR: operator= | 1 |
|
| IR: operator= | 1 |
|
||||||
|
|||||||
@@ -1109,7 +1109,7 @@ ir.cpp:
|
|||||||
# 255| r1_2(int) = Load : r1_1, m3_0
|
# 255| r1_2(int) = Load : r1_1, m3_0
|
||||||
# 255| r1_3(int) = Sub : r1_2, r1_0
|
# 255| r1_3(int) = Sub : r1_2, r1_0
|
||||||
# 255| m1_4(int) = Store : r1_1, r1_3
|
# 255| m1_4(int) = Store : r1_1, r1_3
|
||||||
#-----| Goto -> Block 3
|
#-----| Goto (back edge) -> Block 3
|
||||||
|
|
||||||
# 257| Block 2
|
# 257| Block 2
|
||||||
# 257| v2_0(void) = NoOp :
|
# 257| v2_0(void) = NoOp :
|
||||||
@@ -1149,7 +1149,7 @@ ir.cpp:
|
|||||||
# 262| r1_9(bool) = CompareGT : r1_7, r1_8
|
# 262| r1_9(bool) = CompareGT : r1_7, r1_8
|
||||||
# 262| v1_10(void) = ConditionalBranch : r1_9
|
# 262| v1_10(void) = ConditionalBranch : r1_9
|
||||||
#-----| False -> Block 2
|
#-----| False -> Block 2
|
||||||
#-----| True -> Block 1
|
#-----| True (back edge) -> Block 1
|
||||||
|
|
||||||
# 263| Block 2
|
# 263| Block 2
|
||||||
# 263| v2_0(void) = NoOp :
|
# 263| v2_0(void) = NoOp :
|
||||||
@@ -1168,7 +1168,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 268| Block 1
|
# 268| Block 1
|
||||||
# 268| v1_0(void) = NoOp :
|
# 268| v1_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 272| For_Init() -> void
|
# 272| For_Init() -> void
|
||||||
# 272| Block 0
|
# 272| Block 0
|
||||||
@@ -1182,7 +1182,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 274| Block 1
|
# 274| Block 1
|
||||||
# 274| v1_0(void) = NoOp :
|
# 274| v1_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 278| For_Condition() -> void
|
# 278| For_Condition() -> void
|
||||||
# 278| Block 0
|
# 278| Block 0
|
||||||
@@ -1205,7 +1205,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 281| Block 2
|
# 281| Block 2
|
||||||
# 281| v2_0(void) = NoOp :
|
# 281| v2_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 283| Block 3
|
# 283| Block 3
|
||||||
# 283| v3_0(void) = NoOp :
|
# 283| v3_0(void) = NoOp :
|
||||||
@@ -1231,7 +1231,7 @@ ir.cpp:
|
|||||||
# 287| r1_4(int) = Load : r1_3, m1_0
|
# 287| r1_4(int) = Load : r1_3, m1_0
|
||||||
# 287| r1_5(int) = Add : r1_4, r1_2
|
# 287| r1_5(int) = Add : r1_4, r1_2
|
||||||
# 287| m1_6(int) = Store : r1_3, r1_5
|
# 287| m1_6(int) = Store : r1_3, r1_5
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 292| For_InitCondition() -> void
|
# 292| For_InitCondition() -> void
|
||||||
# 292| Block 0
|
# 292| Block 0
|
||||||
@@ -1254,7 +1254,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 294| Block 2
|
# 294| Block 2
|
||||||
# 294| v2_0(void) = NoOp :
|
# 294| v2_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 296| Block 3
|
# 296| Block 3
|
||||||
# 296| v3_0(void) = NoOp :
|
# 296| v3_0(void) = NoOp :
|
||||||
@@ -1280,7 +1280,7 @@ ir.cpp:
|
|||||||
# 299| r1_4(int) = Load : r1_3, m1_0
|
# 299| r1_4(int) = Load : r1_3, m1_0
|
||||||
# 299| r1_5(int) = Add : r1_4, r1_2
|
# 299| r1_5(int) = Add : r1_4, r1_2
|
||||||
# 299| m1_6(int) = Store : r1_3, r1_5
|
# 299| m1_6(int) = Store : r1_3, r1_5
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 304| For_ConditionUpdate() -> void
|
# 304| For_ConditionUpdate() -> void
|
||||||
# 304| Block 0
|
# 304| Block 0
|
||||||
@@ -1309,7 +1309,7 @@ ir.cpp:
|
|||||||
# 306| r2_3(int) = Load : r2_2, m1_0
|
# 306| r2_3(int) = Load : r2_2, m1_0
|
||||||
# 306| r2_4(int) = Add : r2_3, r2_1
|
# 306| r2_4(int) = Add : r2_3, r2_1
|
||||||
# 306| m2_5(int) = Store : r2_2, r2_4
|
# 306| m2_5(int) = Store : r2_2, r2_4
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 309| Block 3
|
# 309| Block 3
|
||||||
# 309| v3_0(void) = NoOp :
|
# 309| v3_0(void) = NoOp :
|
||||||
@@ -1344,7 +1344,7 @@ ir.cpp:
|
|||||||
# 312| r2_3(int) = Load : r2_2, m1_0
|
# 312| r2_3(int) = Load : r2_2, m1_0
|
||||||
# 312| r2_4(int) = Add : r2_3, r2_1
|
# 312| r2_4(int) = Add : r2_3, r2_1
|
||||||
# 312| m2_5(int) = Store : r2_2, r2_4
|
# 312| m2_5(int) = Store : r2_2, r2_4
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 315| Block 3
|
# 315| Block 3
|
||||||
# 315| v3_0(void) = NoOp :
|
# 315| v3_0(void) = NoOp :
|
||||||
@@ -1378,7 +1378,7 @@ ir.cpp:
|
|||||||
# 318| r2_2(int) = Load : r2_1, m1_0
|
# 318| r2_2(int) = Load : r2_1, m1_0
|
||||||
# 318| r2_3(int) = Add : r2_2, r2_0
|
# 318| r2_3(int) = Add : r2_2, r2_0
|
||||||
# 318| m2_4(int) = Store : r2_1, r2_3
|
# 318| m2_4(int) = Store : r2_1, r2_3
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 319| Block 3
|
# 319| Block 3
|
||||||
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
||||||
@@ -1440,7 +1440,7 @@ ir.cpp:
|
|||||||
# 326| r4_3(int) = Load : r4_2, m1_0
|
# 326| r4_3(int) = Load : r4_2, m1_0
|
||||||
# 326| r4_4(int) = Add : r4_3, r4_1
|
# 326| r4_4(int) = Add : r4_3, r4_1
|
||||||
# 326| m4_5(int) = Store : r4_2, r4_4
|
# 326| m4_5(int) = Store : r4_2, r4_4
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 331| Block 5
|
# 331| Block 5
|
||||||
# 331| v5_0(void) = NoOp :
|
# 331| v5_0(void) = NoOp :
|
||||||
@@ -1482,7 +1482,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 334| Block 4
|
# 334| Block 4
|
||||||
# 334| v4_0(void) = NoOp :
|
# 334| v4_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 339| Block 5
|
# 339| Block 5
|
||||||
# 339| v5_0(void) = NoOp :
|
# 339| v5_0(void) = NoOp :
|
||||||
@@ -1552,7 +1552,7 @@ ir.cpp:
|
|||||||
# 356| r3_2(int) = Load : r3_1, m5_0
|
# 356| r3_2(int) = Load : r3_1, m5_0
|
||||||
# 356| r3_3(int) = Sub : r3_2, r3_0
|
# 356| r3_3(int) = Sub : r3_2, r3_0
|
||||||
# 356| m3_4(int) = Store : r3_1, r3_3
|
# 356| m3_4(int) = Store : r3_1, r3_3
|
||||||
#-----| Goto -> Block 5
|
#-----| Goto (back edge) -> Block 5
|
||||||
|
|
||||||
# 357| Block 4
|
# 357| Block 4
|
||||||
# 357| v4_0(void) = NoOp :
|
# 357| v4_0(void) = NoOp :
|
||||||
@@ -1611,7 +1611,7 @@ ir.cpp:
|
|||||||
# 366| r4_5(bool) = CompareGT : r4_3, r4_4
|
# 366| r4_5(bool) = CompareGT : r4_3, r4_4
|
||||||
# 366| v4_6(void) = ConditionalBranch : r4_5
|
# 366| v4_6(void) = ConditionalBranch : r4_5
|
||||||
#-----| False -> Block 5
|
#-----| False -> Block 5
|
||||||
#-----| True -> Block 1
|
#-----| True (back edge) -> Block 1
|
||||||
|
|
||||||
# 367| Block 5
|
# 367| Block 5
|
||||||
# 367| v5_0(void) = NoOp :
|
# 367| v5_0(void) = NoOp :
|
||||||
@@ -4263,7 +4263,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 979| Block 1
|
# 979| Block 1
|
||||||
# 979| v1_0(void) = NoOp :
|
# 979| v1_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 7
|
#-----| Goto (back edge) -> Block 7
|
||||||
|
|
||||||
# 981| Block 2
|
# 981| Block 2
|
||||||
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
||||||
@@ -4283,7 +4283,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 981| Block 3
|
# 981| Block 3
|
||||||
# 981| v3_0(void) = NoOp :
|
# 981| v3_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 2
|
#-----| Goto (back edge) -> Block 2
|
||||||
|
|
||||||
# 983| Block 4
|
# 983| Block 4
|
||||||
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
||||||
@@ -4299,7 +4299,7 @@ ir.cpp:
|
|||||||
|
|
||||||
# 983| Block 5
|
# 983| Block 5
|
||||||
# 983| v5_0(void) = NoOp :
|
# 983| v5_0(void) = NoOp :
|
||||||
#-----| Goto -> Block 4
|
#-----| Goto (back edge) -> Block 4
|
||||||
|
|
||||||
# 985| Block 6
|
# 985| Block 6
|
||||||
# 985| v6_0(void) = NoOp :
|
# 985| v6_0(void) = NoOp :
|
||||||
@@ -4517,3 +4517,44 @@ ir.cpp:
|
|||||||
|
|
||||||
# 1049| Block 2
|
# 1049| Block 2
|
||||||
# 1049| v2_0(void) = Unreached :
|
# 1049| v2_0(void) = Unreached :
|
||||||
|
|
||||||
|
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||||
|
# 1058| Block 0
|
||||||
|
# 1058| v0_0(void) = EnterFunction :
|
||||||
|
# 1058| mu0_1(unknown) = AliasedDefinition :
|
||||||
|
# 1058| mu0_2(unknown) = UnmodeledDefinition :
|
||||||
|
# 1058| r0_3(glval<int>) = VariableAddress[n] :
|
||||||
|
# 1058| m0_4(int) = InitializeParameter[n] : r0_3
|
||||||
|
# 1058| r0_5(glval<char *>) = VariableAddress[p] :
|
||||||
|
# 1058| m0_6(char *) = InitializeParameter[p] : r0_5
|
||||||
|
#-----| Goto -> Block 3
|
||||||
|
|
||||||
|
# 1060| Block 1
|
||||||
|
# 1060| r1_0(char) = Constant[0] :
|
||||||
|
# 1060| r1_1(glval<char *>) = VariableAddress[p] :
|
||||||
|
# 1060| r1_2(char *) = Load : r1_1, m3_1
|
||||||
|
# 1060| r1_3(int) = Constant[1] :
|
||||||
|
# 1060| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
|
||||||
|
# 1060| m1_5(char *) = Store : r1_1, r1_4
|
||||||
|
# 1060| mu1_6(char) = Store : r1_2, r1_0
|
||||||
|
#-----| Goto (back edge) -> Block 3
|
||||||
|
|
||||||
|
# 1061| Block 2
|
||||||
|
# 1061| v2_0(void) = NoOp :
|
||||||
|
# 1058| v2_1(void) = ReturnVoid :
|
||||||
|
# 1058| v2_2(void) = UnmodeledUse : mu*
|
||||||
|
# 1058| v2_3(void) = ExitFunction :
|
||||||
|
|
||||||
|
# 1059| Block 3
|
||||||
|
# 1059| m3_0(int) = Phi : from 0:m0_4, from 1:m3_6
|
||||||
|
# 1059| m3_1(char *) = Phi : from 0:m0_6, from 1:m1_5
|
||||||
|
# 1059| r3_2(glval<int>) = VariableAddress[n] :
|
||||||
|
# 1059| r3_3(int) = Load : r3_2, m3_0
|
||||||
|
# 1059| r3_4(int) = Constant[1] :
|
||||||
|
# 1059| r3_5(int) = Sub : r3_3, r3_4
|
||||||
|
# 1059| m3_6(int) = Store : r3_2, r3_5
|
||||||
|
# 1059| r3_7(int) = Constant[0] :
|
||||||
|
# 1059| r3_8(bool) = CompareGT : r3_3, r3_7
|
||||||
|
# 1059| v3_9(void) = ConditionalBranch : r3_8
|
||||||
|
#-----| False -> Block 2
|
||||||
|
#-----| True -> Block 1
|
||||||
|
|||||||
@@ -8,3 +8,6 @@ unexplainedLoop
|
|||||||
unnecessaryPhiInstruction
|
unnecessaryPhiInstruction
|
||||||
operandAcrossFunctions
|
operandAcrossFunctions
|
||||||
instructionWithoutUniqueBlock
|
instructionWithoutUniqueBlock
|
||||||
|
containsLoopOfForwardEdges
|
||||||
|
lostReachability
|
||||||
|
backEdgeCountMismatch
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ void skip_init() {
|
|||||||
void run_init() {
|
void run_init() {
|
||||||
int nonstatic;
|
int nonstatic;
|
||||||
static int x1 = global_int;
|
static int x1 = global_int;
|
||||||
|
|
||||||
|
// It makes no sense to initialize a static variable to the address of a
|
||||||
|
// non-static variable, but in principle it can be done:
|
||||||
static int *x2 = &nonstatic;
|
static int *x2 = &nonstatic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
| test.cpp:100:10:100:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
|
| test.cpp:100:10:100:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
|
||||||
| test.cpp:102:10:102:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
|
| test.cpp:102:10:102:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
|
||||||
| test.cpp:107:5:107:10 | Phi: test10 | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:115:18:115:22 | test.cpp:115:18:115:22 |
|
| test.cpp:107:5:107:10 | Phi: test10 | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:115:18:115:22 | test.cpp:115:18:115:22 |
|
||||||
|
| test.cpp:130:10:130:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
|
||||||
| test.cpp:140:10:140:10 | Store: i | file://:0:0:0:0 | 0 | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
|
| test.cpp:140:10:140:10 | Store: i | file://:0:0:0:0 | 0 | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
|
||||||
| test.cpp:140:10:140:10 | Store: i | test.cpp:135:16:135:16 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:139:11:139:15 | test.cpp:139:11:139:15 |
|
| test.cpp:140:10:140:10 | Store: i | test.cpp:135:16:135:16 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:139:11:139:15 | test.cpp:139:11:139:15 |
|
||||||
| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | Phi: i | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
|
| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | Phi: i | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
|
||||||
@@ -54,3 +55,8 @@
|
|||||||
| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | false | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 |
|
| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | false | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 |
|
||||||
| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | true | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 |
|
| test.cpp:167:12:167:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 1 | true | CompareEQ: ... == ... | test.cpp:166:9:166:16 | test.cpp:166:9:166:16 |
|
||||||
| test.cpp:169:12:169:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 |
|
| test.cpp:169:12:169:12 | Load: x | test.cpp:153:23:153:23 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cpp:154:6:154:10 | test.cpp:154:6:154:10 |
|
||||||
|
| test.cpp:177:10:177:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 1 | false | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
|
||||||
|
| test.cpp:179:10:179:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
|
||||||
|
| test.cpp:183:10:183:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 |
|
||||||
|
| test.cpp:185:10:185:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
|
||||||
|
| test.cpp:187:10:187:10 | Store: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 |
|
||||||
|
|||||||
@@ -170,3 +170,19 @@ int test14(int x, int y) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// more interesting bounds with irreducible CFG
|
||||||
|
int test15(int i, int x) {
|
||||||
|
if (x < i) {
|
||||||
|
sink(i); // i >= x + 1
|
||||||
|
} else {
|
||||||
|
sink(i); // i <= x
|
||||||
|
goto inLoop;
|
||||||
|
}
|
||||||
|
for(; i < x; i++) {
|
||||||
|
sink(i); // i <= x - 1
|
||||||
|
inLoop:
|
||||||
|
sink(i); // i <= x
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|||||||
@@ -446,7 +446,7 @@ test.cpp:
|
|||||||
# 56| valnum = r5_3
|
# 56| valnum = r5_3
|
||||||
# 56| m5_4(char *) = Store : r5_0, r5_3
|
# 56| m5_4(char *) = Store : r5_0, r5_3
|
||||||
# 56| valnum = r5_3
|
# 56| valnum = r5_3
|
||||||
#-----| Goto -> Block 3
|
#-----| Goto (back edge) -> Block 3
|
||||||
|
|
||||||
# 59| Block 6
|
# 59| Block 6
|
||||||
# 59| r6_0(glval<char *>) = VariableAddress[ptr] :
|
# 59| r6_0(glval<char *>) = VariableAddress[ptr] :
|
||||||
@@ -480,7 +480,7 @@ test.cpp:
|
|||||||
# 62| valnum = r8_3
|
# 62| valnum = r8_3
|
||||||
# 62| m8_4(unsigned int) = Store : r8_0, r8_3
|
# 62| m8_4(unsigned int) = Store : r8_0, r8_3
|
||||||
# 62| valnum = r8_3
|
# 62| valnum = r8_3
|
||||||
#-----| Goto -> Block 1
|
#-----| Goto (back edge) -> Block 1
|
||||||
|
|
||||||
# 63| Block 9
|
# 63| Block 9
|
||||||
# 63| v9_0(void) = NoOp :
|
# 63| v9_0(void) = NoOp :
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
| test.cpp:16:13:16:14 | _t | This parameter of type $@ is 4096 bytes - consider passing a pointer/reference instead. | test.cpp:6:8:6:20 | myLargeStruct | myLargeStruct |
|
| test.cpp:16:13:16:14 | _t | This parameter of type $@ is 4096 bytes - consider passing a const pointer/reference instead. | test.cpp:6:8:6:20 | myLargeStruct | myLargeStruct |
|
||||||
| test.cpp:24:44:24:48 | mtc_t | This parameter of type $@ is 4096 bytes - consider passing a pointer/reference instead. | test.cpp:11:7:11:21 | myTemplateClass<myLargeStruct> | myTemplateClass<myLargeStruct> |
|
| test.cpp:24:44:24:48 | mtc_t | This parameter of type $@ is 4096 bytes - consider passing a const pointer/reference instead. | test.cpp:11:7:11:21 | myTemplateClass<myLargeStruct> | myTemplateClass<myLargeStruct> |
|
||||||
| test.cpp:28:49:28:49 | b | This parameter of type $@ is 4096 bytes - consider passing a pointer/reference instead. | test.cpp:6:8:6:20 | myLargeStruct | myLargeStruct |
|
| test.cpp:28:49:28:49 | b | This parameter of type $@ is 4096 bytes - consider passing a const pointer/reference instead. | test.cpp:6:8:6:20 | myLargeStruct | myLargeStruct |
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
| test3.c:15:10:15:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
|
| test3.c:15:10:15:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
|
||||||
| test3.c:15:14:15:14 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
|
| test3.c:15:14:15:14 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
|
||||||
| test3.c:15:18:15:18 | z | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
|
| test3.c:15:18:15:18 | z | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
|
||||||
|
| test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
||||||
|
| test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
||||||
|
| test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
||||||
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value |
|
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value |
|
||||||
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
|
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
|
||||||
| test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
|
| test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
| test3.c:12:31:12:34 | * ... | $@ flows to here and is used in an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value |
|
| test3.c:12:31:12:34 | * ... | $@ flows to here and is used in an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value |
|
||||||
| test3.c:13:16:13:19 | * ... | $@ flows to here and is used in an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value |
|
| test3.c:13:16:13:19 | * ... | $@ flows to here and is used in an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value |
|
||||||
| test4.cpp:13:17:13:20 | access to array | $@ flows to here and is used in an expression which might overflow negatively. | test4.cpp:9:13:9:16 | argv | User-provided value |
|
| test4.cpp:13:17:13:20 | access to array | $@ flows to here and is used in an expression which might overflow negatively. | test4.cpp:9:13:9:16 | argv | User-provided value |
|
||||||
|
| test5.cpp:10:9:10:15 | call to strtoul | $@ flows to here and is used in an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
char *gets(char *s);
|
||||||
|
unsigned long int strtoul( const char * nptr, char ** endptr, int base);
|
||||||
|
|
||||||
|
int getTaintedInt()
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
|
gets(buf);
|
||||||
|
return strtoul(buf, 0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void useTaintedInt()
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
x = getTaintedInt() * 1024; // BAD: arithmetic on a tainted value
|
||||||
|
y = getTaintedInt();
|
||||||
|
y = y * 1024; // BAD: arithmetic on a tainted value
|
||||||
|
}
|
||||||
@@ -112,7 +112,7 @@ namespace Semmle.Autobuild
|
|||||||
var o = JObject.Parse(File.ReadAllText(path));
|
var o = JObject.Parse(File.ReadAllText(path));
|
||||||
version = (string)o["sdk"]["version"];
|
version = (string)o["sdk"]["version"];
|
||||||
}
|
}
|
||||||
catch
|
catch // lgtm[cs/catch-of-all-exceptions]
|
||||||
{
|
{
|
||||||
// not a valid global.json file
|
// not a valid global.json file
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ namespace Semmle.Autobuild
|
|||||||
ToolsVersion = new Version(toolsVersion);
|
ToolsVersion = new Version(toolsVersion);
|
||||||
ValidToolsVersion = true;
|
ValidToolsVersion = true;
|
||||||
}
|
}
|
||||||
catch // Generic catch clause - Version constructor throws about 5 different exceptions.
|
catch // lgtm[cs/catch-of-all-exceptions]
|
||||||
|
// Generic catch clause - Version constructor throws about 5 different exceptions.
|
||||||
{
|
{
|
||||||
builder.Log(Severity.Warning, "Project {0} has invalid tools version {1}", path, toolsVersion);
|
builder.Log(Severity.Warning, "Project {0} has invalid tools version {1}", path, toolsVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ namespace Semmle.Util
|
|||||||
entries[0] :
|
entries[0] :
|
||||||
Path.Combine(parentPath, name);
|
Path.Combine(parentPath, name);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch // lgtm[cs/catch-of-all-exceptions]
|
||||||
{
|
{
|
||||||
// IO error or security error querying directory.
|
// IO error or security error querying directory.
|
||||||
return Path.Combine(parentPath, name);
|
return Path.Combine(parentPath, name);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import semmle.code.csharp.frameworks.Format
|
|||||||
from FormatCall format, int unused, ValidFormatString src
|
from FormatCall format, int unused, ValidFormatString src
|
||||||
where
|
where
|
||||||
src = format.getAFormatSource() and
|
src = format.getAFormatSource() and
|
||||||
unused = format.getAnUnusedArgument(src)
|
unused = format.getAnUnusedArgument(src) and
|
||||||
|
not src.getValue() = ""
|
||||||
select format, "The $@ ignores $@.", src, "format string", format.getSuppliedExpr(unused),
|
select format, "The $@ ignores $@.", src, "format string", format.getSuppliedExpr(unused),
|
||||||
"this supplied value"
|
"this supplied value"
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class SuppressionScope extends @commentline {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -26,9 +26,7 @@ predicate isReadonlyCompatibleDefinition(AssignableDefinition def, Field f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate canBeReadonly(Field f) {
|
predicate canBeReadonly(Field f) {
|
||||||
forex(AssignableDefinition def | defTargetsField(def, f) |
|
forex(AssignableDefinition def | defTargetsField(def, f) | isReadonlyCompatibleDefinition(def, f))
|
||||||
isReadonlyCompatibleDefinition(def, f)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
from Field f
|
from Field f
|
||||||
@@ -36,5 +34,5 @@ where
|
|||||||
canBeReadonly(f) and
|
canBeReadonly(f) and
|
||||||
not f.isConst() and
|
not f.isConst() and
|
||||||
not f.isReadOnly() and
|
not f.isReadOnly() and
|
||||||
(f.isEffectivelyPrivate() or f.isEffectivelyInternal())
|
not f.isEffectivelyPublic()
|
||||||
select f, "Field '" + f.getName() + "' can be 'readonly'."
|
select f, "Field '" + f.getName() + "' can be 'readonly'."
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ where
|
|||||||
v.getType() instanceof CollectionType and
|
v.getType() instanceof CollectionType and
|
||||||
(
|
(
|
||||||
v instanceof LocalVariable or
|
v instanceof LocalVariable or
|
||||||
v = any(Field f | f.isEffectivelyPrivate() or f.isEffectivelyInternal())
|
v = any(Field f | not f.isEffectivelyPublic())
|
||||||
) and
|
) and
|
||||||
forex(Access a | a = v.getAnAccess() |
|
forex(Access a | a = v.getAnAccess() |
|
||||||
a = any(ModifierMethodCall m).getQualifier() or
|
a = any(ModifierMethodCall m).getQualifier() or
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ predicate alwaysDefaultToString(ValueOrRefType t) {
|
|||||||
not exists(RefType overriding |
|
not exists(RefType overriding |
|
||||||
overriding.getAMethod() instanceof ToStringMethod and
|
overriding.getAMethod() instanceof ToStringMethod and
|
||||||
overriding.getABaseType+() = t
|
overriding.getABaseType+() = t
|
||||||
)
|
) and
|
||||||
|
((t.isAbstract() or t instanceof Interface) implies not t.isEffectivelyPublic())
|
||||||
}
|
}
|
||||||
|
|
||||||
newtype TDefaultToStringType = TDefaultToStringType0(ValueOrRefType t) { alwaysDefaultToString(t) }
|
newtype TDefaultToStringType = TDefaultToStringType0(ValueOrRefType t) { alwaysDefaultToString(t) }
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ abstract class Use extends @type_mention_parent {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
2
csharp/ql/src/external/CodeDuplication.qll
vendored
2
csharp/ql/src/external/CodeDuplication.qll
vendored
@@ -6,7 +6,7 @@ private string relativePath(File file) { result = file.getRelativePath().replace
|
|||||||
* Holds if the `index`-th token of block `copy` is in file `file`, spanning
|
* Holds if the `index`-th token of block `copy` is in file `file`, spanning
|
||||||
* column `sc` of line `sl` to column `ec` of line `el`.
|
* column `sc` of line `sl` to column `ec` of line `el`.
|
||||||
*
|
*
|
||||||
* For more information, see [LGTM locations](https://lgtm.com/docs/ql/locations).
|
* For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) {
|
predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) {
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ class Declaration extends DotNet::Declaration, Element, @cil_declaration {
|
|||||||
final predicate isSourceDeclaration() { this = getSourceDeclaration() }
|
final predicate isSourceDeclaration() { this = getSourceDeclaration() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private CS::Declaration toCSharpNonTypeParameter(Declaration d) { result.getLabel() = d.getLabel() }
|
private CS::Declaration toCSharpNonTypeParameter(Declaration d) { result.matchesHandle(d) }
|
||||||
|
|
||||||
private CS::TypeParameter toCSharpTypeParameter(TypeParameter tp) {
|
private CS::TypeParameter toCSharpTypeParameter(TypeParameter tp) {
|
||||||
toCSharpTypeParameterJoin(tp, result.getIndex(), result.getGeneric())
|
toCSharpTypeParameterJoin(tp, result.getIndex(), result.getGeneric())
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline, nomagic]
|
pragma[nomagic]
|
||||||
private predicate toCSharpTypeParameterJoin(TypeParameter tp, int i, CS::UnboundGeneric ug) {
|
private predicate toCSharpTypeParameterJoin(TypeParameter tp, int i, CS::UnboundGeneric ug) {
|
||||||
exists(TypeContainer tc |
|
exists(TypeContainer tc |
|
||||||
tp.getIndex() = i and
|
tp.getIndex() = i and
|
||||||
|
|||||||
@@ -402,17 +402,14 @@ module AssignableInternal {
|
|||||||
* `a`, if any.
|
* `a`, if any.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
Expr getAccessorCallValueArgument(Access a) {
|
Expr getAccessorCallValueArgument(AccessorCall ac) {
|
||||||
a.getTarget() instanceof DeclarationWithAccessors and
|
exists(AssignExpr ae | tupleAssignmentDefinition(ae, ac) |
|
||||||
(
|
tupleAssignmentPair(ae, ac, result)
|
||||||
exists(AssignExpr ae | tupleAssignmentDefinition(ae, a) |
|
)
|
||||||
tupleAssignmentPair(ae, a, result)
|
or
|
||||||
)
|
exists(Assignment ass | ac = ass.getLValue() |
|
||||||
or
|
result = ass.getRValue() and
|
||||||
exists(Assignment ass | a = ass.getLValue() |
|
not ass.(AssignOperation).hasExpandedAssignment()
|
||||||
result = ass.getRValue() and
|
|
||||||
not ass.(AssignOperation).hasExpandedAssignment()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class Container extends @container {
|
|||||||
/**
|
/**
|
||||||
* Gets a URL representing the location of this container.
|
* Gets a URL representing the location of this container.
|
||||||
*
|
*
|
||||||
* For more information see https://lgtm.com/help/ql/locations#providing-urls.
|
* For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls).
|
||||||
*/
|
*/
|
||||||
string getURL() { none() }
|
string getURL() { none() }
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class Location extends @location {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ class Modifiable extends Declaration, @modifiable {
|
|||||||
this.isInternal() or
|
this.isInternal() or
|
||||||
this.getDeclaringType+().isInternal()
|
this.getDeclaringType+().isInternal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this declaration is effectively `public`, because it
|
||||||
|
* and all enclosing types are `public`.
|
||||||
|
*/
|
||||||
|
predicate isEffectivelyPublic() { not isEffectivelyPrivate() and not isEffectivelyInternal() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A declaration that is a member of a type. */
|
/** A declaration that is a member of a type. */
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ class IndexerProperty extends Property {
|
|||||||
IndexerCall getAnIndexerCall() {
|
IndexerCall getAnIndexerCall() {
|
||||||
result = getType().(RefType).getAnIndexer().getAnAccessor().getACall() and
|
result = getType().(RefType).getAnIndexer().getAnAccessor().getACall() and
|
||||||
// The qualifier of this indexer call should be a value returned from an access of this property
|
// The qualifier of this indexer call should be a value returned from an access of this property
|
||||||
exists(Expr qualifier | qualifier = result.getAccess().getQualifier() |
|
exists(Expr qualifier | qualifier = result.(IndexerAccess).getQualifier() |
|
||||||
DataFlow::localFlow(DataFlow::exprNode(this.getAnAccess()), DataFlow::exprNode(qualifier))
|
DataFlow::localFlow(DataFlow::exprNode(this.getAnAccess()), DataFlow::exprNode(qualifier))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -48,16 +48,13 @@ module AbstractValues {
|
|||||||
|
|
||||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||||
s.(BooleanSuccessor).getValue() = this.getValue() and
|
s.(BooleanSuccessor).getValue() = this.getValue() and
|
||||||
exists(BooleanCompletion c |
|
exists(BooleanCompletion c | s.matchesCompletion(c) |
|
||||||
s.matchesCompletion(c) |
|
|
||||||
c.isValidFor(cfe) and
|
c.isValidFor(cfe) and
|
||||||
e = cfe
|
e = cfe
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override BooleanValue getDualValue() {
|
override BooleanValue getDualValue() { result.getValue() = this.getValue().booleanNot() }
|
||||||
result.getValue() = this.getValue().booleanNot()
|
|
||||||
}
|
|
||||||
|
|
||||||
override Expr getAnExpr() {
|
override Expr getAnExpr() {
|
||||||
result.getType() instanceof BoolType and
|
result.getType() instanceof BoolType and
|
||||||
@@ -74,13 +71,9 @@ module AbstractValues {
|
|||||||
/** Gets the underlying integer value. */
|
/** Gets the underlying integer value. */
|
||||||
int getValue() { this = TIntegerValue(result) }
|
int getValue() { this = TIntegerValue(result) }
|
||||||
|
|
||||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { none() }
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
override BooleanValue getDualValue() {
|
override BooleanValue getDualValue() { none() }
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
override Expr getAnExpr() {
|
override Expr getAnExpr() {
|
||||||
result.getValue().toInt() = this.getValue() and
|
result.getValue().toInt() = this.getValue() and
|
||||||
@@ -103,8 +96,7 @@ module AbstractValues {
|
|||||||
|
|
||||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||||
this = TNullValue(s.(NullnessSuccessor).getValue()) and
|
this = TNullValue(s.(NullnessSuccessor).getValue()) and
|
||||||
exists(NullnessCompletion c |
|
exists(NullnessCompletion c | s.matchesCompletion(c) |
|
||||||
s.matchesCompletion(c) |
|
|
||||||
c.isValidFor(cfe) and
|
c.isValidFor(cfe) and
|
||||||
e = cfe
|
e = cfe
|
||||||
)
|
)
|
||||||
@@ -115,20 +107,14 @@ module AbstractValues {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override DereferenceableExpr getAnExpr() {
|
override DereferenceableExpr getAnExpr() {
|
||||||
if this.isNull() then
|
if this.isNull()
|
||||||
result instanceof AlwaysNullExpr
|
then result instanceof AlwaysNullExpr
|
||||||
else
|
else exists(Expr e | nonNullValue(e) | nonNullValueImplied*(e, result))
|
||||||
exists(Expr e |
|
|
||||||
nonNullValue(e) |
|
|
||||||
nonNullValueImplied*(e, result)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSingleton() { this.isNull() }
|
override predicate isSingleton() { this.isNull() }
|
||||||
|
|
||||||
override string toString() {
|
override string toString() { if this.isNull() then result = "null" else result = "non-null" }
|
||||||
if this.isNull() then result = "null" else result = "non-null"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A value that represents match or non-match against a specific `case` statement. */
|
/** A value that represents match or non-match against a specific `case` statement. */
|
||||||
@@ -141,8 +127,7 @@ module AbstractValues {
|
|||||||
|
|
||||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||||
this = TMatchValue(_, s.(MatchingSuccessor).getValue()) and
|
this = TMatchValue(_, s.(MatchingSuccessor).getValue()) and
|
||||||
exists(MatchingCompletion c, SwitchStmt ss, CaseStmt cs |
|
exists(MatchingCompletion c, SwitchStmt ss, CaseStmt cs | s.matchesCompletion(c) |
|
||||||
s.matchesCompletion(c) |
|
|
||||||
c.isValidFor(cfe) and
|
c.isValidFor(cfe) and
|
||||||
switchMatching(ss, cs, cfe) and
|
switchMatching(ss, cs, cfe) and
|
||||||
e = ss.getCondition() and
|
e = ss.getCondition() and
|
||||||
@@ -152,9 +137,9 @@ module AbstractValues {
|
|||||||
|
|
||||||
override MatchValue getDualValue() {
|
override MatchValue getDualValue() {
|
||||||
result = any(MatchValue mv |
|
result = any(MatchValue mv |
|
||||||
mv.getCaseStmt() = this.getCaseStmt() and
|
mv.getCaseStmt() = this.getCaseStmt() and
|
||||||
if this.isMatch() then not mv.isMatch() else mv.isMatch()
|
if this.isMatch() then not mv.isMatch() else mv.isMatch()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Expr getAnExpr() { none() }
|
override Expr getAnExpr() { none() }
|
||||||
@@ -162,8 +147,7 @@ module AbstractValues {
|
|||||||
override predicate isSingleton() { none() }
|
override predicate isSingleton() { none() }
|
||||||
|
|
||||||
override string toString() {
|
override string toString() {
|
||||||
exists(string s |
|
exists(string s | s = this.getCaseStmt().toString() |
|
||||||
s = this.getCaseStmt().toString() |
|
|
||||||
if this.isMatch() then result = "match " + s else result = "non-match " + s
|
if this.isMatch() then result = "match " + s else result = "non-match " + s
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -176,8 +160,7 @@ module AbstractValues {
|
|||||||
|
|
||||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||||
this = TEmptyCollectionValue(s.(EmptinessSuccessor).getValue()) and
|
this = TEmptyCollectionValue(s.(EmptinessSuccessor).getValue()) and
|
||||||
exists(EmptinessCompletion c, ForeachStmt fs |
|
exists(EmptinessCompletion c, ForeachStmt fs | s.matchesCompletion(c) |
|
||||||
s.matchesCompletion(c) |
|
|
||||||
c.isValidFor(cfe) and
|
c.isValidFor(cfe) and
|
||||||
foreachEmptiness(fs, cfe) and
|
foreachEmptiness(fs, cfe) and
|
||||||
e = fs.getIterableExpr()
|
e = fs.getIterableExpr()
|
||||||
@@ -192,9 +175,7 @@ module AbstractValues {
|
|||||||
|
|
||||||
override predicate isSingleton() { none() }
|
override predicate isSingleton() { none() }
|
||||||
|
|
||||||
override string toString() {
|
override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" }
|
||||||
if this.isEmpty() then result = "empty" else result = "non-empty"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private import AbstractValues
|
private import AbstractValues
|
||||||
@@ -212,7 +193,8 @@ class DereferenceableExpr extends Expr {
|
|||||||
// incorrectly `int`, while it should have been `int?`. We apply
|
// incorrectly `int`, while it should have been `int?`. We apply
|
||||||
// `getNullEquivParent()` as a workaround
|
// `getNullEquivParent()` as a workaround
|
||||||
this = getNullEquivParent*(e) and
|
this = getNullEquivParent*(e) and
|
||||||
t = e.getType() |
|
t = e.getType()
|
||||||
|
|
|
||||||
t instanceof NullableType and
|
t instanceof NullableType and
|
||||||
isNullableType = true
|
isNullableType = true
|
||||||
or
|
or
|
||||||
@@ -222,9 +204,7 @@ class DereferenceableExpr extends Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this expression has a nullable type `T?`. */
|
/** Holds if this expression has a nullable type `T?`. */
|
||||||
predicate hasNullableType() {
|
predicate hasNullableType() { isNullableType = true }
|
||||||
isNullableType = true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an expression that directly tests whether this expression is `null`.
|
* Gets an expression that directly tests whether this expression is `null`.
|
||||||
@@ -237,23 +217,22 @@ class DereferenceableExpr extends Expr {
|
|||||||
* expression `x` is guaranteed to be non-`null`.
|
* expression `x` is guaranteed to be non-`null`.
|
||||||
*/
|
*/
|
||||||
private Expr getABooleanNullCheck(BooleanValue v, boolean isNull) {
|
private Expr getABooleanNullCheck(BooleanValue v, boolean isNull) {
|
||||||
exists(boolean branch |
|
exists(boolean branch | branch = v.getValue() |
|
||||||
branch = v.getValue() |
|
|
||||||
// Comparison with `null`, for example `x != null`
|
// Comparison with `null`, for example `x != null`
|
||||||
exists(ComparisonTest ct, ComparisonKind ck, NullLiteral nl |
|
exists(ComparisonTest ct, ComparisonKind ck, NullLiteral nl |
|
||||||
ct.getExpr() = result and
|
ct.getExpr() = result and
|
||||||
ct.getAnArgument() = this and
|
ct.getAnArgument() = this and
|
||||||
ct.getAnArgument() = nl and
|
ct.getAnArgument() = nl and
|
||||||
this != nl and
|
this != nl and
|
||||||
ck = ct.getComparisonKind() |
|
ck = ct.getComparisonKind()
|
||||||
|
|
|
||||||
ck.isEquality() and isNull = branch
|
ck.isEquality() and isNull = branch
|
||||||
or
|
or
|
||||||
ck.isInequality() and isNull = branch.booleanNot()
|
ck.isInequality() and isNull = branch.booleanNot()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// Comparison with a non-`null` value, for example `x?.Length > 0`
|
// Comparison with a non-`null` value, for example `x?.Length > 0`
|
||||||
exists(ComparisonTest ct, ComparisonKind ck, Expr e |
|
exists(ComparisonTest ct, ComparisonKind ck, Expr e | ct.getExpr() = result |
|
||||||
ct.getExpr() = result |
|
|
||||||
ct.getAnArgument() = this and
|
ct.getAnArgument() = this and
|
||||||
ct.getAnArgument() = e and
|
ct.getAnArgument() = e and
|
||||||
e = any(NullValue nv | not nv.isNull()).getAnExpr() and
|
e = any(NullValue nv | not nv.isNull()).getAnExpr() and
|
||||||
@@ -264,8 +243,7 @@ class DereferenceableExpr extends Expr {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// Call to `string.IsNullOrEmpty()` or `string.IsNullOrWhiteSpace()`
|
// Call to `string.IsNullOrEmpty()` or `string.IsNullOrWhiteSpace()`
|
||||||
exists(MethodCall mc, string name |
|
exists(MethodCall mc, string name | result = mc |
|
||||||
result = mc |
|
|
||||||
mc.getTarget() = any(SystemStringClass c).getAMethod(name) and
|
mc.getTarget() = any(SystemStringClass c).getAMethod(name) and
|
||||||
name.regexpMatch("IsNullOr(Empty|WhiteSpace)") and
|
name.regexpMatch("IsNullOr(Empty|WhiteSpace)") and
|
||||||
mc.getArgument(0) = this and
|
mc.getArgument(0) = this and
|
||||||
@@ -274,27 +252,28 @@ class DereferenceableExpr extends Expr {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
result = any(IsExpr ie |
|
result = any(IsExpr ie |
|
||||||
ie.getExpr() = this and
|
ie.getExpr() = this and
|
||||||
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral then
|
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral
|
||||||
// E.g. `x is null`
|
then
|
||||||
isNull = branch
|
// E.g. `x is null`
|
||||||
else (
|
isNull = branch
|
||||||
// E.g. `x is string` or `x is ""`
|
else (
|
||||||
branch = true and isNull = false
|
// E.g. `x is string` or `x is ""`
|
||||||
or
|
branch = true and isNull = false
|
||||||
// E.g. `x is string` where `x` has type `string`
|
or
|
||||||
ie = any(IsTypeExpr ite | ite.getCheckedType() = ite.getExpr().getType()) and
|
// E.g. `x is string` where `x` has type `string`
|
||||||
branch = false and
|
ie = any(IsTypeExpr ite | ite.getCheckedType() = ite.getExpr().getType()) and
|
||||||
isNull = true
|
branch = false and
|
||||||
|
isNull = true
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
or
|
or
|
||||||
this.hasNullableType() and
|
this.hasNullableType() and
|
||||||
result = any(PropertyAccess pa |
|
result = any(PropertyAccess pa |
|
||||||
pa.getQualifier() = this and
|
pa.getQualifier() = this and
|
||||||
pa.getTarget().hasName("HasValue") and
|
pa.getTarget().hasName("HasValue") and
|
||||||
if branch = true then isNull = false else isNull = true
|
if branch = true then isNull = false else isNull = true
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
isCustomNullCheck(result, this, v, isNull)
|
isCustomNullCheck(result, this, v, isNull)
|
||||||
)
|
)
|
||||||
@@ -326,22 +305,24 @@ class DereferenceableExpr extends Expr {
|
|||||||
cs = v.getCaseStmt() and
|
cs = v.getCaseStmt() and
|
||||||
this = ss.getCondition() and
|
this = ss.getCondition() and
|
||||||
result = this and
|
result = this and
|
||||||
cs = ss.getACase() |
|
cs = ss.getACase()
|
||||||
|
|
|
||||||
// E.g. `case string`
|
// E.g. `case string`
|
||||||
cs instanceof TypeCase and
|
cs instanceof TypeCase and
|
||||||
v.isMatch() and
|
v.isMatch() and
|
||||||
isNull = false
|
isNull = false
|
||||||
or
|
or
|
||||||
cs = any(ConstCase cc |
|
cs = any(ConstCase cc |
|
||||||
if cc.getExpr() instanceof NullLiteral then
|
if cc.getExpr() instanceof NullLiteral
|
||||||
// `case null`
|
then
|
||||||
if v.isMatch() then isNull = true else isNull = false
|
// `case null`
|
||||||
else (
|
if v.isMatch() then isNull = true else isNull = false
|
||||||
// E.g. `case ""`
|
else (
|
||||||
v.isMatch() and
|
// E.g. `case ""`
|
||||||
isNull = false
|
v.isMatch() and
|
||||||
|
isNull = false
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,14 +337,13 @@ class DereferenceableExpr extends Expr {
|
|||||||
* `x` is guaranteed to be `null`.
|
* `x` is guaranteed to be `null`.
|
||||||
*/
|
*/
|
||||||
private Expr getANullnessNullCheck(NullValue v, boolean isNull) {
|
private Expr getANullnessNullCheck(NullValue v, boolean isNull) {
|
||||||
exists(NullnessCompletion c |
|
exists(NullnessCompletion c | c.isValidFor(this) |
|
||||||
c.isValidFor(this) |
|
|
||||||
result = this and
|
result = this and
|
||||||
if c.isNull() then (
|
if c.isNull()
|
||||||
|
then (
|
||||||
v.isNull() and
|
v.isNull() and
|
||||||
isNull = true
|
isNull = true
|
||||||
)
|
) else (
|
||||||
else (
|
|
||||||
not v.isNull() and
|
not v.isNull() and
|
||||||
isNull = false
|
isNull = false
|
||||||
)
|
)
|
||||||
@@ -417,9 +397,7 @@ class AccessOrCallExpr extends Expr {
|
|||||||
* An expression can have more than one SSA qualifier in the presence
|
* An expression can have more than one SSA qualifier in the presence
|
||||||
* of control flow splitting.
|
* of control flow splitting.
|
||||||
*/
|
*/
|
||||||
Ssa::Definition getAnSsaQualifier(ControlFlow::Node cfn) {
|
Ssa::Definition getAnSsaQualifier(ControlFlow::Node cfn) { result = getAnSsaQualifier(this, cfn) }
|
||||||
result = getAnSsaQualifier(this, cfn)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Declaration getDeclarationTarget(Expr e) {
|
private Declaration getDeclarationTarget(Expr e) {
|
||||||
@@ -484,7 +462,9 @@ private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Nod
|
|||||||
*/
|
*/
|
||||||
class GuardedExpr extends AccessOrCallExpr {
|
class GuardedExpr extends AccessOrCallExpr {
|
||||||
private Guard g;
|
private Guard g;
|
||||||
|
|
||||||
private AccessOrCallExpr sub0;
|
private AccessOrCallExpr sub0;
|
||||||
|
|
||||||
private AbstractValue v0;
|
private AbstractValue v0;
|
||||||
|
|
||||||
GuardedExpr() { isGuardedByExpr(this, g, sub0, v0) }
|
GuardedExpr() { isGuardedByExpr(this, g, sub0, v0) }
|
||||||
@@ -511,9 +491,7 @@ class GuardedExpr extends AccessOrCallExpr {
|
|||||||
* expression is guarded by a structurally equal expression having abstract
|
* expression is guarded by a structurally equal expression having abstract
|
||||||
* value `v`.
|
* value `v`.
|
||||||
*/
|
*/
|
||||||
predicate mustHaveValue(AbstractValue v) {
|
predicate mustHaveValue(AbstractValue v) { exists(Expr e | e = this.getAGuard(e, v)) }
|
||||||
exists(Expr e | e = this.getAGuard(e, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this expression is guarded by expression `cond`, which must
|
* Holds if this expression is guarded by expression `cond`, which must
|
||||||
@@ -549,7 +527,9 @@ class GuardedExpr extends AccessOrCallExpr {
|
|||||||
*/
|
*/
|
||||||
class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
|
class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
|
||||||
private Guard g;
|
private Guard g;
|
||||||
|
|
||||||
private AccessOrCallExpr sub0;
|
private AccessOrCallExpr sub0;
|
||||||
|
|
||||||
private AbstractValue v0;
|
private AbstractValue v0;
|
||||||
|
|
||||||
GuardedControlFlowNode() { isGuardedByNode(this, g, sub0, v0) }
|
GuardedControlFlowNode() { isGuardedByNode(this, g, sub0, v0) }
|
||||||
@@ -576,9 +556,7 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
|
|||||||
* control flow node is guarded by a structurally equal expression having
|
* control flow node is guarded by a structurally equal expression having
|
||||||
* abstract value `v`.
|
* abstract value `v`.
|
||||||
*/
|
*/
|
||||||
predicate mustHaveValue(AbstractValue v) {
|
predicate mustHaveValue(AbstractValue v) { exists(Expr e | e = this.getAGuard(e, v)) }
|
||||||
exists(Expr e | e = this.getAGuard(e, v))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -601,12 +579,13 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
|
|||||||
*/
|
*/
|
||||||
class GuardedDataFlowNode extends DataFlow::ExprNode {
|
class GuardedDataFlowNode extends DataFlow::ExprNode {
|
||||||
private Guard g;
|
private Guard g;
|
||||||
|
|
||||||
private AccessOrCallExpr sub0;
|
private AccessOrCallExpr sub0;
|
||||||
|
|
||||||
private AbstractValue v0;
|
private AbstractValue v0;
|
||||||
|
|
||||||
GuardedDataFlowNode() {
|
GuardedDataFlowNode() {
|
||||||
exists(ControlFlow::Nodes::ElementNode cfn |
|
exists(ControlFlow::Nodes::ElementNode cfn | exists(this.getExprAtNode(cfn)) |
|
||||||
exists(this.getExprAtNode(cfn)) |
|
|
||||||
isGuardedByNode(cfn, g, sub0, v0)
|
isGuardedByNode(cfn, g, sub0, v0)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -633,23 +612,17 @@ class GuardedDataFlowNode extends DataFlow::ExprNode {
|
|||||||
* data flow node is guarded by a structurally equal expression having
|
* data flow node is guarded by a structurally equal expression having
|
||||||
* abstract value `v`.
|
* abstract value `v`.
|
||||||
*/
|
*/
|
||||||
predicate mustHaveValue(AbstractValue v) {
|
predicate mustHaveValue(AbstractValue v) { exists(Expr e | e = this.getAGuard(e, v)) }
|
||||||
exists(Expr e | e = this.getAGuard(e, v))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An expression guarded by a `null` check. */
|
/** An expression guarded by a `null` check. */
|
||||||
class NullGuardedExpr extends GuardedExpr {
|
class NullGuardedExpr extends GuardedExpr {
|
||||||
NullGuardedExpr() {
|
NullGuardedExpr() { this.mustHaveValue(any(NullValue v | not v.isNull())) }
|
||||||
this.mustHaveValue(any(NullValue v | not v.isNull()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A data flow node guarded by a `null` check. */
|
/** A data flow node guarded by a `null` check. */
|
||||||
class NullGuardedDataFlowNode extends GuardedDataFlowNode {
|
class NullGuardedDataFlowNode extends GuardedDataFlowNode {
|
||||||
NullGuardedDataFlowNode() {
|
NullGuardedDataFlowNode() { this.mustHaveValue(any(NullValue v | not v.isNull())) }
|
||||||
this.mustHaveValue(any(NullValue v | not v.isNull()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** INTERNAL: Do not use. */
|
/** INTERNAL: Do not use. */
|
||||||
@@ -657,16 +630,10 @@ module Internal {
|
|||||||
private import ControlFlow::Internal
|
private import ControlFlow::Internal
|
||||||
|
|
||||||
newtype TAbstractValue =
|
newtype TAbstractValue =
|
||||||
TBooleanValue(boolean b) { b = true or b = false }
|
TBooleanValue(boolean b) { b = true or b = false } or
|
||||||
or
|
TIntegerValue(int i) { i = any(Expr e).getValue().toInt() } or
|
||||||
TIntegerValue(int i) {
|
TNullValue(boolean b) { b = true or b = false } or
|
||||||
i = any(Expr e).getValue().toInt()
|
TMatchValue(CaseStmt cs, boolean b) { b = true or b = false } or
|
||||||
}
|
|
||||||
or
|
|
||||||
TNullValue(boolean b) { b = true or b = false }
|
|
||||||
or
|
|
||||||
TMatchValue(CaseStmt cs, boolean b) { b = true or b = false }
|
|
||||||
or
|
|
||||||
TEmptyCollectionValue(boolean b) { b = true or b = false }
|
TEmptyCollectionValue(boolean b) { b = true or b = false }
|
||||||
|
|
||||||
/** Holds if expression `e` is a non-`null` value. */
|
/** Holds if expression `e` is a non-`null` value. */
|
||||||
@@ -682,6 +649,11 @@ module Internal {
|
|||||||
or
|
or
|
||||||
e instanceof AddExpr and
|
e instanceof AddExpr and
|
||||||
e.getType() instanceof StringType
|
e.getType() instanceof StringType
|
||||||
|
or
|
||||||
|
e = any(MethodCall mc |
|
||||||
|
mc.getTarget() = any(SystemObjectClass c).getGetTypeMethod() and
|
||||||
|
not mc.isConditional()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if expression `e2` is a non-`null` value whenever `e1` is. */
|
/** Holds if expression `e2` is a non-`null` value whenever `e1` is. */
|
||||||
@@ -698,20 +670,20 @@ module Internal {
|
|||||||
*/
|
*/
|
||||||
Expr getNullEquivParent(Expr e) {
|
Expr getNullEquivParent(Expr e) {
|
||||||
result = any(QualifiableExpr qe |
|
result = any(QualifiableExpr qe |
|
||||||
qe.isConditional() and
|
qe.isConditional() and
|
||||||
(
|
(
|
||||||
e = qe.getQualifier()
|
e = qe.getQualifier()
|
||||||
or
|
or
|
||||||
e = qe.(ExtensionMethodCall).getArgument(0)
|
e = qe.(ExtensionMethodCall).getArgument(0)
|
||||||
) and
|
) and
|
||||||
(
|
(
|
||||||
// The accessed declaration must have a value type in order
|
// The accessed declaration must have a value type in order
|
||||||
// for `only if` to hold
|
// for `only if` to hold
|
||||||
result.(FieldAccess).getTarget().getType() instanceof ValueType
|
result.(FieldAccess).getTarget().getType() instanceof ValueType
|
||||||
or
|
or
|
||||||
result.(Call).getTarget().getReturnType() instanceof ValueType
|
result.(Call).getTarget().getReturnType() instanceof ValueType
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// In C#, `null + 1` has type `int?` with value `null`
|
// In C#, `null + 1` has type `int?` with value `null`
|
||||||
exists(BinaryArithmeticOperation bao, Expr o |
|
exists(BinaryArithmeticOperation bao, Expr o |
|
||||||
@@ -730,14 +702,12 @@ module Internal {
|
|||||||
*/
|
*/
|
||||||
Expr getANullImplyingChild(Expr e) {
|
Expr getANullImplyingChild(Expr e) {
|
||||||
e = any(QualifiableExpr qe |
|
e = any(QualifiableExpr qe |
|
||||||
qe.isConditional() and
|
qe.isConditional() and
|
||||||
result = qe.getQualifier()
|
result = qe.getQualifier()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// In C#, `null + 1` has type `int?` with value `null`
|
// In C#, `null + 1` has type `int?` with value `null`
|
||||||
e = any(BinaryArithmeticOperation bao |
|
e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand())
|
||||||
result = bao.getAnOperand()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An expression whose value may control the execution of another element. */
|
/** An expression whose value may control the execution of another element. */
|
||||||
@@ -763,7 +733,8 @@ module Internal {
|
|||||||
/** Holds if basic block `bb` only is reached when this guard has abstract value `v`. */
|
/** Holds if basic block `bb` only is reached when this guard has abstract value `v`. */
|
||||||
predicate controls(BasicBlock bb, AbstractValue v) {
|
predicate controls(BasicBlock bb, AbstractValue v) {
|
||||||
exists(ControlFlowElement cfe, ConditionalSuccessor s, AbstractValue v0, Guard g |
|
exists(ControlFlowElement cfe, ConditionalSuccessor s, AbstractValue v0, Guard g |
|
||||||
cfe.controlsBlock(bb, s) |
|
cfe.controlsBlock(bb, s)
|
||||||
|
|
|
||||||
v0.branch(cfe, s, g) and
|
v0.branch(cfe, s, g) and
|
||||||
impliesSteps(g, v0, this, v)
|
impliesSteps(g, v0, this, v)
|
||||||
)
|
)
|
||||||
@@ -780,8 +751,7 @@ module Internal {
|
|||||||
|
|
|
|
||||||
a.strictlyDominates(cfn.getBasicBlock())
|
a.strictlyDominates(cfn.getBasicBlock())
|
||||||
or
|
or
|
||||||
exists(BasicBlock bb, int i, int j |
|
exists(BasicBlock bb, int i, int j | bb.getNode(i) = a.getAControlFlowNode() |
|
||||||
bb.getNode(i) = a.getAControlFlowNode() |
|
|
||||||
bb.getNode(j) = cfn and
|
bb.getNode(j) = cfn and
|
||||||
j > i
|
j > i
|
||||||
)
|
)
|
||||||
@@ -793,8 +763,7 @@ module Internal {
|
|||||||
* because of an assertion.
|
* because of an assertion.
|
||||||
*/
|
*/
|
||||||
predicate assertionControlsElement(ControlFlowElement cfe, AbstractValue v) {
|
predicate assertionControlsElement(ControlFlowElement cfe, AbstractValue v) {
|
||||||
forex(ControlFlow::Node cfn |
|
forex(ControlFlow::Node cfn | cfn = cfe.getAControlFlowNode() |
|
||||||
cfn = cfe.getAControlFlowNode() |
|
|
||||||
this.assertionControlsNode(cfn, v)
|
this.assertionControlsNode(cfn, v)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -804,16 +773,14 @@ module Internal {
|
|||||||
* not taking implications into account.
|
* not taking implications into account.
|
||||||
*/
|
*/
|
||||||
predicate preControlsDirect(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
|
predicate preControlsDirect(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
|
||||||
exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s |
|
exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s | cb.controls(bb, s) |
|
||||||
cb.controls(bb, s) |
|
|
||||||
v.branch(cb.getLastElement(), s, this)
|
v.branch(cb.getLastElement(), s, this)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if pre-basic-block `bb` only is reached when this guard has abstract value `v`. */
|
/** Holds if pre-basic-block `bb` only is reached when this guard has abstract value `v`. */
|
||||||
predicate preControls(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
|
predicate preControls(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
|
||||||
exists(AbstractValue v0, Guard g |
|
exists(AbstractValue v0, Guard g | g.preControlsDirect(bb, v0) |
|
||||||
g.preControlsDirect(bb, v0) |
|
|
||||||
preImpliesSteps(g, v0, this, v)
|
preImpliesSteps(g, v0, this, v)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -821,7 +788,8 @@ module Internal {
|
|||||||
/** Gets the successor block that is reached when this guard has abstract value `v`. */
|
/** Gets the successor block that is reached when this guard has abstract value `v`. */
|
||||||
PreBasicBlocks::PreBasicBlock getConditionalSuccessor(AbstractValue v) {
|
PreBasicBlocks::PreBasicBlock getConditionalSuccessor(AbstractValue v) {
|
||||||
exists(PreBasicBlocks::ConditionBlock pred, ConditionalSuccessor s |
|
exists(PreBasicBlocks::ConditionBlock pred, ConditionalSuccessor s |
|
||||||
v.branch(pred.getLastElement(), s, this) |
|
v.branch(pred.getLastElement(), s, this)
|
||||||
|
|
|
||||||
result = pred.getASuccessorByType(s)
|
result = pred.getASuccessorByType(s)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -849,10 +817,10 @@ module Internal {
|
|||||||
|
|
||||||
private Expr stripConditionalExpr(Expr e) {
|
private Expr stripConditionalExpr(Expr e) {
|
||||||
e = any(ConditionalExpr ce |
|
e = any(ConditionalExpr ce |
|
||||||
result = stripConditionalExpr(ce.getThen())
|
result = stripConditionalExpr(ce.getThen())
|
||||||
or
|
or
|
||||||
result = stripConditionalExpr(ce.getElse())
|
result = stripConditionalExpr(ce.getElse())
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
not e instanceof ConditionalExpr and
|
not e instanceof ConditionalExpr and
|
||||||
result = e
|
result = e
|
||||||
@@ -878,7 +846,8 @@ module Internal {
|
|||||||
predicate nullGuardedReturn(Expr ret, boolean isNull) {
|
predicate nullGuardedReturn(Expr ret, boolean isNull) {
|
||||||
canReturn(p.getCallable(), ret) and
|
canReturn(p.getCallable(), ret) and
|
||||||
exists(PreBasicBlocks::PreBasicBlock bb, NullValue nv |
|
exists(PreBasicBlocks::PreBasicBlock bb, NullValue nv |
|
||||||
this.getARead().(Guard).preControls(bb, nv) |
|
this.getARead().(Guard).preControls(bb, nv)
|
||||||
|
|
|
||||||
ret = bb.getAnElement() and
|
ret = bb.getAnElement() and
|
||||||
if nv.isNull() then isNull = true else isNull = false
|
if nv.isNull() then isNull = true else isNull = false
|
||||||
)
|
)
|
||||||
@@ -890,18 +859,17 @@ module Internal {
|
|||||||
* `p` belongs, and `ret` having Boolean value `retVal` allows the conclusion
|
* `p` belongs, and `ret` having Boolean value `retVal` allows the conclusion
|
||||||
* that the parameter `p` either is `null` or non-`null`, as specified by `isNull`.
|
* that the parameter `p` either is `null` or non-`null`, as specified by `isNull`.
|
||||||
*/
|
*/
|
||||||
private predicate validReturnInCustomNullCheck(Expr ret, Parameter p, BooleanValue retVal, boolean isNull) {
|
private predicate validReturnInCustomNullCheck(
|
||||||
exists(Callable c |
|
Expr ret, Parameter p, BooleanValue retVal, boolean isNull
|
||||||
canReturn(c, ret) |
|
) {
|
||||||
|
exists(Callable c | canReturn(c, ret) |
|
||||||
p.getCallable() = c and
|
p.getCallable() = c and
|
||||||
c.getReturnType() instanceof BoolType
|
c.getReturnType() instanceof BoolType
|
||||||
) and
|
) and
|
||||||
exists(PreSsaImplicitParameterDefinition def |
|
exists(PreSsaImplicitParameterDefinition def | p = def.getParameter() |
|
||||||
p = def.getParameter() |
|
|
||||||
def.nullGuardedReturn(ret, isNull)
|
def.nullGuardedReturn(ret, isNull)
|
||||||
or
|
or
|
||||||
exists(NullValue nv |
|
exists(NullValue nv | preImpliesSteps(ret, retVal, def.getARead(), nv) |
|
||||||
preImpliesSteps(ret, retVal, def.getARead(), nv) |
|
|
||||||
if nv.isNull() then isNull = true else isNull = false
|
if nv.isNull() then isNull = true else isNull = false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -922,7 +890,7 @@ module Internal {
|
|||||||
forex(Expr ret |
|
forex(Expr ret |
|
||||||
canReturn(result, ret) and
|
canReturn(result, ret) and
|
||||||
not ret.(BoolLiteral).getBoolValue() = retVal.getValue().booleanNot()
|
not ret.(BoolLiteral).getBoolValue() = retVal.getValue().booleanNot()
|
||||||
|
|
|
|
||||||
validReturnInCustomNullCheck(ret, p, retVal, isNull)
|
validReturnInCustomNullCheck(ret, p, retVal, isNull)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -931,19 +899,20 @@ module Internal {
|
|||||||
* Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned
|
* Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned
|
||||||
* expression `e`.
|
* expression `e`.
|
||||||
*/
|
*/
|
||||||
private predicate conditionalAssign(Guard guard, AbstractValue vGuard, PreSsa::Definition def, Expr e) {
|
private predicate conditionalAssign(
|
||||||
|
Guard guard, AbstractValue vGuard, PreSsa::Definition def, Expr e
|
||||||
|
) {
|
||||||
// For example:
|
// For example:
|
||||||
// v = guard ? e : x;
|
// v = guard ? e : x;
|
||||||
exists(ConditionalExpr c |
|
exists(ConditionalExpr c | c = def.getDefinition().getSource() |
|
||||||
c = def.getDefinition().getSource() |
|
|
||||||
guard = c.getCondition() and
|
guard = c.getCondition() and
|
||||||
vGuard = any(BooleanValue bv |
|
vGuard = any(BooleanValue bv |
|
||||||
bv.getValue() = true and
|
bv.getValue() = true and
|
||||||
e = c.getThen()
|
e = c.getThen()
|
||||||
or
|
or
|
||||||
bv.getValue() = false and
|
bv.getValue() = false and
|
||||||
e = c.getElse()
|
e = c.getElse()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(PreSsa::Definition upd, PreBasicBlocks::PreBasicBlock bbGuard |
|
exists(PreSsa::Definition upd, PreBasicBlocks::PreBasicBlock bbGuard |
|
||||||
@@ -953,8 +922,7 @@ module Internal {
|
|||||||
bbGuard.getAnElement() = guard and
|
bbGuard.getAnElement() = guard and
|
||||||
bbGuard.strictlyDominates(def.getBasicBlock()) and
|
bbGuard.strictlyDominates(def.getBasicBlock()) and
|
||||||
not guard.preControlsDirect(def.getBasicBlock(), vGuard) and
|
not guard.preControlsDirect(def.getBasicBlock(), vGuard) and
|
||||||
forall(PreSsa::Definition other |
|
forall(PreSsa::Definition other | other != upd and other = def.getAPhiInput() |
|
||||||
other != upd and other = def.getAPhiInput() |
|
|
||||||
// For example:
|
// For example:
|
||||||
// if (guard)
|
// if (guard)
|
||||||
// upd = a;
|
// upd = a;
|
||||||
@@ -978,7 +946,9 @@ module Internal {
|
|||||||
* Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned
|
* Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned
|
||||||
* an expression with abstract value `vDef`.
|
* an expression with abstract value `vDef`.
|
||||||
*/
|
*/
|
||||||
private predicate conditionalAssignVal(Expr guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) {
|
private predicate conditionalAssignVal(
|
||||||
|
Expr guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef
|
||||||
|
) {
|
||||||
conditionalAssign(guard, vGuard, def, vDef.getAnExpr())
|
conditionalAssign(guard, vGuard, def, vDef.getAnExpr())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -998,24 +968,24 @@ module Internal {
|
|||||||
* expression `x` is guaranteed to be equal to `""`.
|
* expression `x` is guaranteed to be equal to `""`.
|
||||||
*/
|
*/
|
||||||
private Expr getABooleanEqualityCheck(Expr e1, BooleanValue v, Expr e2) {
|
private Expr getABooleanEqualityCheck(Expr e1, BooleanValue v, Expr e2) {
|
||||||
exists(boolean branch |
|
exists(boolean branch | branch = v.getValue() |
|
||||||
branch = v.getValue() |
|
|
||||||
exists(ComparisonTest ct, ComparisonKind ck |
|
exists(ComparisonTest ct, ComparisonKind ck |
|
||||||
ct.getExpr() = result and
|
ct.getExpr() = result and
|
||||||
ct.getAnArgument() = e1 and
|
ct.getAnArgument() = e1 and
|
||||||
ct.getAnArgument() = e2 and
|
ct.getAnArgument() = e2 and
|
||||||
e2 != e1 and
|
e2 != e1 and
|
||||||
ck = ct.getComparisonKind() |
|
ck = ct.getComparisonKind()
|
||||||
|
|
|
||||||
ck.isEquality() and branch = true
|
ck.isEquality() and branch = true
|
||||||
or
|
or
|
||||||
ck.isInequality() and branch = false
|
ck.isInequality() and branch = false
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
result = any(IsExpr ie |
|
result = any(IsExpr ie |
|
||||||
ie.getExpr() = e1 and
|
ie.getExpr() = e1 and
|
||||||
e2 = ie.(IsConstantExpr).getConstant() and
|
e2 = ie.(IsConstantExpr).getConstant() and
|
||||||
branch = true
|
branch = true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1042,8 +1012,7 @@ module Internal {
|
|||||||
* then `o` is guaranteed to be equal to `""`.
|
* then `o` is guaranteed to be equal to `""`.
|
||||||
*/
|
*/
|
||||||
private Expr getAMatchingEqualityCheck(Expr e1, MatchValue v, Expr e2) {
|
private Expr getAMatchingEqualityCheck(Expr e1, MatchValue v, Expr e2) {
|
||||||
exists(SwitchStmt ss, ConstCase cc |
|
exists(SwitchStmt ss, ConstCase cc | cc = v.getCaseStmt() |
|
||||||
cc = v.getCaseStmt() |
|
|
||||||
e1 = ss.getCondition() and
|
e1 = ss.getCondition() and
|
||||||
result = e1 and
|
result = e1 and
|
||||||
cc = ss.getACase() and
|
cc = ss.getACase() and
|
||||||
@@ -1078,10 +1047,11 @@ module Internal {
|
|||||||
* Holds if the evaluation of `guard` to `vGuard` implies that `def` does not
|
* Holds if the evaluation of `guard` to `vGuard` implies that `def` does not
|
||||||
* have the value `vDef`.
|
* have the value `vDef`.
|
||||||
*/
|
*/
|
||||||
private predicate guardImpliesNotEqual(Expr guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) {
|
private predicate guardImpliesNotEqual(
|
||||||
|
Expr guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef
|
||||||
|
) {
|
||||||
relevantEq(def, vDef) and
|
relevantEq(def, vDef) and
|
||||||
exists(AssignableRead ar |
|
exists(AssignableRead ar | ar = def.getARead() |
|
||||||
ar = def.getARead() |
|
|
||||||
// For example:
|
// For example:
|
||||||
// if (de == null); vGuard = TBooleanValue(false); vDef = TNullValue(true)
|
// if (de == null); vGuard = TBooleanValue(false); vDef = TNullValue(true)
|
||||||
// but not
|
// but not
|
||||||
@@ -1094,7 +1064,8 @@ module Internal {
|
|||||||
// or
|
// or
|
||||||
// if (de == null); vGuard = TBooleanValue(true); vDef = TNullValue(false)
|
// if (de == null); vGuard = TBooleanValue(true); vDef = TNullValue(false)
|
||||||
exists(NullValue nv |
|
exists(NullValue nv |
|
||||||
guard = ar.(DereferenceableExpr).getANullCheck(vGuard, any(boolean b | nv = TNullValue(b))) |
|
guard = ar.(DereferenceableExpr).getANullCheck(vGuard, any(boolean b | nv = TNullValue(b)))
|
||||||
|
|
|
||||||
vDef = nv.getDualValue()
|
vDef = nv.getDualValue()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -1115,8 +1086,7 @@ module Internal {
|
|||||||
|
|
|
|
||||||
not exists(input.getDefinition().getSource())
|
not exists(input.getDefinition().getSource())
|
||||||
or
|
or
|
||||||
exists(Expr e |
|
exists(Expr e | e = stripConditionalExpr(input.getDefinition().getSource()) |
|
||||||
e = stripConditionalExpr(input.getDefinition().getSource()) |
|
|
||||||
not e = any(AbstractValue v).getAnExpr()
|
not e = any(AbstractValue v).getAnExpr()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -1133,7 +1103,8 @@ module Internal {
|
|||||||
fromBackEdge = false
|
fromBackEdge = false
|
||||||
or
|
or
|
||||||
exists(PreSsa::Definition input, PreBasicBlocks::PreBasicBlock pred, boolean fbe |
|
exists(PreSsa::Definition input, PreBasicBlocks::PreBasicBlock pred, boolean fbe |
|
||||||
input = def.getAPhiInput() |
|
input = def.getAPhiInput()
|
||||||
|
|
|
||||||
pred = def.getBasicBlock().getAPredecessor() and
|
pred = def.getBasicBlock().getAPredecessor() and
|
||||||
PreSsa::ssaDefReachesEndOfBlock(pred, input, _) and
|
PreSsa::ssaDefReachesEndOfBlock(pred, input, _) and
|
||||||
result = getADefinition(input, fbe) and
|
result = getADefinition(input, fbe) and
|
||||||
@@ -1146,10 +1117,11 @@ module Internal {
|
|||||||
* `fromBackEdge` indicates whether the flow from `e` to `def` goes through a
|
* `fromBackEdge` indicates whether the flow from `e` to `def` goes through a
|
||||||
* back edge.
|
* back edge.
|
||||||
*/
|
*/
|
||||||
private predicate possibleValue(PreSsa::Definition def, boolean fromBackEdge, Expr e, AbstractValue v) {
|
private predicate possibleValue(
|
||||||
|
PreSsa::Definition def, boolean fromBackEdge, Expr e, AbstractValue v
|
||||||
|
) {
|
||||||
not hasPossibleUnknownValue(def) and
|
not hasPossibleUnknownValue(def) and
|
||||||
exists(PreSsa::Definition input |
|
exists(PreSsa::Definition input | input = getADefinition(def, fromBackEdge) |
|
||||||
input = getADefinition(def, fromBackEdge) |
|
|
||||||
e = stripConditionalExpr(input.getDefinition().getSource()) and
|
e = stripConditionalExpr(input.getDefinition().getSource()) and
|
||||||
v.getAnExpr() = e
|
v.getAnExpr() = e
|
||||||
)
|
)
|
||||||
@@ -1176,7 +1148,9 @@ module Internal {
|
|||||||
* Holds if `guard` having abstract value `vGuard` implies that `def` has
|
* Holds if `guard` having abstract value `vGuard` implies that `def` has
|
||||||
* abstract value `vDef`.
|
* abstract value `vDef`.
|
||||||
*/
|
*/
|
||||||
private predicate guardImpliesEqual(Guard guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) {
|
private predicate guardImpliesEqual(
|
||||||
|
Guard guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef
|
||||||
|
) {
|
||||||
guard = getAnEqualityCheck(def.getARead(), vGuard, vDef.getAnExpr())
|
guard = getAnEqualityCheck(def.getARead(), vGuard, vDef.getAnExpr())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1184,17 +1158,15 @@ module Internal {
|
|||||||
* A helper class for calculating structurally equal access/call expressions.
|
* A helper class for calculating structurally equal access/call expressions.
|
||||||
*/
|
*/
|
||||||
private class ConditionOnExprComparisonConfig extends InternalStructuralComparisonConfiguration {
|
private class ConditionOnExprComparisonConfig extends InternalStructuralComparisonConfiguration {
|
||||||
ConditionOnExprComparisonConfig() {
|
ConditionOnExprComparisonConfig() { this = "ConditionOnExprComparisonConfig" }
|
||||||
this = "ConditionOnExprComparisonConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate candidate(Element x, Element y) {
|
override predicate candidate(Element x, Element y) {
|
||||||
exists(BasicBlock bb, Declaration d |
|
exists(BasicBlock bb, Declaration d |
|
||||||
candidateAux(x, d, bb) and
|
candidateAux(x, d, bb) and
|
||||||
y = any(AccessOrCallExpr e |
|
y = any(AccessOrCallExpr e |
|
||||||
e.getAControlFlowNode().getBasicBlock() = bb and
|
e.getAControlFlowNode().getBasicBlock() = bb and
|
||||||
e.getTarget() = d
|
e.getTarget() = d
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1203,11 +1175,10 @@ module Internal {
|
|||||||
* is a sub expression of a condition that controls whether basic block
|
* is a sub expression of a condition that controls whether basic block
|
||||||
* `bb` is reached.
|
* `bb` is reached.
|
||||||
*/
|
*/
|
||||||
pragma [noinline]
|
pragma[noinline]
|
||||||
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
|
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
|
||||||
target = e.getTarget() and
|
target = e.getTarget() and
|
||||||
exists(Guard g |
|
exists(Guard g | e = g.getAChildExpr*() |
|
||||||
e = g.getAChildExpr*() |
|
|
||||||
g.controls(bb, _)
|
g.controls(bb, _)
|
||||||
or
|
or
|
||||||
g.assertionControlsElement(bb.getANode().getElement(), _)
|
g.assertionControlsElement(bb.getANode().getElement(), _)
|
||||||
@@ -1215,18 +1186,23 @@ module Internal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private cached module Cached {
|
cached
|
||||||
|
private module Cached {
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate isGuardedByNode0(ControlFlow::Node cfn, AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) {
|
private predicate isGuardedByNode0(
|
||||||
|
ControlFlow::Node cfn, AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub,
|
||||||
|
AbstractValue v
|
||||||
|
) {
|
||||||
cfn = guarded.getAControlFlowNode() and
|
cfn = guarded.getAControlFlowNode() and
|
||||||
g.controls(cfn.getBasicBlock(), v) and
|
g.controls(cfn.getBasicBlock(), v) and
|
||||||
exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded))
|
exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate isGuardedByExpr1(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) {
|
private predicate isGuardedByExpr1(
|
||||||
forex(ControlFlow::Node cfn |
|
AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v
|
||||||
cfn = guarded.getAControlFlowNode() |
|
) {
|
||||||
|
forex(ControlFlow::Node cfn | cfn = guarded.getAControlFlowNode() |
|
||||||
isGuardedByNode0(cfn, guarded, g, sub, v)
|
isGuardedByNode0(cfn, guarded, g, sub, v)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -1235,17 +1211,20 @@ module Internal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate isGuardedByExpr(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) {
|
predicate isGuardedByExpr(
|
||||||
|
AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v
|
||||||
|
) {
|
||||||
isGuardedByExpr1(guarded, g, sub, v) and
|
isGuardedByExpr1(guarded, g, sub, v) and
|
||||||
sub = g.getAChildExpr*() and
|
sub = g.getAChildExpr*() and
|
||||||
forall(Ssa::Definition def |
|
forall(Ssa::Definition def | def = sub.getAnSsaQualifier(_) |
|
||||||
def = sub.getAnSsaQualifier(_) |
|
|
||||||
def = guarded.getAnSsaQualifier(_)
|
def = guarded.getAnSsaQualifier(_)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate isGuardedByNode1(ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) {
|
private predicate isGuardedByNode1(
|
||||||
|
ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v
|
||||||
|
) {
|
||||||
isGuardedByNode0(guarded, _, g, sub, v)
|
isGuardedByNode0(guarded, _, g, sub, v)
|
||||||
or
|
or
|
||||||
g.assertionControlsNode(guarded, v) and
|
g.assertionControlsNode(guarded, v) and
|
||||||
@@ -1253,13 +1232,15 @@ module Internal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate isGuardedByNode(ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) {
|
predicate isGuardedByNode(
|
||||||
|
ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v
|
||||||
|
) {
|
||||||
isGuardedByNode1(guarded, g, sub, v) and
|
isGuardedByNode1(guarded, g, sub, v) and
|
||||||
sub = g.getAChildExpr*() and
|
sub = g.getAChildExpr*() and
|
||||||
forall(Ssa::Definition def |
|
forall(Ssa::Definition def | def = sub.getAnSsaQualifier(_) |
|
||||||
def = sub.getAnSsaQualifier(_) |
|
|
||||||
exists(ControlFlow::Node cfn |
|
exists(ControlFlow::Node cfn |
|
||||||
def = guarded.getElement().(AccessOrCallExpr).getAnSsaQualifier(cfn) |
|
def = guarded.getElement().(AccessOrCallExpr).getAnSsaQualifier(cfn)
|
||||||
|
|
|
||||||
cfn.getBasicBlock() = guarded.getBasicBlock()
|
cfn.getBasicBlock() = guarded.getBasicBlock()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -1276,10 +1257,8 @@ module Internal {
|
|||||||
predicate impliesStep(Guard g1, AbstractValue v1, Guard g2, AbstractValue v2) {
|
predicate impliesStep(Guard g1, AbstractValue v1, Guard g2, AbstractValue v2) {
|
||||||
preImpliesStep(g1, v1, g2, v2)
|
preImpliesStep(g1, v1, g2, v2)
|
||||||
or
|
or
|
||||||
forex(ControlFlow::Node cfn |
|
forex(ControlFlow::Node cfn | cfn = g1.getAControlFlowNode() |
|
||||||
cfn = g1.getAControlFlowNode() |
|
exists(Ssa::ExplicitDefinition def | def.getADefinition().getSource() = g2 |
|
||||||
exists(Ssa::ExplicitDefinition def |
|
|
||||||
def.getADefinition().getSource() = g2 |
|
|
||||||
g1 = def.getAReadAtNode(cfn) and
|
g1 = def.getAReadAtNode(cfn) and
|
||||||
v1 = g1.getAValue() and
|
v1 = g1.getAValue() and
|
||||||
v2 = v1
|
v2 = v1
|
||||||
@@ -1292,7 +1271,8 @@ module Internal {
|
|||||||
// The predicates in this module should be cached in the same stage as the cache stage
|
// The predicates in this module should be cached in the same stage as the cache stage
|
||||||
// in ControlFlowGraph.qll. This is to avoid recomputation of pre-basic-blocks and
|
// in ControlFlowGraph.qll. This is to avoid recomputation of pre-basic-blocks and
|
||||||
// pre-SSA predicates
|
// pre-SSA predicates
|
||||||
cached module CachedWithCFG {
|
cached
|
||||||
|
module CachedWithCFG {
|
||||||
cached
|
cached
|
||||||
predicate isCustomNullCheck(Call call, Expr arg, BooleanValue v, boolean isNull) {
|
predicate isCustomNullCheck(Call call, Expr arg, BooleanValue v, boolean isNull) {
|
||||||
exists(Callable callable, Parameter p |
|
exists(Callable callable, Parameter p |
|
||||||
@@ -1312,24 +1292,24 @@ module Internal {
|
|||||||
cached
|
cached
|
||||||
predicate preImpliesStep(Guard g1, AbstractValue v1, Guard g2, AbstractValue v2) {
|
predicate preImpliesStep(Guard g1, AbstractValue v1, Guard g2, AbstractValue v2) {
|
||||||
g1 = any(BinaryOperation bo |
|
g1 = any(BinaryOperation bo |
|
||||||
(
|
(
|
||||||
bo instanceof BitwiseAndExpr or
|
bo instanceof BitwiseAndExpr or
|
||||||
bo instanceof LogicalAndExpr
|
bo instanceof LogicalAndExpr
|
||||||
) and
|
) and
|
||||||
g2 = bo.getAnOperand() and
|
g2 = bo.getAnOperand() and
|
||||||
v1 = TBooleanValue(true) and
|
v1 = TBooleanValue(true) and
|
||||||
v2 = v1
|
v2 = v1
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
g1 = any(BinaryOperation bo |
|
g1 = any(BinaryOperation bo |
|
||||||
(
|
(
|
||||||
bo instanceof BitwiseOrExpr or
|
bo instanceof BitwiseOrExpr or
|
||||||
bo instanceof LogicalOrExpr
|
bo instanceof LogicalOrExpr
|
||||||
) and
|
) and
|
||||||
g2 = bo.getAnOperand() and
|
g2 = bo.getAnOperand() and
|
||||||
v1 = TBooleanValue(false) and
|
v1 = TBooleanValue(false) and
|
||||||
v2 = v1
|
v2 = v1
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
g2 = g1.(LogicalNotExpr).getOperand() and
|
g2 = g1.(LogicalNotExpr).getOperand() and
|
||||||
v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanNot())
|
v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanNot())
|
||||||
@@ -1339,7 +1319,8 @@ module Internal {
|
|||||||
b = boolLit.getBoolValue() and
|
b = boolLit.getBoolValue() and
|
||||||
g2 = ct.getAnArgument() and
|
g2 = ct.getAnArgument() and
|
||||||
g1 = ct.getExpr() and
|
g1 = ct.getExpr() and
|
||||||
v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanXor(polarity).booleanXor(b)) |
|
v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanXor(polarity).booleanXor(b))
|
||||||
|
|
|
||||||
ct.getComparisonKind().isEquality() and
|
ct.getComparisonKind().isEquality() and
|
||||||
polarity = true
|
polarity = true
|
||||||
or
|
or
|
||||||
@@ -1376,14 +1357,13 @@ module Internal {
|
|||||||
or
|
or
|
||||||
v1 = g1.getAValue() and
|
v1 = g1.getAValue() and
|
||||||
v1 = any(MatchValue mv |
|
v1 = any(MatchValue mv |
|
||||||
mv.isMatch() and
|
mv.isMatch() and
|
||||||
g2 = g1 and
|
g2 = g1 and
|
||||||
v2.getAnExpr() = mv.getCaseStmt().(ConstCase).getExpr() and
|
v2.getAnExpr() = mv.getCaseStmt().(ConstCase).getExpr() and
|
||||||
v1 != v2
|
v1 != v2
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(boolean isNull |
|
exists(boolean isNull | g1 = g2.(DereferenceableExpr).getANullCheck(v1, isNull) |
|
||||||
g1 = g2.(DereferenceableExpr).getANullCheck(v1, isNull) |
|
|
||||||
v2 = any(NullValue nv | if nv.isNull() then isNull = true else isNull = false) and
|
v2 = any(NullValue nv | if nv.isNull() then isNull = true else isNull = false) and
|
||||||
(g1 != g2 or v1 != v2)
|
(g1 != g2 or v1 != v2)
|
||||||
)
|
)
|
||||||
@@ -1410,8 +1390,7 @@ module Internal {
|
|||||||
v1 = g1.getAValue() and
|
v1 = g1.getAValue() and
|
||||||
v2 = v1.(NullValue)
|
v2 = v1.(NullValue)
|
||||||
or
|
or
|
||||||
exists(PreSsa::Definition def |
|
exists(PreSsa::Definition def | def.getDefinition().getSource() = g2 |
|
||||||
def.getDefinition().getSource() = g2 |
|
|
||||||
g1 = def.getARead() and
|
g1 = def.getARead() and
|
||||||
v1 = g1.getAValue() and
|
v1 = g1.getAValue() and
|
||||||
v2 = v1
|
v2 = v1
|
||||||
@@ -1452,8 +1431,7 @@ module Internal {
|
|||||||
v1 = v2 and
|
v1 = v2 and
|
||||||
v1 = g1.getAValue()
|
v1 = g1.getAValue()
|
||||||
or
|
or
|
||||||
exists(Expr mid, AbstractValue vMid |
|
exists(Expr mid, AbstractValue vMid | preImpliesSteps(g1, v1, mid, vMid) |
|
||||||
preImpliesSteps(g1, v1, mid, vMid) |
|
|
||||||
preImpliesStep(mid, vMid, g2, v2)
|
preImpliesStep(mid, vMid, g2, v2)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1470,8 +1448,7 @@ module Internal {
|
|||||||
v1 = v2 and
|
v1 = v2 and
|
||||||
v1 = g1.getAValue()
|
v1 = g1.getAValue()
|
||||||
or
|
or
|
||||||
exists(Expr mid, AbstractValue vMid |
|
exists(Expr mid, AbstractValue vMid | impliesSteps(g1, v1, mid, vMid) |
|
||||||
impliesSteps(g1, v1, mid, vMid) |
|
|
||||||
impliesStep(mid, vMid, g2, v2)
|
impliesStep(mid, vMid, g2, v2)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,19 +6,17 @@
|
|||||||
import csharp
|
import csharp
|
||||||
|
|
||||||
module TaintTracking {
|
module TaintTracking {
|
||||||
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
|
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
|
||||||
private import semmle.code.csharp.dispatch.Dispatch
|
private import semmle.code.csharp.dispatch.Dispatch
|
||||||
private import semmle.code.csharp.commons.ComparisonTest
|
private import semmle.code.csharp.commons.ComparisonTest
|
||||||
private import cil
|
private import cil
|
||||||
private import dotnet
|
private import dotnet
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if taint propagates from `source` to `sink` in zero or more local
|
* Holds if taint propagates from `source` to `sink` in zero or more local
|
||||||
* (intra-procedural) steps.
|
* (intra-procedural) steps.
|
||||||
*/
|
*/
|
||||||
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) {
|
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) }
|
||||||
localTaintStep*(source, sink)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||||
@@ -69,8 +67,7 @@ module TaintTracking {
|
|||||||
/** Holds if the intermediate node `node` is a taint sanitizer. */
|
/** Holds if the intermediate node `node` is a taint sanitizer. */
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final
|
final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) }
|
||||||
override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `pred` to `succ`
|
* Holds if the additional taint propagation step from `pred` to `succ`
|
||||||
@@ -78,22 +75,22 @@ module TaintTracking {
|
|||||||
*/
|
*/
|
||||||
predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||||
|
|
||||||
final
|
final override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
|
||||||
isAdditionalTaintStep(pred, succ) or
|
isAdditionalTaintStep(pred, succ) or
|
||||||
localAdditionalTaintStep(pred, succ) or
|
localAdditionalTaintStep(pred, succ) or
|
||||||
DataFlow::Internal::flowThroughCallableLibraryOutRef(_, pred, succ, false)
|
DataFlow::Internal::flowThroughCallableLibraryOutRef(_, pred, succ, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
final
|
final override predicate isAdditionalFlowStepIntoCall(
|
||||||
override predicate isAdditionalFlowStepIntoCall(DataFlow::Node call, DataFlow::Node arg, DotNet::Parameter p, CallContext::CallContext cc) {
|
DataFlow::Node call, DataFlow::Node arg, DotNet::Parameter p, CallContext::CallContext cc
|
||||||
|
) {
|
||||||
DataFlow::Internal::flowIntoCallableLibraryCall(_, arg, call, p, false, cc)
|
DataFlow::Internal::flowIntoCallableLibraryCall(_, arg, call, p, false, cc)
|
||||||
}
|
}
|
||||||
|
|
||||||
final
|
final override predicate isAdditionalFlowStepOutOfCall(
|
||||||
override predicate isAdditionalFlowStepOutOfCall(DataFlow::Node call, DataFlow::Node ret, DataFlow::Node out, CallContext::CallContext cc) {
|
DataFlow::Node call, DataFlow::Node ret, DataFlow::Node out, CallContext::CallContext cc
|
||||||
exists(DispatchCall dc, Callable callable |
|
) {
|
||||||
canYieldReturn(callable, ret.asExpr()) |
|
exists(DispatchCall dc, Callable callable | canYieldReturn(callable, ret.asExpr()) |
|
||||||
dc.getCall() = call.asExpr() and
|
dc.getCall() = call.asExpr() and
|
||||||
call = out and
|
call = out and
|
||||||
callable = dc.getADynamicTarget() and
|
callable = dc.getADynamicTarget() and
|
||||||
@@ -112,9 +109,7 @@ module TaintTracking {
|
|||||||
|
|
||||||
/** INTERNAL: Do not use. */
|
/** INTERNAL: Do not use. */
|
||||||
module Internal {
|
module Internal {
|
||||||
predicate canYieldReturn(Callable c, Expr e) {
|
predicate canYieldReturn(Callable c, Expr e) { c.getSourceDeclaration().canYieldReturn(e) }
|
||||||
c.getSourceDeclaration().canYieldReturn(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) {
|
private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) {
|
||||||
result = node.asParameter() or
|
result = node.asParameter() or
|
||||||
@@ -126,14 +121,15 @@ module TaintTracking {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the qualifier of element access `ea`. */
|
/** Gets the qualifier of element access `ea`. */
|
||||||
private Expr getElementAccessQualifier(ElementAccess ea) {
|
private Expr getElementAccessQualifier(ElementAccess ea) { result = ea.getQualifier() }
|
||||||
result = ea.getQualifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LocalTaintExprStepConfiguration extends DataFlow::Internal::ExprStepConfiguration {
|
private class LocalTaintExprStepConfiguration extends DataFlow::Internal::ExprStepConfiguration {
|
||||||
LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" }
|
LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" }
|
||||||
|
|
||||||
override predicate stepsToExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) {
|
override predicate stepsToExpr(
|
||||||
|
Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope,
|
||||||
|
boolean isSuccessor
|
||||||
|
) {
|
||||||
exactScope = false and
|
exactScope = false and
|
||||||
(
|
(
|
||||||
// Taint propagation using library code
|
// Taint propagation using library code
|
||||||
@@ -154,7 +150,11 @@ module TaintTracking {
|
|||||||
or
|
or
|
||||||
// Taint from object initializer
|
// Taint from object initializer
|
||||||
exists(ElementInitializer ei |
|
exists(ElementInitializer ei |
|
||||||
ei = exprTo.(ObjectCreation).getInitializer().(CollectionInitializer).getAnElementInitializer() and
|
ei = exprTo
|
||||||
|
.(ObjectCreation)
|
||||||
|
.getInitializer()
|
||||||
|
.(CollectionInitializer)
|
||||||
|
.getAnElementInitializer() and
|
||||||
exprFrom = ei.getArgument(ei.getNumberOfArguments() - 1) and // assume the last argument is the value (i.e., not a key)
|
exprFrom = ei.getArgument(ei.getNumberOfArguments() - 1) and // assume the last argument is the value (i.e., not a key)
|
||||||
scope = exprTo and
|
scope = exprTo and
|
||||||
isSuccessor = false
|
isSuccessor = false
|
||||||
@@ -187,11 +187,11 @@ module TaintTracking {
|
|||||||
or
|
or
|
||||||
// Taint from tuple argument
|
// Taint from tuple argument
|
||||||
exprTo = any(TupleExpr te |
|
exprTo = any(TupleExpr te |
|
||||||
exprFrom = te.getAnArgument() and
|
exprFrom = te.getAnArgument() and
|
||||||
te.isReadAccess() and
|
te.isReadAccess() and
|
||||||
scope = exprTo and
|
scope = exprTo and
|
||||||
isSuccessor = true
|
isSuccessor = true
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exprFrom = exprTo.(InterpolatedStringExpr).getAChild() and
|
exprFrom = exprTo.(InterpolatedStringExpr).getAChild() and
|
||||||
scope = exprTo and
|
scope = exprTo and
|
||||||
@@ -199,19 +199,23 @@ module TaintTracking {
|
|||||||
or
|
or
|
||||||
// Taint from tuple expression
|
// Taint from tuple expression
|
||||||
exprTo = any(MemberAccess ma |
|
exprTo = any(MemberAccess ma |
|
||||||
ma.getQualifier().getType() instanceof TupleType and
|
ma.getQualifier().getType() instanceof TupleType and
|
||||||
exprFrom = ma.getQualifier() and
|
exprFrom = ma.getQualifier() and
|
||||||
scope = exprTo and
|
scope = exprTo and
|
||||||
isSuccessor = true
|
isSuccessor = true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate stepsToDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) {
|
override predicate stepsToDefinition(
|
||||||
|
Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope,
|
||||||
|
boolean isSuccessor
|
||||||
|
) {
|
||||||
// Taint from `foreach` expression
|
// Taint from `foreach` expression
|
||||||
exists(ForeachStmt fs |
|
exists(ForeachStmt fs |
|
||||||
exprFrom = fs.getIterableExpr() and
|
exprFrom = fs.getIterableExpr() and
|
||||||
defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = fs.getVariableDeclExpr() and
|
defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = fs
|
||||||
|
.getVariableDeclExpr() and
|
||||||
isSuccessor = true
|
isSuccessor = true
|
||||||
|
|
|
|
||||||
scope = fs and
|
scope = fs and
|
||||||
@@ -226,10 +230,13 @@ module TaintTracking {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cached module Cached {
|
cached
|
||||||
cached predicate forceCachingInSameStage() { any() }
|
module Cached {
|
||||||
|
cached
|
||||||
|
predicate forceCachingInSameStage() { any() }
|
||||||
|
|
||||||
cached predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
cached
|
||||||
|
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||||
DataFlow::Internal::Cached::forceCachingInSameStage() and
|
DataFlow::Internal::Cached::forceCachingInSameStage() and
|
||||||
any(LocalTaintExprStepConfiguration x).hasStep(nodeFrom, nodeTo)
|
any(LocalTaintExprStepConfiguration x).hasStep(nodeFrom, nodeTo)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -47,10 +47,7 @@ module Steps {
|
|||||||
* Holds if modifiable `m` is effectively private or internal (either directly
|
* Holds if modifiable `m` is effectively private or internal (either directly
|
||||||
* or because one of `m`'s enclosing types is).
|
* or because one of `m`'s enclosing types is).
|
||||||
*/
|
*/
|
||||||
private predicate isEffectivelyInternalOrPrivate(Modifiable m) {
|
private predicate isEffectivelyInternalOrPrivate(Modifiable m) { not m.isEffectivelyPublic() }
|
||||||
m.isEffectivelyInternal() or
|
|
||||||
m.isEffectivelyPrivate()
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate flowIn(Parameter p, Expr pred, AssignableRead succ) {
|
private predicate flowIn(Parameter p, Expr pred, AssignableRead succ) {
|
||||||
exists(AssignableDefinitions::ImplicitParameterDefinition def, Call c | succ = getARead(def) |
|
exists(AssignableDefinitions::ImplicitParameterDefinition def, Call c | succ = getARead(def) |
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ private module Internal {
|
|||||||
|
|
|
|
||||||
succ.(AssignableRead) = a.getAnAccess() and
|
succ.(AssignableRead) = a.getAnAccess() and
|
||||||
pred = a.getAnAssignedValue() and
|
pred = a.getAnAssignedValue() and
|
||||||
a = any(Modifiable m | m.isEffectivelyInternal() or m.isEffectivelyPrivate())
|
a = any(Modifiable m | not m.isEffectivelyPublic())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,7 +477,7 @@ private module Internal {
|
|||||||
|
|
||||||
override Expr getArgument(int i) { result = getCall().getArgument(i) }
|
override Expr getArgument(int i) { result = getCall().getArgument(i) }
|
||||||
|
|
||||||
override Expr getQualifier() { result = getCall().getAccess().getQualifier() }
|
override Expr getQualifier() { result = getCall().(MemberAccess).getQualifier() }
|
||||||
|
|
||||||
override Accessor getAStaticTarget() { result = getCall().getTarget() }
|
override Accessor getAStaticTarget() { result = getCall().getTarget() }
|
||||||
|
|
||||||
|
|||||||
@@ -380,6 +380,17 @@ class MemberConstantAccess extends FieldAccess {
|
|||||||
override string toString() { result = "access to constant " + this.getTarget().getName() }
|
override string toString() { result = "access to constant " + this.getTarget().getName() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An internal helper class to share logic between `PropertyAccess` and
|
||||||
|
* `PropertyCall`.
|
||||||
|
*/
|
||||||
|
library class PropertyAccessExpr extends Expr, @property_access_expr {
|
||||||
|
/** Gets the target of this property access. */
|
||||||
|
Property getProperty() { expr_access(this, result) }
|
||||||
|
|
||||||
|
override string toString() { result = "access to property " + this.getProperty().getName() }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An access to a property, for example the access to `P` on line 5 in
|
* An access to a property, for example the access to `P` on line 5 in
|
||||||
*
|
*
|
||||||
@@ -393,13 +404,8 @@ class MemberConstantAccess extends FieldAccess {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class PropertyAccess extends AssignableMemberAccess, @property_access_expr {
|
class PropertyAccess extends AssignableMemberAccess, PropertyAccessExpr {
|
||||||
/** Gets the target of this property access. */
|
|
||||||
Property getProperty() { expr_access(this, result) }
|
|
||||||
|
|
||||||
override Property getTarget() { result = this.getProperty() }
|
override Property getTarget() { result = this.getProperty() }
|
||||||
|
|
||||||
override string toString() { result = "access to property " + this.getProperty().getName() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -509,6 +515,17 @@ class ElementRead extends ElementAccess, AssignableRead { }
|
|||||||
*/
|
*/
|
||||||
class ElementWrite extends ElementAccess, AssignableWrite { }
|
class ElementWrite extends ElementAccess, AssignableWrite { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An internal helper class to share logic between `IndexerAccess` and
|
||||||
|
* `IndexerCall`.
|
||||||
|
*/
|
||||||
|
library class IndexerAccessExpr extends Expr, @indexer_access_expr {
|
||||||
|
/** Gets the target of this indexer access. */
|
||||||
|
Indexer getIndexer() { expr_access(this, result) }
|
||||||
|
|
||||||
|
override string toString() { result = "access to indexer" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An access to an indexer, for example the access to `c` on line 5 in
|
* An access to an indexer, for example the access to `c` on line 5 in
|
||||||
*
|
*
|
||||||
@@ -522,17 +539,12 @@ class ElementWrite extends ElementAccess, AssignableWrite { }
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class IndexerAccess extends AssignableMemberAccess, ElementAccess, @indexer_access_expr {
|
class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccessExpr {
|
||||||
/** Gets the target of this indexer access. */
|
|
||||||
Indexer getIndexer() { expr_access(this, result) }
|
|
||||||
|
|
||||||
override Indexer getTarget() { result = this.getIndexer() }
|
override Indexer getTarget() { result = this.getIndexer() }
|
||||||
|
|
||||||
override Indexer getQualifiedDeclaration() {
|
override Indexer getQualifiedDeclaration() {
|
||||||
result = ElementAccess.super.getQualifiedDeclaration()
|
result = ElementAccess.super.getQualifiedDeclaration()
|
||||||
}
|
}
|
||||||
|
|
||||||
override string toString() { result = "access to indexer" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -588,6 +600,17 @@ class VirtualIndexerAccess extends IndexerAccess {
|
|||||||
VirtualIndexerAccess() { targetIsOverridableOrImplementable() }
|
VirtualIndexerAccess() { targetIsOverridableOrImplementable() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An internal helper class to share logic between `EventAccess` and
|
||||||
|
* `EventCall`.
|
||||||
|
*/
|
||||||
|
library class EventAccessExpr extends Expr, @event_access_expr {
|
||||||
|
/** Gets the target of this event access. */
|
||||||
|
Event getEvent() { expr_access(this, result) }
|
||||||
|
|
||||||
|
override string toString() { result = "access to event " + this.getEvent().getName() }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An access to an event, for example the accesses to `Click` on lines
|
* An access to an event, for example the accesses to `Click` on lines
|
||||||
* 7 and 8 in
|
* 7 and 8 in
|
||||||
@@ -605,13 +628,8 @@ class VirtualIndexerAccess extends IndexerAccess {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class EventAccess extends AssignableMemberAccess, @event_access_expr {
|
class EventAccess extends AssignableMemberAccess, EventAccessExpr {
|
||||||
/** Gets the target of this event access. */
|
|
||||||
Event getEvent() { expr_access(this, result) }
|
|
||||||
|
|
||||||
override Event getTarget() { result = getEvent() }
|
override Event getTarget() { result = getEvent() }
|
||||||
|
|
||||||
override string toString() { result = "access to event " + this.getEvent().getName() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,24 +11,13 @@ private import semmle.code.csharp.dataflow.DelegateDataFlow
|
|||||||
private import semmle.code.csharp.dispatch.Dispatch
|
private import semmle.code.csharp.dispatch.Dispatch
|
||||||
private import dotnet
|
private import dotnet
|
||||||
|
|
||||||
/** INTERNAL: Do not use. */
|
|
||||||
library class CallImpl extends Expr {
|
|
||||||
cached
|
|
||||||
CallImpl() {
|
|
||||||
this instanceof @call and
|
|
||||||
not this instanceof @call_access_expr
|
|
||||||
or
|
|
||||||
this instanceof AccessorCallImpl::AccessorCallImpl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A call. Either a method call (`MethodCall`), a constructor initializer call
|
* A call. Either a method call (`MethodCall`), a constructor initializer call
|
||||||
* (`ConstructorInitializer`), a call to a user-defined operator (`OperatorCall`),
|
* (`ConstructorInitializer`), a call to a user-defined operator (`OperatorCall`),
|
||||||
* a delegate call (`DelegateCall`), an accessor call (`AccessorCall`), a
|
* a delegate call (`DelegateCall`), an accessor call (`AccessorCall`), a
|
||||||
* constructor call (`ObjectCreation`), or a local function call (`LocalFunctionCall`).
|
* constructor call (`ObjectCreation`), or a local function call (`LocalFunctionCall`).
|
||||||
*/
|
*/
|
||||||
class Call extends DotNet::Call, CallImpl {
|
class Call extends DotNet::Call, Expr, @call {
|
||||||
/**
|
/**
|
||||||
* Gets the static (compile-time) target of this call. For example, the
|
* Gets the static (compile-time) target of this call. For example, the
|
||||||
* static target of `x.M()` on line 9 is `A.M` in
|
* static target of `x.M()` on line 9 is `A.M` in
|
||||||
@@ -565,159 +554,15 @@ class DelegateCall extends Call, @delegate_invocation_expr {
|
|||||||
override string toString() { result = "delegate call" }
|
override string toString() { result = "delegate call" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides logic for determining the syntactic nodes associated with calls
|
|
||||||
* to accessors. Example:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* int Prop { get; set; }
|
|
||||||
* public int GetProp() => Prop;
|
|
||||||
* public void SetProp(int i) { Prop = i + 1; }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* In the body of `GetProp()`, the call to the accessor `get_Prop()` is simply
|
|
||||||
* the access `Prop`. However, in the body of `SetProp()`, the call to the accessor
|
|
||||||
* `set_Prop()` is not the access `Prop`, but rather the assignment `Prop = i + 1`.
|
|
||||||
* (Using `Prop` as the call to `set_Prop()` will yield an incorrect control flow
|
|
||||||
* graph, where `set_Prop()` is called before `i + 1` is evaluated.)
|
|
||||||
*/
|
|
||||||
private module AccessorCallImpl {
|
|
||||||
/**
|
|
||||||
* Holds if `e` is a tuple assignment with multiple setter assignments,
|
|
||||||
* for example `(Prop1, Prop2) = (0, 1)`, where both `Prop1` and `Prop2`
|
|
||||||
* are properties.
|
|
||||||
*
|
|
||||||
* In such cases, we cannot associate the compound assignment with the
|
|
||||||
* setter calls, so we instead revert to representing the calls via the
|
|
||||||
* individual accesses on the left hand side.
|
|
||||||
*/
|
|
||||||
private predicate multiTupleSetter(Expr e) {
|
|
||||||
strictcount(AssignableDefinitions::TupleAssignmentDefinition def |
|
|
||||||
def.getExpr() = e and
|
|
||||||
def.getTargetAccess().getTarget() instanceof DeclarationWithGetSetAccessors
|
|
||||||
) > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class AccessorCallImpl extends Expr {
|
|
||||||
abstract Access getAccess();
|
|
||||||
|
|
||||||
abstract Accessor getTarget();
|
|
||||||
|
|
||||||
abstract Expr getArgument(int i);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class PropertyCallImpl extends AccessorCallImpl {
|
|
||||||
PropertyAccess pa;
|
|
||||||
|
|
||||||
override PropertyAccess getAccess() { result = pa }
|
|
||||||
|
|
||||||
abstract override Accessor getTarget();
|
|
||||||
|
|
||||||
abstract override Expr getArgument(int i);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PropertyGetterCall extends PropertyCallImpl, @property_access_expr {
|
|
||||||
PropertyGetterCall() {
|
|
||||||
this instanceof AssignableRead and
|
|
||||||
pa = this
|
|
||||||
}
|
|
||||||
|
|
||||||
override Getter getTarget() { result = pa.getProperty().getGetter() }
|
|
||||||
|
|
||||||
override Expr getArgument(int i) { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
class PropertySetterCall extends PropertyCallImpl {
|
|
||||||
PropertySetterCall() {
|
|
||||||
exists(AssignableDefinition def | pa = def.getTargetAccess() |
|
|
||||||
(if multiTupleSetter(def.getExpr()) then this = pa else this = def.getExpr()) and
|
|
||||||
not def.getExpr().(AssignOperation).hasExpandedAssignment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override Expr getArgument(int i) {
|
|
||||||
i = 0 and
|
|
||||||
result = AssignableInternal::getAccessorCallValueArgument(pa)
|
|
||||||
}
|
|
||||||
|
|
||||||
override Setter getTarget() { result = pa.getProperty().getSetter() }
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class IndexerCallImpl extends AccessorCallImpl {
|
|
||||||
IndexerAccess ia;
|
|
||||||
|
|
||||||
override IndexerAccess getAccess() { result = ia }
|
|
||||||
|
|
||||||
abstract override Accessor getTarget();
|
|
||||||
|
|
||||||
abstract override Expr getArgument(int i);
|
|
||||||
}
|
|
||||||
|
|
||||||
class IndexerGetterCall extends IndexerCallImpl, @indexer_access_expr {
|
|
||||||
IndexerGetterCall() {
|
|
||||||
this instanceof AssignableRead and
|
|
||||||
ia = this
|
|
||||||
}
|
|
||||||
|
|
||||||
override Getter getTarget() { result = ia.getIndexer().getGetter() }
|
|
||||||
|
|
||||||
override Expr getArgument(int i) { result = ia.getIndex(i) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class IndexerSetterCall extends IndexerCallImpl {
|
|
||||||
IndexerSetterCall() {
|
|
||||||
exists(AssignableDefinition def | ia = def.getTargetAccess() |
|
|
||||||
(if multiTupleSetter(def.getExpr()) then this = ia else this = def.getExpr()) and
|
|
||||||
not def.getExpr().(AssignOperation).hasExpandedAssignment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override Setter getTarget() { result = ia.getIndexer().getSetter() }
|
|
||||||
|
|
||||||
override Expr getArgument(int i) {
|
|
||||||
result = ia.getIndex(i)
|
|
||||||
or
|
|
||||||
i = count(ia.getAnIndex()) and
|
|
||||||
result = AssignableInternal::getAccessorCallValueArgument(ia)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class EventCallImpl extends AccessorCallImpl, @assign_event_expr {
|
|
||||||
override EventAccess getAccess() { result = this.(AddOrRemoveEventExpr).getLValue() }
|
|
||||||
|
|
||||||
override EventAccessor getTarget() {
|
|
||||||
exists(Event e | e = this.getAccess().getEvent() |
|
|
||||||
this instanceof AddEventExpr and result = e.getAddEventAccessor()
|
|
||||||
or
|
|
||||||
this instanceof RemoveEventExpr and result = e.getRemoveEventAccessor()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override Expr getArgument(int i) {
|
|
||||||
i = 0 and
|
|
||||||
result = this.(AddOrRemoveEventExpr).getRValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A call to an accessor. Either a property accessor call (`PropertyCall`),
|
* A call to an accessor. Either a property accessor call (`PropertyCall`),
|
||||||
* an indexer accessor call (`IndexerCall`), or an event accessor call
|
* an indexer accessor call (`IndexerCall`), or an event accessor call
|
||||||
* (`EventCall`).
|
* (`EventCall`).
|
||||||
*/
|
*/
|
||||||
class AccessorCall extends Call {
|
class AccessorCall extends Call, QualifiableExpr, @call_access_expr {
|
||||||
private AccessorCallImpl::AccessorCallImpl impl;
|
override Accessor getTarget() { none() }
|
||||||
|
|
||||||
AccessorCall() { this = impl }
|
override Expr getArgument(int i) { none() }
|
||||||
|
|
||||||
/** Gets the underlying access. */
|
|
||||||
MemberAccess getAccess() { result = impl.getAccess() }
|
|
||||||
|
|
||||||
override Accessor getTarget() { result = impl.getTarget() }
|
|
||||||
|
|
||||||
override Expr getArgument(int i) { result = impl.getArgument(i) }
|
|
||||||
|
|
||||||
override string toString() { none() } // avoid multiple `toString()`s
|
|
||||||
|
|
||||||
override Accessor getARuntimeTarget() { result = Call.super.getARuntimeTarget() }
|
override Accessor getARuntimeTarget() { result = Call.super.getARuntimeTarget() }
|
||||||
}
|
}
|
||||||
@@ -736,15 +581,21 @@ class AccessorCall extends Call {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class PropertyCall extends AccessorCall {
|
class PropertyCall extends AccessorCall, PropertyAccessExpr {
|
||||||
private AccessorCallImpl::PropertyCallImpl impl;
|
override Accessor getTarget() {
|
||||||
|
exists(PropertyAccess pa, Property p | pa = this and p = getProperty() |
|
||||||
|
pa instanceof AssignableRead and result = p.getGetter()
|
||||||
|
or
|
||||||
|
pa instanceof AssignableWrite and result = p.getSetter()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
PropertyCall() { this = impl }
|
override Expr getArgument(int i) {
|
||||||
|
i = 0 and
|
||||||
|
result = AssignableInternal::getAccessorCallValueArgument(this)
|
||||||
|
}
|
||||||
|
|
||||||
override PropertyAccess getAccess() { result = impl.getAccess() }
|
override string toString() { result = PropertyAccessExpr.super.toString() }
|
||||||
|
|
||||||
/** Gets property targeted by this property call. */
|
|
||||||
Property getProperty() { result = this.getAccess().getTarget() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -763,15 +614,23 @@ class PropertyCall extends AccessorCall {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class IndexerCall extends AccessorCall {
|
class IndexerCall extends AccessorCall, IndexerAccessExpr {
|
||||||
private AccessorCallImpl::IndexerCallImpl impl;
|
override Accessor getTarget() {
|
||||||
|
exists(IndexerAccess ia, Indexer i | ia = this and i = getIndexer() |
|
||||||
|
ia instanceof AssignableRead and result = i.getGetter()
|
||||||
|
or
|
||||||
|
ia instanceof AssignableWrite and result = i.getSetter()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
IndexerCall() { this = impl }
|
override Expr getArgument(int i) {
|
||||||
|
result = this.(ElementAccess).getIndex(i)
|
||||||
|
or
|
||||||
|
i = count(this.(ElementAccess).getAnIndex()) and
|
||||||
|
result = AssignableInternal::getAccessorCallValueArgument(this)
|
||||||
|
}
|
||||||
|
|
||||||
override IndexerAccess getAccess() { result = impl.getAccess() }
|
override string toString() { result = IndexerAccessExpr.super.toString() }
|
||||||
|
|
||||||
/** Gets indexer targeted by this index call. */
|
|
||||||
Indexer getIndexer() { result = this.getAccess().getTarget() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -795,15 +654,27 @@ class IndexerCall extends AccessorCall {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class EventCall extends AccessorCall, @assign_event_expr {
|
class EventCall extends AccessorCall, EventAccessExpr {
|
||||||
private AccessorCallImpl::EventCallImpl impl;
|
override EventAccessor getTarget() {
|
||||||
|
exists(Event e, AddOrRemoveEventExpr aoree |
|
||||||
|
e = getEvent() and
|
||||||
|
aoree.getLValue() = this
|
||||||
|
|
|
||||||
|
aoree instanceof AddEventExpr and result = e.getAddEventAccessor()
|
||||||
|
or
|
||||||
|
aoree instanceof RemoveEventExpr and result = e.getRemoveEventAccessor()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
EventCall() { this = impl }
|
override Expr getArgument(int i) {
|
||||||
|
i = 0 and
|
||||||
|
exists(AddOrRemoveEventExpr aoree |
|
||||||
|
aoree.getLValue() = this and
|
||||||
|
result = aoree.getRValue()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override EventAccess getAccess() { result = impl.getAccess() }
|
override string toString() { result = EventAccessExpr.super.toString() }
|
||||||
|
|
||||||
/** Gets event targeted by this event call. */
|
|
||||||
Event getEvent() { result = this.getAccess().getTarget() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ class XmlReaderSettingsCreation extends ObjectCreation {
|
|||||||
p = this.getType().(RefType).getAProperty() and
|
p = this.getType().(RefType).getAProperty() and
|
||||||
exists(PropertyCall set, Expr arg |
|
exists(PropertyCall set, Expr arg |
|
||||||
set.getTarget() = p.getSetter() and
|
set.getTarget() = p.getSetter() and
|
||||||
DataFlow::localFlow(DataFlow::exprNode(this), DataFlow::exprNode(set.getAccess().getQualifier())) and
|
DataFlow::localFlow(DataFlow::exprNode(this), DataFlow::exprNode(set.getQualifier())) and
|
||||||
arg = set.getAnArgument() and
|
arg = set.getAnArgument() and
|
||||||
result = getBitwiseOrOperand*(arg)
|
result = getBitwiseOrOperand*(arg)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ class PrivateVariableAccess extends PrivateDataExpr, VariableAccess {
|
|||||||
/** Reading the text property of a control that might contain private data. */
|
/** Reading the text property of a control that might contain private data. */
|
||||||
class PrivateControlAccess extends PrivateDataExpr {
|
class PrivateControlAccess extends PrivateDataExpr {
|
||||||
PrivateControlAccess() {
|
PrivateControlAccess() {
|
||||||
exists(TextControl c | this = c.getARead() and c.getName().toLowerCase().matches(privateNames()))
|
exists(TextControl c |
|
||||||
|
this = c.getARead() and c.getName().toLowerCase().matches(privateNames())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class NamedElement extends Element, @dotnet_named_element {
|
|||||||
predicate compiledFromSource() {
|
predicate compiledFromSource() {
|
||||||
not this.fromSource() and
|
not this.fromSource() and
|
||||||
exists(NamedElement other | other != this |
|
exists(NamedElement other | other != this |
|
||||||
other.getLabel() = this.getLabel() and
|
this.matchesHandle(other) and
|
||||||
other.fromSource()
|
other.fromSource()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
import Expr
|
import Expr
|
||||||
import Type
|
import Type
|
||||||
import Callable
|
import Callable
|
||||||
private import csharp as CS
|
|
||||||
|
|
||||||
/** An expression. */
|
/** An expression. */
|
||||||
class Expr extends Element, @dotnet_expr {
|
class Expr extends Element, @dotnet_expr {
|
||||||
@@ -26,9 +25,7 @@ class Expr extends Element, @dotnet_expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A call. */
|
/** A call. */
|
||||||
class Call extends Expr {
|
class Call extends Expr, @dotnet_call {
|
||||||
Call() { this instanceof @cil_call_any or this instanceof CS::CallImpl }
|
|
||||||
|
|
||||||
/** Gets the target of this call. */
|
/** Gets the target of this call. */
|
||||||
Callable getTarget() { none() }
|
Callable getTarget() { none() }
|
||||||
|
|
||||||
|
|||||||
@@ -17,23 +17,21 @@
|
|||||||
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | o |
|
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | o |
|
||||||
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:18:40:35 | array creation of type Int32[] | args |
|
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:18:40:35 | array creation of type Int32[] | args |
|
||||||
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:41:40:41 | 0 | o |
|
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:41:40:41 | 0 | o |
|
||||||
| arguments.cs:54:9:54:16 | ... = ... | arguments.cs:54:16:54:16 | 0 | value |
|
| arguments.cs:54:9:54:12 | access to property Prop | arguments.cs:54:16:54:16 | 0 | value |
|
||||||
| arguments.cs:55:9:55:25 | ... = ... | arguments.cs:55:16:55:25 | access to indexer | value |
|
| arguments.cs:55:9:55:12 | access to property Prop | arguments.cs:55:16:55:25 | access to indexer | value |
|
||||||
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:21:55:21 | 1 | a |
|
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:21:55:21 | 1 | a |
|
||||||
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:24:55:24 | 2 | b |
|
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:24:55:24 | 2 | b |
|
||||||
| arguments.cs:56:10:56:13 | access to property Prop | arguments.cs:56:31:56:31 | 5 | value |
|
| arguments.cs:56:10:56:13 | access to property Prop | arguments.cs:56:31:56:31 | 5 | value |
|
||||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:21:56:21 | 3 | a |
|
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:21:56:21 | 3 | a |
|
||||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:24:56:24 | 4 | b |
|
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:24:56:24 | 4 | b |
|
||||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:34:56:34 | 6 | value |
|
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:34:56:34 | 6 | value |
|
||||||
| arguments.cs:58:9:58:17 | ... = ... | arguments.cs:58:9:58:17 | ... + ... | value |
|
| arguments.cs:58:9:58:12 | access to property Prop | arguments.cs:58:9:58:17 | ... + ... | value |
|
||||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | a |
|
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | a |
|
||||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | b |
|
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | b |
|
||||||
| arguments.cs:59:9:59:20 | ...++ | arguments.cs:59:14:59:14 | 8 | a |
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:9:60:26 | ... + ... | value |
|
||||||
| arguments.cs:59:9:59:20 | ...++ | arguments.cs:59:17:59:17 | 9 | b |
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | a |
|
||||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | a |
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | a |
|
||||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | b |
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | b |
|
||||||
| arguments.cs:60:9:60:26 | ... = ... | arguments.cs:60:9:60:26 | ... + ... | value |
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | b |
|
||||||
| arguments.cs:60:9:60:26 | ... = ... | arguments.cs:60:14:60:15 | 10 | a |
|
|
||||||
| arguments.cs:60:9:60:26 | ... = ... | arguments.cs:60:18:60:19 | 11 | b |
|
|
||||||
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:21:62:22 | 15 | a |
|
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:21:62:22 | 15 | a |
|
||||||
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:25:62:26 | 16 | b |
|
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:25:62:26 | 16 | b |
|
||||||
|
|||||||
@@ -17,23 +17,23 @@
|
|||||||
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | arguments.cs:33:17:33:17 | o |
|
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | arguments.cs:33:17:33:17 | o |
|
||||||
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:18:40:35 | array creation of type Int32[] | arguments.cs:33:33:33:36 | args |
|
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:18:40:35 | array creation of type Int32[] | arguments.cs:33:33:33:36 | args |
|
||||||
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:41:40:41 | 0 | arguments.cs:33:17:33:17 | o |
|
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:41:40:41 | 0 | arguments.cs:33:17:33:17 | o |
|
||||||
| arguments.cs:54:9:54:16 | ... = ... | arguments.cs:54:16:54:16 | 0 | arguments.cs:48:21:48:23 | value |
|
| arguments.cs:54:9:54:12 | access to property Prop | arguments.cs:54:16:54:16 | 0 | arguments.cs:48:21:48:23 | value |
|
||||||
| arguments.cs:55:9:55:25 | ... = ... | arguments.cs:55:16:55:25 | access to indexer | arguments.cs:48:21:48:23 | value |
|
| arguments.cs:55:9:55:12 | access to property Prop | arguments.cs:55:16:55:25 | access to indexer | arguments.cs:48:21:48:23 | value |
|
||||||
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:21:55:21 | 1 | arguments.cs:50:18:50:18 | a |
|
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:21:55:21 | 1 | arguments.cs:50:18:50:18 | a |
|
||||||
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:24:55:24 | 2 | arguments.cs:50:25:50:25 | b |
|
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:24:55:24 | 2 | arguments.cs:50:25:50:25 | b |
|
||||||
| arguments.cs:56:10:56:13 | access to property Prop | arguments.cs:56:31:56:31 | 5 | arguments.cs:48:21:48:23 | value |
|
| arguments.cs:56:10:56:13 | access to property Prop | arguments.cs:56:31:56:31 | 5 | arguments.cs:48:21:48:23 | value |
|
||||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:21:56:21 | 3 | arguments.cs:50:18:50:18 | a |
|
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:21:56:21 | 3 | arguments.cs:50:18:50:18 | a |
|
||||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:24:56:24 | 4 | arguments.cs:50:25:50:25 | b |
|
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:24:56:24 | 4 | arguments.cs:50:25:50:25 | b |
|
||||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:34:56:34 | 6 | arguments.cs:50:44:50:46 | value |
|
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:34:56:34 | 6 | arguments.cs:50:44:50:46 | value |
|
||||||
| arguments.cs:58:9:58:17 | ... = ... | arguments.cs:58:9:58:17 | ... + ... | arguments.cs:48:21:48:23 | value |
|
| arguments.cs:58:9:58:12 | access to property Prop | arguments.cs:58:9:58:17 | ... + ... | arguments.cs:48:21:48:23 | value |
|
||||||
|
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | arguments.cs:50:18:50:18 | a |
|
||||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | arguments.cs:50:18:50:18 | a |
|
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | arguments.cs:50:18:50:18 | a |
|
||||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | arguments.cs:50:25:50:25 | b |
|
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | arguments.cs:50:25:50:25 | b |
|
||||||
| arguments.cs:59:9:59:20 | ...++ | arguments.cs:59:14:59:14 | 8 | arguments.cs:50:18:50:18 | a |
|
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | arguments.cs:50:25:50:25 | b |
|
||||||
| arguments.cs:59:9:59:20 | ...++ | arguments.cs:59:17:59:17 | 9 | arguments.cs:50:25:50:25 | b |
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:9:60:26 | ... + ... | arguments.cs:50:44:50:46 | value |
|
||||||
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | arguments.cs:50:18:50:18 | a |
|
||||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | arguments.cs:50:18:50:18 | a |
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | arguments.cs:50:18:50:18 | a |
|
||||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | arguments.cs:50:25:50:25 | b |
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | arguments.cs:50:25:50:25 | b |
|
||||||
| arguments.cs:60:9:60:26 | ... = ... | arguments.cs:60:9:60:26 | ... + ... | arguments.cs:50:44:50:46 | value |
|
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | arguments.cs:50:25:50:25 | b |
|
||||||
| arguments.cs:60:9:60:26 | ... = ... | arguments.cs:60:14:60:15 | 10 | arguments.cs:50:18:50:18 | a |
|
|
||||||
| arguments.cs:60:9:60:26 | ... = ... | arguments.cs:60:18:60:19 | 11 | arguments.cs:50:25:50:25 | b |
|
|
||||||
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:21:62:22 | 15 | arguments.cs:50:18:50:18 | a |
|
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:21:62:22 | 15 | arguments.cs:50:18:50:18 | a |
|
||||||
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:25:62:26 | 16 | arguments.cs:50:25:50:25 | b |
|
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:25:62:26 | 16 | arguments.cs:50:25:50:25 | b |
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
nonUniqueSetRepresentation
|
||||||
|
breakInvariant2
|
||||||
|
breakInvariant3
|
||||||
|
breakInvariant4
|
||||||
|
breakInvariant5
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import csharp
|
||||||
|
import semmle.code.csharp.controlflow.Completion
|
||||||
|
import ControlFlow
|
||||||
|
import ControlFlow::Internal
|
||||||
|
|
||||||
|
query predicate nonUniqueSetRepresentation(Splits s1, Splits s2) {
|
||||||
|
forex(Nodes::Split s | s = s1.getASplit() | s = s2.getASplit()) and
|
||||||
|
forex(Nodes::Split s | s = s2.getASplit() | s = s1.getASplit()) and
|
||||||
|
s1 != s2
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate breakInvariant2(
|
||||||
|
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||||
|
SplitInternal split, Completion c
|
||||||
|
) {
|
||||||
|
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||||
|
split = predSplits.getASplit() and
|
||||||
|
split.hasSuccessor(pred, succ, c) and
|
||||||
|
not split = succSplits.getASplit()
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate breakInvariant3(
|
||||||
|
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||||
|
SplitInternal split, Completion c
|
||||||
|
) {
|
||||||
|
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||||
|
split = predSplits.getASplit() and
|
||||||
|
split.hasExit(pred, succ, c) and
|
||||||
|
split = succSplits.getASplit()
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate breakInvariant4(
|
||||||
|
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||||
|
SplitInternal split, Completion c
|
||||||
|
) {
|
||||||
|
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||||
|
split.hasEntry(pred, succ, c) and
|
||||||
|
not split = predSplits.getASplit() and
|
||||||
|
not split = succSplits.getASplit()
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate breakInvariant5(
|
||||||
|
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||||
|
SplitInternal split, Completion c
|
||||||
|
) {
|
||||||
|
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||||
|
split = succSplits.getASplit() and
|
||||||
|
not (split.hasSuccessor(pred, succ, c) and split = predSplits.getASplit()) and
|
||||||
|
not (split.hasEntry(pred, succ, c) and not split = predSplits.getASplit())
|
||||||
|
}
|
||||||
@@ -68,6 +68,8 @@
|
|||||||
| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false |
|
| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false |
|
||||||
| Guards.cs:205:13:205:13 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true |
|
| Guards.cs:205:13:205:13 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true |
|
||||||
| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true |
|
| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true |
|
||||||
|
| Guards.cs:269:11:269:12 | access to parameter o1 | Guards.cs:268:13:268:41 | call to operator == | Guards.cs:268:13:268:14 | access to parameter o1 | true |
|
||||||
|
| Guards.cs:271:11:271:12 | access to parameter o1 | Guards.cs:270:13:270:42 | call to operator == | Guards.cs:270:13:270:14 | access to parameter o1 | true |
|
||||||
| Splitting.cs:13:17:13:17 | access to parameter o | Splitting.cs:12:17:12:25 | ... != ... | Splitting.cs:12:17:12:17 | access to parameter o | true |
|
| Splitting.cs:13:17:13:17 | access to parameter o | Splitting.cs:12:17:12:25 | ... != ... | Splitting.cs:12:17:12:17 | access to parameter o | true |
|
||||||
| Splitting.cs:23:24:23:24 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | true |
|
| Splitting.cs:23:24:23:24 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | true |
|
||||||
| Splitting.cs:25:13:25:13 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | false |
|
| Splitting.cs:25:13:25:13 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | false |
|
||||||
|
|||||||
@@ -164,6 +164,10 @@
|
|||||||
| Guards.cs:205:13:205:13 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true |
|
| Guards.cs:205:13:205:13 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true |
|
||||||
| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | non-null |
|
| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | non-null |
|
||||||
| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true |
|
| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true |
|
||||||
|
| Guards.cs:269:11:269:12 | access to parameter o1 | Guards.cs:268:13:268:14 | access to parameter o1 | Guards.cs:268:13:268:14 | access to parameter o1 | non-null |
|
||||||
|
| Guards.cs:269:11:269:12 | access to parameter o1 | Guards.cs:268:13:268:41 | call to operator == | Guards.cs:268:13:268:14 | access to parameter o1 | true |
|
||||||
|
| Guards.cs:269:11:269:12 | access to parameter o1 | Guards.cs:268:16:268:25 | call to method GetType | Guards.cs:268:13:268:14 | access to parameter o1 | non-null |
|
||||||
|
| Guards.cs:271:11:271:12 | access to parameter o1 | Guards.cs:270:13:270:42 | call to operator == | Guards.cs:270:13:270:14 | access to parameter o1 | true |
|
||||||
| Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | non-null |
|
| Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | non-null |
|
||||||
| Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:25 | ... != ... | Splitting.cs:12:17:12:17 | access to parameter o | true |
|
| Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:25 | ... != ... | Splitting.cs:12:17:12:17 | access to parameter o | true |
|
||||||
| Splitting.cs:14:13:14:13 | [b (line 9): false] access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | false |
|
| Splitting.cs:14:13:14:13 | [b (line 9): false] access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | false |
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user