Merge branch 'master' into js/vue-support-1

This commit is contained in:
Esben Sparre Andreasen
2019-02-06 16:57:16 +01:00
committed by GitHub
474 changed files with 77341 additions and 76917 deletions

View File

@@ -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()`.

View File

@@ -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

View File

@@ -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.

View File

@@ -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. |

View File

@@ -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)

View File

@@ -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
... ...
} }

View File

@@ -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()

View File

@@ -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

View File

@@ -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."
} }

View File

@@ -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, _, _)

View File

@@ -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"

View File

@@ -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,

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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.
*/ */

View File

@@ -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()
) )
} }

View File

@@ -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

View File

@@ -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)) }

View File

@@ -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.
*/ */

View File

@@ -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, _)
} }

View File

@@ -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() {

View File

@@ -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
} }
} }

View File

@@ -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

View File

@@ -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"
) )
} }

View File

@@ -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.
*/ */

View File

@@ -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, _)
} }

View File

@@ -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() {

View File

@@ -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
} }
} }

View File

@@ -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

View File

@@ -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))
} }
} }

View File

@@ -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.

View File

@@ -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() {

View File

@@ -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

View File

@@ -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, _)
} }
/** /**

View File

@@ -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())
} }
} }

View File

@@ -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()

View File

@@ -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())
} }

View File

@@ -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.
*/ */

View File

@@ -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, _)
} }

View File

@@ -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() {

View File

@@ -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
} }
} }

View File

@@ -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

View File

@@ -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"
) )
} }

View 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)
}

View File

@@ -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)
)
) )
} }

View File

@@ -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 }
}

View 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 : &param;
constexpr int *ternary_false = !int_const ? &param : &int_var;
constexpr int *ternary_overflow = (unsigned char)256 ? &param : &int_var;
constexpr int *ternary_ptr_cond = (&int_arr+1) ? &int_var : &param;;
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 ? &param : &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;
}

View 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

View File

@@ -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 ...

View File

@@ -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

View File

@@ -8,3 +8,6 @@ unexplainedLoop
unnecessaryPhiInstruction unnecessaryPhiInstruction
operandAcrossFunctions operandAcrossFunctions
instructionWithoutUniqueBlock instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch

View File

@@ -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

View File

@@ -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

View File

@@ -8,3 +8,6 @@ unexplainedLoop
unnecessaryPhiInstruction unnecessaryPhiInstruction
operandAcrossFunctions operandAcrossFunctions
instructionWithoutUniqueBlock instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch

View File

@@ -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 |

View File

@@ -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

View File

@@ -8,3 +8,6 @@ unexplainedLoop
unnecessaryPhiInstruction unnecessaryPhiInstruction
operandAcrossFunctions operandAcrossFunctions
instructionWithoutUniqueBlock instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch

View File

@@ -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;
} }

View File

@@ -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 |

View File

@@ -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;
}

View File

@@ -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 :

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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
}

View File

@@ -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;

View File

@@ -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);
} }

View File

@@ -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);

View File

@@ -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"

View File

@@ -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

View File

@@ -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'."

View File

@@ -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

View File

@@ -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) }

View File

@@ -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

View File

@@ -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) {

View File

@@ -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

View File

@@ -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()
)
) )
} }
} }

View File

@@ -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() }

View File

@@ -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

View File

@@ -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. */

View File

@@ -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))
) )
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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) |

View File

@@ -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() }

View File

@@ -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() }
} }
/** /**

View File

@@ -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() }
} }
/** /**

View File

@@ -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)
) )

View File

@@ -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())
)
} }
} }

View File

@@ -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()
) )
} }

View File

@@ -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() }

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -0,0 +1,5 @@
nonUniqueSetRepresentation
breakInvariant2
breakInvariant3
breakInvariant4
breakInvariant5

View File

@@ -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())
}

View File

@@ -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 |

View File

@@ -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