mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge branch 'master' into js/vue-support-1
This commit is contained in:
@@ -26,4 +26,5 @@
|
||||
|
||||
## Changes to QL libraries
|
||||
|
||||
There is a new `Namespace.isInline()` predicate, which holds if the namespace was declared as `inline namespace`.
|
||||
* There is a new `Namespace.isInline()` predicate, which holds if the namespace was declared as `inline namespace`.
|
||||
* The `Expr.isConstant()` predicate now also holds for _address constant expressions_, which are addresses that will be constant after the program has been linked. These address constants do not have a result for `Expr.getValue()`.
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
| 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`. |
|
||||
| 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
|
||||
|
||||
@@ -24,6 +26,4 @@
|
||||
|
||||
## 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
|
||||
|
||||
@@ -24,5 +24,8 @@
|
||||
`semmle.code.java.dataflow.DataFlow`,
|
||||
`semmle.code.java.dataflow.TaintTracking`, and
|
||||
`semmle.code.java.dataflow.FlowSources` since 1.16.
|
||||
* Taint tracking now includes additional default data-flow steps through
|
||||
collections, maps, and iterators. This affects all security queries, which
|
||||
can report more results based on such paths.
|
||||
|
||||
|
||||
|
||||
@@ -10,11 +10,16 @@
|
||||
|
||||
* The taint tracking library now recognizes flow through persistent storage, class fields, and callbacks in certain cases. This may give more results for the security queries.
|
||||
|
||||
* 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
|
||||
|
||||
| **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.|
|
||||
| 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. |
|
||||
| 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. |
|
||||
@@ -28,6 +33,7 @@
|
||||
| **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. |
|
||||
| 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`. |
|
||||
| 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. |
|
||||
|
||||
@@ -64,7 +64,7 @@ class SuppressionScope extends ElementBase {
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* 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) {
|
||||
this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn)
|
||||
|
||||
@@ -8,6 +8,6 @@ int doFoo(Names n) { //wrong: n is passed by value (meaning the entire structure
|
||||
...
|
||||
}
|
||||
|
||||
int doBar(Names &n) { //better, only a reference is passed
|
||||
int doBar(const Names &n) { //better, only a reference is passed
|
||||
...
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @name Large object passed by value
|
||||
* @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
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
@@ -20,5 +20,5 @@ where f.getAParameter() = p
|
||||
and not t.getUnderlyingType() instanceof ArrayType
|
||||
and not f instanceof CopyAssignmentOperator
|
||||
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()
|
||||
|
||||
@@ -127,7 +127,7 @@ class CommentBlock extends Comment {
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* 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) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
||||
|
||||
@@ -43,7 +43,7 @@ string comparisonOnLiterals(ComparisonOperation op) {
|
||||
simple(op.getLeftOperand()) and
|
||||
simple(op.getRightOperand()) 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() + "."
|
||||
else result = "This comparison involves two literals and should be simplified."
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ class RangeFunction extends Function {
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* 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) {
|
||||
super.getLocation().hasLocationInfo(path, sl, sc, _, _)
|
||||
|
||||
@@ -16,18 +16,18 @@ import semmle.code.cpp.security.Overflow
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
|
||||
predicate taintedVarAccess(Expr origin, VariableAccess va) {
|
||||
isUserInput(origin, _) and
|
||||
tainted(origin, va)
|
||||
}
|
||||
|
||||
from Expr origin, Operation op, VariableAccess va, string effect
|
||||
where taintedVarAccess(origin, va)
|
||||
and op.getAnOperand() = va
|
||||
from Expr origin, Operation op, Expr e, string effect
|
||||
where isUserInput(origin, _)
|
||||
and tainted(origin, e)
|
||||
and op.getAnOperand() = e
|
||||
and
|
||||
(
|
||||
(missingGuardAgainstUnderflow(op, va) and effect = "underflow") or
|
||||
(missingGuardAgainstOverflow(op, va) and effect = "overflow")
|
||||
(missingGuardAgainstUnderflow(op, e) and effect = "underflow") or
|
||||
(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"
|
||||
|
||||
@@ -23,7 +23,7 @@ class Top extends Element {
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* 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,
|
||||
|
||||
@@ -34,7 +34,7 @@ abstract class Container extends Locatable, @container {
|
||||
* DEPRECATED: Use `getLocation` instead.
|
||||
* 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();
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class Location extends @location {
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* 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) {
|
||||
|
||||
@@ -195,7 +195,7 @@ class BasicBlock extends ControlFlowNodeBase {
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -461,38 +461,16 @@ private predicate skipInitializer(Initializer init) {
|
||||
*/
|
||||
private predicate runtimeExprInStaticInitializer(Expr e) {
|
||||
inStaticInitializer(e) and
|
||||
if
|
||||
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")
|
||||
if e instanceof AggregateLiteral
|
||||
then runtimeExprInStaticInitializer(e.getAChild())
|
||||
else (
|
||||
// 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()
|
||||
)
|
||||
)
|
||||
else not e.getFullyConverted().isConstant()
|
||||
}
|
||||
|
||||
/** Holds if `e` is part of the initializer of a local static variable. */
|
||||
private predicate inStaticInitializer(Expr e) {
|
||||
exists(LocalVariable local |
|
||||
local.isStatic() and
|
||||
e.(Node).getParentNode*() = local.getInitializer()
|
||||
e.getParent+() = local.getInitializer()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import semmle.code.cpp.Element
|
||||
private import semmle.code.cpp.Enclosing
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
private import semmle.code.cpp.internal.AddressConstantExpression
|
||||
|
||||
/**
|
||||
* 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))) }
|
||||
|
||||
/** 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
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.dataflow.EscapesTree
|
||||
|
||||
predicate addressConstantExpression(Expr e) {
|
||||
constantAddressPointer(e)
|
||||
or
|
||||
constantAddressReference(e)
|
||||
or
|
||||
// Special case for function pointers, where `fp == *fp`.
|
||||
constantAddressLValue(e) and
|
||||
e.getType() instanceof FunctionPointerType
|
||||
}
|
||||
|
||||
/** Holds if `v` is a constexpr variable initialized to a constant address. */
|
||||
private predicate addressConstantVariable(Variable v) {
|
||||
addressConstantExpression(v.getInitializer().getExpr().getFullyConverted()) and
|
||||
// Here we should also require that `v` is constexpr, but we don't have that
|
||||
// information in the db. See CPP-314. Instead, we require that the variable
|
||||
// is never defined except in its initializer.
|
||||
forall(Expr def | definition(v, def) | def = any(Initializer init).getExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `lvalue` is an lvalue whose address is an _address constant
|
||||
* expression_.
|
||||
*/
|
||||
private predicate constantAddressLValue(Expr lvalue) {
|
||||
lvalue.(VariableAccess).getTarget() = any(Variable v |
|
||||
v.(Variable).isStatic()
|
||||
or
|
||||
v instanceof GlobalOrNamespaceVariable
|
||||
)
|
||||
or
|
||||
// There is no `Conversion` for the implicit conversion from a function type
|
||||
// to a function _pointer_ type. Instead, the type of a `FunctionAccess`
|
||||
// tells us how it's going to be used.
|
||||
lvalue.(FunctionAccess).getType() instanceof RoutineType
|
||||
or
|
||||
// String literals have array types and undergo array-to-pointer conversion.
|
||||
lvalue instanceof StringLiteral
|
||||
or
|
||||
// lvalue -> lvalue
|
||||
exists(Expr prev |
|
||||
constantAddressLValue(prev) and
|
||||
lvalueToLvalueStep(prev, lvalue)
|
||||
)
|
||||
or
|
||||
// pointer -> lvalue
|
||||
exists(Expr prev |
|
||||
constantAddressPointer(prev) and
|
||||
pointerToLvalueStep(prev, lvalue)
|
||||
)
|
||||
or
|
||||
// reference -> lvalue
|
||||
exists(Expr prev |
|
||||
constantAddressReference(prev) and
|
||||
referenceToLvalueStep(prev, lvalue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `pointer` is an _address constant expression_ of pointer type. */
|
||||
private predicate constantAddressPointer(Expr pointer) {
|
||||
// There is no `Conversion` for the implicit conversion from a function type
|
||||
// to a function _pointer_ type. Instead, the type of a `FunctionAccess`
|
||||
// tells us how it's going to be used.
|
||||
pointer.(FunctionAccess).getType() instanceof FunctionPointerType
|
||||
or
|
||||
addressConstantVariable(pointer.(VariableAccess).getTarget()) and
|
||||
pointer.getType().getUnderlyingType() instanceof PointerType
|
||||
or
|
||||
// pointer -> pointer
|
||||
exists(Expr prev |
|
||||
constantAddressPointer(prev) and
|
||||
pointerToPointerStep(prev, pointer)
|
||||
)
|
||||
or
|
||||
// lvalue -> pointer
|
||||
exists(Expr prev |
|
||||
constantAddressLValue(prev) and
|
||||
lvalueToPointerStep(prev, pointer)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `reference` is an _address constant expression_ of reference type. */
|
||||
private predicate constantAddressReference(Expr reference) {
|
||||
addressConstantVariable(reference.(VariableAccess).getTarget()) and
|
||||
reference.getType().getUnderlyingType() instanceof ReferenceType
|
||||
or
|
||||
addressConstantVariable(reference.(VariableAccess).getTarget()) and
|
||||
reference.getType().getUnderlyingType() instanceof FunctionReferenceType // not a ReferenceType
|
||||
or
|
||||
// reference -> reference
|
||||
exists(Expr prev |
|
||||
constantAddressReference(prev) and
|
||||
referenceToReferenceStep(prev, reference)
|
||||
)
|
||||
or
|
||||
// lvalue -> reference
|
||||
exists(Expr prev |
|
||||
constantAddressLValue(prev) and
|
||||
lvalueToReferenceStep(prev, reference)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
|
||||
lvalueIn = lvalueOut.(DotFieldAccess).getQualifier().getFullyConverted()
|
||||
or
|
||||
lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr)
|
||||
or
|
||||
// Special case for function pointers, where `fp == *fp`.
|
||||
lvalueIn = lvalueOut.(PointerDereferenceExpr).getOperand().getFullyConverted() and
|
||||
lvalueIn.getType() instanceof FunctionPointerType
|
||||
}
|
||||
|
||||
private predicate pointerToLvalueStep(Expr pointerIn, Expr lvalueOut) {
|
||||
lvalueOut = any(ArrayExpr ae |
|
||||
pointerIn = ae.getArrayBase().getFullyConverted() and
|
||||
hasConstantValue(ae.getArrayOffset().getFullyConverted())
|
||||
)
|
||||
or
|
||||
pointerIn = lvalueOut.(PointerDereferenceExpr).getOperand().getFullyConverted()
|
||||
or
|
||||
pointerIn = lvalueOut.(PointerFieldAccess).getQualifier().getFullyConverted()
|
||||
}
|
||||
|
||||
private predicate lvalueToPointerStep(Expr lvalueIn, Expr pointerOut) {
|
||||
lvalueIn.getConversion() = pointerOut.(ArrayToPointerConversion)
|
||||
or
|
||||
lvalueIn = pointerOut.(AddressOfExpr).getOperand().getFullyConverted()
|
||||
}
|
||||
|
||||
private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) {
|
||||
(
|
||||
pointerOut instanceof PointerAddExpr
|
||||
or
|
||||
pointerOut instanceof PointerSubExpr
|
||||
) and
|
||||
pointerIn = pointerOut.getAChild().getFullyConverted() and
|
||||
pointerIn.getType().getUnspecifiedType() instanceof PointerType and
|
||||
// The pointer arg won't be constant in the sense of `hasConstantValue`, so
|
||||
// this will have to match the integer argument.
|
||||
hasConstantValue(pointerOut.getAChild().getFullyConverted())
|
||||
or
|
||||
pointerIn = pointerOut.(UnaryPlusExpr).getOperand().getFullyConverted()
|
||||
or
|
||||
pointerIn.getConversion() = pointerOut.(Cast)
|
||||
or
|
||||
pointerIn.getConversion() = pointerOut.(ParenthesisExpr)
|
||||
or
|
||||
pointerOut = any(ConditionalExpr cond |
|
||||
cond.getCondition().getFullyConverted().getValue().toInt() != 0 and
|
||||
pointerIn = cond.getThen().getFullyConverted()
|
||||
or
|
||||
cond.getCondition().getFullyConverted().getValue().toInt() = 0 and
|
||||
pointerIn = cond.getElse().getFullyConverted()
|
||||
)
|
||||
or
|
||||
// The comma operator is allowed by C++17 but disallowed by C99. This
|
||||
// disjunct is a compromise that's chosen for being easy to implement.
|
||||
pointerOut = any(CommaExpr comma |
|
||||
hasConstantValue(comma.getLeftOperand()) and
|
||||
pointerIn = comma.getRightOperand().getFullyConverted()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) {
|
||||
lvalueIn.getConversion() = referenceOut.(ReferenceToExpr)
|
||||
}
|
||||
|
||||
private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) {
|
||||
// This probably cannot happen. It would require an expression to be
|
||||
// converted to a reference and back again without an intermediate variable
|
||||
// assignment.
|
||||
referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr)
|
||||
}
|
||||
|
||||
private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) {
|
||||
referenceIn.getConversion() = referenceOut.(Cast)
|
||||
or
|
||||
referenceIn.getConversion() = referenceOut.(ParenthesisExpr)
|
||||
}
|
||||
|
||||
/** Holds if `e` is constant according to the database. */
|
||||
private predicate hasConstantValue(Expr e) { valuebind(_, underlyingElement(e)) }
|
||||
@@ -56,6 +56,11 @@ class FunctionIR extends TFunctionIR {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final UnmodeledUseInstruction getUnmodeledUseInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
|
||||
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||
backEdgeSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
|
||||
exists(Instruction predecessor, EdgeKind kind |
|
||||
instr = predecessor.getSuccessor(kind) and
|
||||
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)
|
||||
}
|
||||
|
||||
/** Gets the index of `i` in its `IRBlock`. */
|
||||
private int getMemberIndex(Instruction i) {
|
||||
startsBasicBlock(i) and
|
||||
result = 0
|
||||
or
|
||||
exists(Instruction iPrev |
|
||||
adjacentInBlock(iPrev, i) and
|
||||
result = getMemberIndex(iPrev) + 1
|
||||
)
|
||||
}
|
||||
/** Holds if `i` is the `index`th instruction the block starting with `first`. */
|
||||
private Instruction getInstructionFromFirst(Instruction first, int index) =
|
||||
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
|
||||
|
||||
/** Holds if `i` is the `index`th instruction in `block`. */
|
||||
cached Instruction getInstruction(TIRBlock block, int index) {
|
||||
exists(Instruction first |
|
||||
block = MkIRBlock(first) and
|
||||
index = getMemberIndex(result) and
|
||||
adjacentInBlock*(first, result)
|
||||
)
|
||||
result = getInstructionFromFirst(getFirstInstruction(block), index)
|
||||
}
|
||||
|
||||
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) {
|
||||
blockSuccessor(pred, succ, _)
|
||||
}
|
||||
|
||||
@@ -3,31 +3,7 @@ import FunctionIR
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.TempVariableTag
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
|
||||
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)
|
||||
}
|
||||
private import semmle.code.cpp.ir.internal.TIRVariable
|
||||
|
||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
result.getVariable() = var and
|
||||
@@ -40,7 +16,7 @@ IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
FunctionIR funcIR;
|
||||
Function func;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
@@ -72,14 +48,14 @@ abstract class IRVariable extends TIRVariable {
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
result = func
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +102,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
LocalScopeVariable localVar;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
||||
this = TIRAutomaticUserVariable(localVar, func) and
|
||||
var = localVar
|
||||
}
|
||||
|
||||
@@ -137,7 +113,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, funcIR)
|
||||
this = TIRStaticUserVariable(var, func)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +128,7 @@ class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
||||
this = TIRTempVariable(func, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
|
||||
@@ -10,8 +10,6 @@ import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
|
||||
class InstructionTag = Construction::InstructionTagType;
|
||||
|
||||
module InstructionSanity {
|
||||
/**
|
||||
* Holds if the instruction `instr` should be expected to have an operand
|
||||
@@ -157,23 +155,60 @@ module InstructionSanity {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
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.
|
||||
*/
|
||||
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() {
|
||||
result = getOpcode().toString() + ": " + getAST().toString()
|
||||
}
|
||||
@@ -196,9 +231,9 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
final string getOperationString() {
|
||||
if exists(getImmediateString()) then
|
||||
result = getOperationPrefix() + opcode.toString() + "[" + getImmediateString() + "]"
|
||||
result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]"
|
||||
else
|
||||
result = getOperationPrefix() + opcode.toString()
|
||||
result = getOperationPrefix() + getOpcode().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +251,7 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if resultType instanceof VoidType then
|
||||
if getResultType() instanceof VoidType then
|
||||
result = "v"
|
||||
else if hasMemoryResult() then
|
||||
if isResultModeled() then
|
||||
@@ -261,8 +296,8 @@ class Instruction extends Construction::TInstruction {
|
||||
|
||||
private string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(resultType.toString()) and
|
||||
if (resultType instanceof UnknownType and
|
||||
valcat = getValueCategoryString(getResultType().toString()) and
|
||||
if (getResultType() instanceof UnknownType and
|
||||
not isGLValue() and
|
||||
exists(getResultSize())) then (
|
||||
result = valcat + "[" + getResultSize().toString() + "]"
|
||||
@@ -330,28 +365,28 @@ class Instruction extends Construction::TInstruction {
|
||||
* Gets the function that contains this instruction.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
result = getFunctionIR().getFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the FunctionIR object that contains the IR for this instruction.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
result = Construction::getInstructionEnclosingFunctionIR(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the AST that caused this instruction to be generated.
|
||||
*/
|
||||
final Locatable getAST() {
|
||||
result = ast
|
||||
result = Construction::getInstructionAST(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
final predicate isGLValue() {
|
||||
glvalue = true
|
||||
Construction::instructionHasType(this, _, true)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,10 +447,10 @@ class Instruction extends Construction::TInstruction {
|
||||
result = nullptr.getSize()
|
||||
)
|
||||
)
|
||||
else if resultType instanceof UnknownType then
|
||||
else if getResultType() instanceof UnknownType then
|
||||
result = Construction::getInstructionResultSize(this)
|
||||
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.
|
||||
*/
|
||||
final Opcode getOpcode() {
|
||||
result = opcode
|
||||
}
|
||||
|
||||
final InstructionTag getTag() {
|
||||
result = instructionTag
|
||||
result = Construction::getInstructionOpcode(this)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,6 +520,24 @@ class Instruction extends Construction::TInstruction {
|
||||
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.
|
||||
*/
|
||||
@@ -578,19 +627,19 @@ class ConstantValueInstruction extends Instruction {
|
||||
|
||||
class EnterFunctionInstruction extends Instruction {
|
||||
EnterFunctionInstruction() {
|
||||
opcode instanceof Opcode::EnterFunction
|
||||
getOpcode() instanceof Opcode::EnterFunction
|
||||
}
|
||||
}
|
||||
|
||||
class VariableAddressInstruction extends VariableInstruction {
|
||||
VariableAddressInstruction() {
|
||||
opcode instanceof Opcode::VariableAddress
|
||||
getOpcode() instanceof Opcode::VariableAddress
|
||||
}
|
||||
}
|
||||
|
||||
class InitializeParameterInstruction extends VariableInstruction {
|
||||
InitializeParameterInstruction() {
|
||||
opcode instanceof Opcode::InitializeParameter
|
||||
getOpcode() instanceof Opcode::InitializeParameter
|
||||
}
|
||||
|
||||
final Parameter getParameter() {
|
||||
@@ -607,13 +656,13 @@ class InitializeParameterInstruction extends VariableInstruction {
|
||||
*/
|
||||
class InitializeThisInstruction extends Instruction {
|
||||
InitializeThisInstruction() {
|
||||
opcode instanceof Opcode::InitializeThis
|
||||
getOpcode() instanceof Opcode::InitializeThis
|
||||
}
|
||||
}
|
||||
|
||||
class FieldAddressInstruction extends FieldInstruction {
|
||||
FieldAddressInstruction() {
|
||||
opcode instanceof Opcode::FieldAddress
|
||||
getOpcode() instanceof Opcode::FieldAddress
|
||||
}
|
||||
|
||||
final Instruction getObjectAddress() {
|
||||
@@ -623,7 +672,7 @@ class FieldAddressInstruction extends FieldInstruction {
|
||||
|
||||
class UninitializedInstruction extends VariableInstruction {
|
||||
UninitializedInstruction() {
|
||||
opcode instanceof Opcode::Uninitialized
|
||||
getOpcode() instanceof Opcode::Uninitialized
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -640,25 +689,25 @@ class UninitializedInstruction extends VariableInstruction {
|
||||
|
||||
class NoOpInstruction extends Instruction {
|
||||
NoOpInstruction() {
|
||||
opcode instanceof Opcode::NoOp
|
||||
getOpcode() instanceof Opcode::NoOp
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnInstruction extends Instruction {
|
||||
ReturnInstruction() {
|
||||
opcode instanceof ReturnOpcode
|
||||
getOpcode() instanceof ReturnOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnVoidInstruction extends ReturnInstruction {
|
||||
ReturnVoidInstruction() {
|
||||
opcode instanceof Opcode::ReturnVoid
|
||||
getOpcode() instanceof Opcode::ReturnVoid
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnValueInstruction extends ReturnInstruction {
|
||||
ReturnValueInstruction() {
|
||||
opcode instanceof Opcode::ReturnValue
|
||||
getOpcode() instanceof Opcode::ReturnValue
|
||||
}
|
||||
|
||||
final Instruction getReturnValue() {
|
||||
@@ -668,7 +717,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
||||
|
||||
class CopyInstruction extends Instruction {
|
||||
CopyInstruction() {
|
||||
opcode instanceof CopyOpcode
|
||||
getOpcode() instanceof CopyOpcode
|
||||
}
|
||||
|
||||
final Instruction getSourceValue() {
|
||||
@@ -678,13 +727,13 @@ class CopyInstruction extends Instruction {
|
||||
|
||||
class CopyValueInstruction extends CopyInstruction {
|
||||
CopyValueInstruction() {
|
||||
opcode instanceof Opcode::CopyValue
|
||||
getOpcode() instanceof Opcode::CopyValue
|
||||
}
|
||||
}
|
||||
|
||||
class LoadInstruction extends CopyInstruction {
|
||||
LoadInstruction() {
|
||||
opcode instanceof Opcode::Load
|
||||
getOpcode() instanceof Opcode::Load
|
||||
}
|
||||
|
||||
final Instruction getSourceAddress() {
|
||||
@@ -694,7 +743,7 @@ class LoadInstruction extends CopyInstruction {
|
||||
|
||||
class StoreInstruction extends CopyInstruction {
|
||||
StoreInstruction() {
|
||||
opcode instanceof Opcode::Store
|
||||
getOpcode() instanceof Opcode::Store
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -708,7 +757,7 @@ class StoreInstruction extends CopyInstruction {
|
||||
|
||||
class ConditionalBranchInstruction extends Instruction {
|
||||
ConditionalBranchInstruction() {
|
||||
opcode instanceof Opcode::ConditionalBranch
|
||||
getOpcode() instanceof Opcode::ConditionalBranch
|
||||
}
|
||||
|
||||
final Instruction getCondition() {
|
||||
@@ -726,25 +775,25 @@ class ConditionalBranchInstruction extends Instruction {
|
||||
|
||||
class ExitFunctionInstruction extends Instruction {
|
||||
ExitFunctionInstruction() {
|
||||
opcode instanceof Opcode::ExitFunction
|
||||
getOpcode() instanceof Opcode::ExitFunction
|
||||
}
|
||||
}
|
||||
|
||||
class ConstantInstruction extends ConstantValueInstruction {
|
||||
ConstantInstruction() {
|
||||
opcode instanceof Opcode::Constant
|
||||
getOpcode() instanceof Opcode::Constant
|
||||
}
|
||||
}
|
||||
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() {
|
||||
resultType instanceof IntegralType
|
||||
getResultType() instanceof IntegralType
|
||||
}
|
||||
}
|
||||
|
||||
class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() {
|
||||
resultType instanceof FloatingPointType
|
||||
getResultType() instanceof FloatingPointType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,7 +815,7 @@ class StringConstantInstruction extends Instruction {
|
||||
|
||||
class BinaryInstruction extends Instruction {
|
||||
BinaryInstruction() {
|
||||
opcode instanceof BinaryOpcode
|
||||
getOpcode() instanceof BinaryOpcode
|
||||
}
|
||||
|
||||
final Instruction getLeftOperand() {
|
||||
@@ -789,67 +838,67 @@ class BinaryInstruction extends Instruction {
|
||||
|
||||
class AddInstruction extends BinaryInstruction {
|
||||
AddInstruction() {
|
||||
opcode instanceof Opcode::Add
|
||||
getOpcode() instanceof Opcode::Add
|
||||
}
|
||||
}
|
||||
|
||||
class SubInstruction extends BinaryInstruction {
|
||||
SubInstruction() {
|
||||
opcode instanceof Opcode::Sub
|
||||
getOpcode() instanceof Opcode::Sub
|
||||
}
|
||||
}
|
||||
|
||||
class MulInstruction extends BinaryInstruction {
|
||||
MulInstruction() {
|
||||
opcode instanceof Opcode::Mul
|
||||
getOpcode() instanceof Opcode::Mul
|
||||
}
|
||||
}
|
||||
|
||||
class DivInstruction extends BinaryInstruction {
|
||||
DivInstruction() {
|
||||
opcode instanceof Opcode::Div
|
||||
getOpcode() instanceof Opcode::Div
|
||||
}
|
||||
}
|
||||
|
||||
class RemInstruction extends BinaryInstruction {
|
||||
RemInstruction() {
|
||||
opcode instanceof Opcode::Rem
|
||||
getOpcode() instanceof Opcode::Rem
|
||||
}
|
||||
}
|
||||
|
||||
class NegateInstruction extends UnaryInstruction {
|
||||
NegateInstruction() {
|
||||
opcode instanceof Opcode::Negate
|
||||
getOpcode() instanceof Opcode::Negate
|
||||
}
|
||||
}
|
||||
|
||||
class BitAndInstruction extends BinaryInstruction {
|
||||
BitAndInstruction() {
|
||||
opcode instanceof Opcode::BitAnd
|
||||
getOpcode() instanceof Opcode::BitAnd
|
||||
}
|
||||
}
|
||||
|
||||
class BitOrInstruction extends BinaryInstruction {
|
||||
BitOrInstruction() {
|
||||
opcode instanceof Opcode::BitOr
|
||||
getOpcode() instanceof Opcode::BitOr
|
||||
}
|
||||
}
|
||||
|
||||
class BitXorInstruction extends BinaryInstruction {
|
||||
BitXorInstruction() {
|
||||
opcode instanceof Opcode::BitXor
|
||||
getOpcode() instanceof Opcode::BitXor
|
||||
}
|
||||
}
|
||||
|
||||
class ShiftLeftInstruction extends BinaryInstruction {
|
||||
ShiftLeftInstruction() {
|
||||
opcode instanceof Opcode::ShiftLeft
|
||||
getOpcode() instanceof Opcode::ShiftLeft
|
||||
}
|
||||
}
|
||||
|
||||
class ShiftRightInstruction extends BinaryInstruction {
|
||||
ShiftRightInstruction() {
|
||||
opcode instanceof Opcode::ShiftRight
|
||||
getOpcode() instanceof Opcode::ShiftRight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,7 +906,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
int elementSize;
|
||||
|
||||
PointerArithmeticInstruction() {
|
||||
opcode instanceof PointerArithmeticOpcode and
|
||||
getOpcode() instanceof PointerArithmeticOpcode and
|
||||
elementSize = Construction::getInstructionElementSize(this)
|
||||
}
|
||||
|
||||
@@ -872,31 +921,31 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
|
||||
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
||||
PointerOffsetInstruction() {
|
||||
opcode instanceof PointerOffsetOpcode
|
||||
getOpcode() instanceof PointerOffsetOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class PointerAddInstruction extends PointerOffsetInstruction {
|
||||
PointerAddInstruction() {
|
||||
opcode instanceof Opcode::PointerAdd
|
||||
getOpcode() instanceof Opcode::PointerAdd
|
||||
}
|
||||
}
|
||||
|
||||
class PointerSubInstruction extends PointerOffsetInstruction {
|
||||
PointerSubInstruction() {
|
||||
opcode instanceof Opcode::PointerSub
|
||||
getOpcode() instanceof Opcode::PointerSub
|
||||
}
|
||||
}
|
||||
|
||||
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
||||
PointerDiffInstruction() {
|
||||
opcode instanceof Opcode::PointerDiff
|
||||
getOpcode() instanceof Opcode::PointerDiff
|
||||
}
|
||||
}
|
||||
|
||||
class UnaryInstruction extends Instruction {
|
||||
UnaryInstruction() {
|
||||
opcode instanceof UnaryOpcode
|
||||
getOpcode() instanceof UnaryOpcode
|
||||
}
|
||||
|
||||
final Instruction getOperand() {
|
||||
@@ -906,7 +955,7 @@ class UnaryInstruction extends Instruction {
|
||||
|
||||
class ConvertInstruction extends UnaryInstruction {
|
||||
ConvertInstruction() {
|
||||
opcode instanceof Opcode::Convert
|
||||
getOpcode() instanceof Opcode::Convert
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,7 +1007,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
*/
|
||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToBaseInstruction() {
|
||||
opcode instanceof Opcode::ConvertToBase
|
||||
getOpcode() instanceof Opcode::ConvertToBase
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,7 +1017,7 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
*/
|
||||
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToVirtualBaseInstruction() {
|
||||
opcode instanceof Opcode::ConvertToVirtualBase
|
||||
getOpcode() instanceof Opcode::ConvertToVirtualBase
|
||||
}
|
||||
}
|
||||
|
||||
@@ -978,37 +1027,37 @@ class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
||||
*/
|
||||
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToDerivedInstruction() {
|
||||
opcode instanceof Opcode::ConvertToDerived
|
||||
getOpcode() instanceof Opcode::ConvertToDerived
|
||||
}
|
||||
}
|
||||
|
||||
class BitComplementInstruction extends UnaryInstruction {
|
||||
BitComplementInstruction() {
|
||||
opcode instanceof Opcode::BitComplement
|
||||
getOpcode() instanceof Opcode::BitComplement
|
||||
}
|
||||
}
|
||||
|
||||
class LogicalNotInstruction extends UnaryInstruction {
|
||||
LogicalNotInstruction() {
|
||||
opcode instanceof Opcode::LogicalNot
|
||||
getOpcode() instanceof Opcode::LogicalNot
|
||||
}
|
||||
}
|
||||
|
||||
class CompareInstruction extends BinaryInstruction {
|
||||
CompareInstruction() {
|
||||
opcode instanceof CompareOpcode
|
||||
getOpcode() instanceof CompareOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class CompareEQInstruction extends CompareInstruction {
|
||||
CompareEQInstruction() {
|
||||
opcode instanceof Opcode::CompareEQ
|
||||
getOpcode() instanceof Opcode::CompareEQ
|
||||
}
|
||||
}
|
||||
|
||||
class CompareNEInstruction extends CompareInstruction {
|
||||
CompareNEInstruction() {
|
||||
opcode instanceof Opcode::CompareNE
|
||||
getOpcode() instanceof Opcode::CompareNE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,7 +1066,7 @@ class CompareNEInstruction extends CompareInstruction {
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
getOpcode() instanceof RelationalOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1050,7 +1099,7 @@ class RelationalInstruction extends CompareInstruction {
|
||||
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
getOpcode() instanceof Opcode::CompareLT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1068,7 +1117,7 @@ class CompareLTInstruction extends RelationalInstruction {
|
||||
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() {
|
||||
opcode instanceof Opcode::CompareGT
|
||||
getOpcode() instanceof Opcode::CompareGT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1086,7 +1135,7 @@ class CompareGTInstruction extends RelationalInstruction {
|
||||
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
getOpcode() instanceof Opcode::CompareLE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1104,7 +1153,7 @@ class CompareLEInstruction extends RelationalInstruction {
|
||||
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() {
|
||||
opcode instanceof Opcode::CompareGE
|
||||
getOpcode() instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1122,7 +1171,7 @@ class CompareGEInstruction extends RelationalInstruction {
|
||||
|
||||
class SwitchInstruction extends Instruction {
|
||||
SwitchInstruction() {
|
||||
opcode instanceof Opcode::Switch
|
||||
getOpcode() instanceof Opcode::Switch
|
||||
}
|
||||
|
||||
final Instruction getExpression() {
|
||||
@@ -1145,7 +1194,7 @@ class SwitchInstruction extends Instruction {
|
||||
*/
|
||||
class CallInstruction extends Instruction {
|
||||
CallInstruction() {
|
||||
opcode instanceof Opcode::Call
|
||||
getOpcode() instanceof Opcode::Call
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1188,7 +1237,7 @@ class CallInstruction extends Instruction {
|
||||
*/
|
||||
class SideEffectInstruction extends Instruction {
|
||||
SideEffectInstruction() {
|
||||
opcode instanceof SideEffectOpcode
|
||||
getOpcode() instanceof SideEffectOpcode
|
||||
}
|
||||
|
||||
final Instruction getPrimaryInstruction() {
|
||||
@@ -1202,7 +1251,7 @@ class SideEffectInstruction extends Instruction {
|
||||
*/
|
||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
CallSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallSideEffect
|
||||
getOpcode() instanceof Opcode::CallSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1216,7 +1265,7 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
CallReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallReadSideEffect
|
||||
getOpcode() instanceof Opcode::CallReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1225,7 +1274,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectReadSideEffect
|
||||
getOpcode() instanceof Opcode::IndirectReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1234,7 +1283,7 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferReadSideEffect
|
||||
getOpcode() instanceof Opcode::BufferReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1243,7 +1292,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectWriteSideEffect
|
||||
getOpcode() instanceof Opcode::IndirectWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1257,7 +1306,7 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferWriteSideEffect
|
||||
getOpcode() instanceof Opcode::BufferWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1272,7 +1321,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectMayWriteSideEffect
|
||||
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1286,7 +1335,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferMayWriteSideEffect
|
||||
getOpcode() instanceof Opcode::BufferMayWriteSideEffect
|
||||
}
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
@@ -1298,7 +1347,7 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class ThrowInstruction extends Instruction {
|
||||
ThrowInstruction() {
|
||||
opcode instanceof ThrowOpcode
|
||||
getOpcode() instanceof ThrowOpcode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1307,7 +1356,7 @@ class ThrowInstruction extends Instruction {
|
||||
*/
|
||||
class ThrowValueInstruction extends ThrowInstruction {
|
||||
ThrowValueInstruction() {
|
||||
opcode instanceof Opcode::ThrowValue
|
||||
getOpcode() instanceof Opcode::ThrowValue
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1330,7 +1379,7 @@ class ThrowValueInstruction extends ThrowInstruction {
|
||||
*/
|
||||
class ReThrowInstruction extends ThrowInstruction {
|
||||
ReThrowInstruction() {
|
||||
opcode instanceof Opcode::ReThrow
|
||||
getOpcode() instanceof Opcode::ReThrow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1339,7 +1388,7 @@ class ReThrowInstruction extends ThrowInstruction {
|
||||
*/
|
||||
class UnwindInstruction extends Instruction {
|
||||
UnwindInstruction() {
|
||||
opcode instanceof Opcode::Unwind
|
||||
getOpcode() instanceof Opcode::Unwind
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,7 +1397,7 @@ class UnwindInstruction extends Instruction {
|
||||
*/
|
||||
class CatchInstruction extends Instruction {
|
||||
CatchInstruction() {
|
||||
opcode instanceof CatchOpcode
|
||||
getOpcode() instanceof CatchOpcode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1359,7 +1408,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
Type exceptionType;
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
opcode instanceof Opcode::CatchByType and
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
exceptionType = Construction::getInstructionExceptionType(this)
|
||||
}
|
||||
|
||||
@@ -1380,13 +1429,13 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
*/
|
||||
class CatchAnyInstruction extends CatchInstruction {
|
||||
CatchAnyInstruction() {
|
||||
opcode instanceof Opcode::CatchAny
|
||||
getOpcode() instanceof Opcode::CatchAny
|
||||
}
|
||||
}
|
||||
|
||||
class UnmodeledDefinitionInstruction extends Instruction {
|
||||
UnmodeledDefinitionInstruction() {
|
||||
opcode instanceof Opcode::UnmodeledDefinition
|
||||
getOpcode() instanceof Opcode::UnmodeledDefinition
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1399,7 +1448,7 @@ class UnmodeledDefinitionInstruction extends Instruction {
|
||||
*/
|
||||
class AliasedDefinitionInstruction extends Instruction {
|
||||
AliasedDefinitionInstruction() {
|
||||
opcode instanceof Opcode::AliasedDefinition
|
||||
getOpcode() instanceof Opcode::AliasedDefinition
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1409,7 +1458,7 @@ class AliasedDefinitionInstruction extends Instruction {
|
||||
|
||||
class UnmodeledUseInstruction extends Instruction {
|
||||
UnmodeledUseInstruction() {
|
||||
opcode instanceof Opcode::UnmodeledUse
|
||||
getOpcode() instanceof Opcode::UnmodeledUse
|
||||
}
|
||||
|
||||
override string getOperandsString() {
|
||||
@@ -1429,7 +1478,7 @@ class UnmodeledUseInstruction extends Instruction {
|
||||
*/
|
||||
class PhiInstruction extends Instruction {
|
||||
PhiInstruction() {
|
||||
opcode instanceof Opcode::Phi
|
||||
getOpcode() instanceof Opcode::Phi
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1481,7 +1530,7 @@ class PhiInstruction extends Instruction {
|
||||
*/
|
||||
class ChiInstruction extends Instruction {
|
||||
ChiInstruction() {
|
||||
opcode instanceof Opcode::Chi
|
||||
getOpcode() instanceof Opcode::Chi
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1511,7 +1560,7 @@ class ChiInstruction extends Instruction {
|
||||
*/
|
||||
class UnreachedInstruction extends Instruction {
|
||||
UnreachedInstruction() {
|
||||
opcode instanceof Opcode::Unreached
|
||||
getOpcode() instanceof Opcode::Unreached
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1521,6 +1570,6 @@ class UnreachedInstruction extends Instruction {
|
||||
*/
|
||||
class BuiltInInstruction extends Instruction {
|
||||
BuiltInInstruction() {
|
||||
opcode instanceof BuiltInOpcode
|
||||
getOpcode() instanceof BuiltInOpcode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +287,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
||||
(
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = kind.toString()
|
||||
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||
then value = kind.toString() + " (back edge)"
|
||||
else value = kind.toString()
|
||||
) or
|
||||
(
|
||||
key = "semmle.order" and
|
||||
|
||||
@@ -14,25 +14,6 @@ cached private module Cached {
|
||||
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) {
|
||||
exists(OldIR::FunctionIR funcIR |
|
||||
funcIR.getFunction() = func
|
||||
@@ -40,7 +21,7 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
cached OldInstruction getOldInstruction(Instruction instr) {
|
||||
instr.getTag() = WrappedInstructionTag(result)
|
||||
instr = WrappedInstruction(result)
|
||||
}
|
||||
|
||||
private Instruction getNewInstruction(OldInstruction instr) {
|
||||
@@ -52,90 +33,35 @@ cached private module Cached {
|
||||
* corresponding to `instr` if there is no `Chi` node.
|
||||
*/
|
||||
private Instruction getNewFinalInstruction(OldInstruction instr) {
|
||||
result = getChiInstruction(instr)
|
||||
result = Chi(instr)
|
||||
or
|
||||
not exists(getChiInstruction(instr)) and
|
||||
not exists(Chi(instr)) and
|
||||
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) {
|
||||
result.getFunction() = var.getFunction() and
|
||||
(
|
||||
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
|
||||
)
|
||||
)
|
||||
// This is just a type cast. Both classes derive from the same newtype.
|
||||
result = var
|
||||
}
|
||||
|
||||
cached newtype TInstruction =
|
||||
MkInstruction(FunctionIR funcIR, Opcode opcode, Locatable ast,
|
||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
hasInstruction(funcIR.getFunction(), opcode, ast, tag,
|
||||
resultType, isGLValue)
|
||||
WrappedInstruction(OldInstruction oldInstruction) {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction
|
||||
} or
|
||||
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,
|
||||
Type type) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
@@ -169,7 +95,7 @@ cached private module Cached {
|
||||
if defIndex >= 0 then
|
||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instruction.getFunction(), defBlock, vvar)
|
||||
result = Phi(defBlock, vvar)
|
||||
)
|
||||
)
|
||||
else (
|
||||
@@ -189,13 +115,14 @@ cached private module Cached {
|
||||
else
|
||||
result = getNewInstruction(oldOperand.getDefinitionInstruction())
|
||||
) or
|
||||
instruction.getTag() = ChiTag(getOldInstruction(result)) and
|
||||
instruction = Chi(getOldInstruction(result)) and
|
||||
tag instanceof ChiPartialOperandTag
|
||||
or
|
||||
instruction instanceof UnmodeledUseInstruction and
|
||||
tag instanceof UnmodeledUseOperandTag and
|
||||
result instanceof UnmodeledDefinitionInstruction and
|
||||
instruction.getFunction() = result.getFunction()
|
||||
exists(FunctionIR f |
|
||||
tag instanceof UnmodeledUseOperandTag and
|
||||
result = f.getUnmodeledDefinitionInstruction() and
|
||||
instruction = f.getUnmodeledUseInstruction()
|
||||
)
|
||||
or
|
||||
tag instanceof ChiTotalOperandTag and
|
||||
result = getChiInstructionTotalOperand(instruction)
|
||||
@@ -207,21 +134,21 @@ cached private module Cached {
|
||||
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
|
||||
hasPhiNode(vvar, phiBlock) and
|
||||
predBlock = phiBlock.getAFeasiblePredecessor() and
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
instr = Phi(phiBlock, vvar) and
|
||||
newPredecessorBlock = getNewBlock(predBlock) and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instr.getFunction(), defBlock, vvar)
|
||||
result = Phi(defBlock, vvar)
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
|
||||
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
|
||||
int defRank, int defIndex, OldBlock useBlock, int useRank |
|
||||
ChiTag(oldInstr) = chiInstr.getTag() and
|
||||
chiInstr = Chi(oldInstr) and
|
||||
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||
@@ -229,13 +156,13 @@ cached private module Cached {
|
||||
if defIndex >= 0 then
|
||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(chiInstr.getFunction(), defBlock, vvar)
|
||||
result = Phi(defBlock, vvar)
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
exists(OldBlock oldBlock |
|
||||
instr.getTag() = PhiTag(_, oldBlock) and
|
||||
instr = Phi(oldBlock, _) and
|
||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
)
|
||||
}
|
||||
@@ -256,15 +183,14 @@ cached private module Cached {
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
if(hasChiNode(_, getOldInstruction(instruction)))
|
||||
then
|
||||
result = getChiInstruction(getOldInstruction(instruction)) and
|
||||
result = Chi(getOldInstruction(instruction)) and
|
||||
kind instanceof GotoEdge
|
||||
else (
|
||||
exists(OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
(
|
||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) then (
|
||||
result.getTag() = UnreachedTag() and
|
||||
result.getFunction() = instruction.getFunction()
|
||||
result = Unreached(instruction.getFunction())
|
||||
)
|
||||
else (
|
||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
@@ -272,12 +198,106 @@ cached private module Cached {
|
||||
)
|
||||
) or
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = getChiInstruction(oldInstruction) and
|
||||
instruction = Chi(oldInstruction) and
|
||||
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) {
|
||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||
}
|
||||
@@ -328,13 +348,13 @@ cached private module Cached {
|
||||
)
|
||||
or
|
||||
exists(OldIR::Instruction oldInstruction |
|
||||
instruction.getTag() = ChiTag(oldInstruction) and
|
||||
instruction = Chi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||
OldInstruction instr, OldBlock block, int index) {
|
||||
OldBlock block, int index, OldInstruction instr) {
|
||||
block.getInstruction(index) = instr and
|
||||
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) {
|
||||
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,
|
||||
int index) {
|
||||
private predicate hasUse(Alias::VirtualVariable vvar, OldBlock block, int index,
|
||||
OldInstruction use) {
|
||||
exists(Alias::MemoryAccess access |
|
||||
(
|
||||
access = Alias::getOperandMemoryAccess(use.getAnOperand())
|
||||
@@ -374,10 +394,16 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
|
||||
exists (int index | hasUse(vvar, _, block, index) |
|
||||
not exists (int j | ssa_variableUpdate(vvar, _, block, j) | j < index)
|
||||
) or
|
||||
(variableLiveOnExitFromBlock(vvar, block) and not ssa_variableUpdate(vvar, _, block, _))
|
||||
exists(int firstAccess |
|
||||
hasUse(vvar, block, firstAccess, _) and
|
||||
firstAccess = min(int index |
|
||||
hasUse(vvar, block, index, _)
|
||||
or
|
||||
ssa_variableUpdate(vvar, block, index, _)
|
||||
)
|
||||
)
|
||||
or
|
||||
(variableLiveOnExitFromBlock(vvar, block) and not ssa_variableUpdate(vvar, block, _, _))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -404,7 +430,7 @@ cached private module Cached {
|
||||
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
|
||||
OldInstruction use) {
|
||||
exists(int index |
|
||||
hasUse(vvar, use, block, index) and
|
||||
hasUse(vvar, block, index, use) and
|
||||
defUseRank(vvar, block, rankIndex, index)
|
||||
)
|
||||
}
|
||||
@@ -517,11 +543,11 @@ cached private module CachedForDebugging {
|
||||
result = "NonSSA: " + oldInstr.getUniqueId()
|
||||
) or
|
||||
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
instr = Phi(phiBlock, vvar) and
|
||||
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
||||
) or
|
||||
(
|
||||
instr.getTag() = UnreachedTag() and
|
||||
instr = Unreached(_) and
|
||||
result = "Unreached"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ class FunctionIR extends TFunctionIR {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final UnmodeledUseInstruction getUnmodeledUseInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
|
||||
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||
backEdgeSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
|
||||
exists(Instruction predecessor, EdgeKind kind |
|
||||
instr = predecessor.getSuccessor(kind) and
|
||||
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)
|
||||
}
|
||||
|
||||
/** Gets the index of `i` in its `IRBlock`. */
|
||||
private int getMemberIndex(Instruction i) {
|
||||
startsBasicBlock(i) and
|
||||
result = 0
|
||||
or
|
||||
exists(Instruction iPrev |
|
||||
adjacentInBlock(iPrev, i) and
|
||||
result = getMemberIndex(iPrev) + 1
|
||||
)
|
||||
}
|
||||
/** Holds if `i` is the `index`th instruction the block starting with `first`. */
|
||||
private Instruction getInstructionFromFirst(Instruction first, int index) =
|
||||
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
|
||||
|
||||
/** Holds if `i` is the `index`th instruction in `block`. */
|
||||
cached Instruction getInstruction(TIRBlock block, int index) {
|
||||
exists(Instruction first |
|
||||
block = MkIRBlock(first) and
|
||||
index = getMemberIndex(result) and
|
||||
adjacentInBlock*(first, result)
|
||||
)
|
||||
result = getInstructionFromFirst(getFirstInstruction(block), index)
|
||||
}
|
||||
|
||||
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) {
|
||||
blockSuccessor(pred, succ, _)
|
||||
}
|
||||
|
||||
@@ -3,31 +3,7 @@ import FunctionIR
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.TempVariableTag
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
|
||||
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)
|
||||
}
|
||||
private import semmle.code.cpp.ir.internal.TIRVariable
|
||||
|
||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
result.getVariable() = var and
|
||||
@@ -40,7 +16,7 @@ IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
FunctionIR funcIR;
|
||||
Function func;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
@@ -72,14 +48,14 @@ abstract class IRVariable extends TIRVariable {
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
result = func
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +102,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
LocalScopeVariable localVar;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
||||
this = TIRAutomaticUserVariable(localVar, func) and
|
||||
var = localVar
|
||||
}
|
||||
|
||||
@@ -137,7 +113,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, funcIR)
|
||||
this = TIRStaticUserVariable(var, func)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +128,7 @@ class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
||||
this = TIRTempVariable(func, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
|
||||
@@ -10,8 +10,6 @@ import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
|
||||
class InstructionTag = Construction::InstructionTagType;
|
||||
|
||||
module InstructionSanity {
|
||||
/**
|
||||
* Holds if the instruction `instr` should be expected to have an operand
|
||||
@@ -157,23 +155,60 @@ module InstructionSanity {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
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.
|
||||
*/
|
||||
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() {
|
||||
result = getOpcode().toString() + ": " + getAST().toString()
|
||||
}
|
||||
@@ -196,9 +231,9 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
final string getOperationString() {
|
||||
if exists(getImmediateString()) then
|
||||
result = getOperationPrefix() + opcode.toString() + "[" + getImmediateString() + "]"
|
||||
result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]"
|
||||
else
|
||||
result = getOperationPrefix() + opcode.toString()
|
||||
result = getOperationPrefix() + getOpcode().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +251,7 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if resultType instanceof VoidType then
|
||||
if getResultType() instanceof VoidType then
|
||||
result = "v"
|
||||
else if hasMemoryResult() then
|
||||
if isResultModeled() then
|
||||
@@ -261,8 +296,8 @@ class Instruction extends Construction::TInstruction {
|
||||
|
||||
private string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(resultType.toString()) and
|
||||
if (resultType instanceof UnknownType and
|
||||
valcat = getValueCategoryString(getResultType().toString()) and
|
||||
if (getResultType() instanceof UnknownType and
|
||||
not isGLValue() and
|
||||
exists(getResultSize())) then (
|
||||
result = valcat + "[" + getResultSize().toString() + "]"
|
||||
@@ -330,28 +365,28 @@ class Instruction extends Construction::TInstruction {
|
||||
* Gets the function that contains this instruction.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
result = getFunctionIR().getFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the FunctionIR object that contains the IR for this instruction.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
result = Construction::getInstructionEnclosingFunctionIR(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the AST that caused this instruction to be generated.
|
||||
*/
|
||||
final Locatable getAST() {
|
||||
result = ast
|
||||
result = Construction::getInstructionAST(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
final predicate isGLValue() {
|
||||
glvalue = true
|
||||
Construction::instructionHasType(this, _, true)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,10 +447,10 @@ class Instruction extends Construction::TInstruction {
|
||||
result = nullptr.getSize()
|
||||
)
|
||||
)
|
||||
else if resultType instanceof UnknownType then
|
||||
else if getResultType() instanceof UnknownType then
|
||||
result = Construction::getInstructionResultSize(this)
|
||||
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.
|
||||
*/
|
||||
final Opcode getOpcode() {
|
||||
result = opcode
|
||||
}
|
||||
|
||||
final InstructionTag getTag() {
|
||||
result = instructionTag
|
||||
result = Construction::getInstructionOpcode(this)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,6 +520,24 @@ class Instruction extends Construction::TInstruction {
|
||||
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.
|
||||
*/
|
||||
@@ -578,19 +627,19 @@ class ConstantValueInstruction extends Instruction {
|
||||
|
||||
class EnterFunctionInstruction extends Instruction {
|
||||
EnterFunctionInstruction() {
|
||||
opcode instanceof Opcode::EnterFunction
|
||||
getOpcode() instanceof Opcode::EnterFunction
|
||||
}
|
||||
}
|
||||
|
||||
class VariableAddressInstruction extends VariableInstruction {
|
||||
VariableAddressInstruction() {
|
||||
opcode instanceof Opcode::VariableAddress
|
||||
getOpcode() instanceof Opcode::VariableAddress
|
||||
}
|
||||
}
|
||||
|
||||
class InitializeParameterInstruction extends VariableInstruction {
|
||||
InitializeParameterInstruction() {
|
||||
opcode instanceof Opcode::InitializeParameter
|
||||
getOpcode() instanceof Opcode::InitializeParameter
|
||||
}
|
||||
|
||||
final Parameter getParameter() {
|
||||
@@ -607,13 +656,13 @@ class InitializeParameterInstruction extends VariableInstruction {
|
||||
*/
|
||||
class InitializeThisInstruction extends Instruction {
|
||||
InitializeThisInstruction() {
|
||||
opcode instanceof Opcode::InitializeThis
|
||||
getOpcode() instanceof Opcode::InitializeThis
|
||||
}
|
||||
}
|
||||
|
||||
class FieldAddressInstruction extends FieldInstruction {
|
||||
FieldAddressInstruction() {
|
||||
opcode instanceof Opcode::FieldAddress
|
||||
getOpcode() instanceof Opcode::FieldAddress
|
||||
}
|
||||
|
||||
final Instruction getObjectAddress() {
|
||||
@@ -623,7 +672,7 @@ class FieldAddressInstruction extends FieldInstruction {
|
||||
|
||||
class UninitializedInstruction extends VariableInstruction {
|
||||
UninitializedInstruction() {
|
||||
opcode instanceof Opcode::Uninitialized
|
||||
getOpcode() instanceof Opcode::Uninitialized
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -640,25 +689,25 @@ class UninitializedInstruction extends VariableInstruction {
|
||||
|
||||
class NoOpInstruction extends Instruction {
|
||||
NoOpInstruction() {
|
||||
opcode instanceof Opcode::NoOp
|
||||
getOpcode() instanceof Opcode::NoOp
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnInstruction extends Instruction {
|
||||
ReturnInstruction() {
|
||||
opcode instanceof ReturnOpcode
|
||||
getOpcode() instanceof ReturnOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnVoidInstruction extends ReturnInstruction {
|
||||
ReturnVoidInstruction() {
|
||||
opcode instanceof Opcode::ReturnVoid
|
||||
getOpcode() instanceof Opcode::ReturnVoid
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnValueInstruction extends ReturnInstruction {
|
||||
ReturnValueInstruction() {
|
||||
opcode instanceof Opcode::ReturnValue
|
||||
getOpcode() instanceof Opcode::ReturnValue
|
||||
}
|
||||
|
||||
final Instruction getReturnValue() {
|
||||
@@ -668,7 +717,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
||||
|
||||
class CopyInstruction extends Instruction {
|
||||
CopyInstruction() {
|
||||
opcode instanceof CopyOpcode
|
||||
getOpcode() instanceof CopyOpcode
|
||||
}
|
||||
|
||||
final Instruction getSourceValue() {
|
||||
@@ -678,13 +727,13 @@ class CopyInstruction extends Instruction {
|
||||
|
||||
class CopyValueInstruction extends CopyInstruction {
|
||||
CopyValueInstruction() {
|
||||
opcode instanceof Opcode::CopyValue
|
||||
getOpcode() instanceof Opcode::CopyValue
|
||||
}
|
||||
}
|
||||
|
||||
class LoadInstruction extends CopyInstruction {
|
||||
LoadInstruction() {
|
||||
opcode instanceof Opcode::Load
|
||||
getOpcode() instanceof Opcode::Load
|
||||
}
|
||||
|
||||
final Instruction getSourceAddress() {
|
||||
@@ -694,7 +743,7 @@ class LoadInstruction extends CopyInstruction {
|
||||
|
||||
class StoreInstruction extends CopyInstruction {
|
||||
StoreInstruction() {
|
||||
opcode instanceof Opcode::Store
|
||||
getOpcode() instanceof Opcode::Store
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -708,7 +757,7 @@ class StoreInstruction extends CopyInstruction {
|
||||
|
||||
class ConditionalBranchInstruction extends Instruction {
|
||||
ConditionalBranchInstruction() {
|
||||
opcode instanceof Opcode::ConditionalBranch
|
||||
getOpcode() instanceof Opcode::ConditionalBranch
|
||||
}
|
||||
|
||||
final Instruction getCondition() {
|
||||
@@ -726,25 +775,25 @@ class ConditionalBranchInstruction extends Instruction {
|
||||
|
||||
class ExitFunctionInstruction extends Instruction {
|
||||
ExitFunctionInstruction() {
|
||||
opcode instanceof Opcode::ExitFunction
|
||||
getOpcode() instanceof Opcode::ExitFunction
|
||||
}
|
||||
}
|
||||
|
||||
class ConstantInstruction extends ConstantValueInstruction {
|
||||
ConstantInstruction() {
|
||||
opcode instanceof Opcode::Constant
|
||||
getOpcode() instanceof Opcode::Constant
|
||||
}
|
||||
}
|
||||
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() {
|
||||
resultType instanceof IntegralType
|
||||
getResultType() instanceof IntegralType
|
||||
}
|
||||
}
|
||||
|
||||
class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() {
|
||||
resultType instanceof FloatingPointType
|
||||
getResultType() instanceof FloatingPointType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,7 +815,7 @@ class StringConstantInstruction extends Instruction {
|
||||
|
||||
class BinaryInstruction extends Instruction {
|
||||
BinaryInstruction() {
|
||||
opcode instanceof BinaryOpcode
|
||||
getOpcode() instanceof BinaryOpcode
|
||||
}
|
||||
|
||||
final Instruction getLeftOperand() {
|
||||
@@ -789,67 +838,67 @@ class BinaryInstruction extends Instruction {
|
||||
|
||||
class AddInstruction extends BinaryInstruction {
|
||||
AddInstruction() {
|
||||
opcode instanceof Opcode::Add
|
||||
getOpcode() instanceof Opcode::Add
|
||||
}
|
||||
}
|
||||
|
||||
class SubInstruction extends BinaryInstruction {
|
||||
SubInstruction() {
|
||||
opcode instanceof Opcode::Sub
|
||||
getOpcode() instanceof Opcode::Sub
|
||||
}
|
||||
}
|
||||
|
||||
class MulInstruction extends BinaryInstruction {
|
||||
MulInstruction() {
|
||||
opcode instanceof Opcode::Mul
|
||||
getOpcode() instanceof Opcode::Mul
|
||||
}
|
||||
}
|
||||
|
||||
class DivInstruction extends BinaryInstruction {
|
||||
DivInstruction() {
|
||||
opcode instanceof Opcode::Div
|
||||
getOpcode() instanceof Opcode::Div
|
||||
}
|
||||
}
|
||||
|
||||
class RemInstruction extends BinaryInstruction {
|
||||
RemInstruction() {
|
||||
opcode instanceof Opcode::Rem
|
||||
getOpcode() instanceof Opcode::Rem
|
||||
}
|
||||
}
|
||||
|
||||
class NegateInstruction extends UnaryInstruction {
|
||||
NegateInstruction() {
|
||||
opcode instanceof Opcode::Negate
|
||||
getOpcode() instanceof Opcode::Negate
|
||||
}
|
||||
}
|
||||
|
||||
class BitAndInstruction extends BinaryInstruction {
|
||||
BitAndInstruction() {
|
||||
opcode instanceof Opcode::BitAnd
|
||||
getOpcode() instanceof Opcode::BitAnd
|
||||
}
|
||||
}
|
||||
|
||||
class BitOrInstruction extends BinaryInstruction {
|
||||
BitOrInstruction() {
|
||||
opcode instanceof Opcode::BitOr
|
||||
getOpcode() instanceof Opcode::BitOr
|
||||
}
|
||||
}
|
||||
|
||||
class BitXorInstruction extends BinaryInstruction {
|
||||
BitXorInstruction() {
|
||||
opcode instanceof Opcode::BitXor
|
||||
getOpcode() instanceof Opcode::BitXor
|
||||
}
|
||||
}
|
||||
|
||||
class ShiftLeftInstruction extends BinaryInstruction {
|
||||
ShiftLeftInstruction() {
|
||||
opcode instanceof Opcode::ShiftLeft
|
||||
getOpcode() instanceof Opcode::ShiftLeft
|
||||
}
|
||||
}
|
||||
|
||||
class ShiftRightInstruction extends BinaryInstruction {
|
||||
ShiftRightInstruction() {
|
||||
opcode instanceof Opcode::ShiftRight
|
||||
getOpcode() instanceof Opcode::ShiftRight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,7 +906,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
int elementSize;
|
||||
|
||||
PointerArithmeticInstruction() {
|
||||
opcode instanceof PointerArithmeticOpcode and
|
||||
getOpcode() instanceof PointerArithmeticOpcode and
|
||||
elementSize = Construction::getInstructionElementSize(this)
|
||||
}
|
||||
|
||||
@@ -872,31 +921,31 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
|
||||
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
||||
PointerOffsetInstruction() {
|
||||
opcode instanceof PointerOffsetOpcode
|
||||
getOpcode() instanceof PointerOffsetOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class PointerAddInstruction extends PointerOffsetInstruction {
|
||||
PointerAddInstruction() {
|
||||
opcode instanceof Opcode::PointerAdd
|
||||
getOpcode() instanceof Opcode::PointerAdd
|
||||
}
|
||||
}
|
||||
|
||||
class PointerSubInstruction extends PointerOffsetInstruction {
|
||||
PointerSubInstruction() {
|
||||
opcode instanceof Opcode::PointerSub
|
||||
getOpcode() instanceof Opcode::PointerSub
|
||||
}
|
||||
}
|
||||
|
||||
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
||||
PointerDiffInstruction() {
|
||||
opcode instanceof Opcode::PointerDiff
|
||||
getOpcode() instanceof Opcode::PointerDiff
|
||||
}
|
||||
}
|
||||
|
||||
class UnaryInstruction extends Instruction {
|
||||
UnaryInstruction() {
|
||||
opcode instanceof UnaryOpcode
|
||||
getOpcode() instanceof UnaryOpcode
|
||||
}
|
||||
|
||||
final Instruction getOperand() {
|
||||
@@ -906,7 +955,7 @@ class UnaryInstruction extends Instruction {
|
||||
|
||||
class ConvertInstruction extends UnaryInstruction {
|
||||
ConvertInstruction() {
|
||||
opcode instanceof Opcode::Convert
|
||||
getOpcode() instanceof Opcode::Convert
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,7 +1007,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
*/
|
||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToBaseInstruction() {
|
||||
opcode instanceof Opcode::ConvertToBase
|
||||
getOpcode() instanceof Opcode::ConvertToBase
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,7 +1017,7 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
*/
|
||||
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToVirtualBaseInstruction() {
|
||||
opcode instanceof Opcode::ConvertToVirtualBase
|
||||
getOpcode() instanceof Opcode::ConvertToVirtualBase
|
||||
}
|
||||
}
|
||||
|
||||
@@ -978,37 +1027,37 @@ class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
||||
*/
|
||||
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToDerivedInstruction() {
|
||||
opcode instanceof Opcode::ConvertToDerived
|
||||
getOpcode() instanceof Opcode::ConvertToDerived
|
||||
}
|
||||
}
|
||||
|
||||
class BitComplementInstruction extends UnaryInstruction {
|
||||
BitComplementInstruction() {
|
||||
opcode instanceof Opcode::BitComplement
|
||||
getOpcode() instanceof Opcode::BitComplement
|
||||
}
|
||||
}
|
||||
|
||||
class LogicalNotInstruction extends UnaryInstruction {
|
||||
LogicalNotInstruction() {
|
||||
opcode instanceof Opcode::LogicalNot
|
||||
getOpcode() instanceof Opcode::LogicalNot
|
||||
}
|
||||
}
|
||||
|
||||
class CompareInstruction extends BinaryInstruction {
|
||||
CompareInstruction() {
|
||||
opcode instanceof CompareOpcode
|
||||
getOpcode() instanceof CompareOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class CompareEQInstruction extends CompareInstruction {
|
||||
CompareEQInstruction() {
|
||||
opcode instanceof Opcode::CompareEQ
|
||||
getOpcode() instanceof Opcode::CompareEQ
|
||||
}
|
||||
}
|
||||
|
||||
class CompareNEInstruction extends CompareInstruction {
|
||||
CompareNEInstruction() {
|
||||
opcode instanceof Opcode::CompareNE
|
||||
getOpcode() instanceof Opcode::CompareNE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,7 +1066,7 @@ class CompareNEInstruction extends CompareInstruction {
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
getOpcode() instanceof RelationalOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1050,7 +1099,7 @@ class RelationalInstruction extends CompareInstruction {
|
||||
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
getOpcode() instanceof Opcode::CompareLT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1068,7 +1117,7 @@ class CompareLTInstruction extends RelationalInstruction {
|
||||
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() {
|
||||
opcode instanceof Opcode::CompareGT
|
||||
getOpcode() instanceof Opcode::CompareGT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1086,7 +1135,7 @@ class CompareGTInstruction extends RelationalInstruction {
|
||||
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
getOpcode() instanceof Opcode::CompareLE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1104,7 +1153,7 @@ class CompareLEInstruction extends RelationalInstruction {
|
||||
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() {
|
||||
opcode instanceof Opcode::CompareGE
|
||||
getOpcode() instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1122,7 +1171,7 @@ class CompareGEInstruction extends RelationalInstruction {
|
||||
|
||||
class SwitchInstruction extends Instruction {
|
||||
SwitchInstruction() {
|
||||
opcode instanceof Opcode::Switch
|
||||
getOpcode() instanceof Opcode::Switch
|
||||
}
|
||||
|
||||
final Instruction getExpression() {
|
||||
@@ -1145,7 +1194,7 @@ class SwitchInstruction extends Instruction {
|
||||
*/
|
||||
class CallInstruction extends Instruction {
|
||||
CallInstruction() {
|
||||
opcode instanceof Opcode::Call
|
||||
getOpcode() instanceof Opcode::Call
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1188,7 +1237,7 @@ class CallInstruction extends Instruction {
|
||||
*/
|
||||
class SideEffectInstruction extends Instruction {
|
||||
SideEffectInstruction() {
|
||||
opcode instanceof SideEffectOpcode
|
||||
getOpcode() instanceof SideEffectOpcode
|
||||
}
|
||||
|
||||
final Instruction getPrimaryInstruction() {
|
||||
@@ -1202,7 +1251,7 @@ class SideEffectInstruction extends Instruction {
|
||||
*/
|
||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
CallSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallSideEffect
|
||||
getOpcode() instanceof Opcode::CallSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1216,7 +1265,7 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
CallReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallReadSideEffect
|
||||
getOpcode() instanceof Opcode::CallReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1225,7 +1274,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectReadSideEffect
|
||||
getOpcode() instanceof Opcode::IndirectReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1234,7 +1283,7 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferReadSideEffect
|
||||
getOpcode() instanceof Opcode::BufferReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1243,7 +1292,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectWriteSideEffect
|
||||
getOpcode() instanceof Opcode::IndirectWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1257,7 +1306,7 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferWriteSideEffect
|
||||
getOpcode() instanceof Opcode::BufferWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1272,7 +1321,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectMayWriteSideEffect
|
||||
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1286,7 +1335,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferMayWriteSideEffect
|
||||
getOpcode() instanceof Opcode::BufferMayWriteSideEffect
|
||||
}
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
@@ -1298,7 +1347,7 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class ThrowInstruction extends Instruction {
|
||||
ThrowInstruction() {
|
||||
opcode instanceof ThrowOpcode
|
||||
getOpcode() instanceof ThrowOpcode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1307,7 +1356,7 @@ class ThrowInstruction extends Instruction {
|
||||
*/
|
||||
class ThrowValueInstruction extends ThrowInstruction {
|
||||
ThrowValueInstruction() {
|
||||
opcode instanceof Opcode::ThrowValue
|
||||
getOpcode() instanceof Opcode::ThrowValue
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1330,7 +1379,7 @@ class ThrowValueInstruction extends ThrowInstruction {
|
||||
*/
|
||||
class ReThrowInstruction extends ThrowInstruction {
|
||||
ReThrowInstruction() {
|
||||
opcode instanceof Opcode::ReThrow
|
||||
getOpcode() instanceof Opcode::ReThrow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1339,7 +1388,7 @@ class ReThrowInstruction extends ThrowInstruction {
|
||||
*/
|
||||
class UnwindInstruction extends Instruction {
|
||||
UnwindInstruction() {
|
||||
opcode instanceof Opcode::Unwind
|
||||
getOpcode() instanceof Opcode::Unwind
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,7 +1397,7 @@ class UnwindInstruction extends Instruction {
|
||||
*/
|
||||
class CatchInstruction extends Instruction {
|
||||
CatchInstruction() {
|
||||
opcode instanceof CatchOpcode
|
||||
getOpcode() instanceof CatchOpcode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1359,7 +1408,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
Type exceptionType;
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
opcode instanceof Opcode::CatchByType and
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
exceptionType = Construction::getInstructionExceptionType(this)
|
||||
}
|
||||
|
||||
@@ -1380,13 +1429,13 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
*/
|
||||
class CatchAnyInstruction extends CatchInstruction {
|
||||
CatchAnyInstruction() {
|
||||
opcode instanceof Opcode::CatchAny
|
||||
getOpcode() instanceof Opcode::CatchAny
|
||||
}
|
||||
}
|
||||
|
||||
class UnmodeledDefinitionInstruction extends Instruction {
|
||||
UnmodeledDefinitionInstruction() {
|
||||
opcode instanceof Opcode::UnmodeledDefinition
|
||||
getOpcode() instanceof Opcode::UnmodeledDefinition
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1399,7 +1448,7 @@ class UnmodeledDefinitionInstruction extends Instruction {
|
||||
*/
|
||||
class AliasedDefinitionInstruction extends Instruction {
|
||||
AliasedDefinitionInstruction() {
|
||||
opcode instanceof Opcode::AliasedDefinition
|
||||
getOpcode() instanceof Opcode::AliasedDefinition
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1409,7 +1458,7 @@ class AliasedDefinitionInstruction extends Instruction {
|
||||
|
||||
class UnmodeledUseInstruction extends Instruction {
|
||||
UnmodeledUseInstruction() {
|
||||
opcode instanceof Opcode::UnmodeledUse
|
||||
getOpcode() instanceof Opcode::UnmodeledUse
|
||||
}
|
||||
|
||||
override string getOperandsString() {
|
||||
@@ -1429,7 +1478,7 @@ class UnmodeledUseInstruction extends Instruction {
|
||||
*/
|
||||
class PhiInstruction extends Instruction {
|
||||
PhiInstruction() {
|
||||
opcode instanceof Opcode::Phi
|
||||
getOpcode() instanceof Opcode::Phi
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1481,7 +1530,7 @@ class PhiInstruction extends Instruction {
|
||||
*/
|
||||
class ChiInstruction extends Instruction {
|
||||
ChiInstruction() {
|
||||
opcode instanceof Opcode::Chi
|
||||
getOpcode() instanceof Opcode::Chi
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1511,7 +1560,7 @@ class ChiInstruction extends Instruction {
|
||||
*/
|
||||
class UnreachedInstruction extends Instruction {
|
||||
UnreachedInstruction() {
|
||||
opcode instanceof Opcode::Unreached
|
||||
getOpcode() instanceof Opcode::Unreached
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1521,6 +1570,6 @@ class UnreachedInstruction extends Instruction {
|
||||
*/
|
||||
class BuiltInInstruction extends Instruction {
|
||||
BuiltInInstruction() {
|
||||
opcode instanceof BuiltInOpcode
|
||||
getOpcode() instanceof BuiltInOpcode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +287,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
||||
(
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = kind.toString()
|
||||
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||
then value = kind.toString() + " (back edge)"
|
||||
else value = kind.toString()
|
||||
) or
|
||||
(
|
||||
key = "semmle.order" and
|
||||
|
||||
@@ -5,30 +5,15 @@ private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import TranslatedStmt
|
||||
private import TranslatedFunction
|
||||
|
||||
class InstructionTagType extends TInstructionTag {
|
||||
final string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
|
||||
instruction = MkInstruction(result, _)
|
||||
}
|
||||
|
||||
private TranslatedElement getInstructionTranslatedElement(
|
||||
Instruction instruction) {
|
||||
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(), _)
|
||||
InstructionTag getInstructionTag(Instruction instruction) {
|
||||
instruction = MkInstruction(_, result)
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -38,21 +23,10 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
cached newtype TInstruction =
|
||||
MkInstruction(FunctionIR funcIR, Opcode opcode, Locatable ast,
|
||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
hasInstruction(funcIR.getFunction(), opcode, ast, tag,
|
||||
resultType, isGLValue)
|
||||
MkInstruction(TranslatedElement element, InstructionTag tag) {
|
||||
element.hasInstruction(_, tag, _, _)
|
||||
}
|
||||
|
||||
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,
|
||||
Type type) {
|
||||
exists(TranslatedElement element |
|
||||
@@ -87,7 +61,7 @@ cached private module Cached {
|
||||
|
||||
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
|
||||
instruction.getTag(), tag)
|
||||
getInstructionTag(instruction), tag)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionOperandDefinition(Instruction instruction,
|
||||
@@ -101,12 +75,112 @@ cached private module Cached {
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
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) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionVariable(
|
||||
instruction.getTag())
|
||||
getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
cached Field getInstructionField(Instruction instruction) {
|
||||
@@ -117,41 +191,39 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
cached Function getInstructionFunction(Instruction instruction) {
|
||||
exists(InstructionTag tag |
|
||||
result = getInstructionTranslatedElementAndTag(instruction, tag)
|
||||
.getInstructionFunction(tag)
|
||||
)
|
||||
result = getInstructionTranslatedElement(instruction)
|
||||
.getInstructionFunction(getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
cached string getInstructionConstantValue(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction).getInstructionConstantValue(
|
||||
instruction.getTag())
|
||||
getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction).getInstructionStringLiteral(
|
||||
instruction.getTag())
|
||||
getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
cached Type getInstructionExceptionType(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction).getInstructionExceptionType(
|
||||
instruction.getTag())
|
||||
getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
cached predicate getInstructionInheritance(Instruction instruction,
|
||||
Class baseClass, Class derivedClass) {
|
||||
getInstructionTranslatedElement(instruction).getInstructionInheritance(
|
||||
instruction.getTag(), baseClass, derivedClass)
|
||||
getInstructionTag(instruction), baseClass, derivedClass)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate instructionOrigin(Instruction instruction,
|
||||
TranslatedElement element, InstructionTag tag) {
|
||||
element = getInstructionTranslatedElement(instruction) and
|
||||
tag = instruction.getTag()
|
||||
tag = getInstructionTag(instruction)
|
||||
}
|
||||
|
||||
cached int getInstructionElementSize(Instruction instruction) {
|
||||
@@ -179,12 +251,14 @@ cached private module Cached {
|
||||
import CachedForDebugging
|
||||
cached private module CachedForDebugging {
|
||||
cached string getTempVariableUniqueId(IRTempVariable var) {
|
||||
result = getTempVariableTranslatedElement(var).getId() + ":" +
|
||||
getTempVariableTagId(var.getTag())
|
||||
exists(TranslatedElement element |
|
||||
var = element.getTempVariable(_) and
|
||||
result = element.getId() + ":" + getTempVariableTagId(var.getTag())
|
||||
)
|
||||
}
|
||||
|
||||
cached string getInstructionUniqueId(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction).getId() + ":" +
|
||||
getInstructionTagId(instruction.getTag())
|
||||
getInstructionTagId(getInstructionTag(instruction))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,12 @@ newtype TInstructionTag =
|
||||
elementIsInitialized(elementIndex)
|
||||
}
|
||||
|
||||
class InstructionTag extends TInstructionTag {
|
||||
final string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a unique string for the instruction tag. Primarily used for generating
|
||||
* instruction IDs to ensure stable IR dumps.
|
||||
|
||||
@@ -255,26 +255,22 @@ abstract class TranslatedDirectCall extends TranslatedCall {
|
||||
*/
|
||||
abstract class TranslatedCallExpr extends TranslatedNonConstantExpr,
|
||||
TranslatedCall {
|
||||
Call call;
|
||||
|
||||
TranslatedCallExpr() {
|
||||
expr = call
|
||||
}
|
||||
override Call expr;
|
||||
|
||||
override final Type getCallResultType() {
|
||||
result = getResultType()
|
||||
}
|
||||
|
||||
override final predicate hasArguments() {
|
||||
exists(call.getArgument(0))
|
||||
exists(expr.getArgument(0))
|
||||
}
|
||||
|
||||
override final TranslatedExpr getQualifier() {
|
||||
result = getTranslatedExpr(call.getQualifier().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getQualifier().getFullyConverted())
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
class TranslatedExprCall extends TranslatedCallExpr {
|
||||
ExprCall exprCall;
|
||||
override ExprCall expr;
|
||||
|
||||
TranslatedExprCall() {
|
||||
expr = exprCall
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
|
||||
FunctionCall funcCall;
|
||||
|
||||
TranslatedFunctionCall() {
|
||||
expr = funcCall
|
||||
}
|
||||
override FunctionCall expr;
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
tag = CallTargetTag() and result = funcCall.getTarget()
|
||||
tag = CallTargetTag() and result = expr.getTarget()
|
||||
}
|
||||
|
||||
override predicate hasReadSideEffect() {
|
||||
not funcCall.getTarget().(SideEffectFunction).neverReadsMemory()
|
||||
not expr.getTarget().(SideEffectFunction).neverReadsMemory()
|
||||
}
|
||||
|
||||
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 {
|
||||
TranslatedStructorCall() {
|
||||
funcCall instanceof ConstructorCall or
|
||||
funcCall instanceof DestructorCall
|
||||
expr instanceof ConstructorCall or
|
||||
expr instanceof DestructorCall
|
||||
}
|
||||
|
||||
override Instruction getQualifierResult() {
|
||||
|
||||
@@ -75,11 +75,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition,
|
||||
}
|
||||
|
||||
class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
||||
ParenthesisExpr paren;
|
||||
|
||||
TranslatedParenthesisCondition() {
|
||||
paren = expr
|
||||
}
|
||||
override ParenthesisExpr expr;
|
||||
|
||||
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
@@ -92,16 +88,12 @@ class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
||||
}
|
||||
|
||||
final override TranslatedCondition getOperand() {
|
||||
result = getTranslatedCondition(paren.getExpr())
|
||||
result = getTranslatedCondition(expr.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedNotCondition extends TranslatedFlexibleCondition {
|
||||
NotExpr notExpr;
|
||||
|
||||
TranslatedNotCondition() {
|
||||
notExpr = expr
|
||||
}
|
||||
override NotExpr expr;
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
@@ -114,7 +106,7 @@ class TranslatedNotCondition extends TranslatedFlexibleCondition {
|
||||
}
|
||||
|
||||
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
|
||||
TranslatedNativeCondition, ConditionContext {
|
||||
BinaryLogicalOperation op;
|
||||
|
||||
TranslatedBinaryLogicalOperation() {
|
||||
op = expr
|
||||
}
|
||||
override BinaryLogicalOperation expr;
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getLeftOperand() or
|
||||
@@ -157,17 +145,17 @@ abstract class TranslatedBinaryLogicalOperation extends
|
||||
}
|
||||
|
||||
final TranslatedCondition getLeftOperand() {
|
||||
result = getTranslatedCondition(op.getLeftOperand().getFullyConverted())
|
||||
result = getTranslatedCondition(expr.getLeftOperand().getFullyConverted())
|
||||
}
|
||||
|
||||
final TranslatedCondition getRightOperand() {
|
||||
result = getTranslatedCondition(op.getRightOperand().getFullyConverted())
|
||||
result = getTranslatedCondition(expr.getRightOperand().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
|
||||
TranslatedLogicalAndExpr() {
|
||||
op instanceof LogicalAndExpr
|
||||
expr instanceof LogicalAndExpr
|
||||
}
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
@@ -188,9 +176,7 @@ class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
|
||||
}
|
||||
|
||||
class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
|
||||
TranslatedLogicalOrExpr() {
|
||||
op instanceof LogicalOrExpr
|
||||
}
|
||||
override LogicalOrExpr expr;
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
(child = getLeftOperand() or child = getRightOperand()) and
|
||||
|
||||
@@ -9,6 +9,7 @@ private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
private import TranslatedFunction
|
||||
private import TranslatedStmt
|
||||
private import IRConstruction
|
||||
|
||||
/**
|
||||
* Gets the built-in `int` type.
|
||||
@@ -17,53 +18,42 @@ Type getIntType() {
|
||||
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
|
||||
* they were explicit nodes in the expression tree, rather than as implicit
|
||||
* nodes as in the regular AST representation.
|
||||
*/
|
||||
private Element getRealParent(Expr expr) {
|
||||
if expr.hasConversion() then (
|
||||
// The expression has a conversion, so treat that as its parent
|
||||
result = expr.getConversion()
|
||||
)
|
||||
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
|
||||
)
|
||||
result = expr.getParentWithConversions()
|
||||
or
|
||||
result.(Destructor).getADestruction() = expr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` and all of its descendants should be ignored for the purposes
|
||||
* of IR generation due to some property of `expr` itself. Unlike
|
||||
* `ignoreExpr()`, this predicate does not ignore an expression solely because
|
||||
* it is a descendant of an ignored element.
|
||||
* Holds if `expr` is a constant of a type that can be replaced directly with
|
||||
* its value in the IR. This does not include address constants as we have no
|
||||
* means to express those as QL values.
|
||||
*/
|
||||
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) {
|
||||
// Ignore parentless expressions
|
||||
not exists(getRealParent(expr)) or
|
||||
isOrphan(expr) or
|
||||
// Ignore the constants in SwitchCase, since their values are embedded in the
|
||||
// CaseEdge.
|
||||
getRealParent(expr) instanceof SwitchCase or
|
||||
// Ignore descendants of constant expressions, since we'll just substitute the
|
||||
// constant value.
|
||||
getRealParent(expr).(Expr).isConstant() or
|
||||
isIRConstant(getRealParent(expr)) or
|
||||
// The `DestructorCall` node for a `DestructorFieldDestruction` has a `FieldAccess`
|
||||
// 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
|
||||
@@ -73,7 +63,8 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
// REVIEW: Ignore initializers for `NewArrayExpr` until we determine how to
|
||||
// represent them.
|
||||
newExpr.getInitializer().getFullyConverted() = expr
|
||||
)
|
||||
) or
|
||||
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +85,7 @@ private predicate ignoreExprOnly(Expr expr) {
|
||||
*/
|
||||
private predicate ignoreExpr(Expr expr) {
|
||||
ignoreExprOnly(expr) or
|
||||
ignoreExprAndDescendants(getRealParent*(expr))
|
||||
ignoreExprAndDescendants(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +137,7 @@ private predicate translateStmt(Stmt stmt) {
|
||||
*/
|
||||
private predicate isNativeCondition(Expr expr) {
|
||||
expr instanceof BinaryLogicalOperation and
|
||||
not expr.isConstant()
|
||||
not isIRConstant(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,7 +150,7 @@ private predicate isFlexibleCondition(Expr expr) {
|
||||
expr instanceof NotExpr
|
||||
) 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`.
|
||||
*/
|
||||
final Instruction getInstruction(InstructionTag tag) {
|
||||
result.getAST() = getAST() and
|
||||
result.getTag() = tag
|
||||
getInstructionTranslatedElement(result) = this and
|
||||
getInstructionTag(result) = tag
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -646,7 +637,8 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
*/
|
||||
final IRTempVariable getTempVariable(TempVariableTag tag) {
|
||||
result.getAST() = getAST() and
|
||||
result.getTag() = tag
|
||||
result.getTag() = tag and
|
||||
hasTempVariable(tag, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -369,11 +369,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
||||
}
|
||||
|
||||
class TranslatedCommaExpr extends TranslatedNonConstantExpr {
|
||||
CommaExpr comma;
|
||||
|
||||
TranslatedCommaExpr() {
|
||||
comma = expr
|
||||
}
|
||||
override CommaExpr expr;
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getLeftOperand().getFirstInstruction()
|
||||
@@ -412,20 +408,16 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
private TranslatedExpr getLeftOperand() {
|
||||
result = getTranslatedExpr(comma.getLeftOperand().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getLeftOperand().getFullyConverted())
|
||||
}
|
||||
|
||||
private TranslatedExpr getRightOperand() {
|
||||
result = getTranslatedExpr(comma.getRightOperand().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getRightOperand().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
CrementOperation op;
|
||||
|
||||
TranslatedCrementOperation() {
|
||||
op = expr
|
||||
}
|
||||
override CrementOperation expr;
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getOperand()
|
||||
@@ -564,7 +556,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
final TranslatedExpr getOperand() {
|
||||
result = getTranslatedExpr(op.getOperand().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getOperand().getFullyConverted())
|
||||
}
|
||||
|
||||
final Opcode getOpcode() {
|
||||
@@ -572,14 +564,14 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
resultType = getResultType() and
|
||||
(
|
||||
(
|
||||
op instanceof IncrementOperation and
|
||||
expr instanceof IncrementOperation and
|
||||
if resultType instanceof PointerType then
|
||||
result instanceof Opcode::PointerAdd
|
||||
else
|
||||
result instanceof Opcode::Add
|
||||
) or
|
||||
(
|
||||
op instanceof DecrementOperation and
|
||||
expr instanceof DecrementOperation and
|
||||
if resultType instanceof PointerType then
|
||||
result instanceof Opcode::PointerSub
|
||||
else
|
||||
@@ -591,9 +583,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
class TranslatedPrefixCrementOperation extends TranslatedCrementOperation {
|
||||
TranslatedPrefixCrementOperation() {
|
||||
op instanceof PrefixCrementOperation
|
||||
}
|
||||
override PrefixCrementOperation expr;
|
||||
|
||||
override Instruction getResult() {
|
||||
if expr.isPRValueCategory() then (
|
||||
@@ -612,9 +602,7 @@ class TranslatedPrefixCrementOperation extends TranslatedCrementOperation {
|
||||
}
|
||||
|
||||
class TranslatedPostfixCrementOperation extends TranslatedCrementOperation {
|
||||
TranslatedPostfixCrementOperation() {
|
||||
op instanceof PostfixCrementOperation
|
||||
}
|
||||
override PostfixCrementOperation expr;
|
||||
|
||||
override Instruction getResult() {
|
||||
// The result is a prvalue copy of the original value
|
||||
@@ -623,11 +611,7 @@ class TranslatedPostfixCrementOperation extends TranslatedCrementOperation {
|
||||
}
|
||||
|
||||
class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
||||
ArrayExpr arrayExpr;
|
||||
|
||||
TranslatedArrayExpr() {
|
||||
arrayExpr = expr
|
||||
}
|
||||
override ArrayExpr expr;
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getBaseOperand().getFirstInstruction()
|
||||
@@ -689,11 +673,11 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
private TranslatedExpr getBaseOperand() {
|
||||
result = getTranslatedExpr(arrayExpr.getArrayBase().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getArrayBase().getFullyConverted())
|
||||
}
|
||||
|
||||
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 {
|
||||
UnaryOperation op;
|
||||
override UnaryOperation expr;
|
||||
|
||||
TranslatedTransparentUnaryOperation() {
|
||||
op = expr and
|
||||
(
|
||||
// *p is the same as p until the result is loaded.
|
||||
expr instanceof PointerDereferenceExpr or
|
||||
@@ -747,31 +730,28 @@ class TranslatedTransparentUnaryOperation extends TranslatedTransparentExpr {
|
||||
}
|
||||
|
||||
override TranslatedExpr getOperand() {
|
||||
result = getTranslatedExpr(op.getOperand().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getOperand().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedTransparentConversion extends TranslatedTransparentExpr {
|
||||
Conversion conv;
|
||||
override Conversion expr;
|
||||
|
||||
TranslatedTransparentConversion() {
|
||||
conv = expr and
|
||||
(
|
||||
conv instanceof ParenthesisExpr or
|
||||
conv instanceof ReferenceDereferenceExpr or
|
||||
conv instanceof ReferenceToExpr
|
||||
expr instanceof ParenthesisExpr or
|
||||
expr instanceof ReferenceDereferenceExpr or
|
||||
expr instanceof ReferenceToExpr
|
||||
)
|
||||
}
|
||||
|
||||
override TranslatedExpr getOperand() {
|
||||
result = getTranslatedExpr(conv.getExpr())
|
||||
result = getTranslatedExpr(expr.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedThisExpr extends TranslatedNonConstantExpr {
|
||||
TranslatedThisExpr() {
|
||||
expr instanceof ThisExpr
|
||||
}
|
||||
override ThisExpr expr;
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
none()
|
||||
@@ -817,18 +797,14 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr {
|
||||
VariableAccess access;
|
||||
|
||||
TranslatedVariableAccess() {
|
||||
access = expr
|
||||
}
|
||||
override VariableAccess expr;
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getQualifier() // Might not exist
|
||||
}
|
||||
|
||||
final TranslatedExpr getQualifier() {
|
||||
result = getTranslatedExpr(access.getQualifier().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getQualifier().getFullyConverted())
|
||||
}
|
||||
|
||||
override Instruction getResult() {
|
||||
@@ -874,18 +850,13 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getIRUserVariable(access.getEnclosingFunction(),
|
||||
access.getTarget())
|
||||
result = getIRUserVariable(expr.getEnclosingFunction(),
|
||||
expr.getTarget())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedFieldAccess extends TranslatedVariableAccess {
|
||||
FieldAccess fieldAccess;
|
||||
|
||||
TranslatedFieldAccess() {
|
||||
//REVIEW: Implicit 'this'?
|
||||
fieldAccess = access
|
||||
}
|
||||
override FieldAccess expr;
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getQualifier().getFirstInstruction()
|
||||
@@ -908,16 +879,12 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
|
||||
|
||||
override Field getInstructionField(InstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = access.getTarget()
|
||||
result = expr.getTarget()
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
||||
FunctionAccess access;
|
||||
|
||||
TranslatedFunctionAccess() {
|
||||
access = expr
|
||||
}
|
||||
override FunctionAccess expr;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
none()
|
||||
@@ -942,13 +909,13 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
||||
Type resultType, boolean isGLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::FunctionAddress and
|
||||
resultType = access.getType().getUnspecifiedType() and
|
||||
resultType = expr.getType().getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
}
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = access.getTarget()
|
||||
result = expr.getTarget()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
@@ -962,7 +929,7 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
||||
abstract class TranslatedNonConstantExpr extends TranslatedCoreExpr, TTranslatedValueExpr {
|
||||
TranslatedNonConstantExpr() {
|
||||
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 {
|
||||
TranslatedConstantExpr() {
|
||||
this = TTranslatedValueExpr(expr) and
|
||||
expr.isConstant()
|
||||
isIRConstant(expr)
|
||||
}
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
@@ -1035,15 +1002,11 @@ class TranslatedArithmeticLiteral extends TranslatedConstantExpr {
|
||||
}
|
||||
|
||||
class TranslatedStringLiteral extends TranslatedConstantExpr {
|
||||
StringLiteral stringLiteral;
|
||||
|
||||
TranslatedStringLiteral() {
|
||||
stringLiteral = expr
|
||||
}
|
||||
override StringLiteral expr;
|
||||
|
||||
override StringLiteral getInstructionStringLiteral(InstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = stringLiteral
|
||||
result = expr
|
||||
}
|
||||
|
||||
override Opcode getOpcode() {
|
||||
@@ -1127,11 +1090,7 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr {
|
||||
}
|
||||
|
||||
abstract class TranslatedConversion extends TranslatedNonConstantExpr {
|
||||
Conversion conv;
|
||||
|
||||
TranslatedConversion() {
|
||||
conv = expr
|
||||
}
|
||||
override Conversion expr;
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getOperand().getFirstInstruction()
|
||||
@@ -1193,15 +1152,15 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
|
||||
*/
|
||||
class TranslatedSimpleConversion extends TranslatedSingleInstructionConversion {
|
||||
TranslatedSimpleConversion() {
|
||||
conv instanceof ArithmeticConversion or
|
||||
conv instanceof PointerConversion or
|
||||
conv instanceof PointerToMemberConversion or
|
||||
conv instanceof PointerToIntegralConversion or
|
||||
conv instanceof IntegralToPointerConversion or
|
||||
conv instanceof GlvalueConversion or
|
||||
conv instanceof ArrayToPointerConversion or
|
||||
conv instanceof PrvalueAdjustmentConversion or
|
||||
conv instanceof VoidConversion
|
||||
expr instanceof ArithmeticConversion or
|
||||
expr instanceof PointerConversion or
|
||||
expr instanceof PointerToMemberConversion or
|
||||
expr instanceof PointerToIntegralConversion or
|
||||
expr instanceof IntegralToPointerConversion or
|
||||
expr instanceof GlvalueConversion or
|
||||
expr instanceof ArrayToPointerConversion or
|
||||
expr instanceof PrvalueAdjustmentConversion or
|
||||
expr instanceof VoidConversion
|
||||
}
|
||||
|
||||
override Opcode getOpcode() {
|
||||
@@ -1214,7 +1173,7 @@ class TranslatedSimpleConversion extends TranslatedSingleInstructionConversion {
|
||||
*/
|
||||
class TranslatedDynamicCast extends TranslatedSingleInstructionConversion {
|
||||
TranslatedDynamicCast() {
|
||||
conv instanceof DynamicCast
|
||||
expr instanceof DynamicCast
|
||||
}
|
||||
|
||||
override Opcode getOpcode() {
|
||||
@@ -1237,22 +1196,19 @@ class TranslatedDynamicCast extends TranslatedSingleInstructionConversion {
|
||||
* expression.
|
||||
*/
|
||||
class TranslatedInheritanceConversion extends TranslatedSingleInstructionConversion {
|
||||
InheritanceConversion inheritanceConv;
|
||||
override InheritanceConversion expr;
|
||||
|
||||
TranslatedInheritanceConversion() {
|
||||
inheritanceConv = conv
|
||||
}
|
||||
|
||||
override predicate getInstructionInheritance(InstructionTag tag, Class baseClass,
|
||||
Class derivedClass) {
|
||||
tag = OnlyInstructionTag() and
|
||||
baseClass = inheritanceConv.getBaseClass() and
|
||||
derivedClass = inheritanceConv.getDerivedClass()
|
||||
baseClass = expr.getBaseClass() and
|
||||
derivedClass = expr.getDerivedClass()
|
||||
}
|
||||
|
||||
override Opcode getOpcode() {
|
||||
if inheritanceConv instanceof BaseClassConversion then (
|
||||
if inheritanceConv.(BaseClassConversion).isVirtual() then
|
||||
if expr instanceof BaseClassConversion then (
|
||||
if expr.(BaseClassConversion).isVirtual() then
|
||||
result instanceof Opcode::ConvertToVirtualBase
|
||||
else
|
||||
result instanceof Opcode::ConvertToBase
|
||||
@@ -1267,9 +1223,7 @@ class TranslatedInheritanceConversion extends TranslatedSingleInstructionConvers
|
||||
* a comparison with zero.
|
||||
*/
|
||||
class TranslatedBoolConversion extends TranslatedConversion {
|
||||
TranslatedBoolConversion() {
|
||||
conv instanceof BoolConversion
|
||||
}
|
||||
override BoolConversion expr;
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
@@ -1471,11 +1425,7 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
|
||||
}
|
||||
|
||||
abstract class TranslatedAssignment extends TranslatedNonConstantExpr {
|
||||
Assignment assign;
|
||||
|
||||
TranslatedAssignment() {
|
||||
expr = assign
|
||||
}
|
||||
override Assignment expr;
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getLeftOperand() or
|
||||
@@ -1506,20 +1456,20 @@ abstract class TranslatedAssignment extends TranslatedNonConstantExpr {
|
||||
|
||||
final TranslatedExpr getLeftOperand() {
|
||||
result = getTranslatedExpr(
|
||||
assign.getLValue().getFullyConverted()
|
||||
expr.getLValue().getFullyConverted()
|
||||
)
|
||||
}
|
||||
|
||||
final TranslatedExpr getRightOperand() {
|
||||
result = getTranslatedExpr(
|
||||
assign.getRValue().getFullyConverted()
|
||||
expr.getRValue().getFullyConverted()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedAssignExpr extends TranslatedAssignment {
|
||||
TranslatedAssignExpr() {
|
||||
assign instanceof AssignExpr
|
||||
expr instanceof AssignExpr
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
@@ -1570,11 +1520,7 @@ class TranslatedAssignExpr extends TranslatedAssignment {
|
||||
}
|
||||
|
||||
class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
AssignOperation assignOp;
|
||||
|
||||
TranslatedAssignOperation() {
|
||||
expr = assignOp
|
||||
}
|
||||
override AssignOperation expr;
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
@@ -1629,10 +1575,10 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
}
|
||||
|
||||
private Type getConvertedLeftOperandType() {
|
||||
if(assignOp instanceof AssignLShiftExpr or
|
||||
assignOp instanceof AssignRShiftExpr or
|
||||
assignOp instanceof AssignPointerAddExpr or
|
||||
assignOp instanceof AssignPointerSubExpr) then (
|
||||
if(expr instanceof AssignLShiftExpr or
|
||||
expr instanceof AssignRShiftExpr or
|
||||
expr instanceof AssignPointerAddExpr or
|
||||
expr instanceof AssignPointerSubExpr) then (
|
||||
// No need to convert for a shift. Technically, the left side should
|
||||
// undergo integral promotion, and then the result would be converted back
|
||||
// to the destination type. There's not much point to this, though,
|
||||
@@ -1652,18 +1598,18 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
}
|
||||
|
||||
private Opcode getOpcode() {
|
||||
assignOp instanceof AssignAddExpr and result instanceof Opcode::Add or
|
||||
assignOp instanceof AssignSubExpr and result instanceof Opcode::Sub or
|
||||
assignOp instanceof AssignMulExpr and result instanceof Opcode::Mul or
|
||||
assignOp instanceof AssignDivExpr and result instanceof Opcode::Div or
|
||||
assignOp instanceof AssignRemExpr and result instanceof Opcode::Rem or
|
||||
assignOp instanceof AssignAndExpr and result instanceof Opcode::BitAnd or
|
||||
assignOp instanceof AssignOrExpr and result instanceof Opcode::BitOr or
|
||||
assignOp instanceof AssignXorExpr and result instanceof Opcode::BitXor or
|
||||
assignOp instanceof AssignLShiftExpr and result instanceof Opcode::ShiftLeft or
|
||||
assignOp instanceof AssignRShiftExpr and result instanceof Opcode::ShiftRight or
|
||||
assignOp instanceof AssignPointerAddExpr and result instanceof Opcode::PointerAdd or
|
||||
assignOp instanceof AssignPointerSubExpr and result instanceof Opcode::PointerSub
|
||||
expr instanceof AssignAddExpr and result instanceof Opcode::Add or
|
||||
expr instanceof AssignSubExpr and result instanceof Opcode::Sub or
|
||||
expr instanceof AssignMulExpr and result instanceof Opcode::Mul or
|
||||
expr instanceof AssignDivExpr and result instanceof Opcode::Div or
|
||||
expr instanceof AssignRemExpr and result instanceof Opcode::Rem or
|
||||
expr instanceof AssignAndExpr and result instanceof Opcode::BitAnd or
|
||||
expr instanceof AssignOrExpr and result instanceof Opcode::BitOr or
|
||||
expr instanceof AssignXorExpr and result instanceof Opcode::BitXor or
|
||||
expr instanceof AssignLShiftExpr and result instanceof Opcode::ShiftLeft or
|
||||
expr instanceof AssignRShiftExpr and result instanceof Opcode::ShiftRight or
|
||||
expr instanceof AssignPointerAddExpr and result instanceof Opcode::PointerAdd or
|
||||
expr instanceof AssignPointerSubExpr and result instanceof Opcode::PointerSub
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
@@ -1779,15 +1725,14 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
*/
|
||||
abstract class TranslatedAllocationSize extends TranslatedExpr,
|
||||
TTranslatedAllocationSize {
|
||||
NewOrNewArrayExpr newExpr;
|
||||
override NewOrNewArrayExpr expr;
|
||||
|
||||
TranslatedAllocationSize() {
|
||||
this = TTranslatedAllocationSize(newExpr) and
|
||||
expr = newExpr
|
||||
this = TTranslatedAllocationSize(expr)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Allocation size for " + newExpr.toString()
|
||||
result = "Allocation size for " + expr.toString()
|
||||
}
|
||||
|
||||
override final predicate producesExprResult() {
|
||||
@@ -1812,7 +1757,7 @@ TranslatedAllocationSize getTranslatedAllocationSize(NewOrNewArrayExpr newExpr)
|
||||
*/
|
||||
class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
||||
TranslatedConstantAllocationSize() {
|
||||
not exists(newExpr.(NewArrayExpr).getExtent())
|
||||
not exists(expr.(NewArrayExpr).getExtent())
|
||||
}
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
@@ -1823,7 +1768,7 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
||||
Type resultType, boolean isGLValue) {
|
||||
tag = AllocationSizeTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = newExpr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
|
||||
resultType = expr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
|
||||
isGLValue = false
|
||||
}
|
||||
|
||||
@@ -1844,7 +1789,7 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
|
||||
|
||||
override final string getInstructionConstantValue(InstructionTag tag) {
|
||||
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.
|
||||
*/
|
||||
class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
||||
NewArrayExpr newArrayExpr;
|
||||
override NewArrayExpr expr;
|
||||
|
||||
TranslatedNonConstantAllocationSize() {
|
||||
newArrayExpr = newExpr and
|
||||
exists(newArrayExpr.getExtent())
|
||||
exists(expr.getExtent())
|
||||
}
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
@@ -1870,7 +1814,7 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
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.
|
||||
tag = AllocationExtentConvertTag() and opcode instanceof Opcode::Convert or
|
||||
@@ -1909,7 +1853,7 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
||||
|
||||
override final string getInstructionConstantValue(InstructionTag tag) {
|
||||
tag = AllocationElementSizeTag() and
|
||||
result = newArrayExpr.getAllocatedElementType().getSize().toString()
|
||||
result = expr.getAllocatedElementType().getSize().toString()
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
@@ -1929,7 +1873,7 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
||||
}
|
||||
|
||||
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,
|
||||
TranslatedDirectCall {
|
||||
NewOrNewArrayExpr newExpr;
|
||||
override NewOrNewArrayExpr expr;
|
||||
|
||||
TranslatedAllocatorCall() {
|
||||
this = TTranslatedAllocatorCall(newExpr) and
|
||||
expr = newExpr
|
||||
this = TTranslatedAllocatorCall(expr)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Allocator call for " + newExpr.toString()
|
||||
result = "Allocator call for " + expr.toString()
|
||||
}
|
||||
|
||||
override final predicate producesExprResult() {
|
||||
@@ -1955,11 +1898,11 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
|
||||
}
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
tag = CallTargetTag() and result = newExpr.getAllocator()
|
||||
tag = CallTargetTag() and result = expr.getAllocator()
|
||||
}
|
||||
|
||||
override final Type getCallResultType() {
|
||||
result = newExpr.getAllocator().getType().getUnspecifiedType()
|
||||
result = expr.getAllocator().getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
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
|
||||
// case.
|
||||
if index = 0 then
|
||||
result = getTranslatedAllocationSize(newExpr)
|
||||
else if(index = 1 and newExpr.hasAlignedAllocation()) then
|
||||
result = getTranslatedExpr(newExpr.getAlignmentArgument())
|
||||
result = getTranslatedAllocationSize(expr)
|
||||
else if(index = 1 and expr.hasAlignedAllocation()) then
|
||||
result = getTranslatedExpr(expr.getAlignmentArgument())
|
||||
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,
|
||||
StructorCallContext {
|
||||
DestructorFieldDestruction destruction;
|
||||
|
||||
TranslatedDestructorFieldDestruction() {
|
||||
destruction = expr
|
||||
}
|
||||
override DestructorFieldDestruction expr;
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getDestructorCall()
|
||||
@@ -2023,7 +1962,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
|
||||
Type resultType, boolean isGLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::FieldAddress and
|
||||
resultType = destruction.getTarget().getType().getUnspecifiedType() and
|
||||
resultType = expr.getTarget().getType().getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
}
|
||||
|
||||
@@ -2050,12 +1989,12 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
|
||||
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getTranslatedFunction(destruction.getEnclosingFunction()).getInitializeThisInstruction()
|
||||
result = getTranslatedFunction(expr.getEnclosingFunction()).getInitializeThisInstruction()
|
||||
}
|
||||
|
||||
override final Field getInstructionField(InstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = destruction.getTarget()
|
||||
result = expr.getTarget()
|
||||
}
|
||||
|
||||
override final Instruction getReceiver() {
|
||||
@@ -2063,17 +2002,13 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
|
||||
}
|
||||
|
||||
private TranslatedExpr getDestructorCall() {
|
||||
result = getTranslatedExpr(destruction.getExpr())
|
||||
result = getTranslatedExpr(expr.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
ConditionContext {
|
||||
ConditionalExpr condExpr;
|
||||
|
||||
TranslatedConditionalExpr() {
|
||||
condExpr = expr
|
||||
}
|
||||
override ConditionalExpr expr;
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getCondition() or
|
||||
@@ -2256,29 +2191,29 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
}
|
||||
|
||||
private TranslatedCondition getCondition() {
|
||||
result = getTranslatedCondition(condExpr.getCondition().getFullyConverted())
|
||||
result = getTranslatedCondition(expr.getCondition().getFullyConverted())
|
||||
}
|
||||
|
||||
private TranslatedExpr getThen() {
|
||||
result = getTranslatedExpr(condExpr.getThen().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getThen().getFullyConverted())
|
||||
}
|
||||
|
||||
private TranslatedExpr getElse() {
|
||||
result = getTranslatedExpr(condExpr.getElse().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getElse().getFullyConverted())
|
||||
}
|
||||
|
||||
private predicate thenIsVoid() {
|
||||
getThen().getResultType() instanceof VoidType or
|
||||
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
|
||||
// thrown, rather than `void`. Handle that case here.
|
||||
condExpr.getThen() instanceof ThrowExpr
|
||||
expr.getThen() instanceof ThrowExpr
|
||||
}
|
||||
|
||||
private predicate elseIsVoid() {
|
||||
getElse().getResultType() instanceof VoidType or
|
||||
// A `ThrowExpr.getType()` incorrectly returns the type of exception being
|
||||
// thrown, rather than `void`. Handle that case here.
|
||||
condExpr.getElse() instanceof ThrowExpr
|
||||
expr.getElse() instanceof ThrowExpr
|
||||
}
|
||||
|
||||
private predicate resultIsVoid() {
|
||||
@@ -2290,11 +2225,8 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
* IR translation of a `throw` expression.
|
||||
*/
|
||||
abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
||||
ThrowExpr throw;
|
||||
override ThrowExpr expr;
|
||||
|
||||
TranslatedThrowExpr() {
|
||||
throw = expr
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
@@ -2325,7 +2257,7 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
||||
class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
||||
InitializationContext {
|
||||
TranslatedThrowValueExpr() {
|
||||
not throw instanceof ReThrowExpr
|
||||
not expr instanceof ReThrowExpr
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
@@ -2362,7 +2294,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getIRTempVariable(throw, ThrowTempVar())
|
||||
result = getIRTempVariable(expr, ThrowTempVar())
|
||||
}
|
||||
|
||||
override final predicate hasTempVariable(TempVariableTag tag, Type type) {
|
||||
@@ -2395,7 +2327,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
||||
|
||||
TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(
|
||||
throw.getExpr().getFullyConverted())
|
||||
expr.getExpr().getFullyConverted())
|
||||
}
|
||||
|
||||
override final Opcode getThrowOpcode() {
|
||||
@@ -2403,7 +2335,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
||||
}
|
||||
|
||||
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;`).
|
||||
*/
|
||||
class TranslatedReThrowExpr extends TranslatedThrowExpr {
|
||||
TranslatedReThrowExpr() {
|
||||
throw instanceof ReThrowExpr
|
||||
}
|
||||
override ReThrowExpr expr;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
none()
|
||||
@@ -2493,9 +2423,7 @@ abstract class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
||||
* The IR translation of a `BuiltInVarArgsStart` expression.
|
||||
*/
|
||||
class TranslatedVarArgsStart extends TranslatedBuiltInOperation {
|
||||
TranslatedVarArgsStart() {
|
||||
expr instanceof BuiltInVarArgsStart
|
||||
}
|
||||
override BuiltInVarArgsStart expr;
|
||||
|
||||
override final Opcode getOpcode() {
|
||||
result instanceof Opcode::VarArgsStart
|
||||
@@ -2506,9 +2434,7 @@ class TranslatedVarArgsStart extends TranslatedBuiltInOperation {
|
||||
* The IR translation of a `BuiltInVarArgsEnd` expression.
|
||||
*/
|
||||
class TranslatedVarArgsEnd extends TranslatedBuiltInOperation {
|
||||
TranslatedVarArgsEnd() {
|
||||
expr instanceof BuiltInVarArgsEnd
|
||||
}
|
||||
override BuiltInVarArgsEnd expr;
|
||||
|
||||
override final Opcode getOpcode() {
|
||||
result instanceof Opcode::VarArgsEnd
|
||||
@@ -2519,9 +2445,7 @@ class TranslatedVarArgsEnd extends TranslatedBuiltInOperation {
|
||||
* The IR translation of a `BuiltInVarArg` expression.
|
||||
*/
|
||||
class TranslatedVarArg extends TranslatedBuiltInOperation {
|
||||
TranslatedVarArg() {
|
||||
expr instanceof BuiltInVarArg
|
||||
}
|
||||
override BuiltInVarArg expr;
|
||||
|
||||
override final Opcode getOpcode() {
|
||||
result instanceof Opcode::VarArg
|
||||
@@ -2532,9 +2456,7 @@ class TranslatedVarArg extends TranslatedBuiltInOperation {
|
||||
* The IR translation of a `BuiltInVarArgCopy` expression.
|
||||
*/
|
||||
class TranslatedVarArgCopy extends TranslatedBuiltInOperation {
|
||||
TranslatedVarArgCopy() {
|
||||
expr instanceof BuiltInVarArgCopy
|
||||
}
|
||||
override BuiltInVarArgCopy expr;
|
||||
|
||||
override final Opcode getOpcode() {
|
||||
result instanceof Opcode::VarArgCopy
|
||||
@@ -2546,11 +2468,7 @@ class TranslatedVarArgCopy extends TranslatedBuiltInOperation {
|
||||
*/
|
||||
abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
|
||||
InitializationContext {
|
||||
NewOrNewArrayExpr newExpr;
|
||||
|
||||
TranslatedNewOrNewArrayExpr() {
|
||||
expr = newExpr
|
||||
}
|
||||
override NewOrNewArrayExpr expr;
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getAllocatorCall() or
|
||||
@@ -2600,7 +2518,7 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
|
||||
}
|
||||
|
||||
private TranslatedAllocatorCall getAllocatorCall() {
|
||||
result = getTranslatedAllocatorCall(newExpr)
|
||||
result = getTranslatedAllocatorCall(expr)
|
||||
}
|
||||
|
||||
abstract TranslatedInitialization getInitialization();
|
||||
@@ -2610,16 +2528,14 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
|
||||
* The IR translation of a `new` expression.
|
||||
*/
|
||||
class TranslatedNewExpr extends TranslatedNewOrNewArrayExpr {
|
||||
TranslatedNewExpr() {
|
||||
newExpr instanceof NewExpr
|
||||
}
|
||||
override NewExpr expr;
|
||||
|
||||
override final Type getTargetType() {
|
||||
result = newExpr.getAllocatedType().getUnspecifiedType()
|
||||
result = expr.getAllocatedType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
|
||||
TranslatedNewArrayExpr() {
|
||||
newExpr instanceof NewArrayExpr
|
||||
}
|
||||
override NewArrayExpr expr;
|
||||
|
||||
override final Type getTargetType() {
|
||||
result = newExpr.getAllocatedType().getUnspecifiedType()
|
||||
result = expr.getAllocatedType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
override final TranslatedInitialization getInitialization() {
|
||||
@@ -2650,11 +2564,7 @@ class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
|
||||
* ```
|
||||
*/
|
||||
class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr {
|
||||
ConditionDeclExpr condDeclExpr;
|
||||
|
||||
TranslatedConditionDeclExpr() {
|
||||
condDeclExpr = expr
|
||||
}
|
||||
override ConditionDeclExpr expr;
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
result = getDecl().getFirstInstruction()
|
||||
@@ -2687,10 +2597,10 @@ class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
private TranslatedConditionDecl getDecl() {
|
||||
result = getTranslatedConditionDecl(condDeclExpr)
|
||||
result = getTranslatedConditionDecl(expr)
|
||||
}
|
||||
|
||||
private TranslatedExpr getConditionExpr() {
|
||||
result = getTranslatedExpr(condDeclExpr.getVariableAccess().getFullyConverted())
|
||||
result = getTranslatedExpr(expr.getVariableAccess().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,16 +120,12 @@ abstract class TranslatedListInitialization extends TranslatedInitialization,
|
||||
class TranslatedClassListInitialization extends
|
||||
TranslatedListInitialization
|
||||
{
|
||||
ClassAggregateLiteral initList;
|
||||
|
||||
TranslatedClassListInitialization() {
|
||||
initList = expr
|
||||
}
|
||||
override ClassAggregateLiteral expr;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
exists(TranslatedFieldInitialization fieldInit |
|
||||
result = fieldInit and
|
||||
fieldInit = getTranslatedFieldInitialization(initList, _) and
|
||||
fieldInit = getTranslatedFieldInitialization(expr, _) and
|
||||
fieldInit.getOrder() = id
|
||||
)
|
||||
}
|
||||
@@ -141,16 +137,12 @@ class TranslatedClassListInitialization extends
|
||||
*/
|
||||
class TranslatedArrayListInitialization extends
|
||||
TranslatedListInitialization {
|
||||
ArrayAggregateLiteral initList;
|
||||
|
||||
TranslatedArrayListInitialization() {
|
||||
initList = expr
|
||||
}
|
||||
override ArrayAggregateLiteral expr;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
// The children are in initialization order
|
||||
result = rank[id + 1](TranslatedElementInitialization init |
|
||||
init.getInitList() = initList |
|
||||
init.getInitList() = expr |
|
||||
init order by init.getElementIndex()
|
||||
)
|
||||
}
|
||||
@@ -231,9 +223,7 @@ class TranslatedSimpleDirectInitialization extends
|
||||
*/
|
||||
class TranslatedStringLiteralInitialization extends
|
||||
TranslatedDirectInitialization {
|
||||
TranslatedStringLiteralInitialization() {
|
||||
expr instanceof StringLiteral
|
||||
}
|
||||
override StringLiteral expr;
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
@@ -434,11 +424,7 @@ class TranslatedStringLiteralInitialization extends
|
||||
|
||||
class TranslatedConstructorInitialization extends
|
||||
TranslatedDirectInitialization, StructorCallContext {
|
||||
ConstructorCall ctorCall;
|
||||
|
||||
TranslatedConstructorInitialization() {
|
||||
ctorCall = expr
|
||||
}
|
||||
override ConstructorCall expr;
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
@@ -1008,9 +994,7 @@ TranslatedConstructorCallFromConstructor getTranslatedConstructorBaseInit(Constr
|
||||
* Represents the IR translation of a delegating constructor call from within a constructor.
|
||||
*/
|
||||
class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromConstructor {
|
||||
TranslatedConstructorDelegationInit() {
|
||||
call instanceof ConstructorDelegationInit
|
||||
}
|
||||
override ConstructorDelegationInit call;
|
||||
|
||||
override final string toString() {
|
||||
result = "delegation construct: " + call.toString()
|
||||
|
||||
@@ -632,7 +632,7 @@ class TranslatedForStmt extends TranslatedLoop {
|
||||
exists(forStmt.getInitialization())
|
||||
}
|
||||
|
||||
private TranslatedExpr getUpdate() {
|
||||
TranslatedExpr getUpdate() {
|
||||
result = getTranslatedExpr(forStmt.getUpdate().getFullyConverted())
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,11 @@ class FunctionIR extends TFunctionIR {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final UnmodeledUseInstruction getUnmodeledUseInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
|
||||
@@ -90,6 +90,10 @@ class IRBlock extends IRBlockBase {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final IRBlock getBackEdgeSuccessor(EdgeKind kind) {
|
||||
backEdgeSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
@@ -132,7 +136,10 @@ private predicate startsBasicBlock(Instruction instr) {
|
||||
exists(Instruction predecessor, EdgeKind kind |
|
||||
instr = predecessor.getSuccessor(kind) and
|
||||
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)
|
||||
}
|
||||
|
||||
/** Gets the index of `i` in its `IRBlock`. */
|
||||
private int getMemberIndex(Instruction i) {
|
||||
startsBasicBlock(i) and
|
||||
result = 0
|
||||
or
|
||||
exists(Instruction iPrev |
|
||||
adjacentInBlock(iPrev, i) and
|
||||
result = getMemberIndex(iPrev) + 1
|
||||
)
|
||||
}
|
||||
/** Holds if `i` is the `index`th instruction the block starting with `first`. */
|
||||
private Instruction getInstructionFromFirst(Instruction first, int index) =
|
||||
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
|
||||
|
||||
/** Holds if `i` is the `index`th instruction in `block`. */
|
||||
cached Instruction getInstruction(TIRBlock block, int index) {
|
||||
exists(Instruction first |
|
||||
block = MkIRBlock(first) and
|
||||
index = getMemberIndex(result) and
|
||||
adjacentInBlock*(first, result)
|
||||
)
|
||||
result = getInstructionFromFirst(getFirstInstruction(block), index)
|
||||
}
|
||||
|
||||
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) {
|
||||
blockSuccessor(pred, succ, _)
|
||||
}
|
||||
|
||||
@@ -3,31 +3,7 @@ import FunctionIR
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.TempVariableTag
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
|
||||
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)
|
||||
}
|
||||
private import semmle.code.cpp.ir.internal.TIRVariable
|
||||
|
||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
result.getVariable() = var and
|
||||
@@ -40,7 +16,7 @@ IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
FunctionIR funcIR;
|
||||
Function func;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
@@ -72,14 +48,14 @@ abstract class IRVariable extends TIRVariable {
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
result = func
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +102,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
LocalScopeVariable localVar;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
||||
this = TIRAutomaticUserVariable(localVar, func) and
|
||||
var = localVar
|
||||
}
|
||||
|
||||
@@ -137,7 +113,7 @@ class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, funcIR)
|
||||
this = TIRStaticUserVariable(var, func)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +128,7 @@ class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
||||
this = TIRTempVariable(func, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
|
||||
@@ -10,8 +10,6 @@ import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
|
||||
class InstructionTag = Construction::InstructionTagType;
|
||||
|
||||
module InstructionSanity {
|
||||
/**
|
||||
* Holds if the instruction `instr` should be expected to have an operand
|
||||
@@ -157,23 +155,60 @@ module InstructionSanity {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
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.
|
||||
*/
|
||||
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() {
|
||||
result = getOpcode().toString() + ": " + getAST().toString()
|
||||
}
|
||||
@@ -196,9 +231,9 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
final string getOperationString() {
|
||||
if exists(getImmediateString()) then
|
||||
result = getOperationPrefix() + opcode.toString() + "[" + getImmediateString() + "]"
|
||||
result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]"
|
||||
else
|
||||
result = getOperationPrefix() + opcode.toString()
|
||||
result = getOperationPrefix() + getOpcode().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +251,7 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if resultType instanceof VoidType then
|
||||
if getResultType() instanceof VoidType then
|
||||
result = "v"
|
||||
else if hasMemoryResult() then
|
||||
if isResultModeled() then
|
||||
@@ -261,8 +296,8 @@ class Instruction extends Construction::TInstruction {
|
||||
|
||||
private string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(resultType.toString()) and
|
||||
if (resultType instanceof UnknownType and
|
||||
valcat = getValueCategoryString(getResultType().toString()) and
|
||||
if (getResultType() instanceof UnknownType and
|
||||
not isGLValue() and
|
||||
exists(getResultSize())) then (
|
||||
result = valcat + "[" + getResultSize().toString() + "]"
|
||||
@@ -330,28 +365,28 @@ class Instruction extends Construction::TInstruction {
|
||||
* Gets the function that contains this instruction.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
result = getFunctionIR().getFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the FunctionIR object that contains the IR for this instruction.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
result = Construction::getInstructionEnclosingFunctionIR(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the AST that caused this instruction to be generated.
|
||||
*/
|
||||
final Locatable getAST() {
|
||||
result = ast
|
||||
result = Construction::getInstructionAST(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
final predicate isGLValue() {
|
||||
glvalue = true
|
||||
Construction::instructionHasType(this, _, true)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,10 +447,10 @@ class Instruction extends Construction::TInstruction {
|
||||
result = nullptr.getSize()
|
||||
)
|
||||
)
|
||||
else if resultType instanceof UnknownType then
|
||||
else if getResultType() instanceof UnknownType then
|
||||
result = Construction::getInstructionResultSize(this)
|
||||
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.
|
||||
*/
|
||||
final Opcode getOpcode() {
|
||||
result = opcode
|
||||
}
|
||||
|
||||
final InstructionTag getTag() {
|
||||
result = instructionTag
|
||||
result = Construction::getInstructionOpcode(this)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,6 +520,24 @@ class Instruction extends Construction::TInstruction {
|
||||
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.
|
||||
*/
|
||||
@@ -578,19 +627,19 @@ class ConstantValueInstruction extends Instruction {
|
||||
|
||||
class EnterFunctionInstruction extends Instruction {
|
||||
EnterFunctionInstruction() {
|
||||
opcode instanceof Opcode::EnterFunction
|
||||
getOpcode() instanceof Opcode::EnterFunction
|
||||
}
|
||||
}
|
||||
|
||||
class VariableAddressInstruction extends VariableInstruction {
|
||||
VariableAddressInstruction() {
|
||||
opcode instanceof Opcode::VariableAddress
|
||||
getOpcode() instanceof Opcode::VariableAddress
|
||||
}
|
||||
}
|
||||
|
||||
class InitializeParameterInstruction extends VariableInstruction {
|
||||
InitializeParameterInstruction() {
|
||||
opcode instanceof Opcode::InitializeParameter
|
||||
getOpcode() instanceof Opcode::InitializeParameter
|
||||
}
|
||||
|
||||
final Parameter getParameter() {
|
||||
@@ -607,13 +656,13 @@ class InitializeParameterInstruction extends VariableInstruction {
|
||||
*/
|
||||
class InitializeThisInstruction extends Instruction {
|
||||
InitializeThisInstruction() {
|
||||
opcode instanceof Opcode::InitializeThis
|
||||
getOpcode() instanceof Opcode::InitializeThis
|
||||
}
|
||||
}
|
||||
|
||||
class FieldAddressInstruction extends FieldInstruction {
|
||||
FieldAddressInstruction() {
|
||||
opcode instanceof Opcode::FieldAddress
|
||||
getOpcode() instanceof Opcode::FieldAddress
|
||||
}
|
||||
|
||||
final Instruction getObjectAddress() {
|
||||
@@ -623,7 +672,7 @@ class FieldAddressInstruction extends FieldInstruction {
|
||||
|
||||
class UninitializedInstruction extends VariableInstruction {
|
||||
UninitializedInstruction() {
|
||||
opcode instanceof Opcode::Uninitialized
|
||||
getOpcode() instanceof Opcode::Uninitialized
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -640,25 +689,25 @@ class UninitializedInstruction extends VariableInstruction {
|
||||
|
||||
class NoOpInstruction extends Instruction {
|
||||
NoOpInstruction() {
|
||||
opcode instanceof Opcode::NoOp
|
||||
getOpcode() instanceof Opcode::NoOp
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnInstruction extends Instruction {
|
||||
ReturnInstruction() {
|
||||
opcode instanceof ReturnOpcode
|
||||
getOpcode() instanceof ReturnOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnVoidInstruction extends ReturnInstruction {
|
||||
ReturnVoidInstruction() {
|
||||
opcode instanceof Opcode::ReturnVoid
|
||||
getOpcode() instanceof Opcode::ReturnVoid
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnValueInstruction extends ReturnInstruction {
|
||||
ReturnValueInstruction() {
|
||||
opcode instanceof Opcode::ReturnValue
|
||||
getOpcode() instanceof Opcode::ReturnValue
|
||||
}
|
||||
|
||||
final Instruction getReturnValue() {
|
||||
@@ -668,7 +717,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
||||
|
||||
class CopyInstruction extends Instruction {
|
||||
CopyInstruction() {
|
||||
opcode instanceof CopyOpcode
|
||||
getOpcode() instanceof CopyOpcode
|
||||
}
|
||||
|
||||
final Instruction getSourceValue() {
|
||||
@@ -678,13 +727,13 @@ class CopyInstruction extends Instruction {
|
||||
|
||||
class CopyValueInstruction extends CopyInstruction {
|
||||
CopyValueInstruction() {
|
||||
opcode instanceof Opcode::CopyValue
|
||||
getOpcode() instanceof Opcode::CopyValue
|
||||
}
|
||||
}
|
||||
|
||||
class LoadInstruction extends CopyInstruction {
|
||||
LoadInstruction() {
|
||||
opcode instanceof Opcode::Load
|
||||
getOpcode() instanceof Opcode::Load
|
||||
}
|
||||
|
||||
final Instruction getSourceAddress() {
|
||||
@@ -694,7 +743,7 @@ class LoadInstruction extends CopyInstruction {
|
||||
|
||||
class StoreInstruction extends CopyInstruction {
|
||||
StoreInstruction() {
|
||||
opcode instanceof Opcode::Store
|
||||
getOpcode() instanceof Opcode::Store
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -708,7 +757,7 @@ class StoreInstruction extends CopyInstruction {
|
||||
|
||||
class ConditionalBranchInstruction extends Instruction {
|
||||
ConditionalBranchInstruction() {
|
||||
opcode instanceof Opcode::ConditionalBranch
|
||||
getOpcode() instanceof Opcode::ConditionalBranch
|
||||
}
|
||||
|
||||
final Instruction getCondition() {
|
||||
@@ -726,25 +775,25 @@ class ConditionalBranchInstruction extends Instruction {
|
||||
|
||||
class ExitFunctionInstruction extends Instruction {
|
||||
ExitFunctionInstruction() {
|
||||
opcode instanceof Opcode::ExitFunction
|
||||
getOpcode() instanceof Opcode::ExitFunction
|
||||
}
|
||||
}
|
||||
|
||||
class ConstantInstruction extends ConstantValueInstruction {
|
||||
ConstantInstruction() {
|
||||
opcode instanceof Opcode::Constant
|
||||
getOpcode() instanceof Opcode::Constant
|
||||
}
|
||||
}
|
||||
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() {
|
||||
resultType instanceof IntegralType
|
||||
getResultType() instanceof IntegralType
|
||||
}
|
||||
}
|
||||
|
||||
class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() {
|
||||
resultType instanceof FloatingPointType
|
||||
getResultType() instanceof FloatingPointType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,7 +815,7 @@ class StringConstantInstruction extends Instruction {
|
||||
|
||||
class BinaryInstruction extends Instruction {
|
||||
BinaryInstruction() {
|
||||
opcode instanceof BinaryOpcode
|
||||
getOpcode() instanceof BinaryOpcode
|
||||
}
|
||||
|
||||
final Instruction getLeftOperand() {
|
||||
@@ -789,67 +838,67 @@ class BinaryInstruction extends Instruction {
|
||||
|
||||
class AddInstruction extends BinaryInstruction {
|
||||
AddInstruction() {
|
||||
opcode instanceof Opcode::Add
|
||||
getOpcode() instanceof Opcode::Add
|
||||
}
|
||||
}
|
||||
|
||||
class SubInstruction extends BinaryInstruction {
|
||||
SubInstruction() {
|
||||
opcode instanceof Opcode::Sub
|
||||
getOpcode() instanceof Opcode::Sub
|
||||
}
|
||||
}
|
||||
|
||||
class MulInstruction extends BinaryInstruction {
|
||||
MulInstruction() {
|
||||
opcode instanceof Opcode::Mul
|
||||
getOpcode() instanceof Opcode::Mul
|
||||
}
|
||||
}
|
||||
|
||||
class DivInstruction extends BinaryInstruction {
|
||||
DivInstruction() {
|
||||
opcode instanceof Opcode::Div
|
||||
getOpcode() instanceof Opcode::Div
|
||||
}
|
||||
}
|
||||
|
||||
class RemInstruction extends BinaryInstruction {
|
||||
RemInstruction() {
|
||||
opcode instanceof Opcode::Rem
|
||||
getOpcode() instanceof Opcode::Rem
|
||||
}
|
||||
}
|
||||
|
||||
class NegateInstruction extends UnaryInstruction {
|
||||
NegateInstruction() {
|
||||
opcode instanceof Opcode::Negate
|
||||
getOpcode() instanceof Opcode::Negate
|
||||
}
|
||||
}
|
||||
|
||||
class BitAndInstruction extends BinaryInstruction {
|
||||
BitAndInstruction() {
|
||||
opcode instanceof Opcode::BitAnd
|
||||
getOpcode() instanceof Opcode::BitAnd
|
||||
}
|
||||
}
|
||||
|
||||
class BitOrInstruction extends BinaryInstruction {
|
||||
BitOrInstruction() {
|
||||
opcode instanceof Opcode::BitOr
|
||||
getOpcode() instanceof Opcode::BitOr
|
||||
}
|
||||
}
|
||||
|
||||
class BitXorInstruction extends BinaryInstruction {
|
||||
BitXorInstruction() {
|
||||
opcode instanceof Opcode::BitXor
|
||||
getOpcode() instanceof Opcode::BitXor
|
||||
}
|
||||
}
|
||||
|
||||
class ShiftLeftInstruction extends BinaryInstruction {
|
||||
ShiftLeftInstruction() {
|
||||
opcode instanceof Opcode::ShiftLeft
|
||||
getOpcode() instanceof Opcode::ShiftLeft
|
||||
}
|
||||
}
|
||||
|
||||
class ShiftRightInstruction extends BinaryInstruction {
|
||||
ShiftRightInstruction() {
|
||||
opcode instanceof Opcode::ShiftRight
|
||||
getOpcode() instanceof Opcode::ShiftRight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,7 +906,7 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
int elementSize;
|
||||
|
||||
PointerArithmeticInstruction() {
|
||||
opcode instanceof PointerArithmeticOpcode and
|
||||
getOpcode() instanceof PointerArithmeticOpcode and
|
||||
elementSize = Construction::getInstructionElementSize(this)
|
||||
}
|
||||
|
||||
@@ -872,31 +921,31 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
|
||||
class PointerOffsetInstruction extends PointerArithmeticInstruction {
|
||||
PointerOffsetInstruction() {
|
||||
opcode instanceof PointerOffsetOpcode
|
||||
getOpcode() instanceof PointerOffsetOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class PointerAddInstruction extends PointerOffsetInstruction {
|
||||
PointerAddInstruction() {
|
||||
opcode instanceof Opcode::PointerAdd
|
||||
getOpcode() instanceof Opcode::PointerAdd
|
||||
}
|
||||
}
|
||||
|
||||
class PointerSubInstruction extends PointerOffsetInstruction {
|
||||
PointerSubInstruction() {
|
||||
opcode instanceof Opcode::PointerSub
|
||||
getOpcode() instanceof Opcode::PointerSub
|
||||
}
|
||||
}
|
||||
|
||||
class PointerDiffInstruction extends PointerArithmeticInstruction {
|
||||
PointerDiffInstruction() {
|
||||
opcode instanceof Opcode::PointerDiff
|
||||
getOpcode() instanceof Opcode::PointerDiff
|
||||
}
|
||||
}
|
||||
|
||||
class UnaryInstruction extends Instruction {
|
||||
UnaryInstruction() {
|
||||
opcode instanceof UnaryOpcode
|
||||
getOpcode() instanceof UnaryOpcode
|
||||
}
|
||||
|
||||
final Instruction getOperand() {
|
||||
@@ -906,7 +955,7 @@ class UnaryInstruction extends Instruction {
|
||||
|
||||
class ConvertInstruction extends UnaryInstruction {
|
||||
ConvertInstruction() {
|
||||
opcode instanceof Opcode::Convert
|
||||
getOpcode() instanceof Opcode::Convert
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,7 +1007,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
*/
|
||||
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToBaseInstruction() {
|
||||
opcode instanceof Opcode::ConvertToBase
|
||||
getOpcode() instanceof Opcode::ConvertToBase
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,7 +1017,7 @@ class ConvertToBaseInstruction extends InheritanceConversionInstruction {
|
||||
*/
|
||||
class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToVirtualBaseInstruction() {
|
||||
opcode instanceof Opcode::ConvertToVirtualBase
|
||||
getOpcode() instanceof Opcode::ConvertToVirtualBase
|
||||
}
|
||||
}
|
||||
|
||||
@@ -978,37 +1027,37 @@ class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction {
|
||||
*/
|
||||
class ConvertToDerivedInstruction extends InheritanceConversionInstruction {
|
||||
ConvertToDerivedInstruction() {
|
||||
opcode instanceof Opcode::ConvertToDerived
|
||||
getOpcode() instanceof Opcode::ConvertToDerived
|
||||
}
|
||||
}
|
||||
|
||||
class BitComplementInstruction extends UnaryInstruction {
|
||||
BitComplementInstruction() {
|
||||
opcode instanceof Opcode::BitComplement
|
||||
getOpcode() instanceof Opcode::BitComplement
|
||||
}
|
||||
}
|
||||
|
||||
class LogicalNotInstruction extends UnaryInstruction {
|
||||
LogicalNotInstruction() {
|
||||
opcode instanceof Opcode::LogicalNot
|
||||
getOpcode() instanceof Opcode::LogicalNot
|
||||
}
|
||||
}
|
||||
|
||||
class CompareInstruction extends BinaryInstruction {
|
||||
CompareInstruction() {
|
||||
opcode instanceof CompareOpcode
|
||||
getOpcode() instanceof CompareOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class CompareEQInstruction extends CompareInstruction {
|
||||
CompareEQInstruction() {
|
||||
opcode instanceof Opcode::CompareEQ
|
||||
getOpcode() instanceof Opcode::CompareEQ
|
||||
}
|
||||
}
|
||||
|
||||
class CompareNEInstruction extends CompareInstruction {
|
||||
CompareNEInstruction() {
|
||||
opcode instanceof Opcode::CompareNE
|
||||
getOpcode() instanceof Opcode::CompareNE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,7 +1066,7 @@ class CompareNEInstruction extends CompareInstruction {
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
getOpcode() instanceof RelationalOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1050,7 +1099,7 @@ class RelationalInstruction extends CompareInstruction {
|
||||
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
getOpcode() instanceof Opcode::CompareLT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1068,7 +1117,7 @@ class CompareLTInstruction extends RelationalInstruction {
|
||||
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() {
|
||||
opcode instanceof Opcode::CompareGT
|
||||
getOpcode() instanceof Opcode::CompareGT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1086,7 +1135,7 @@ class CompareGTInstruction extends RelationalInstruction {
|
||||
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
getOpcode() instanceof Opcode::CompareLE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1104,7 +1153,7 @@ class CompareLEInstruction extends RelationalInstruction {
|
||||
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() {
|
||||
opcode instanceof Opcode::CompareGE
|
||||
getOpcode() instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
@@ -1122,7 +1171,7 @@ class CompareGEInstruction extends RelationalInstruction {
|
||||
|
||||
class SwitchInstruction extends Instruction {
|
||||
SwitchInstruction() {
|
||||
opcode instanceof Opcode::Switch
|
||||
getOpcode() instanceof Opcode::Switch
|
||||
}
|
||||
|
||||
final Instruction getExpression() {
|
||||
@@ -1145,7 +1194,7 @@ class SwitchInstruction extends Instruction {
|
||||
*/
|
||||
class CallInstruction extends Instruction {
|
||||
CallInstruction() {
|
||||
opcode instanceof Opcode::Call
|
||||
getOpcode() instanceof Opcode::Call
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1188,7 +1237,7 @@ class CallInstruction extends Instruction {
|
||||
*/
|
||||
class SideEffectInstruction extends Instruction {
|
||||
SideEffectInstruction() {
|
||||
opcode instanceof SideEffectOpcode
|
||||
getOpcode() instanceof SideEffectOpcode
|
||||
}
|
||||
|
||||
final Instruction getPrimaryInstruction() {
|
||||
@@ -1202,7 +1251,7 @@ class SideEffectInstruction extends Instruction {
|
||||
*/
|
||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
CallSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallSideEffect
|
||||
getOpcode() instanceof Opcode::CallSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1216,7 +1265,7 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
CallReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallReadSideEffect
|
||||
getOpcode() instanceof Opcode::CallReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1225,7 +1274,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectReadSideEffect
|
||||
getOpcode() instanceof Opcode::IndirectReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1234,7 +1283,7 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferReadSideEffect
|
||||
getOpcode() instanceof Opcode::BufferReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1243,7 +1292,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectWriteSideEffect
|
||||
getOpcode() instanceof Opcode::IndirectWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1257,7 +1306,7 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferWriteSideEffect
|
||||
getOpcode() instanceof Opcode::BufferWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1272,7 +1321,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectMayWriteSideEffect
|
||||
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1286,7 +1335,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferMayWriteSideEffect
|
||||
getOpcode() instanceof Opcode::BufferMayWriteSideEffect
|
||||
}
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
@@ -1298,7 +1347,7 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
*/
|
||||
class ThrowInstruction extends Instruction {
|
||||
ThrowInstruction() {
|
||||
opcode instanceof ThrowOpcode
|
||||
getOpcode() instanceof ThrowOpcode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1307,7 +1356,7 @@ class ThrowInstruction extends Instruction {
|
||||
*/
|
||||
class ThrowValueInstruction extends ThrowInstruction {
|
||||
ThrowValueInstruction() {
|
||||
opcode instanceof Opcode::ThrowValue
|
||||
getOpcode() instanceof Opcode::ThrowValue
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1330,7 +1379,7 @@ class ThrowValueInstruction extends ThrowInstruction {
|
||||
*/
|
||||
class ReThrowInstruction extends ThrowInstruction {
|
||||
ReThrowInstruction() {
|
||||
opcode instanceof Opcode::ReThrow
|
||||
getOpcode() instanceof Opcode::ReThrow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1339,7 +1388,7 @@ class ReThrowInstruction extends ThrowInstruction {
|
||||
*/
|
||||
class UnwindInstruction extends Instruction {
|
||||
UnwindInstruction() {
|
||||
opcode instanceof Opcode::Unwind
|
||||
getOpcode() instanceof Opcode::Unwind
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,7 +1397,7 @@ class UnwindInstruction extends Instruction {
|
||||
*/
|
||||
class CatchInstruction extends Instruction {
|
||||
CatchInstruction() {
|
||||
opcode instanceof CatchOpcode
|
||||
getOpcode() instanceof CatchOpcode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1359,7 +1408,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
Type exceptionType;
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
opcode instanceof Opcode::CatchByType and
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
exceptionType = Construction::getInstructionExceptionType(this)
|
||||
}
|
||||
|
||||
@@ -1380,13 +1429,13 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
*/
|
||||
class CatchAnyInstruction extends CatchInstruction {
|
||||
CatchAnyInstruction() {
|
||||
opcode instanceof Opcode::CatchAny
|
||||
getOpcode() instanceof Opcode::CatchAny
|
||||
}
|
||||
}
|
||||
|
||||
class UnmodeledDefinitionInstruction extends Instruction {
|
||||
UnmodeledDefinitionInstruction() {
|
||||
opcode instanceof Opcode::UnmodeledDefinition
|
||||
getOpcode() instanceof Opcode::UnmodeledDefinition
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1399,7 +1448,7 @@ class UnmodeledDefinitionInstruction extends Instruction {
|
||||
*/
|
||||
class AliasedDefinitionInstruction extends Instruction {
|
||||
AliasedDefinitionInstruction() {
|
||||
opcode instanceof Opcode::AliasedDefinition
|
||||
getOpcode() instanceof Opcode::AliasedDefinition
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1409,7 +1458,7 @@ class AliasedDefinitionInstruction extends Instruction {
|
||||
|
||||
class UnmodeledUseInstruction extends Instruction {
|
||||
UnmodeledUseInstruction() {
|
||||
opcode instanceof Opcode::UnmodeledUse
|
||||
getOpcode() instanceof Opcode::UnmodeledUse
|
||||
}
|
||||
|
||||
override string getOperandsString() {
|
||||
@@ -1429,7 +1478,7 @@ class UnmodeledUseInstruction extends Instruction {
|
||||
*/
|
||||
class PhiInstruction extends Instruction {
|
||||
PhiInstruction() {
|
||||
opcode instanceof Opcode::Phi
|
||||
getOpcode() instanceof Opcode::Phi
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1481,7 +1530,7 @@ class PhiInstruction extends Instruction {
|
||||
*/
|
||||
class ChiInstruction extends Instruction {
|
||||
ChiInstruction() {
|
||||
opcode instanceof Opcode::Chi
|
||||
getOpcode() instanceof Opcode::Chi
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
@@ -1511,7 +1560,7 @@ class ChiInstruction extends Instruction {
|
||||
*/
|
||||
class UnreachedInstruction extends Instruction {
|
||||
UnreachedInstruction() {
|
||||
opcode instanceof Opcode::Unreached
|
||||
getOpcode() instanceof Opcode::Unreached
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1521,6 +1570,6 @@ class UnreachedInstruction extends Instruction {
|
||||
*/
|
||||
class BuiltInInstruction extends Instruction {
|
||||
BuiltInInstruction() {
|
||||
opcode instanceof BuiltInOpcode
|
||||
getOpcode() instanceof BuiltInOpcode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +287,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
|
||||
(
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = kind.toString()
|
||||
if predBlock.getBackEdgeSuccessor(kind) = succBlock
|
||||
then value = kind.toString() + " (back edge)"
|
||||
else value = kind.toString()
|
||||
) or
|
||||
(
|
||||
key = "semmle.order" and
|
||||
|
||||
@@ -14,25 +14,6 @@ cached private module Cached {
|
||||
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) {
|
||||
exists(OldIR::FunctionIR funcIR |
|
||||
funcIR.getFunction() = func
|
||||
@@ -40,7 +21,7 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
cached OldInstruction getOldInstruction(Instruction instr) {
|
||||
instr.getTag() = WrappedInstructionTag(result)
|
||||
instr = WrappedInstruction(result)
|
||||
}
|
||||
|
||||
private Instruction getNewInstruction(OldInstruction instr) {
|
||||
@@ -52,90 +33,35 @@ cached private module Cached {
|
||||
* corresponding to `instr` if there is no `Chi` node.
|
||||
*/
|
||||
private Instruction getNewFinalInstruction(OldInstruction instr) {
|
||||
result = getChiInstruction(instr)
|
||||
result = Chi(instr)
|
||||
or
|
||||
not exists(getChiInstruction(instr)) and
|
||||
not exists(Chi(instr)) and
|
||||
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) {
|
||||
result.getFunction() = var.getFunction() and
|
||||
(
|
||||
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
|
||||
)
|
||||
)
|
||||
// This is just a type cast. Both classes derive from the same newtype.
|
||||
result = var
|
||||
}
|
||||
|
||||
cached newtype TInstruction =
|
||||
MkInstruction(FunctionIR funcIR, Opcode opcode, Locatable ast,
|
||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
hasInstruction(funcIR.getFunction(), opcode, ast, tag,
|
||||
resultType, isGLValue)
|
||||
WrappedInstruction(OldInstruction oldInstruction) {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction
|
||||
} or
|
||||
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,
|
||||
Type type) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
@@ -169,7 +95,7 @@ cached private module Cached {
|
||||
if defIndex >= 0 then
|
||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instruction.getFunction(), defBlock, vvar)
|
||||
result = Phi(defBlock, vvar)
|
||||
)
|
||||
)
|
||||
else (
|
||||
@@ -189,13 +115,14 @@ cached private module Cached {
|
||||
else
|
||||
result = getNewInstruction(oldOperand.getDefinitionInstruction())
|
||||
) or
|
||||
instruction.getTag() = ChiTag(getOldInstruction(result)) and
|
||||
instruction = Chi(getOldInstruction(result)) and
|
||||
tag instanceof ChiPartialOperandTag
|
||||
or
|
||||
instruction instanceof UnmodeledUseInstruction and
|
||||
tag instanceof UnmodeledUseOperandTag and
|
||||
result instanceof UnmodeledDefinitionInstruction and
|
||||
instruction.getFunction() = result.getFunction()
|
||||
exists(FunctionIR f |
|
||||
tag instanceof UnmodeledUseOperandTag and
|
||||
result = f.getUnmodeledDefinitionInstruction() and
|
||||
instruction = f.getUnmodeledUseInstruction()
|
||||
)
|
||||
or
|
||||
tag instanceof ChiTotalOperandTag and
|
||||
result = getChiInstructionTotalOperand(instruction)
|
||||
@@ -207,21 +134,21 @@ cached private module Cached {
|
||||
OldBlock defBlock, int defRank, int defIndex, OldBlock predBlock |
|
||||
hasPhiNode(vvar, phiBlock) and
|
||||
predBlock = phiBlock.getAFeasiblePredecessor() and
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
instr = Phi(phiBlock, vvar) and
|
||||
newPredecessorBlock = getNewBlock(predBlock) and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instr.getFunction(), defBlock, vvar)
|
||||
result = Phi(defBlock, vvar)
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
|
||||
exists(Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock,
|
||||
int defRank, int defIndex, OldBlock useBlock, int useRank |
|
||||
ChiTag(oldInstr) = chiInstr.getTag() and
|
||||
chiInstr = Chi(oldInstr) and
|
||||
vvar = Alias::getResultMemoryAccess(oldInstr).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||
@@ -229,13 +156,13 @@ cached private module Cached {
|
||||
if defIndex >= 0 then
|
||||
result = getNewFinalInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(chiInstr.getFunction(), defBlock, vvar)
|
||||
result = Phi(defBlock, vvar)
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
exists(OldBlock oldBlock |
|
||||
instr.getTag() = PhiTag(_, oldBlock) and
|
||||
instr = Phi(oldBlock, _) and
|
||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
)
|
||||
}
|
||||
@@ -256,15 +183,14 @@ cached private module Cached {
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
if(hasChiNode(_, getOldInstruction(instruction)))
|
||||
then
|
||||
result = getChiInstruction(getOldInstruction(instruction)) and
|
||||
result = Chi(getOldInstruction(instruction)) and
|
||||
kind instanceof GotoEdge
|
||||
else (
|
||||
exists(OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
(
|
||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) then (
|
||||
result.getTag() = UnreachedTag() and
|
||||
result.getFunction() = instruction.getFunction()
|
||||
result = Unreached(instruction.getFunction())
|
||||
)
|
||||
else (
|
||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
@@ -272,12 +198,106 @@ cached private module Cached {
|
||||
)
|
||||
) or
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = getChiInstruction(oldInstruction) and
|
||||
instruction = Chi(oldInstruction) and
|
||||
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) {
|
||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||
}
|
||||
@@ -328,13 +348,13 @@ cached private module Cached {
|
||||
)
|
||||
or
|
||||
exists(OldIR::Instruction oldInstruction |
|
||||
instruction.getTag() = ChiTag(oldInstruction) and
|
||||
instruction = Chi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||
OldInstruction instr, OldBlock block, int index) {
|
||||
OldBlock block, int index, OldInstruction instr) {
|
||||
block.getInstruction(index) = instr and
|
||||
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) {
|
||||
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,
|
||||
int index) {
|
||||
private predicate hasUse(Alias::VirtualVariable vvar, OldBlock block, int index,
|
||||
OldInstruction use) {
|
||||
exists(Alias::MemoryAccess access |
|
||||
(
|
||||
access = Alias::getOperandMemoryAccess(use.getAnOperand())
|
||||
@@ -374,10 +394,16 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldBlock block) {
|
||||
exists (int index | hasUse(vvar, _, block, index) |
|
||||
not exists (int j | ssa_variableUpdate(vvar, _, block, j) | j < index)
|
||||
) or
|
||||
(variableLiveOnExitFromBlock(vvar, block) and not ssa_variableUpdate(vvar, _, block, _))
|
||||
exists(int firstAccess |
|
||||
hasUse(vvar, block, firstAccess, _) and
|
||||
firstAccess = min(int index |
|
||||
hasUse(vvar, block, index, _)
|
||||
or
|
||||
ssa_variableUpdate(vvar, block, index, _)
|
||||
)
|
||||
)
|
||||
or
|
||||
(variableLiveOnExitFromBlock(vvar, block) and not ssa_variableUpdate(vvar, block, _, _))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -404,7 +430,7 @@ cached private module Cached {
|
||||
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldBlock block, int rankIndex,
|
||||
OldInstruction use) {
|
||||
exists(int index |
|
||||
hasUse(vvar, use, block, index) and
|
||||
hasUse(vvar, block, index, use) and
|
||||
defUseRank(vvar, block, rankIndex, index)
|
||||
)
|
||||
}
|
||||
@@ -517,11 +543,11 @@ cached private module CachedForDebugging {
|
||||
result = "NonSSA: " + oldInstr.getUniqueId()
|
||||
) or
|
||||
exists(Alias::VirtualVariable vvar, OldBlock phiBlock |
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
instr = Phi(phiBlock, vvar) and
|
||||
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
||||
) or
|
||||
(
|
||||
instr.getTag() = UnreachedTag() and
|
||||
instr = Unreached(_) and
|
||||
result = "Unreached"
|
||||
)
|
||||
}
|
||||
|
||||
25
cpp/ql/src/semmle/code/cpp/ir/internal/TIRVariable.qll
Normal file
25
cpp/ql/src/semmle/code/cpp/ir/internal/TIRVariable.qll
Normal file
@@ -0,0 +1,25 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.TempVariableTag
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as Construction
|
||||
|
||||
newtype TIRVariable =
|
||||
TIRAutomaticUserVariable(LocalScopeVariable var, Function func) {
|
||||
Construction::functionHasIR(func) and
|
||||
var.getFunction() = func or
|
||||
var.(Parameter).getCatchBlock().getEnclosingFunction() = func
|
||||
} or
|
||||
TIRStaticUserVariable(Variable var, Function func) {
|
||||
Construction::functionHasIR(func) and
|
||||
(
|
||||
var instanceof GlobalOrNamespaceVariable or
|
||||
var instanceof MemberVariable and not var instanceof Field
|
||||
) and
|
||||
exists(VariableAccess access |
|
||||
access.getTarget() = var and
|
||||
access.getEnclosingFunction() = func
|
||||
)
|
||||
} or
|
||||
TIRTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) {
|
||||
Construction::hasTempVariable(func, ast, tag, type)
|
||||
}
|
||||
|
||||
@@ -559,47 +559,44 @@ private predicate boundedCastExpr(
|
||||
private predicate boundedInstruction(
|
||||
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() |
|
||||
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
|
||||
)
|
||||
or
|
||||
i = b.getInstruction(delta) and
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TNoReason()
|
||||
or
|
||||
exists(Operand mid, int d1, int d2 |
|
||||
boundFlowStep(i, mid, d1, upper) and
|
||||
boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
|
||||
delta = d1 + d2 and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(Operand mid, int factor, int d |
|
||||
boundFlowStepMul(i, mid, factor) and
|
||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
b instanceof ZeroBound and
|
||||
delta = d*factor and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(Operand mid, int factor, int d |
|
||||
boundFlowStepDiv(i, mid, factor) and
|
||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
d >= 0 and
|
||||
b instanceof ZeroBound and
|
||||
delta = d / factor and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(NarrowingCastInstruction cast |
|
||||
cast = i and
|
||||
safeNarrowingCast(cast, upper.booleanNot()) and
|
||||
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
i instanceof PhiInstruction and
|
||||
forex(PhiOperand op | op = i.getAnOperand() |
|
||||
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
|
||||
)
|
||||
or
|
||||
i = b.getInstruction(delta) and
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TNoReason()
|
||||
or
|
||||
exists(Operand mid, int d1, int d2 |
|
||||
boundFlowStep(i, mid, d1, upper) and
|
||||
boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
|
||||
delta = d1 + d2 and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(Operand mid, int factor, int d |
|
||||
boundFlowStepMul(i, mid, factor) and
|
||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
b instanceof ZeroBound and
|
||||
delta = d*factor and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(Operand mid, int factor, int d |
|
||||
boundFlowStepDiv(i, mid, factor) and
|
||||
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
d >= 0 and
|
||||
b instanceof ZeroBound and
|
||||
delta = d / factor and
|
||||
not exists(getValue(getConstantValue(i)))
|
||||
)
|
||||
or
|
||||
exists(NarrowingCastInstruction cast |
|
||||
cast = i and
|
||||
safeNarrowingCast(cast, upper.booleanNot()) and
|
||||
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -63,24 +63,7 @@ predicate valueFlowStep(Instruction i, Operand op, int delta) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isReducibleCFG(Function f) {
|
||||
not exists(LabelStmt l, GotoStmt goto |
|
||||
goto.getTarget() = l and
|
||||
l.getLocation().isBefore(goto.getLocation()) and
|
||||
l.getEnclosingFunction() = f
|
||||
) and
|
||||
not exists(LabelStmt ls, Loop l |
|
||||
ls.getParent*() = l and
|
||||
l.getEnclosingFunction() = f
|
||||
) and
|
||||
not exists(SwitchCase cs |
|
||||
cs.getSwitchStmt().getStmt() != cs.getParentStmt() and
|
||||
cs.getEnclosingFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
predicate backEdge(PhiInstruction phi, PhiOperand op) {
|
||||
phi.getAnOperand() = op and
|
||||
phi.getBlock().dominates(op.getPredecessorBlock())
|
||||
// TODO: identify backedges during IR construction
|
||||
phi.getBlock() = op.getPredecessorBlock().getBackEdgeSuccessor(_)
|
||||
}
|
||||
86
cpp/ql/test/library-tests/constants/addresses/addresses.cpp
Normal file
86
cpp/ql/test/library-tests/constants/addresses/addresses.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// semmle-extractor-options: --c++14
|
||||
|
||||
const int int_const = 1;
|
||||
extern const int extern_int_const = 1;
|
||||
extern const int extern_int_const_noinit;
|
||||
|
||||
int int_var;
|
||||
int int_arr[4];
|
||||
int int_arr_arr[4][4];
|
||||
|
||||
int *const const_ptr = &int_var;
|
||||
|
||||
void sideEffect();
|
||||
using fptr = void (*)();
|
||||
using fref = void (&)();
|
||||
|
||||
|
||||
|
||||
// All variables in this function are initialized to constants, as witnessed by
|
||||
// the `constexpr` annotation that compiles under C++14.
|
||||
void constantAddresses(int param) {
|
||||
constexpr int *ptr_int = &int_var;
|
||||
constexpr int *ptr_deref_chain = &*&int_var;
|
||||
constexpr int *ptr_array = &int_arr[1] + 1;
|
||||
constexpr int (*ptr_to_array)[4] = &int_arr_arr[1] + 1;
|
||||
constexpr int *array2d = &int_arr_arr[1][1] + 1;
|
||||
constexpr int *const_ints = &int_arr_arr[int_const][extern_int_const];
|
||||
|
||||
// Commented out because clang and EDG disagree on whether this is
|
||||
// constant.
|
||||
//constexpr int *stmtexpr_int = &int_arr[ ({ 1; }) ];
|
||||
|
||||
constexpr int *comma_int = &int_arr[ ((void)0, 1) ];
|
||||
constexpr int *comma_addr = ((void)0, &int_var);
|
||||
constexpr int *ternary_true = int_const ? &int_var : ¶m;
|
||||
constexpr int *ternary_false = !int_const ? ¶m : &int_var;
|
||||
constexpr int *ternary_overflow = (unsigned char)256 ? ¶m : &int_var;
|
||||
constexpr int *ternary_ptr_cond = (&int_arr+1) ? &int_var : ¶m;;
|
||||
constexpr int *ptr_subtract = &int_arr[&int_arr[1] - &int_arr[0]];
|
||||
|
||||
constexpr int *constexpr_va = ptr_subtract + 1;
|
||||
|
||||
constexpr int &ref_int = int_var;
|
||||
constexpr int &ref_array2d = int_arr_arr[1][1];
|
||||
constexpr int &ref_va = ref_array2d;
|
||||
constexpr int &ref_va_arith = *(&ref_array2d + 1);
|
||||
|
||||
constexpr fptr fp_implicit = sideEffect;
|
||||
constexpr fptr fp_explicit = &sideEffect;
|
||||
constexpr fptr fp_chain_addressof = &**&**sideEffect;
|
||||
constexpr fptr fp_chain_deref = **&**&**sideEffect;
|
||||
constexpr fptr fp_shortchain_deref = *&sideEffect;
|
||||
|
||||
constexpr fref fr_int = sideEffect;
|
||||
constexpr fref fr_deref = *&sideEffect;
|
||||
constexpr fref fr_2deref = **sideEffect;
|
||||
constexpr fref fr_va = fr_int;
|
||||
|
||||
constexpr const char *char_ptr = "str";
|
||||
constexpr const char *char_ptr_1 = "str" + 1;
|
||||
constexpr char char_arr[] = "str";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// All variables in this function are initialized to non-const values. Writing
|
||||
// `constexpr` in front of any of the variables will be a compile error
|
||||
// (C++14).
|
||||
void nonConstantAddresses(const int param, int *const pparam, int &rparam, fref frparam) {
|
||||
int *int_param = &int_arr[param];
|
||||
int *int_noinit = &int_arr[extern_int_const_noinit];
|
||||
|
||||
int *side_effect_stmtexpr = &int_arr[ ({ sideEffect(); 1; }) ];
|
||||
int *side_effect_comma_int = &int_arr[ (sideEffect(), 1) ];
|
||||
int *side_effect_comma_addr = (sideEffect(), &int_var);
|
||||
int *side_effect_comma_addr2 = ((void)(sideEffect(), 1), &int_var);
|
||||
int *ternary_int = &int_arr[int_const ? param : 1];
|
||||
const int *ternary_addr = int_const ? ¶m : &int_var;
|
||||
int *va_non_constexpr = pparam;
|
||||
|
||||
int *&&ref_to_temporary = &int_var; // reference to temporary is not a const
|
||||
int &ref_param = rparam;
|
||||
|
||||
fref fr_param = frparam;
|
||||
}
|
||||
16
cpp/ql/test/library-tests/constants/addresses/addresses.ql
Normal file
16
cpp/ql/test/library-tests/constants/addresses/addresses.ql
Normal file
@@ -0,0 +1,16 @@
|
||||
import cpp
|
||||
|
||||
from Expr e, string msg, LocalVariable var, Function f
|
||||
where
|
||||
e = var.getInitializer().getExpr().getFullyConverted() and
|
||||
var.getFunction() = f and
|
||||
(
|
||||
e.isConstant() and
|
||||
f.getName() = "nonConstantAddresses" and
|
||||
msg = "misclassified as constant"
|
||||
or
|
||||
not e.isConstant() and
|
||||
f.getName() = "constantAddresses" and
|
||||
msg = "misclassified as NOT constant"
|
||||
)
|
||||
select e, var.getName(), msg
|
||||
@@ -6782,3 +6782,47 @@ ir.cpp:
|
||||
# 1055| 0: i
|
||||
# 1055| Type = int
|
||||
# 1055| ValueCategory = prvalue(load)
|
||||
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||
# 1058| params:
|
||||
# 1058| 0: n
|
||||
# 1058| Type = int
|
||||
# 1058| 1: p
|
||||
# 1058| Type = char *
|
||||
# 1058| body: { ... }
|
||||
# 1059| 0: while (...) ...
|
||||
# 1059| 0: ... > ...
|
||||
# 1059| Type = bool
|
||||
# 1059| ValueCategory = prvalue
|
||||
# 1059| 0: ... --
|
||||
# 1059| Type = int
|
||||
# 1059| ValueCategory = prvalue
|
||||
# 1059| 0: n
|
||||
# 1059| Type = int
|
||||
# 1059| ValueCategory = lvalue
|
||||
# 1059| 1: 0
|
||||
# 1059| Type = int
|
||||
# 1059| Value = 0
|
||||
# 1059| ValueCategory = prvalue
|
||||
# 1060| 1: ExprStmt
|
||||
# 1060| 0: ... = ...
|
||||
# 1060| Type = char
|
||||
# 1060| ValueCategory = lvalue
|
||||
# 1060| 0: * ...
|
||||
# 1060| Type = char
|
||||
# 1060| ValueCategory = lvalue
|
||||
# 1060| 0: ... ++
|
||||
# 1060| Type = char *
|
||||
# 1060| ValueCategory = prvalue
|
||||
# 1060| 0: p
|
||||
# 1060| Type = char *
|
||||
# 1060| ValueCategory = lvalue
|
||||
# 1060| 1: (char)...
|
||||
# 1060| Conversion = integral conversion
|
||||
# 1060| Type = char
|
||||
# 1060| Value = 0
|
||||
# 1060| ValueCategory = prvalue
|
||||
# 1060| expr: 0
|
||||
# 1060| Type = int
|
||||
# 1060| Value = 0
|
||||
# 1060| ValueCategory = prvalue
|
||||
# 1061| 1: return ...
|
||||
|
||||
@@ -1116,7 +1116,7 @@ ir.cpp:
|
||||
# 255| r1_2(int) = Load : r1_1, m3_0
|
||||
# 255| r1_3(int) = Sub : r1_2, r1_0
|
||||
# 255| m1_4(int) = Store : r1_1, r1_3
|
||||
#-----| Goto -> Block 3
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 257| Block 2
|
||||
# 257| v2_0(void) = NoOp :
|
||||
@@ -1156,7 +1156,7 @@ ir.cpp:
|
||||
# 262| r1_9(bool) = CompareGT : r1_7, r1_8
|
||||
# 262| v1_10(void) = ConditionalBranch : r1_9
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 263| Block 2
|
||||
# 263| v2_0(void) = NoOp :
|
||||
@@ -1175,7 +1175,7 @@ ir.cpp:
|
||||
|
||||
# 268| Block 1
|
||||
# 268| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 272| For_Init() -> void
|
||||
# 272| Block 0
|
||||
@@ -1189,7 +1189,7 @@ ir.cpp:
|
||||
|
||||
# 274| Block 1
|
||||
# 274| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 278| For_Condition() -> void
|
||||
# 278| Block 0
|
||||
@@ -1212,7 +1212,7 @@ ir.cpp:
|
||||
|
||||
# 281| Block 2
|
||||
# 281| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 278| Block 3
|
||||
# 278| v3_0(void) = Unreached :
|
||||
@@ -1235,7 +1235,7 @@ ir.cpp:
|
||||
# 287| r1_4(int) = Load : r1_3, m1_0
|
||||
# 287| r1_5(int) = Add : r1_4, r1_2
|
||||
# 287| m1_6(int) = Store : r1_3, r1_5
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 292| For_InitCondition() -> void
|
||||
# 292| Block 0
|
||||
@@ -1258,7 +1258,7 @@ ir.cpp:
|
||||
|
||||
# 294| Block 2
|
||||
# 294| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 292| Block 3
|
||||
# 292| v3_0(void) = Unreached :
|
||||
@@ -1281,7 +1281,7 @@ ir.cpp:
|
||||
# 299| r1_4(int) = Load : r1_3, m1_0
|
||||
# 299| r1_5(int) = Add : r1_4, r1_2
|
||||
# 299| m1_6(int) = Store : r1_3, r1_5
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 304| For_ConditionUpdate() -> void
|
||||
# 304| Block 0
|
||||
@@ -1310,7 +1310,7 @@ ir.cpp:
|
||||
# 306| r2_3(int) = Load : r2_2, m1_0
|
||||
# 306| r2_4(int) = Add : r2_3, r2_1
|
||||
# 306| m2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 309| Block 3
|
||||
# 309| v3_0(void) = NoOp :
|
||||
@@ -1345,7 +1345,7 @@ ir.cpp:
|
||||
# 312| r2_3(int) = Load : r2_2, m1_0
|
||||
# 312| r2_4(int) = Add : r2_3, r2_1
|
||||
# 312| m2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 315| Block 3
|
||||
# 315| v3_0(void) = NoOp :
|
||||
@@ -1379,7 +1379,7 @@ ir.cpp:
|
||||
# 318| r2_2(int) = Load : r2_1, m1_0
|
||||
# 318| r2_3(int) = Add : r2_2, r2_0
|
||||
# 318| m2_4(int) = Store : r2_1, r2_3
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 319| Block 3
|
||||
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
||||
@@ -1441,7 +1441,7 @@ ir.cpp:
|
||||
# 326| r4_3(int) = Load : r4_2, m1_0
|
||||
# 326| r4_4(int) = Add : r4_3, r4_1
|
||||
# 326| m4_5(int) = Store : r4_2, r4_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 331| Block 5
|
||||
# 331| v5_0(void) = NoOp :
|
||||
@@ -1479,7 +1479,7 @@ ir.cpp:
|
||||
|
||||
# 334| Block 3
|
||||
# 334| v3_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 333| Block 4
|
||||
# 333| v4_0(void) = Unreached :
|
||||
@@ -1547,7 +1547,7 @@ ir.cpp:
|
||||
# 356| r3_2(int) = Load : r3_1, m5_0
|
||||
# 356| r3_3(int) = Sub : r3_2, r3_0
|
||||
# 356| m3_4(int) = Store : r3_1, r3_3
|
||||
#-----| Goto -> Block 5
|
||||
#-----| Goto (back edge) -> Block 5
|
||||
|
||||
# 357| Block 4
|
||||
# 357| v4_0(void) = NoOp :
|
||||
@@ -1606,7 +1606,7 @@ ir.cpp:
|
||||
# 366| r4_5(bool) = CompareGT : r4_3, r4_4
|
||||
# 366| v4_6(void) = ConditionalBranch : r4_5
|
||||
#-----| False -> Block 5
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 367| Block 5
|
||||
# 367| v5_0(void) = NoOp :
|
||||
@@ -4395,7 +4395,7 @@ ir.cpp:
|
||||
|
||||
# 979| Block 1
|
||||
# 979| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 7
|
||||
#-----| Goto (back edge) -> Block 7
|
||||
|
||||
# 981| Block 2
|
||||
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
||||
@@ -4415,7 +4415,7 @@ ir.cpp:
|
||||
|
||||
# 981| Block 3
|
||||
# 981| v3_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 983| Block 4
|
||||
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
||||
@@ -4431,7 +4431,7 @@ ir.cpp:
|
||||
|
||||
# 983| Block 5
|
||||
# 983| v5_0(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
#-----| Goto (back edge) -> Block 4
|
||||
|
||||
# 985| Block 6
|
||||
# 985| v6_0(void) = NoOp :
|
||||
@@ -4646,3 +4646,46 @@ ir.cpp:
|
||||
|
||||
# 1049| Block 2
|
||||
# 1049| v2_0(void) = Unreached :
|
||||
|
||||
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||
# 1058| Block 0
|
||||
# 1058| v0_0(void) = EnterFunction :
|
||||
# 1058| m0_1(unknown) = AliasedDefinition :
|
||||
# 1058| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1058| r0_3(glval<int>) = VariableAddress[n] :
|
||||
# 1058| m0_4(int) = InitializeParameter[n] : r0_3
|
||||
# 1058| r0_5(glval<char *>) = VariableAddress[p] :
|
||||
# 1058| m0_6(char *) = InitializeParameter[p] : r0_5
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 1060| Block 1
|
||||
# 1060| r1_0(char) = Constant[0] :
|
||||
# 1060| r1_1(glval<char *>) = VariableAddress[p] :
|
||||
# 1060| r1_2(char *) = Load : r1_1, m3_2
|
||||
# 1060| r1_3(int) = Constant[1] :
|
||||
# 1060| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
|
||||
# 1060| m1_5(char *) = Store : r1_1, r1_4
|
||||
# 1060| m1_6(char) = Store : r1_2, r1_0
|
||||
# 1060| m1_7(unknown) = Chi : m3_0, m1_6
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 1061| Block 2
|
||||
# 1061| v2_0(void) = NoOp :
|
||||
# 1058| v2_1(void) = ReturnVoid :
|
||||
# 1058| v2_2(void) = UnmodeledUse : mu*
|
||||
# 1058| v2_3(void) = ExitFunction :
|
||||
|
||||
# 1059| Block 3
|
||||
# 1059| m3_0(unknown) = Phi : from 0:m0_1, from 1:m1_7
|
||||
# 1059| m3_1(int) = Phi : from 0:m0_4, from 1:m3_7
|
||||
# 1059| m3_2(char *) = Phi : from 0:m0_6, from 1:m1_5
|
||||
# 1059| r3_3(glval<int>) = VariableAddress[n] :
|
||||
# 1059| r3_4(int) = Load : r3_3, m3_1
|
||||
# 1059| r3_5(int) = Constant[1] :
|
||||
# 1059| r3_6(int) = Sub : r3_4, r3_5
|
||||
# 1059| m3_7(int) = Store : r3_3, r3_6
|
||||
# 1059| r3_8(int) = Constant[0] :
|
||||
# 1059| r3_9(bool) = CompareGT : r3_4, r3_8
|
||||
# 1059| v3_10(void) = ConditionalBranch : r3_9
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
@@ -8,3 +8,6 @@ unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
|
||||
@@ -1055,4 +1055,9 @@ int DoWhileFalse() {
|
||||
return i;
|
||||
}
|
||||
|
||||
void chiNodeAtEndOfLoop(int n, char *p) {
|
||||
while (n-- > 0)
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17
|
||||
|
||||
@@ -1108,7 +1108,7 @@ ir.cpp:
|
||||
# 255| r1_2(int) = Load : r1_1, mu0_2
|
||||
# 255| r1_3(int) = Sub : r1_2, r1_0
|
||||
# 255| mu1_4(int) = Store : r1_1, r1_3
|
||||
#-----| Goto -> Block 3
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 257| Block 2
|
||||
# 257| v2_0(void) = NoOp :
|
||||
@@ -1146,7 +1146,7 @@ ir.cpp:
|
||||
# 262| r1_8(bool) = CompareGT : r1_6, r1_7
|
||||
# 262| v1_9(void) = ConditionalBranch : r1_8
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 263| Block 2
|
||||
# 263| v2_0(void) = NoOp :
|
||||
@@ -1170,7 +1170,7 @@ ir.cpp:
|
||||
|
||||
# 268| Block 2
|
||||
# 268| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 272| For_Init() -> void
|
||||
# 272| Block 0
|
||||
@@ -1189,7 +1189,7 @@ ir.cpp:
|
||||
|
||||
# 274| Block 2
|
||||
# 274| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 278| For_Condition() -> void
|
||||
# 278| Block 0
|
||||
@@ -1212,7 +1212,7 @@ ir.cpp:
|
||||
|
||||
# 281| Block 2
|
||||
# 281| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 283| Block 3
|
||||
# 283| v3_0(void) = NoOp :
|
||||
@@ -1242,7 +1242,7 @@ ir.cpp:
|
||||
# 287| r2_3(int) = Load : r2_2, mu0_2
|
||||
# 287| r2_4(int) = Add : r2_3, r2_1
|
||||
# 287| mu2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 292| For_InitCondition() -> void
|
||||
# 292| Block 0
|
||||
@@ -1265,7 +1265,7 @@ ir.cpp:
|
||||
|
||||
# 294| Block 2
|
||||
# 294| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 296| Block 3
|
||||
# 296| v3_0(void) = NoOp :
|
||||
@@ -1295,7 +1295,7 @@ ir.cpp:
|
||||
# 299| r2_3(int) = Load : r2_2, mu0_2
|
||||
# 299| r2_4(int) = Add : r2_3, r2_1
|
||||
# 299| mu2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 304| For_ConditionUpdate() -> void
|
||||
# 304| Block 0
|
||||
@@ -1323,7 +1323,7 @@ ir.cpp:
|
||||
# 306| r2_3(int) = Load : r2_2, mu0_2
|
||||
# 306| r2_4(int) = Add : r2_3, r2_1
|
||||
# 306| mu2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 309| Block 3
|
||||
# 309| v3_0(void) = NoOp :
|
||||
@@ -1357,7 +1357,7 @@ ir.cpp:
|
||||
# 312| r2_3(int) = Load : r2_2, mu0_2
|
||||
# 312| r2_4(int) = Add : r2_3, r2_1
|
||||
# 312| mu2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 315| Block 3
|
||||
# 315| v3_0(void) = NoOp :
|
||||
@@ -1390,7 +1390,7 @@ ir.cpp:
|
||||
# 318| r2_2(int) = Load : r2_1, mu0_2
|
||||
# 318| r2_3(int) = Add : r2_2, r2_0
|
||||
# 318| mu2_4(int) = Store : r2_1, r2_3
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 319| Block 3
|
||||
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
||||
@@ -1451,7 +1451,7 @@ ir.cpp:
|
||||
# 326| r4_3(int) = Load : r4_2, mu0_2
|
||||
# 326| r4_4(int) = Add : r4_3, r4_1
|
||||
# 326| mu4_5(int) = Store : r4_2, r4_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 331| Block 5
|
||||
# 331| v5_0(void) = NoOp :
|
||||
@@ -1493,7 +1493,7 @@ ir.cpp:
|
||||
|
||||
# 334| Block 4
|
||||
# 334| v4_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 339| Block 5
|
||||
# 339| v5_0(void) = NoOp :
|
||||
@@ -1563,7 +1563,7 @@ ir.cpp:
|
||||
# 356| r3_2(int) = Load : r3_1, mu0_2
|
||||
# 356| r3_3(int) = Sub : r3_2, r3_0
|
||||
# 356| mu3_4(int) = Store : r3_1, r3_3
|
||||
#-----| Goto -> Block 5
|
||||
#-----| Goto (back edge) -> Block 5
|
||||
|
||||
# 357| Block 4
|
||||
# 357| v4_0(void) = NoOp :
|
||||
@@ -1619,7 +1619,7 @@ ir.cpp:
|
||||
# 366| r4_4(bool) = CompareGT : r4_2, r4_3
|
||||
# 366| v4_5(void) = ConditionalBranch : r4_4
|
||||
#-----| False -> Block 5
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 367| Block 5
|
||||
# 367| v5_0(void) = NoOp :
|
||||
@@ -4282,7 +4282,7 @@ ir.cpp:
|
||||
|
||||
# 979| Block 1
|
||||
# 979| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 7
|
||||
#-----| Goto (back edge) -> Block 7
|
||||
|
||||
# 981| Block 2
|
||||
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
||||
@@ -4302,7 +4302,7 @@ ir.cpp:
|
||||
|
||||
# 981| Block 3
|
||||
# 981| v3_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 983| Block 4
|
||||
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
||||
@@ -4318,7 +4318,7 @@ ir.cpp:
|
||||
|
||||
# 983| Block 5
|
||||
# 983| v5_0(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
#-----| Goto (back edge) -> Block 4
|
||||
|
||||
# 985| Block 6
|
||||
# 985| v6_0(void) = NoOp :
|
||||
@@ -4533,7 +4533,7 @@ ir.cpp:
|
||||
# 1053| r1_5(bool) = Constant[0] :
|
||||
# 1053| v1_6(void) = ConditionalBranch : r1_5
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 1055| Block 2
|
||||
# 1055| r2_0(glval<int>) = VariableAddress[#return] :
|
||||
@@ -4544,3 +4544,42 @@ ir.cpp:
|
||||
# 1049| v2_5(void) = ReturnValue : r2_4, mu0_2
|
||||
# 1049| v2_6(void) = UnmodeledUse : mu*
|
||||
# 1049| v2_7(void) = ExitFunction :
|
||||
|
||||
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||
# 1058| Block 0
|
||||
# 1058| v0_0(void) = EnterFunction :
|
||||
# 1058| mu0_1(unknown) = AliasedDefinition :
|
||||
# 1058| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1058| r0_3(glval<int>) = VariableAddress[n] :
|
||||
# 1058| mu0_4(int) = InitializeParameter[n] : r0_3
|
||||
# 1058| r0_5(glval<char *>) = VariableAddress[p] :
|
||||
# 1058| mu0_6(char *) = InitializeParameter[p] : r0_5
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 1060| Block 1
|
||||
# 1060| r1_0(char) = Constant[0] :
|
||||
# 1060| r1_1(glval<char *>) = VariableAddress[p] :
|
||||
# 1060| r1_2(char *) = Load : r1_1, mu0_2
|
||||
# 1060| r1_3(int) = Constant[1] :
|
||||
# 1060| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
|
||||
# 1060| mu1_5(char *) = Store : r1_1, r1_4
|
||||
# 1060| mu1_6(char) = Store : r1_2, r1_0
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 1061| Block 2
|
||||
# 1061| v2_0(void) = NoOp :
|
||||
# 1058| v2_1(void) = ReturnVoid :
|
||||
# 1058| v2_2(void) = UnmodeledUse : mu*
|
||||
# 1058| v2_3(void) = ExitFunction :
|
||||
|
||||
# 1059| Block 3
|
||||
# 1059| r3_0(glval<int>) = VariableAddress[n] :
|
||||
# 1059| r3_1(int) = Load : r3_0, mu0_2
|
||||
# 1059| r3_2(int) = Constant[1] :
|
||||
# 1059| r3_3(int) = Sub : r3_1, r3_2
|
||||
# 1059| mu3_4(int) = Store : r3_0, r3_3
|
||||
# 1059| r3_5(int) = Constant[0] :
|
||||
# 1059| r3_6(bool) = CompareGT : r3_1, r3_5
|
||||
# 1059| v3_7(void) = ConditionalBranch : r3_6
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
@@ -8,3 +8,6 @@ unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
| IR: VirtualMemberFunction | 1 |
|
||||
| IR: WhileStatements | 4 |
|
||||
| IR: WhileStmtWithDeclaration | 8 |
|
||||
| IR: chiNodeAtEndOfLoop | 4 |
|
||||
| IR: designatedInit | 1 |
|
||||
| IR: min | 4 |
|
||||
| IR: operator= | 1 |
|
||||
|
||||
@@ -1109,7 +1109,7 @@ ir.cpp:
|
||||
# 255| r1_2(int) = Load : r1_1, m3_0
|
||||
# 255| r1_3(int) = Sub : r1_2, r1_0
|
||||
# 255| m1_4(int) = Store : r1_1, r1_3
|
||||
#-----| Goto -> Block 3
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 257| Block 2
|
||||
# 257| v2_0(void) = NoOp :
|
||||
@@ -1149,7 +1149,7 @@ ir.cpp:
|
||||
# 262| r1_9(bool) = CompareGT : r1_7, r1_8
|
||||
# 262| v1_10(void) = ConditionalBranch : r1_9
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 263| Block 2
|
||||
# 263| v2_0(void) = NoOp :
|
||||
@@ -1168,7 +1168,7 @@ ir.cpp:
|
||||
|
||||
# 268| Block 1
|
||||
# 268| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 272| For_Init() -> void
|
||||
# 272| Block 0
|
||||
@@ -1182,7 +1182,7 @@ ir.cpp:
|
||||
|
||||
# 274| Block 1
|
||||
# 274| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 278| For_Condition() -> void
|
||||
# 278| Block 0
|
||||
@@ -1205,7 +1205,7 @@ ir.cpp:
|
||||
|
||||
# 281| Block 2
|
||||
# 281| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 283| Block 3
|
||||
# 283| v3_0(void) = NoOp :
|
||||
@@ -1231,7 +1231,7 @@ ir.cpp:
|
||||
# 287| r1_4(int) = Load : r1_3, m1_0
|
||||
# 287| r1_5(int) = Add : r1_4, r1_2
|
||||
# 287| m1_6(int) = Store : r1_3, r1_5
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 292| For_InitCondition() -> void
|
||||
# 292| Block 0
|
||||
@@ -1254,7 +1254,7 @@ ir.cpp:
|
||||
|
||||
# 294| Block 2
|
||||
# 294| v2_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 296| Block 3
|
||||
# 296| v3_0(void) = NoOp :
|
||||
@@ -1280,7 +1280,7 @@ ir.cpp:
|
||||
# 299| r1_4(int) = Load : r1_3, m1_0
|
||||
# 299| r1_5(int) = Add : r1_4, r1_2
|
||||
# 299| m1_6(int) = Store : r1_3, r1_5
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 304| For_ConditionUpdate() -> void
|
||||
# 304| Block 0
|
||||
@@ -1309,7 +1309,7 @@ ir.cpp:
|
||||
# 306| r2_3(int) = Load : r2_2, m1_0
|
||||
# 306| r2_4(int) = Add : r2_3, r2_1
|
||||
# 306| m2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 309| Block 3
|
||||
# 309| v3_0(void) = NoOp :
|
||||
@@ -1344,7 +1344,7 @@ ir.cpp:
|
||||
# 312| r2_3(int) = Load : r2_2, m1_0
|
||||
# 312| r2_4(int) = Add : r2_3, r2_1
|
||||
# 312| m2_5(int) = Store : r2_2, r2_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 315| Block 3
|
||||
# 315| v3_0(void) = NoOp :
|
||||
@@ -1378,7 +1378,7 @@ ir.cpp:
|
||||
# 318| r2_2(int) = Load : r2_1, m1_0
|
||||
# 318| r2_3(int) = Add : r2_2, r2_0
|
||||
# 318| m2_4(int) = Store : r2_1, r2_3
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 319| Block 3
|
||||
# 319| r3_0(glval<int>) = VariableAddress[i] :
|
||||
@@ -1440,7 +1440,7 @@ ir.cpp:
|
||||
# 326| r4_3(int) = Load : r4_2, m1_0
|
||||
# 326| r4_4(int) = Add : r4_3, r4_1
|
||||
# 326| m4_5(int) = Store : r4_2, r4_4
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 331| Block 5
|
||||
# 331| v5_0(void) = NoOp :
|
||||
@@ -1482,7 +1482,7 @@ ir.cpp:
|
||||
|
||||
# 334| Block 4
|
||||
# 334| v4_0(void) = NoOp :
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 339| Block 5
|
||||
# 339| v5_0(void) = NoOp :
|
||||
@@ -1552,7 +1552,7 @@ ir.cpp:
|
||||
# 356| r3_2(int) = Load : r3_1, m5_0
|
||||
# 356| r3_3(int) = Sub : r3_2, r3_0
|
||||
# 356| m3_4(int) = Store : r3_1, r3_3
|
||||
#-----| Goto -> Block 5
|
||||
#-----| Goto (back edge) -> Block 5
|
||||
|
||||
# 357| Block 4
|
||||
# 357| v4_0(void) = NoOp :
|
||||
@@ -1611,7 +1611,7 @@ ir.cpp:
|
||||
# 366| r4_5(bool) = CompareGT : r4_3, r4_4
|
||||
# 366| v4_6(void) = ConditionalBranch : r4_5
|
||||
#-----| False -> Block 5
|
||||
#-----| True -> Block 1
|
||||
#-----| True (back edge) -> Block 1
|
||||
|
||||
# 367| Block 5
|
||||
# 367| v5_0(void) = NoOp :
|
||||
@@ -4263,7 +4263,7 @@ ir.cpp:
|
||||
|
||||
# 979| Block 1
|
||||
# 979| v1_0(void) = NoOp :
|
||||
#-----| Goto -> Block 7
|
||||
#-----| Goto (back edge) -> Block 7
|
||||
|
||||
# 981| Block 2
|
||||
# 981| r2_0(glval<int>) = VariableAddress[z] :
|
||||
@@ -4283,7 +4283,7 @@ ir.cpp:
|
||||
|
||||
# 981| Block 3
|
||||
# 981| v3_0(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
#-----| Goto (back edge) -> Block 2
|
||||
|
||||
# 983| Block 4
|
||||
# 983| r4_0(glval<int *>) = VariableAddress[p] :
|
||||
@@ -4299,7 +4299,7 @@ ir.cpp:
|
||||
|
||||
# 983| Block 5
|
||||
# 983| v5_0(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
#-----| Goto (back edge) -> Block 4
|
||||
|
||||
# 985| Block 6
|
||||
# 985| v6_0(void) = NoOp :
|
||||
@@ -4517,3 +4517,44 @@ ir.cpp:
|
||||
|
||||
# 1049| Block 2
|
||||
# 1049| v2_0(void) = Unreached :
|
||||
|
||||
# 1058| chiNodeAtEndOfLoop(int, char *) -> void
|
||||
# 1058| Block 0
|
||||
# 1058| v0_0(void) = EnterFunction :
|
||||
# 1058| mu0_1(unknown) = AliasedDefinition :
|
||||
# 1058| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 1058| r0_3(glval<int>) = VariableAddress[n] :
|
||||
# 1058| m0_4(int) = InitializeParameter[n] : r0_3
|
||||
# 1058| r0_5(glval<char *>) = VariableAddress[p] :
|
||||
# 1058| m0_6(char *) = InitializeParameter[p] : r0_5
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 1060| Block 1
|
||||
# 1060| r1_0(char) = Constant[0] :
|
||||
# 1060| r1_1(glval<char *>) = VariableAddress[p] :
|
||||
# 1060| r1_2(char *) = Load : r1_1, m3_1
|
||||
# 1060| r1_3(int) = Constant[1] :
|
||||
# 1060| r1_4(char *) = PointerAdd[1] : r1_2, r1_3
|
||||
# 1060| m1_5(char *) = Store : r1_1, r1_4
|
||||
# 1060| mu1_6(char) = Store : r1_2, r1_0
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 1061| Block 2
|
||||
# 1061| v2_0(void) = NoOp :
|
||||
# 1058| v2_1(void) = ReturnVoid :
|
||||
# 1058| v2_2(void) = UnmodeledUse : mu*
|
||||
# 1058| v2_3(void) = ExitFunction :
|
||||
|
||||
# 1059| Block 3
|
||||
# 1059| m3_0(int) = Phi : from 0:m0_4, from 1:m3_6
|
||||
# 1059| m3_1(char *) = Phi : from 0:m0_6, from 1:m1_5
|
||||
# 1059| r3_2(glval<int>) = VariableAddress[n] :
|
||||
# 1059| r3_3(int) = Load : r3_2, m3_0
|
||||
# 1059| r3_4(int) = Constant[1] :
|
||||
# 1059| r3_5(int) = Sub : r3_3, r3_4
|
||||
# 1059| m3_6(int) = Store : r3_2, r3_5
|
||||
# 1059| r3_7(int) = Constant[0] :
|
||||
# 1059| r3_8(bool) = CompareGT : r3_3, r3_7
|
||||
# 1059| v3_9(void) = ConditionalBranch : r3_8
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
@@ -8,3 +8,6 @@ unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
containsLoopOfForwardEdges
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
|
||||
@@ -54,6 +54,9 @@ void skip_init() {
|
||||
void run_init() {
|
||||
int nonstatic;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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: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: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 | 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 |
|
||||
@@ -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 | 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:177:10:177:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 1 | false | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
|
||||
| test.cpp:179:10:179:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
|
||||
| test.cpp:183:10:183:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 |
|
||||
| test.cpp:185:10:185:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
|
||||
| test.cpp:187:10:187:10 | Store: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 |
|
||||
|
||||
@@ -170,3 +170,19 @@ int test14(int x, int y) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// more interesting bounds with irreducible CFG
|
||||
int test15(int i, int x) {
|
||||
if (x < i) {
|
||||
sink(i); // i >= x + 1
|
||||
} else {
|
||||
sink(i); // i <= x
|
||||
goto inLoop;
|
||||
}
|
||||
for(; i < x; i++) {
|
||||
sink(i); // i <= x - 1
|
||||
inLoop:
|
||||
sink(i); // i <= x
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -446,7 +446,7 @@ test.cpp:
|
||||
# 56| valnum = r5_3
|
||||
# 56| m5_4(char *) = Store : r5_0, r5_3
|
||||
# 56| valnum = r5_3
|
||||
#-----| Goto -> Block 3
|
||||
#-----| Goto (back edge) -> Block 3
|
||||
|
||||
# 59| Block 6
|
||||
# 59| r6_0(glval<char *>) = VariableAddress[ptr] :
|
||||
@@ -480,7 +480,7 @@ test.cpp:
|
||||
# 62| valnum = r8_3
|
||||
# 62| m8_4(unsigned int) = Store : r8_0, r8_3
|
||||
# 62| valnum = r8_3
|
||||
#-----| Goto -> Block 1
|
||||
#-----| Goto (back edge) -> Block 1
|
||||
|
||||
# 63| Block 9
|
||||
# 63| v9_0(void) = NoOp :
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
| test.cpp:16:13:16:14 | _t | This parameter of type $@ is 4096 bytes - consider passing a pointer/reference instead. | test.cpp:6:8:6:20 | myLargeStruct | myLargeStruct |
|
||||
| test.cpp: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: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: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 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 const pointer/reference instead. | test.cpp:6:8:6:20 | myLargeStruct | myLargeStruct |
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
| test3.c:15:10:15:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
|
||||
| test3.c:15: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 |
|
||||
| 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 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 |
|
||||
|
||||
@@ -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: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 |
|
||||
| test5.cpp:10:9:10:15 | call to strtoul | $@ flows to here and is used in an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
char *gets(char *s);
|
||||
unsigned long int strtoul( const char * nptr, char ** endptr, int base);
|
||||
|
||||
int getTaintedInt()
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
gets(buf);
|
||||
return strtoul(buf, 0, 10);
|
||||
}
|
||||
|
||||
void useTaintedInt()
|
||||
{
|
||||
int x, y;
|
||||
|
||||
x = getTaintedInt() * 1024; // BAD: arithmetic on a tainted value
|
||||
y = getTaintedInt();
|
||||
y = y * 1024; // BAD: arithmetic on a tainted value
|
||||
}
|
||||
@@ -112,7 +112,7 @@ namespace Semmle.Autobuild
|
||||
var o = JObject.Parse(File.ReadAllText(path));
|
||||
version = (string)o["sdk"]["version"];
|
||||
}
|
||||
catch
|
||||
catch // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
// not a valid global.json file
|
||||
continue;
|
||||
|
||||
@@ -63,7 +63,8 @@ namespace Semmle.Autobuild
|
||||
ToolsVersion = new Version(toolsVersion);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Semmle.Util
|
||||
entries[0] :
|
||||
Path.Combine(parentPath, name);
|
||||
}
|
||||
catch (Exception)
|
||||
catch // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
// IO error or security error querying directory.
|
||||
return Path.Combine(parentPath, name);
|
||||
|
||||
@@ -15,6 +15,7 @@ import semmle.code.csharp.frameworks.Format
|
||||
from FormatCall format, int unused, ValidFormatString src
|
||||
where
|
||||
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),
|
||||
"this supplied value"
|
||||
|
||||
@@ -53,7 +53,7 @@ class SuppressionScope extends @commentline {
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* 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
|
||||
|
||||
@@ -26,9 +26,7 @@ predicate isReadonlyCompatibleDefinition(AssignableDefinition def, Field f) {
|
||||
}
|
||||
|
||||
predicate canBeReadonly(Field f) {
|
||||
forex(AssignableDefinition def | defTargetsField(def, f) |
|
||||
isReadonlyCompatibleDefinition(def, f)
|
||||
)
|
||||
forex(AssignableDefinition def | defTargetsField(def, f) | isReadonlyCompatibleDefinition(def, f))
|
||||
}
|
||||
|
||||
from Field f
|
||||
@@ -36,5 +34,5 @@ where
|
||||
canBeReadonly(f) and
|
||||
not f.isConst() and
|
||||
not f.isReadOnly() and
|
||||
(f.isEffectivelyPrivate() or f.isEffectivelyInternal())
|
||||
not f.isEffectivelyPublic()
|
||||
select f, "Field '" + f.getName() + "' can be 'readonly'."
|
||||
|
||||
@@ -18,7 +18,7 @@ where
|
||||
v.getType() instanceof CollectionType and
|
||||
(
|
||||
v instanceof LocalVariable or
|
||||
v = any(Field f | f.isEffectivelyPrivate() or f.isEffectivelyInternal())
|
||||
v = any(Field f | not f.isEffectivelyPublic())
|
||||
) and
|
||||
forex(Access a | a = v.getAnAccess() |
|
||||
a = any(ModifierMethodCall m).getQualifier() or
|
||||
|
||||
@@ -54,7 +54,8 @@ predicate alwaysDefaultToString(ValueOrRefType t) {
|
||||
not exists(RefType overriding |
|
||||
overriding.getAMethod() instanceof ToStringMethod and
|
||||
overriding.getABaseType+() = t
|
||||
)
|
||||
) and
|
||||
((t.isAbstract() or t instanceof Interface) implies not t.isEffectivelyPublic())
|
||||
}
|
||||
|
||||
newtype TDefaultToStringType = TDefaultToStringType0(ValueOrRefType t) { alwaysDefaultToString(t) }
|
||||
|
||||
@@ -15,7 +15,7 @@ abstract class Use extends @type_mention_parent {
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* 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
|
||||
|
||||
2
csharp/ql/src/external/CodeDuplication.qll
vendored
2
csharp/ql/src/external/CodeDuplication.qll
vendored
@@ -6,7 +6,7 @@ private string relativePath(File file) { result = file.getRelativePath().replace
|
||||
* Holds if the `index`-th token of block `copy` is in file `file`, spanning
|
||||
* 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]
|
||||
predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) {
|
||||
|
||||
@@ -28,13 +28,13 @@ class Declaration extends DotNet::Declaration, Element, @cil_declaration {
|
||||
final predicate isSourceDeclaration() { this = getSourceDeclaration() }
|
||||
}
|
||||
|
||||
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) {
|
||||
toCSharpTypeParameterJoin(tp, result.getIndex(), result.getGeneric())
|
||||
}
|
||||
|
||||
pragma[noinline, nomagic]
|
||||
pragma[nomagic]
|
||||
private predicate toCSharpTypeParameterJoin(TypeParameter tp, int i, CS::UnboundGeneric ug) {
|
||||
exists(TypeContainer tc |
|
||||
tp.getIndex() = i and
|
||||
|
||||
@@ -402,17 +402,14 @@ module AssignableInternal {
|
||||
* `a`, if any.
|
||||
*/
|
||||
cached
|
||||
Expr getAccessorCallValueArgument(Access a) {
|
||||
a.getTarget() instanceof DeclarationWithAccessors and
|
||||
(
|
||||
exists(AssignExpr ae | tupleAssignmentDefinition(ae, a) |
|
||||
tupleAssignmentPair(ae, a, result)
|
||||
)
|
||||
or
|
||||
exists(Assignment ass | a = ass.getLValue() |
|
||||
result = ass.getRValue() and
|
||||
not ass.(AssignOperation).hasExpandedAssignment()
|
||||
)
|
||||
Expr getAccessorCallValueArgument(AccessorCall ac) {
|
||||
exists(AssignExpr ae | tupleAssignmentDefinition(ae, ac) |
|
||||
tupleAssignmentPair(ae, ac, result)
|
||||
)
|
||||
or
|
||||
exists(Assignment ass | ac = ass.getLValue() |
|
||||
result = ass.getRValue() and
|
||||
not ass.(AssignOperation).hasExpandedAssignment()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class Container extends @container {
|
||||
/**
|
||||
* Gets a URL representing the location of this container.
|
||||
*
|
||||
* 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() }
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class Location extends @location {
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* 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
|
||||
|
||||
@@ -107,6 +107,12 @@ class Modifiable extends Declaration, @modifiable {
|
||||
this.isInternal() or
|
||||
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. */
|
||||
|
||||
@@ -513,7 +513,7 @@ class IndexerProperty extends Property {
|
||||
IndexerCall getAnIndexerCall() {
|
||||
result = getType().(RefType).getAnIndexer().getAnAccessor().getACall() and
|
||||
// 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))
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,16 +48,13 @@ module AbstractValues {
|
||||
|
||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
s.(BooleanSuccessor).getValue() = this.getValue() and
|
||||
exists(BooleanCompletion c |
|
||||
s.matchesCompletion(c) |
|
||||
exists(BooleanCompletion c | s.matchesCompletion(c) |
|
||||
c.isValidFor(cfe) and
|
||||
e = cfe
|
||||
)
|
||||
}
|
||||
|
||||
override BooleanValue getDualValue() {
|
||||
result.getValue() = this.getValue().booleanNot()
|
||||
}
|
||||
override BooleanValue getDualValue() { result.getValue() = this.getValue().booleanNot() }
|
||||
|
||||
override Expr getAnExpr() {
|
||||
result.getType() instanceof BoolType and
|
||||
@@ -74,13 +71,9 @@ module AbstractValues {
|
||||
/** Gets the underlying integer value. */
|
||||
int getValue() { this = TIntegerValue(result) }
|
||||
|
||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
none()
|
||||
}
|
||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) { none() }
|
||||
|
||||
override BooleanValue getDualValue() {
|
||||
none()
|
||||
}
|
||||
override BooleanValue getDualValue() { none() }
|
||||
|
||||
override Expr getAnExpr() {
|
||||
result.getValue().toInt() = this.getValue() and
|
||||
@@ -103,8 +96,7 @@ module AbstractValues {
|
||||
|
||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
this = TNullValue(s.(NullnessSuccessor).getValue()) and
|
||||
exists(NullnessCompletion c |
|
||||
s.matchesCompletion(c) |
|
||||
exists(NullnessCompletion c | s.matchesCompletion(c) |
|
||||
c.isValidFor(cfe) and
|
||||
e = cfe
|
||||
)
|
||||
@@ -115,20 +107,14 @@ module AbstractValues {
|
||||
}
|
||||
|
||||
override DereferenceableExpr getAnExpr() {
|
||||
if this.isNull() then
|
||||
result instanceof AlwaysNullExpr
|
||||
else
|
||||
exists(Expr e |
|
||||
nonNullValue(e) |
|
||||
nonNullValueImplied*(e, result)
|
||||
)
|
||||
if this.isNull()
|
||||
then result instanceof AlwaysNullExpr
|
||||
else exists(Expr e | nonNullValue(e) | nonNullValueImplied*(e, result))
|
||||
}
|
||||
|
||||
override predicate isSingleton() { this.isNull() }
|
||||
|
||||
override string toString() {
|
||||
if this.isNull() then result = "null" else result = "non-null"
|
||||
}
|
||||
override string toString() { if this.isNull() then result = "null" else result = "non-null" }
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
this = TMatchValue(_, s.(MatchingSuccessor).getValue()) and
|
||||
exists(MatchingCompletion c, SwitchStmt ss, CaseStmt cs |
|
||||
s.matchesCompletion(c) |
|
||||
exists(MatchingCompletion c, SwitchStmt ss, CaseStmt cs | s.matchesCompletion(c) |
|
||||
c.isValidFor(cfe) and
|
||||
switchMatching(ss, cs, cfe) and
|
||||
e = ss.getCondition() and
|
||||
@@ -152,9 +137,9 @@ module AbstractValues {
|
||||
|
||||
override MatchValue getDualValue() {
|
||||
result = any(MatchValue mv |
|
||||
mv.getCaseStmt() = this.getCaseStmt() and
|
||||
if this.isMatch() then not mv.isMatch() else mv.isMatch()
|
||||
)
|
||||
mv.getCaseStmt() = this.getCaseStmt() and
|
||||
if this.isMatch() then not mv.isMatch() else mv.isMatch()
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getAnExpr() { none() }
|
||||
@@ -162,8 +147,7 @@ module AbstractValues {
|
||||
override predicate isSingleton() { none() }
|
||||
|
||||
override string toString() {
|
||||
exists(string s |
|
||||
s = this.getCaseStmt().toString() |
|
||||
exists(string s | s = this.getCaseStmt().toString() |
|
||||
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) {
|
||||
this = TEmptyCollectionValue(s.(EmptinessSuccessor).getValue()) and
|
||||
exists(EmptinessCompletion c, ForeachStmt fs |
|
||||
s.matchesCompletion(c) |
|
||||
exists(EmptinessCompletion c, ForeachStmt fs | s.matchesCompletion(c) |
|
||||
c.isValidFor(cfe) and
|
||||
foreachEmptiness(fs, cfe) and
|
||||
e = fs.getIterableExpr()
|
||||
@@ -192,9 +175,7 @@ module AbstractValues {
|
||||
|
||||
override predicate isSingleton() { none() }
|
||||
|
||||
override string toString() {
|
||||
if this.isEmpty() then result = "empty" else result = "non-empty"
|
||||
}
|
||||
override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" }
|
||||
}
|
||||
}
|
||||
private import AbstractValues
|
||||
@@ -212,7 +193,8 @@ class DereferenceableExpr extends Expr {
|
||||
// incorrectly `int`, while it should have been `int?`. We apply
|
||||
// `getNullEquivParent()` as a workaround
|
||||
this = getNullEquivParent*(e) and
|
||||
t = e.getType() |
|
||||
t = e.getType()
|
||||
|
|
||||
t instanceof NullableType and
|
||||
isNullableType = true
|
||||
or
|
||||
@@ -222,9 +204,7 @@ class DereferenceableExpr extends Expr {
|
||||
}
|
||||
|
||||
/** Holds if this expression has a nullable type `T?`. */
|
||||
predicate hasNullableType() {
|
||||
isNullableType = true
|
||||
}
|
||||
predicate hasNullableType() { isNullableType = true }
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
private Expr getABooleanNullCheck(BooleanValue v, boolean isNull) {
|
||||
exists(boolean branch |
|
||||
branch = v.getValue() |
|
||||
exists(boolean branch | branch = v.getValue() |
|
||||
// Comparison with `null`, for example `x != null`
|
||||
exists(ComparisonTest ct, ComparisonKind ck, NullLiteral nl |
|
||||
ct.getExpr() = result and
|
||||
ct.getAnArgument() = this and
|
||||
ct.getAnArgument() = nl and
|
||||
this != nl and
|
||||
ck = ct.getComparisonKind() |
|
||||
ck = ct.getComparisonKind()
|
||||
|
|
||||
ck.isEquality() and isNull = branch
|
||||
or
|
||||
ck.isInequality() and isNull = branch.booleanNot()
|
||||
)
|
||||
or
|
||||
// Comparison with a non-`null` value, for example `x?.Length > 0`
|
||||
exists(ComparisonTest ct, ComparisonKind ck, Expr e |
|
||||
ct.getExpr() = result |
|
||||
exists(ComparisonTest ct, ComparisonKind ck, Expr e | ct.getExpr() = result |
|
||||
ct.getAnArgument() = this and
|
||||
ct.getAnArgument() = e and
|
||||
e = any(NullValue nv | not nv.isNull()).getAnExpr() and
|
||||
@@ -264,8 +243,7 @@ class DereferenceableExpr extends Expr {
|
||||
)
|
||||
or
|
||||
// Call to `string.IsNullOrEmpty()` or `string.IsNullOrWhiteSpace()`
|
||||
exists(MethodCall mc, string name |
|
||||
result = mc |
|
||||
exists(MethodCall mc, string name | result = mc |
|
||||
mc.getTarget() = any(SystemStringClass c).getAMethod(name) and
|
||||
name.regexpMatch("IsNullOr(Empty|WhiteSpace)") and
|
||||
mc.getArgument(0) = this and
|
||||
@@ -274,27 +252,28 @@ class DereferenceableExpr extends Expr {
|
||||
)
|
||||
or
|
||||
result = any(IsExpr ie |
|
||||
ie.getExpr() = this and
|
||||
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral then
|
||||
// E.g. `x is null`
|
||||
isNull = branch
|
||||
else (
|
||||
// E.g. `x is string` or `x is ""`
|
||||
branch = true and isNull = false
|
||||
or
|
||||
// E.g. `x is string` where `x` has type `string`
|
||||
ie = any(IsTypeExpr ite | ite.getCheckedType() = ite.getExpr().getType()) and
|
||||
branch = false and
|
||||
isNull = true
|
||||
ie.getExpr() = this and
|
||||
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral
|
||||
then
|
||||
// E.g. `x is null`
|
||||
isNull = branch
|
||||
else (
|
||||
// E.g. `x is string` or `x is ""`
|
||||
branch = true and isNull = false
|
||||
or
|
||||
// E.g. `x is string` where `x` has type `string`
|
||||
ie = any(IsTypeExpr ite | ite.getCheckedType() = ite.getExpr().getType()) and
|
||||
branch = false and
|
||||
isNull = true
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
this.hasNullableType() and
|
||||
result = any(PropertyAccess pa |
|
||||
pa.getQualifier() = this and
|
||||
pa.getTarget().hasName("HasValue") and
|
||||
if branch = true then isNull = false else isNull = true
|
||||
)
|
||||
pa.getQualifier() = this and
|
||||
pa.getTarget().hasName("HasValue") and
|
||||
if branch = true then isNull = false else isNull = true
|
||||
)
|
||||
or
|
||||
isCustomNullCheck(result, this, v, isNull)
|
||||
)
|
||||
@@ -326,22 +305,24 @@ class DereferenceableExpr extends Expr {
|
||||
cs = v.getCaseStmt() and
|
||||
this = ss.getCondition() and
|
||||
result = this and
|
||||
cs = ss.getACase() |
|
||||
cs = ss.getACase()
|
||||
|
|
||||
// E.g. `case string`
|
||||
cs instanceof TypeCase and
|
||||
v.isMatch() and
|
||||
isNull = false
|
||||
or
|
||||
cs = any(ConstCase cc |
|
||||
if cc.getExpr() instanceof NullLiteral then
|
||||
// `case null`
|
||||
if v.isMatch() then isNull = true else isNull = false
|
||||
else (
|
||||
// E.g. `case ""`
|
||||
v.isMatch() and
|
||||
isNull = false
|
||||
if cc.getExpr() instanceof NullLiteral
|
||||
then
|
||||
// `case null`
|
||||
if v.isMatch() then isNull = true else isNull = false
|
||||
else (
|
||||
// E.g. `case ""`
|
||||
v.isMatch() and
|
||||
isNull = false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -356,14 +337,13 @@ class DereferenceableExpr extends Expr {
|
||||
* `x` is guaranteed to be `null`.
|
||||
*/
|
||||
private Expr getANullnessNullCheck(NullValue v, boolean isNull) {
|
||||
exists(NullnessCompletion c |
|
||||
c.isValidFor(this) |
|
||||
exists(NullnessCompletion c | c.isValidFor(this) |
|
||||
result = this and
|
||||
if c.isNull() then (
|
||||
if c.isNull()
|
||||
then (
|
||||
v.isNull() and
|
||||
isNull = true
|
||||
)
|
||||
else (
|
||||
) else (
|
||||
not v.isNull() and
|
||||
isNull = false
|
||||
)
|
||||
@@ -417,9 +397,7 @@ class AccessOrCallExpr extends Expr {
|
||||
* An expression can have more than one SSA qualifier in the presence
|
||||
* of control flow splitting.
|
||||
*/
|
||||
Ssa::Definition getAnSsaQualifier(ControlFlow::Node cfn) {
|
||||
result = getAnSsaQualifier(this, cfn)
|
||||
}
|
||||
Ssa::Definition getAnSsaQualifier(ControlFlow::Node cfn) { result = getAnSsaQualifier(this, cfn) }
|
||||
}
|
||||
|
||||
private Declaration getDeclarationTarget(Expr e) {
|
||||
@@ -484,7 +462,9 @@ private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Nod
|
||||
*/
|
||||
class GuardedExpr extends AccessOrCallExpr {
|
||||
private Guard g;
|
||||
|
||||
private AccessOrCallExpr sub0;
|
||||
|
||||
private AbstractValue 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
|
||||
* value `v`.
|
||||
*/
|
||||
predicate mustHaveValue(AbstractValue v) {
|
||||
exists(Expr e | e = this.getAGuard(e, v))
|
||||
}
|
||||
predicate mustHaveValue(AbstractValue v) { exists(Expr e | e = this.getAGuard(e, v)) }
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
private Guard g;
|
||||
|
||||
private AccessOrCallExpr sub0;
|
||||
|
||||
private AbstractValue 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
|
||||
* abstract value `v`.
|
||||
*/
|
||||
predicate mustHaveValue(AbstractValue v) {
|
||||
exists(Expr e | e = this.getAGuard(e, v))
|
||||
}
|
||||
predicate mustHaveValue(AbstractValue v) { exists(Expr e | e = this.getAGuard(e, v)) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -601,12 +579,13 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
|
||||
*/
|
||||
class GuardedDataFlowNode extends DataFlow::ExprNode {
|
||||
private Guard g;
|
||||
|
||||
private AccessOrCallExpr sub0;
|
||||
|
||||
private AbstractValue v0;
|
||||
|
||||
GuardedDataFlowNode() {
|
||||
exists(ControlFlow::Nodes::ElementNode cfn |
|
||||
exists(this.getExprAtNode(cfn)) |
|
||||
exists(ControlFlow::Nodes::ElementNode cfn | exists(this.getExprAtNode(cfn)) |
|
||||
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
|
||||
* abstract value `v`.
|
||||
*/
|
||||
predicate mustHaveValue(AbstractValue v) {
|
||||
exists(Expr e | e = this.getAGuard(e, v))
|
||||
}
|
||||
predicate mustHaveValue(AbstractValue v) { exists(Expr e | e = this.getAGuard(e, v)) }
|
||||
}
|
||||
|
||||
/** An expression guarded by a `null` check. */
|
||||
class NullGuardedExpr extends GuardedExpr {
|
||||
NullGuardedExpr() {
|
||||
this.mustHaveValue(any(NullValue v | not v.isNull()))
|
||||
}
|
||||
NullGuardedExpr() { this.mustHaveValue(any(NullValue v | not v.isNull())) }
|
||||
}
|
||||
|
||||
/** A data flow node guarded by a `null` check. */
|
||||
class NullGuardedDataFlowNode extends GuardedDataFlowNode {
|
||||
NullGuardedDataFlowNode() {
|
||||
this.mustHaveValue(any(NullValue v | not v.isNull()))
|
||||
}
|
||||
NullGuardedDataFlowNode() { this.mustHaveValue(any(NullValue v | not v.isNull())) }
|
||||
}
|
||||
|
||||
/** INTERNAL: Do not use. */
|
||||
@@ -657,16 +630,10 @@ module Internal {
|
||||
private import ControlFlow::Internal
|
||||
|
||||
newtype TAbstractValue =
|
||||
TBooleanValue(boolean b) { b = true or b = false }
|
||||
or
|
||||
TIntegerValue(int i) {
|
||||
i = any(Expr e).getValue().toInt()
|
||||
}
|
||||
or
|
||||
TNullValue(boolean b) { b = true or b = false }
|
||||
or
|
||||
TMatchValue(CaseStmt cs, boolean b) { b = true or b = false }
|
||||
or
|
||||
TBooleanValue(boolean b) { b = true or b = false } or
|
||||
TIntegerValue(int i) { i = any(Expr e).getValue().toInt() } 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 }
|
||||
|
||||
/** Holds if expression `e` is a non-`null` value. */
|
||||
@@ -682,6 +649,11 @@ module Internal {
|
||||
or
|
||||
e instanceof AddExpr and
|
||||
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. */
|
||||
@@ -698,20 +670,20 @@ module Internal {
|
||||
*/
|
||||
Expr getNullEquivParent(Expr e) {
|
||||
result = any(QualifiableExpr qe |
|
||||
qe.isConditional() and
|
||||
(
|
||||
e = qe.getQualifier()
|
||||
or
|
||||
e = qe.(ExtensionMethodCall).getArgument(0)
|
||||
) and
|
||||
(
|
||||
// The accessed declaration must have a value type in order
|
||||
// for `only if` to hold
|
||||
result.(FieldAccess).getTarget().getType() instanceof ValueType
|
||||
or
|
||||
result.(Call).getTarget().getReturnType() instanceof ValueType
|
||||
qe.isConditional() and
|
||||
(
|
||||
e = qe.getQualifier()
|
||||
or
|
||||
e = qe.(ExtensionMethodCall).getArgument(0)
|
||||
) and
|
||||
(
|
||||
// The accessed declaration must have a value type in order
|
||||
// for `only if` to hold
|
||||
result.(FieldAccess).getTarget().getType() instanceof ValueType
|
||||
or
|
||||
result.(Call).getTarget().getReturnType() instanceof ValueType
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
// In C#, `null + 1` has type `int?` with value `null`
|
||||
exists(BinaryArithmeticOperation bao, Expr o |
|
||||
@@ -730,14 +702,12 @@ module Internal {
|
||||
*/
|
||||
Expr getANullImplyingChild(Expr e) {
|
||||
e = any(QualifiableExpr qe |
|
||||
qe.isConditional() and
|
||||
result = qe.getQualifier()
|
||||
)
|
||||
qe.isConditional() and
|
||||
result = qe.getQualifier()
|
||||
)
|
||||
or
|
||||
// In C#, `null + 1` has type `int?` with value `null`
|
||||
e = any(BinaryArithmeticOperation bao |
|
||||
result = bao.getAnOperand()
|
||||
)
|
||||
e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand())
|
||||
}
|
||||
|
||||
/** 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`. */
|
||||
predicate controls(BasicBlock bb, AbstractValue v) {
|
||||
exists(ControlFlowElement cfe, ConditionalSuccessor s, AbstractValue v0, Guard g |
|
||||
cfe.controlsBlock(bb, s) |
|
||||
cfe.controlsBlock(bb, s)
|
||||
|
|
||||
v0.branch(cfe, s, g) and
|
||||
impliesSteps(g, v0, this, v)
|
||||
)
|
||||
@@ -780,8 +751,7 @@ module Internal {
|
||||
|
|
||||
a.strictlyDominates(cfn.getBasicBlock())
|
||||
or
|
||||
exists(BasicBlock bb, int i, int j |
|
||||
bb.getNode(i) = a.getAControlFlowNode() |
|
||||
exists(BasicBlock bb, int i, int j | bb.getNode(i) = a.getAControlFlowNode() |
|
||||
bb.getNode(j) = cfn and
|
||||
j > i
|
||||
)
|
||||
@@ -793,8 +763,7 @@ module Internal {
|
||||
* because of an assertion.
|
||||
*/
|
||||
predicate assertionControlsElement(ControlFlowElement cfe, AbstractValue v) {
|
||||
forex(ControlFlow::Node cfn |
|
||||
cfn = cfe.getAControlFlowNode() |
|
||||
forex(ControlFlow::Node cfn | cfn = cfe.getAControlFlowNode() |
|
||||
this.assertionControlsNode(cfn, v)
|
||||
)
|
||||
}
|
||||
@@ -804,16 +773,14 @@ module Internal {
|
||||
* not taking implications into account.
|
||||
*/
|
||||
predicate preControlsDirect(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
|
||||
exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s |
|
||||
cb.controls(bb, s) |
|
||||
exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s | cb.controls(bb, s) |
|
||||
v.branch(cb.getLastElement(), s, this)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if pre-basic-block `bb` only is reached when this guard has abstract value `v`. */
|
||||
predicate preControls(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
|
||||
exists(AbstractValue v0, Guard g |
|
||||
g.preControlsDirect(bb, v0) |
|
||||
exists(AbstractValue v0, Guard g | g.preControlsDirect(bb, v0) |
|
||||
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`. */
|
||||
PreBasicBlocks::PreBasicBlock getConditionalSuccessor(AbstractValue v) {
|
||||
exists(PreBasicBlocks::ConditionBlock pred, ConditionalSuccessor s |
|
||||
v.branch(pred.getLastElement(), s, this) |
|
||||
v.branch(pred.getLastElement(), s, this)
|
||||
|
|
||||
result = pred.getASuccessorByType(s)
|
||||
)
|
||||
}
|
||||
@@ -849,10 +817,10 @@ module Internal {
|
||||
|
||||
private Expr stripConditionalExpr(Expr e) {
|
||||
e = any(ConditionalExpr ce |
|
||||
result = stripConditionalExpr(ce.getThen())
|
||||
or
|
||||
result = stripConditionalExpr(ce.getElse())
|
||||
)
|
||||
result = stripConditionalExpr(ce.getThen())
|
||||
or
|
||||
result = stripConditionalExpr(ce.getElse())
|
||||
)
|
||||
or
|
||||
not e instanceof ConditionalExpr and
|
||||
result = e
|
||||
@@ -878,7 +846,8 @@ module Internal {
|
||||
predicate nullGuardedReturn(Expr ret, boolean isNull) {
|
||||
canReturn(p.getCallable(), ret) and
|
||||
exists(PreBasicBlocks::PreBasicBlock bb, NullValue nv |
|
||||
this.getARead().(Guard).preControls(bb, nv) |
|
||||
this.getARead().(Guard).preControls(bb, nv)
|
||||
|
|
||||
ret = bb.getAnElement() and
|
||||
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
|
||||
* 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) {
|
||||
exists(Callable c |
|
||||
canReturn(c, ret) |
|
||||
private predicate validReturnInCustomNullCheck(
|
||||
Expr ret, Parameter p, BooleanValue retVal, boolean isNull
|
||||
) {
|
||||
exists(Callable c | canReturn(c, ret) |
|
||||
p.getCallable() = c and
|
||||
c.getReturnType() instanceof BoolType
|
||||
) and
|
||||
exists(PreSsaImplicitParameterDefinition def |
|
||||
p = def.getParameter() |
|
||||
exists(PreSsaImplicitParameterDefinition def | p = def.getParameter() |
|
||||
def.nullGuardedReturn(ret, isNull)
|
||||
or
|
||||
exists(NullValue nv |
|
||||
preImpliesSteps(ret, retVal, def.getARead(), nv) |
|
||||
exists(NullValue nv | preImpliesSteps(ret, retVal, def.getARead(), nv) |
|
||||
if nv.isNull() then isNull = true else isNull = false
|
||||
)
|
||||
)
|
||||
@@ -922,7 +890,7 @@ module Internal {
|
||||
forex(Expr ret |
|
||||
canReturn(result, ret) and
|
||||
not ret.(BoolLiteral).getBoolValue() = retVal.getValue().booleanNot()
|
||||
|
|
||||
|
|
||||
validReturnInCustomNullCheck(ret, p, retVal, isNull)
|
||||
)
|
||||
}
|
||||
@@ -931,19 +899,20 @@ module Internal {
|
||||
* Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned
|
||||
* 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:
|
||||
// v = guard ? e : x;
|
||||
exists(ConditionalExpr c |
|
||||
c = def.getDefinition().getSource() |
|
||||
exists(ConditionalExpr c | c = def.getDefinition().getSource() |
|
||||
guard = c.getCondition() and
|
||||
vGuard = any(BooleanValue bv |
|
||||
bv.getValue() = true and
|
||||
e = c.getThen()
|
||||
or
|
||||
bv.getValue() = false and
|
||||
e = c.getElse()
|
||||
)
|
||||
bv.getValue() = true and
|
||||
e = c.getThen()
|
||||
or
|
||||
bv.getValue() = false and
|
||||
e = c.getElse()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(PreSsa::Definition upd, PreBasicBlocks::PreBasicBlock bbGuard |
|
||||
@@ -953,8 +922,7 @@ module Internal {
|
||||
bbGuard.getAnElement() = guard and
|
||||
bbGuard.strictlyDominates(def.getBasicBlock()) and
|
||||
not guard.preControlsDirect(def.getBasicBlock(), vGuard) and
|
||||
forall(PreSsa::Definition other |
|
||||
other != upd and other = def.getAPhiInput() |
|
||||
forall(PreSsa::Definition other | other != upd and other = def.getAPhiInput() |
|
||||
// For example:
|
||||
// if (guard)
|
||||
// upd = a;
|
||||
@@ -978,7 +946,9 @@ module Internal {
|
||||
* Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned
|
||||
* 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())
|
||||
}
|
||||
|
||||
@@ -998,24 +968,24 @@ module Internal {
|
||||
* expression `x` is guaranteed to be equal to `""`.
|
||||
*/
|
||||
private Expr getABooleanEqualityCheck(Expr e1, BooleanValue v, Expr e2) {
|
||||
exists(boolean branch |
|
||||
branch = v.getValue() |
|
||||
exists(boolean branch | branch = v.getValue() |
|
||||
exists(ComparisonTest ct, ComparisonKind ck |
|
||||
ct.getExpr() = result and
|
||||
ct.getAnArgument() = e1 and
|
||||
ct.getAnArgument() = e2 and
|
||||
e2 != e1 and
|
||||
ck = ct.getComparisonKind() |
|
||||
ck = ct.getComparisonKind()
|
||||
|
|
||||
ck.isEquality() and branch = true
|
||||
or
|
||||
ck.isInequality() and branch = false
|
||||
)
|
||||
or
|
||||
result = any(IsExpr ie |
|
||||
ie.getExpr() = e1 and
|
||||
e2 = ie.(IsConstantExpr).getConstant() and
|
||||
branch = true
|
||||
)
|
||||
ie.getExpr() = e1 and
|
||||
e2 = ie.(IsConstantExpr).getConstant() and
|
||||
branch = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1042,8 +1012,7 @@ module Internal {
|
||||
* then `o` is guaranteed to be equal to `""`.
|
||||
*/
|
||||
private Expr getAMatchingEqualityCheck(Expr e1, MatchValue v, Expr e2) {
|
||||
exists(SwitchStmt ss, ConstCase cc |
|
||||
cc = v.getCaseStmt() |
|
||||
exists(SwitchStmt ss, ConstCase cc | cc = v.getCaseStmt() |
|
||||
e1 = ss.getCondition() and
|
||||
result = e1 and
|
||||
cc = ss.getACase() and
|
||||
@@ -1078,10 +1047,11 @@ module Internal {
|
||||
* Holds if the evaluation of `guard` to `vGuard` implies that `def` does not
|
||||
* 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
|
||||
exists(AssignableRead ar |
|
||||
ar = def.getARead() |
|
||||
exists(AssignableRead ar | ar = def.getARead() |
|
||||
// For example:
|
||||
// if (de == null); vGuard = TBooleanValue(false); vDef = TNullValue(true)
|
||||
// but not
|
||||
@@ -1094,7 +1064,8 @@ module Internal {
|
||||
// or
|
||||
// if (de == null); vGuard = TBooleanValue(true); vDef = TNullValue(false)
|
||||
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()
|
||||
)
|
||||
or
|
||||
@@ -1115,8 +1086,7 @@ module Internal {
|
||||
|
|
||||
not exists(input.getDefinition().getSource())
|
||||
or
|
||||
exists(Expr e |
|
||||
e = stripConditionalExpr(input.getDefinition().getSource()) |
|
||||
exists(Expr e | e = stripConditionalExpr(input.getDefinition().getSource()) |
|
||||
not e = any(AbstractValue v).getAnExpr()
|
||||
)
|
||||
)
|
||||
@@ -1133,7 +1103,8 @@ module Internal {
|
||||
fromBackEdge = false
|
||||
or
|
||||
exists(PreSsa::Definition input, PreBasicBlocks::PreBasicBlock pred, boolean fbe |
|
||||
input = def.getAPhiInput() |
|
||||
input = def.getAPhiInput()
|
||||
|
|
||||
pred = def.getBasicBlock().getAPredecessor() and
|
||||
PreSsa::ssaDefReachesEndOfBlock(pred, input, _) and
|
||||
result = getADefinition(input, fbe) and
|
||||
@@ -1146,10 +1117,11 @@ module Internal {
|
||||
* `fromBackEdge` indicates whether the flow from `e` to `def` goes through a
|
||||
* 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
|
||||
exists(PreSsa::Definition input |
|
||||
input = getADefinition(def, fromBackEdge) |
|
||||
exists(PreSsa::Definition input | input = getADefinition(def, fromBackEdge) |
|
||||
e = stripConditionalExpr(input.getDefinition().getSource()) and
|
||||
v.getAnExpr() = e
|
||||
)
|
||||
@@ -1176,7 +1148,9 @@ module Internal {
|
||||
* Holds if `guard` having abstract value `vGuard` implies that `def` has
|
||||
* 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())
|
||||
}
|
||||
|
||||
@@ -1184,17 +1158,15 @@ module Internal {
|
||||
* A helper class for calculating structurally equal access/call expressions.
|
||||
*/
|
||||
private class ConditionOnExprComparisonConfig extends InternalStructuralComparisonConfiguration {
|
||||
ConditionOnExprComparisonConfig() {
|
||||
this = "ConditionOnExprComparisonConfig"
|
||||
}
|
||||
ConditionOnExprComparisonConfig() { this = "ConditionOnExprComparisonConfig" }
|
||||
|
||||
override predicate candidate(Element x, Element y) {
|
||||
exists(BasicBlock bb, Declaration d |
|
||||
candidateAux(x, d, bb) and
|
||||
y = any(AccessOrCallExpr e |
|
||||
e.getAControlFlowNode().getBasicBlock() = bb and
|
||||
e.getTarget() = d
|
||||
)
|
||||
e.getAControlFlowNode().getBasicBlock() = bb and
|
||||
e.getTarget() = d
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1203,11 +1175,10 @@ module Internal {
|
||||
* is a sub expression of a condition that controls whether basic block
|
||||
* `bb` is reached.
|
||||
*/
|
||||
pragma [noinline]
|
||||
pragma[noinline]
|
||||
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
|
||||
target = e.getTarget() and
|
||||
exists(Guard g |
|
||||
e = g.getAChildExpr*() |
|
||||
exists(Guard g | e = g.getAChildExpr*() |
|
||||
g.controls(bb, _)
|
||||
or
|
||||
g.assertionControlsElement(bb.getANode().getElement(), _)
|
||||
@@ -1215,18 +1186,23 @@ module Internal {
|
||||
}
|
||||
}
|
||||
|
||||
private cached module Cached {
|
||||
cached
|
||||
private module Cached {
|
||||
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
|
||||
g.controls(cfn.getBasicBlock(), v) and
|
||||
exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isGuardedByExpr1(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) {
|
||||
forex(ControlFlow::Node cfn |
|
||||
cfn = guarded.getAControlFlowNode() |
|
||||
private predicate isGuardedByExpr1(
|
||||
AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v
|
||||
) {
|
||||
forex(ControlFlow::Node cfn | cfn = guarded.getAControlFlowNode() |
|
||||
isGuardedByNode0(cfn, guarded, g, sub, v)
|
||||
)
|
||||
or
|
||||
@@ -1235,17 +1211,20 @@ module Internal {
|
||||
}
|
||||
|
||||
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
|
||||
sub = g.getAChildExpr*() and
|
||||
forall(Ssa::Definition def |
|
||||
def = sub.getAnSsaQualifier(_) |
|
||||
forall(Ssa::Definition def | def = sub.getAnSsaQualifier(_) |
|
||||
def = guarded.getAnSsaQualifier(_)
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
or
|
||||
g.assertionControlsNode(guarded, v) and
|
||||
@@ -1253,13 +1232,15 @@ module Internal {
|
||||
}
|
||||
|
||||
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
|
||||
sub = g.getAChildExpr*() and
|
||||
forall(Ssa::Definition def |
|
||||
def = sub.getAnSsaQualifier(_) |
|
||||
forall(Ssa::Definition def | def = sub.getAnSsaQualifier(_) |
|
||||
exists(ControlFlow::Node cfn |
|
||||
def = guarded.getElement().(AccessOrCallExpr).getAnSsaQualifier(cfn) |
|
||||
def = guarded.getElement().(AccessOrCallExpr).getAnSsaQualifier(cfn)
|
||||
|
|
||||
cfn.getBasicBlock() = guarded.getBasicBlock()
|
||||
)
|
||||
)
|
||||
@@ -1276,10 +1257,8 @@ module Internal {
|
||||
predicate impliesStep(Guard g1, AbstractValue v1, Guard g2, AbstractValue v2) {
|
||||
preImpliesStep(g1, v1, g2, v2)
|
||||
or
|
||||
forex(ControlFlow::Node cfn |
|
||||
cfn = g1.getAControlFlowNode() |
|
||||
exists(Ssa::ExplicitDefinition def |
|
||||
def.getADefinition().getSource() = g2 |
|
||||
forex(ControlFlow::Node cfn | cfn = g1.getAControlFlowNode() |
|
||||
exists(Ssa::ExplicitDefinition def | def.getADefinition().getSource() = g2 |
|
||||
g1 = def.getAReadAtNode(cfn) and
|
||||
v1 = g1.getAValue() and
|
||||
v2 = v1
|
||||
@@ -1292,7 +1271,8 @@ module Internal {
|
||||
// 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
|
||||
// pre-SSA predicates
|
||||
cached module CachedWithCFG {
|
||||
cached
|
||||
module CachedWithCFG {
|
||||
cached
|
||||
predicate isCustomNullCheck(Call call, Expr arg, BooleanValue v, boolean isNull) {
|
||||
exists(Callable callable, Parameter p |
|
||||
@@ -1312,24 +1292,24 @@ module Internal {
|
||||
cached
|
||||
predicate preImpliesStep(Guard g1, AbstractValue v1, Guard g2, AbstractValue v2) {
|
||||
g1 = any(BinaryOperation bo |
|
||||
(
|
||||
bo instanceof BitwiseAndExpr or
|
||||
bo instanceof LogicalAndExpr
|
||||
) and
|
||||
g2 = bo.getAnOperand() and
|
||||
v1 = TBooleanValue(true) and
|
||||
v2 = v1
|
||||
)
|
||||
(
|
||||
bo instanceof BitwiseAndExpr or
|
||||
bo instanceof LogicalAndExpr
|
||||
) and
|
||||
g2 = bo.getAnOperand() and
|
||||
v1 = TBooleanValue(true) and
|
||||
v2 = v1
|
||||
)
|
||||
or
|
||||
g1 = any(BinaryOperation bo |
|
||||
(
|
||||
bo instanceof BitwiseOrExpr or
|
||||
bo instanceof LogicalOrExpr
|
||||
) and
|
||||
g2 = bo.getAnOperand() and
|
||||
v1 = TBooleanValue(false) and
|
||||
v2 = v1
|
||||
)
|
||||
(
|
||||
bo instanceof BitwiseOrExpr or
|
||||
bo instanceof LogicalOrExpr
|
||||
) and
|
||||
g2 = bo.getAnOperand() and
|
||||
v1 = TBooleanValue(false) and
|
||||
v2 = v1
|
||||
)
|
||||
or
|
||||
g2 = g1.(LogicalNotExpr).getOperand() and
|
||||
v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanNot())
|
||||
@@ -1339,7 +1319,8 @@ module Internal {
|
||||
b = boolLit.getBoolValue() and
|
||||
g2 = ct.getAnArgument() 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
|
||||
polarity = true
|
||||
or
|
||||
@@ -1376,14 +1357,13 @@ module Internal {
|
||||
or
|
||||
v1 = g1.getAValue() and
|
||||
v1 = any(MatchValue mv |
|
||||
mv.isMatch() and
|
||||
g2 = g1 and
|
||||
v2.getAnExpr() = mv.getCaseStmt().(ConstCase).getExpr() and
|
||||
v1 != v2
|
||||
)
|
||||
mv.isMatch() and
|
||||
g2 = g1 and
|
||||
v2.getAnExpr() = mv.getCaseStmt().(ConstCase).getExpr() and
|
||||
v1 != v2
|
||||
)
|
||||
or
|
||||
exists(boolean isNull |
|
||||
g1 = g2.(DereferenceableExpr).getANullCheck(v1, isNull) |
|
||||
exists(boolean isNull | g1 = g2.(DereferenceableExpr).getANullCheck(v1, isNull) |
|
||||
v2 = any(NullValue nv | if nv.isNull() then isNull = true else isNull = false) and
|
||||
(g1 != g2 or v1 != v2)
|
||||
)
|
||||
@@ -1410,8 +1390,7 @@ module Internal {
|
||||
v1 = g1.getAValue() and
|
||||
v2 = v1.(NullValue)
|
||||
or
|
||||
exists(PreSsa::Definition def |
|
||||
def.getDefinition().getSource() = g2 |
|
||||
exists(PreSsa::Definition def | def.getDefinition().getSource() = g2 |
|
||||
g1 = def.getARead() and
|
||||
v1 = g1.getAValue() and
|
||||
v2 = v1
|
||||
@@ -1452,8 +1431,7 @@ module Internal {
|
||||
v1 = v2 and
|
||||
v1 = g1.getAValue()
|
||||
or
|
||||
exists(Expr mid, AbstractValue vMid |
|
||||
preImpliesSteps(g1, v1, mid, vMid) |
|
||||
exists(Expr mid, AbstractValue vMid | preImpliesSteps(g1, v1, mid, vMid) |
|
||||
preImpliesStep(mid, vMid, g2, v2)
|
||||
)
|
||||
}
|
||||
@@ -1470,8 +1448,7 @@ module Internal {
|
||||
v1 = v2 and
|
||||
v1 = g1.getAValue()
|
||||
or
|
||||
exists(Expr mid, AbstractValue vMid |
|
||||
impliesSteps(g1, v1, mid, vMid) |
|
||||
exists(Expr mid, AbstractValue vMid | impliesSteps(g1, v1, mid, vMid) |
|
||||
impliesStep(mid, vMid, g2, v2)
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,19 +6,17 @@
|
||||
import csharp
|
||||
|
||||
module TaintTracking {
|
||||
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.commons.ComparisonTest
|
||||
private import cil
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.commons.ComparisonTest
|
||||
private import cil
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `source` to `sink` in zero or more local
|
||||
* (intra-procedural) steps.
|
||||
*/
|
||||
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) {
|
||||
localTaintStep*(source, sink)
|
||||
}
|
||||
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) }
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
final
|
||||
override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) }
|
||||
final override predicate isBarrier(DataFlow::Node node) { isSanitizer(node) }
|
||||
|
||||
/**
|
||||
* 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() }
|
||||
|
||||
final
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
isAdditionalTaintStep(pred, succ) or
|
||||
localAdditionalTaintStep(pred, succ) or
|
||||
DataFlow::Internal::flowThroughCallableLibraryOutRef(_, pred, succ, false)
|
||||
}
|
||||
|
||||
final
|
||||
override predicate isAdditionalFlowStepIntoCall(DataFlow::Node call, DataFlow::Node arg, DotNet::Parameter p, CallContext::CallContext cc) {
|
||||
final override predicate isAdditionalFlowStepIntoCall(
|
||||
DataFlow::Node call, DataFlow::Node arg, DotNet::Parameter p, CallContext::CallContext cc
|
||||
) {
|
||||
DataFlow::Internal::flowIntoCallableLibraryCall(_, arg, call, p, false, cc)
|
||||
}
|
||||
|
||||
final
|
||||
override predicate isAdditionalFlowStepOutOfCall(DataFlow::Node call, DataFlow::Node ret, DataFlow::Node out, CallContext::CallContext cc) {
|
||||
exists(DispatchCall dc, Callable callable |
|
||||
canYieldReturn(callable, ret.asExpr()) |
|
||||
final override predicate isAdditionalFlowStepOutOfCall(
|
||||
DataFlow::Node call, DataFlow::Node ret, DataFlow::Node out, CallContext::CallContext cc
|
||||
) {
|
||||
exists(DispatchCall dc, Callable callable | canYieldReturn(callable, ret.asExpr()) |
|
||||
dc.getCall() = call.asExpr() and
|
||||
call = out and
|
||||
callable = dc.getADynamicTarget() and
|
||||
@@ -112,9 +109,7 @@ module TaintTracking {
|
||||
|
||||
/** INTERNAL: Do not use. */
|
||||
module Internal {
|
||||
predicate canYieldReturn(Callable c, Expr e) {
|
||||
c.getSourceDeclaration().canYieldReturn(e)
|
||||
}
|
||||
predicate canYieldReturn(Callable c, Expr e) { c.getSourceDeclaration().canYieldReturn(e) }
|
||||
|
||||
private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) {
|
||||
result = node.asParameter() or
|
||||
@@ -126,14 +121,15 @@ module TaintTracking {
|
||||
}
|
||||
|
||||
/** Gets the qualifier of element access `ea`. */
|
||||
private Expr getElementAccessQualifier(ElementAccess ea) {
|
||||
result = ea.getQualifier()
|
||||
}
|
||||
private Expr getElementAccessQualifier(ElementAccess ea) { result = ea.getQualifier() }
|
||||
|
||||
private class LocalTaintExprStepConfiguration extends DataFlow::Internal::ExprStepConfiguration {
|
||||
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
|
||||
(
|
||||
// Taint propagation using library code
|
||||
@@ -154,7 +150,11 @@ module TaintTracking {
|
||||
or
|
||||
// Taint from object initializer
|
||||
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)
|
||||
scope = exprTo and
|
||||
isSuccessor = false
|
||||
@@ -187,11 +187,11 @@ module TaintTracking {
|
||||
or
|
||||
// Taint from tuple argument
|
||||
exprTo = any(TupleExpr te |
|
||||
exprFrom = te.getAnArgument() and
|
||||
te.isReadAccess() and
|
||||
scope = exprTo and
|
||||
isSuccessor = true
|
||||
)
|
||||
exprFrom = te.getAnArgument() and
|
||||
te.isReadAccess() and
|
||||
scope = exprTo and
|
||||
isSuccessor = true
|
||||
)
|
||||
or
|
||||
exprFrom = exprTo.(InterpolatedStringExpr).getAChild() and
|
||||
scope = exprTo and
|
||||
@@ -199,19 +199,23 @@ module TaintTracking {
|
||||
or
|
||||
// Taint from tuple expression
|
||||
exprTo = any(MemberAccess ma |
|
||||
ma.getQualifier().getType() instanceof TupleType and
|
||||
exprFrom = ma.getQualifier() and
|
||||
scope = exprTo and
|
||||
isSuccessor = true
|
||||
)
|
||||
ma.getQualifier().getType() instanceof TupleType and
|
||||
exprFrom = ma.getQualifier() and
|
||||
scope = exprTo and
|
||||
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
|
||||
exists(ForeachStmt fs |
|
||||
exprFrom = fs.getIterableExpr() and
|
||||
defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = fs.getVariableDeclExpr() and
|
||||
defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = fs
|
||||
.getVariableDeclExpr() and
|
||||
isSuccessor = true
|
||||
|
|
||||
scope = fs and
|
||||
@@ -226,10 +230,13 @@ module TaintTracking {
|
||||
}
|
||||
}
|
||||
|
||||
cached module Cached {
|
||||
cached predicate forceCachingInSameStage() { any() }
|
||||
cached
|
||||
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
|
||||
any(LocalTaintExprStepConfiguration x).hasStep(nodeFrom, nodeTo)
|
||||
or
|
||||
|
||||
@@ -47,10 +47,7 @@ module Steps {
|
||||
* Holds if modifiable `m` is effectively private or internal (either directly
|
||||
* or because one of `m`'s enclosing types is).
|
||||
*/
|
||||
private predicate isEffectivelyInternalOrPrivate(Modifiable m) {
|
||||
m.isEffectivelyInternal() or
|
||||
m.isEffectivelyPrivate()
|
||||
}
|
||||
private predicate isEffectivelyInternalOrPrivate(Modifiable m) { not m.isEffectivelyPublic() }
|
||||
|
||||
private predicate flowIn(Parameter p, Expr pred, AssignableRead succ) {
|
||||
exists(AssignableDefinitions::ImplicitParameterDefinition def, Call c | succ = getARead(def) |
|
||||
|
||||
@@ -294,7 +294,7 @@ private module Internal {
|
||||
|
|
||||
succ.(AssignableRead) = a.getAnAccess() 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 getQualifier() { result = getCall().getAccess().getQualifier() }
|
||||
override Expr getQualifier() { result = getCall().(MemberAccess).getQualifier() }
|
||||
|
||||
override Accessor getAStaticTarget() { result = getCall().getTarget() }
|
||||
|
||||
|
||||
@@ -380,6 +380,17 @@ class MemberConstantAccess extends FieldAccess {
|
||||
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
|
||||
*
|
||||
@@ -393,13 +404,8 @@ class MemberConstantAccess extends FieldAccess {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class PropertyAccess extends AssignableMemberAccess, @property_access_expr {
|
||||
/** Gets the target of this property access. */
|
||||
Property getProperty() { expr_access(this, result) }
|
||||
|
||||
class PropertyAccess extends AssignableMemberAccess, PropertyAccessExpr {
|
||||
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 { }
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@@ -522,17 +539,12 @@ class ElementWrite extends ElementAccess, AssignableWrite { }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class IndexerAccess extends AssignableMemberAccess, ElementAccess, @indexer_access_expr {
|
||||
/** Gets the target of this indexer access. */
|
||||
Indexer getIndexer() { expr_access(this, result) }
|
||||
|
||||
class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccessExpr {
|
||||
override Indexer getTarget() { result = this.getIndexer() }
|
||||
|
||||
override Indexer getQualifiedDeclaration() {
|
||||
result = ElementAccess.super.getQualifiedDeclaration()
|
||||
}
|
||||
|
||||
override string toString() { result = "access to indexer" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -588,6 +600,17 @@ class VirtualIndexerAccess extends IndexerAccess {
|
||||
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
|
||||
* 7 and 8 in
|
||||
@@ -605,13 +628,8 @@ class VirtualIndexerAccess extends IndexerAccess {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class EventAccess extends AssignableMemberAccess, @event_access_expr {
|
||||
/** Gets the target of this event access. */
|
||||
Event getEvent() { expr_access(this, result) }
|
||||
|
||||
class EventAccess extends AssignableMemberAccess, EventAccessExpr {
|
||||
override Event getTarget() { result = getEvent() }
|
||||
|
||||
override string toString() { result = "access to event " + this.getEvent().getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,24 +11,13 @@ private import semmle.code.csharp.dataflow.DelegateDataFlow
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import 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
|
||||
* (`ConstructorInitializer`), a call to a user-defined operator (`OperatorCall`),
|
||||
* a delegate call (`DelegateCall`), an accessor call (`AccessorCall`), a
|
||||
* 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
|
||||
* 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" }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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`),
|
||||
* an indexer accessor call (`IndexerCall`), or an event accessor call
|
||||
* (`EventCall`).
|
||||
*/
|
||||
class AccessorCall extends Call {
|
||||
private AccessorCallImpl::AccessorCallImpl impl;
|
||||
class AccessorCall extends Call, QualifiableExpr, @call_access_expr {
|
||||
override Accessor getTarget() { none() }
|
||||
|
||||
AccessorCall() { this = impl }
|
||||
|
||||
/** 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 Expr getArgument(int i) { none() }
|
||||
|
||||
override Accessor getARuntimeTarget() { result = Call.super.getARuntimeTarget() }
|
||||
}
|
||||
@@ -736,15 +581,21 @@ class AccessorCall extends Call {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class PropertyCall extends AccessorCall {
|
||||
private AccessorCallImpl::PropertyCallImpl impl;
|
||||
class PropertyCall extends AccessorCall, PropertyAccessExpr {
|
||||
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() }
|
||||
|
||||
/** Gets property targeted by this property call. */
|
||||
Property getProperty() { result = this.getAccess().getTarget() }
|
||||
override string toString() { result = PropertyAccessExpr.super.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -763,15 +614,23 @@ class PropertyCall extends AccessorCall {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class IndexerCall extends AccessorCall {
|
||||
private AccessorCallImpl::IndexerCallImpl impl;
|
||||
class IndexerCall extends AccessorCall, IndexerAccessExpr {
|
||||
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() }
|
||||
|
||||
/** Gets indexer targeted by this index call. */
|
||||
Indexer getIndexer() { result = this.getAccess().getTarget() }
|
||||
override string toString() { result = IndexerAccessExpr.super.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -795,15 +654,27 @@ class IndexerCall extends AccessorCall {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class EventCall extends AccessorCall, @assign_event_expr {
|
||||
private AccessorCallImpl::EventCallImpl impl;
|
||||
class EventCall extends AccessorCall, EventAccessExpr {
|
||||
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() }
|
||||
|
||||
/** Gets event targeted by this event call. */
|
||||
Event getEvent() { result = this.getAccess().getTarget() }
|
||||
override string toString() { result = EventAccessExpr.super.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -155,7 +155,7 @@ class XmlReaderSettingsCreation extends ObjectCreation {
|
||||
p = this.getType().(RefType).getAProperty() and
|
||||
exists(PropertyCall set, Expr arg |
|
||||
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
|
||||
result = getBitwiseOrOperand*(arg)
|
||||
)
|
||||
|
||||
@@ -63,6 +63,8 @@ class PrivateVariableAccess extends PrivateDataExpr, VariableAccess {
|
||||
/** Reading the text property of a control that might contain private data. */
|
||||
class PrivateControlAccess extends PrivateDataExpr {
|
||||
PrivateControlAccess() {
|
||||
exists(TextControl c | this = c.getARead() and c.getName().toLowerCase().matches(privateNames()))
|
||||
exists(TextControl c |
|
||||
this = c.getARead() and c.getName().toLowerCase().matches(privateNames())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ class NamedElement extends Element, @dotnet_named_element {
|
||||
predicate compiledFromSource() {
|
||||
not this.fromSource() and
|
||||
exists(NamedElement other | other != this |
|
||||
other.getLabel() = this.getLabel() and
|
||||
this.matchesHandle(other) and
|
||||
other.fromSource()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
import Expr
|
||||
import Type
|
||||
import Callable
|
||||
private import csharp as CS
|
||||
|
||||
/** An expression. */
|
||||
class Expr extends Element, @dotnet_expr {
|
||||
@@ -26,9 +25,7 @@ class Expr extends Element, @dotnet_expr {
|
||||
}
|
||||
|
||||
/** A call. */
|
||||
class Call extends Expr {
|
||||
Call() { this instanceof @cil_call_any or this instanceof CS::CallImpl }
|
||||
|
||||
class Call extends Expr, @dotnet_call {
|
||||
/** Gets the target of this call. */
|
||||
Callable getTarget() { none() }
|
||||
|
||||
|
||||
@@ -17,23 +17,21 @@
|
||||
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | o |
|
||||
| arguments.cs: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:54:9:54:16 | ... = ... | 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:54:9:54:12 | access to property Prop | arguments.cs:54:16:54:16 | 0 | 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: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: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: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:17:59:17 | 9 | b |
|
||||
| arguments.cs:59:9:59:20 | ...++ | arguments.cs:59:14:59:14 | 8 | a |
|
||||
| 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:9:60:26 | ... + ... | value |
|
||||
| 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:26 | ... = ... | arguments.cs:60:9:60:26 | ... + ... | value |
|
||||
| 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:60:9:60:20 | access to indexer | 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:25:62:26 | 16 | b |
|
||||
|
||||
@@ -17,23 +17,23 @@
|
||||
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | arguments.cs:33:17:33:17 | o |
|
||||
| arguments.cs: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:54:9:54:16 | ... = ... | 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: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: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: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: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: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: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:20 | ...++ | 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: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: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: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:60:9:60:20 | access to indexer | 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:25:62:26 | 16 | arguments.cs:50:25:50:25 | b |
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
nonUniqueSetRepresentation
|
||||
breakInvariant2
|
||||
breakInvariant3
|
||||
breakInvariant4
|
||||
breakInvariant5
|
||||
@@ -0,0 +1,50 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.controlflow.Completion
|
||||
import ControlFlow
|
||||
import ControlFlow::Internal
|
||||
|
||||
query predicate nonUniqueSetRepresentation(Splits s1, Splits s2) {
|
||||
forex(Nodes::Split s | s = s1.getASplit() | s = s2.getASplit()) and
|
||||
forex(Nodes::Split s | s = s2.getASplit() | s = s1.getASplit()) and
|
||||
s1 != s2
|
||||
}
|
||||
|
||||
query predicate breakInvariant2(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
SplitInternal split, Completion c
|
||||
) {
|
||||
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||
split = predSplits.getASplit() and
|
||||
split.hasSuccessor(pred, succ, c) and
|
||||
not split = succSplits.getASplit()
|
||||
}
|
||||
|
||||
query predicate breakInvariant3(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
SplitInternal split, Completion c
|
||||
) {
|
||||
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||
split = predSplits.getASplit() and
|
||||
split.hasExit(pred, succ, c) and
|
||||
split = succSplits.getASplit()
|
||||
}
|
||||
|
||||
query predicate breakInvariant4(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
SplitInternal split, Completion c
|
||||
) {
|
||||
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||
split.hasEntry(pred, succ, c) and
|
||||
not split = predSplits.getASplit() and
|
||||
not split = succSplits.getASplit()
|
||||
}
|
||||
|
||||
query predicate breakInvariant5(
|
||||
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
|
||||
SplitInternal split, Completion c
|
||||
) {
|
||||
succSplits(pred, predSplits, succ, succSplits, c) and
|
||||
split = succSplits.getASplit() and
|
||||
not (split.hasSuccessor(pred, succ, c) and split = predSplits.getASplit()) and
|
||||
not (split.hasEntry(pred, succ, c) and not split = predSplits.getASplit())
|
||||
}
|
||||
@@ -68,6 +68,8 @@
|
||||
| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false |
|
||||
| Guards.cs: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: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: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 |
|
||||
|
||||
@@ -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: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: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: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 |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user