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

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

View File

@@ -26,4 +26,5 @@
## Changes to QL libraries
There is a new `Namespace.isInline()` predicate, which holds if the namespace was declared as `inline namespace`.
* There is a new `Namespace.isInline()` predicate, which holds if the namespace was declared as `inline namespace`.
* The `Expr.isConstant()` predicate now also holds for _address constant expressions_, which are addresses that will be constant after the program has been linked. These address constants do not have a result for `Expr.getValue()`.

View File

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

View File

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

View File

@@ -10,11 +10,16 @@
* The taint tracking library now recognizes flow through persistent storage, class fields, and callbacks in certain cases. This may give more results for the security queries.
* 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. |

View File

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

View File

@@ -8,6 +8,6 @@ int doFoo(Names n) { //wrong: n is passed by value (meaning the entire structure
...
}
int doBar(Names &n) { //better, only a reference is passed
int doBar(const Names &n) { //better, only a reference is passed
...
}

View File

@@ -1,6 +1,6 @@
/**
* @name Large object passed by value
* @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()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,184 @@
private import cpp
private import semmle.code.cpp.dataflow.EscapesTree
predicate addressConstantExpression(Expr e) {
constantAddressPointer(e)
or
constantAddressReference(e)
or
// Special case for function pointers, where `fp == *fp`.
constantAddressLValue(e) and
e.getType() instanceof FunctionPointerType
}
/** Holds if `v` is a constexpr variable initialized to a constant address. */
private predicate addressConstantVariable(Variable v) {
addressConstantExpression(v.getInitializer().getExpr().getFullyConverted()) and
// Here we should also require that `v` is constexpr, but we don't have that
// information in the db. See CPP-314. Instead, we require that the variable
// is never defined except in its initializer.
forall(Expr def | definition(v, def) | def = any(Initializer init).getExpr())
}
/**
* Holds if `lvalue` is an lvalue whose address is an _address constant
* expression_.
*/
private predicate constantAddressLValue(Expr lvalue) {
lvalue.(VariableAccess).getTarget() = any(Variable v |
v.(Variable).isStatic()
or
v instanceof GlobalOrNamespaceVariable
)
or
// There is no `Conversion` for the implicit conversion from a function type
// to a function _pointer_ type. Instead, the type of a `FunctionAccess`
// tells us how it's going to be used.
lvalue.(FunctionAccess).getType() instanceof RoutineType
or
// String literals have array types and undergo array-to-pointer conversion.
lvalue instanceof StringLiteral
or
// lvalue -> lvalue
exists(Expr prev |
constantAddressLValue(prev) and
lvalueToLvalueStep(prev, lvalue)
)
or
// pointer -> lvalue
exists(Expr prev |
constantAddressPointer(prev) and
pointerToLvalueStep(prev, lvalue)
)
or
// reference -> lvalue
exists(Expr prev |
constantAddressReference(prev) and
referenceToLvalueStep(prev, lvalue)
)
}
/** Holds if `pointer` is an _address constant expression_ of pointer type. */
private predicate constantAddressPointer(Expr pointer) {
// There is no `Conversion` for the implicit conversion from a function type
// to a function _pointer_ type. Instead, the type of a `FunctionAccess`
// tells us how it's going to be used.
pointer.(FunctionAccess).getType() instanceof FunctionPointerType
or
addressConstantVariable(pointer.(VariableAccess).getTarget()) and
pointer.getType().getUnderlyingType() instanceof PointerType
or
// pointer -> pointer
exists(Expr prev |
constantAddressPointer(prev) and
pointerToPointerStep(prev, pointer)
)
or
// lvalue -> pointer
exists(Expr prev |
constantAddressLValue(prev) and
lvalueToPointerStep(prev, pointer)
)
}
/** Holds if `reference` is an _address constant expression_ of reference type. */
private predicate constantAddressReference(Expr reference) {
addressConstantVariable(reference.(VariableAccess).getTarget()) and
reference.getType().getUnderlyingType() instanceof ReferenceType
or
addressConstantVariable(reference.(VariableAccess).getTarget()) and
reference.getType().getUnderlyingType() instanceof FunctionReferenceType // not a ReferenceType
or
// reference -> reference
exists(Expr prev |
constantAddressReference(prev) and
referenceToReferenceStep(prev, reference)
)
or
// lvalue -> reference
exists(Expr prev |
constantAddressLValue(prev) and
lvalueToReferenceStep(prev, reference)
)
}
private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
lvalueIn = lvalueOut.(DotFieldAccess).getQualifier().getFullyConverted()
or
lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr)
or
// Special case for function pointers, where `fp == *fp`.
lvalueIn = lvalueOut.(PointerDereferenceExpr).getOperand().getFullyConverted() and
lvalueIn.getType() instanceof FunctionPointerType
}
private predicate pointerToLvalueStep(Expr pointerIn, Expr lvalueOut) {
lvalueOut = any(ArrayExpr ae |
pointerIn = ae.getArrayBase().getFullyConverted() and
hasConstantValue(ae.getArrayOffset().getFullyConverted())
)
or
pointerIn = lvalueOut.(PointerDereferenceExpr).getOperand().getFullyConverted()
or
pointerIn = lvalueOut.(PointerFieldAccess).getQualifier().getFullyConverted()
}
private predicate lvalueToPointerStep(Expr lvalueIn, Expr pointerOut) {
lvalueIn.getConversion() = pointerOut.(ArrayToPointerConversion)
or
lvalueIn = pointerOut.(AddressOfExpr).getOperand().getFullyConverted()
}
private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) {
(
pointerOut instanceof PointerAddExpr
or
pointerOut instanceof PointerSubExpr
) and
pointerIn = pointerOut.getAChild().getFullyConverted() and
pointerIn.getType().getUnspecifiedType() instanceof PointerType and
// The pointer arg won't be constant in the sense of `hasConstantValue`, so
// this will have to match the integer argument.
hasConstantValue(pointerOut.getAChild().getFullyConverted())
or
pointerIn = pointerOut.(UnaryPlusExpr).getOperand().getFullyConverted()
or
pointerIn.getConversion() = pointerOut.(Cast)
or
pointerIn.getConversion() = pointerOut.(ParenthesisExpr)
or
pointerOut = any(ConditionalExpr cond |
cond.getCondition().getFullyConverted().getValue().toInt() != 0 and
pointerIn = cond.getThen().getFullyConverted()
or
cond.getCondition().getFullyConverted().getValue().toInt() = 0 and
pointerIn = cond.getElse().getFullyConverted()
)
or
// The comma operator is allowed by C++17 but disallowed by C99. This
// disjunct is a compromise that's chosen for being easy to implement.
pointerOut = any(CommaExpr comma |
hasConstantValue(comma.getLeftOperand()) and
pointerIn = comma.getRightOperand().getFullyConverted()
)
}
private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) {
lvalueIn.getConversion() = referenceOut.(ReferenceToExpr)
}
private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) {
// This probably cannot happen. It would require an expression to be
// converted to a reference and back again without an intermediate variable
// assignment.
referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr)
}
private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) {
referenceIn.getConversion() = referenceOut.(Cast)
or
referenceIn.getConversion() = referenceOut.(ParenthesisExpr)
}
/** Holds if `e` is constant according to the database. */
private predicate hasConstantValue(Expr e) { valuebind(_, underlyingElement(e)) }

View File

@@ -56,6 +56,11 @@ class FunctionIR extends TFunctionIR {
result.getFunctionIR() = this
}
pragma[noinline]
final UnmodeledUseInstruction getUnmodeledUseInstruction() {
result.getFunctionIR() = this
}
/**
* Gets the single return instruction for this function.
*/

View File

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

View File

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

View File

@@ -10,8 +10,6 @@ import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.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
}
}

View File

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

View File

@@ -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,87 +33,32 @@ 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)
}
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
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 |
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
function = oldInstruction.getFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
@@ -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
exists(FunctionIR f |
tag instanceof UnmodeledUseOperandTag and
result instanceof UnmodeledDefinitionInstruction and
instruction.getFunction() = result.getFunction()
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"
)
}

View File

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

View File

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

View File

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

View File

@@ -10,8 +10,6 @@ import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.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
}
}

View File

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

View File

@@ -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,19 +23,8 @@ 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)
}
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)
)
MkInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _, _)
}
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
@@ -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))
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -632,7 +632,7 @@ class TranslatedForStmt extends TranslatedLoop {
exists(forStmt.getInitialization())
}
private TranslatedExpr getUpdate() {
TranslatedExpr getUpdate() {
result = getTranslatedExpr(forStmt.getUpdate().getFullyConverted())
}

View File

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

View File

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

View File

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

View File

@@ -10,8 +10,6 @@ import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.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
}
}

View File

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

View File

@@ -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,87 +33,32 @@ 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)
}
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
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 |
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
function = oldInstruction.getFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
)
}
@@ -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
exists(FunctionIR f |
tag instanceof UnmodeledUseOperandTag and
result instanceof UnmodeledDefinitionInstruction and
instruction.getFunction() = result.getFunction()
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"
)
}

View File

@@ -0,0 +1,25 @@
private import cpp
private import semmle.code.cpp.ir.implementation.TempVariableTag
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as Construction
newtype TIRVariable =
TIRAutomaticUserVariable(LocalScopeVariable var, Function func) {
Construction::functionHasIR(func) and
var.getFunction() = func or
var.(Parameter).getCatchBlock().getEnclosingFunction() = func
} or
TIRStaticUserVariable(Variable var, Function func) {
Construction::functionHasIR(func) and
(
var instanceof GlobalOrNamespaceVariable or
var instanceof MemberVariable and not var instanceof Field
) and
exists(VariableAccess access |
access.getTarget() = var and
access.getEnclosingFunction() = func
)
} or
TIRTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) {
Construction::hasTempVariable(func, ast, tag, type)
}

View File

@@ -559,8 +559,6 @@ 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)
@@ -601,5 +599,4 @@ private predicate boundedInstruction(
safeNarrowingCast(cast, upper.booleanNot()) and
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
)
)
}

View File

@@ -63,24 +63,7 @@ predicate valueFlowStep(Instruction i, Operand op, int delta) {
)
}
predicate isReducibleCFG(Function f) {
not exists(LabelStmt l, GotoStmt goto |
goto.getTarget() = l and
l.getLocation().isBefore(goto.getLocation()) and
l.getEnclosingFunction() = f
) and
not exists(LabelStmt ls, Loop l |
ls.getParent*() = l and
l.getEnclosingFunction() = f
) and
not exists(SwitchCase cs |
cs.getSwitchStmt().getStmt() != cs.getParentStmt() and
cs.getEnclosingFunction() = f
)
}
predicate backEdge(PhiInstruction phi, PhiOperand op) {
phi.getAnOperand() = op and
phi.getBlock().dominates(op.getPredecessorBlock())
// TODO: identify backedges during IR construction
phi.getBlock() = op.getPredecessorBlock().getBackEdgeSuccessor(_)
}

View File

@@ -0,0 +1,86 @@
// semmle-extractor-options: --c++14
const int int_const = 1;
extern const int extern_int_const = 1;
extern const int extern_int_const_noinit;
int int_var;
int int_arr[4];
int int_arr_arr[4][4];
int *const const_ptr = &int_var;
void sideEffect();
using fptr = void (*)();
using fref = void (&)();
// All variables in this function are initialized to constants, as witnessed by
// the `constexpr` annotation that compiles under C++14.
void constantAddresses(int param) {
constexpr int *ptr_int = &int_var;
constexpr int *ptr_deref_chain = &*&int_var;
constexpr int *ptr_array = &int_arr[1] + 1;
constexpr int (*ptr_to_array)[4] = &int_arr_arr[1] + 1;
constexpr int *array2d = &int_arr_arr[1][1] + 1;
constexpr int *const_ints = &int_arr_arr[int_const][extern_int_const];
// Commented out because clang and EDG disagree on whether this is
// constant.
//constexpr int *stmtexpr_int = &int_arr[ ({ 1; }) ];
constexpr int *comma_int = &int_arr[ ((void)0, 1) ];
constexpr int *comma_addr = ((void)0, &int_var);
constexpr int *ternary_true = int_const ? &int_var : &param;
constexpr int *ternary_false = !int_const ? &param : &int_var;
constexpr int *ternary_overflow = (unsigned char)256 ? &param : &int_var;
constexpr int *ternary_ptr_cond = (&int_arr+1) ? &int_var : &param;;
constexpr int *ptr_subtract = &int_arr[&int_arr[1] - &int_arr[0]];
constexpr int *constexpr_va = ptr_subtract + 1;
constexpr int &ref_int = int_var;
constexpr int &ref_array2d = int_arr_arr[1][1];
constexpr int &ref_va = ref_array2d;
constexpr int &ref_va_arith = *(&ref_array2d + 1);
constexpr fptr fp_implicit = sideEffect;
constexpr fptr fp_explicit = &sideEffect;
constexpr fptr fp_chain_addressof = &**&**sideEffect;
constexpr fptr fp_chain_deref = **&**&**sideEffect;
constexpr fptr fp_shortchain_deref = *&sideEffect;
constexpr fref fr_int = sideEffect;
constexpr fref fr_deref = *&sideEffect;
constexpr fref fr_2deref = **sideEffect;
constexpr fref fr_va = fr_int;
constexpr const char *char_ptr = "str";
constexpr const char *char_ptr_1 = "str" + 1;
constexpr char char_arr[] = "str";
}
// All variables in this function are initialized to non-const values. Writing
// `constexpr` in front of any of the variables will be a compile error
// (C++14).
void nonConstantAddresses(const int param, int *const pparam, int &rparam, fref frparam) {
int *int_param = &int_arr[param];
int *int_noinit = &int_arr[extern_int_const_noinit];
int *side_effect_stmtexpr = &int_arr[ ({ sideEffect(); 1; }) ];
int *side_effect_comma_int = &int_arr[ (sideEffect(), 1) ];
int *side_effect_comma_addr = (sideEffect(), &int_var);
int *side_effect_comma_addr2 = ((void)(sideEffect(), 1), &int_var);
int *ternary_int = &int_arr[int_const ? param : 1];
const int *ternary_addr = int_const ? &param : &int_var;
int *va_non_constexpr = pparam;
int *&&ref_to_temporary = &int_var; // reference to temporary is not a const
int &ref_param = rparam;
fref fr_param = frparam;
}

View File

@@ -0,0 +1,16 @@
import cpp
from Expr e, string msg, LocalVariable var, Function f
where
e = var.getInitializer().getExpr().getFullyConverted() and
var.getFunction() = f and
(
e.isConstant() and
f.getName() = "nonConstantAddresses" and
msg = "misclassified as constant"
or
not e.isConstant() and
f.getName() = "constantAddresses" and
msg = "misclassified as NOT constant"
)
select e, var.getName(), msg

View File

@@ -6782,3 +6782,47 @@ ir.cpp:
# 1055| 0: i
# 1055| 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 ...

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -36,6 +36,7 @@
| test.cpp:100:10:100:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
| test.cpp: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 |

View File

@@ -170,3 +170,19 @@ int test14(int x, int y) {
}
}
}
// more interesting bounds with irreducible CFG
int test15(int i, int x) {
if (x < i) {
sink(i); // i >= x + 1
} else {
sink(i); // i <= x
goto inLoop;
}
for(; i < x; i++) {
sink(i); // i <= x - 1
inLoop:
sink(i); // i <= x
}
return i;
}

View File

@@ -446,7 +446,7 @@ test.cpp:
# 56| valnum = r5_3
# 56| 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 :

View File

@@ -1,3 +1,3 @@
| test.cpp:16:13:16:14 | _t | This parameter of type $@ is 4096 bytes - consider passing a pointer/reference instead. | test.cpp:6:8:6:20 | myLargeStruct | myLargeStruct |
| test.cpp: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 |

View File

@@ -1,6 +1,9 @@
| test3.c:15:10:15:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
| test3.c:15: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 |

View File

@@ -1,3 +1,4 @@
| test3.c:12:31:12:34 | * ... | $@ flows to here and is used in an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value |
| test3.c: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 |

View File

@@ -0,0 +1,20 @@
char *gets(char *s);
unsigned long int strtoul( const char * nptr, char ** endptr, int base);
int getTaintedInt()
{
char buf[128];
gets(buf);
return strtoul(buf, 0, 10);
}
void useTaintedInt()
{
int x, y;
x = getTaintedInt() * 1024; // BAD: arithmetic on a tainted value
y = getTaintedInt();
y = y * 1024; // BAD: arithmetic on a tainted value
}

View File

@@ -112,7 +112,7 @@ namespace Semmle.Autobuild
var o = JObject.Parse(File.ReadAllText(path));
version = (string)o["sdk"]["version"];
}
catch
catch // lgtm[cs/catch-of-all-exceptions]
{
// not a valid global.json file
continue;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@ private string relativePath(File file) { result = file.getRelativePath().replace
* Holds if the `index`-th token of block `copy` is in file `file`, spanning
* 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) {

View File

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

View File

@@ -402,18 +402,15 @@ 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)
Expr getAccessorCallValueArgument(AccessorCall ac) {
exists(AssignExpr ae | tupleAssignmentDefinition(ae, ac) |
tupleAssignmentPair(ae, ac, result)
)
or
exists(Assignment ass | a = ass.getLValue() |
exists(Assignment ass | ac = ass.getLValue() |
result = ass.getRValue() and
not ass.(AssignOperation).hasExpandedAssignment()
)
)
}
}
import Cached

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
@@ -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
@@ -275,7 +253,8 @@ class DereferenceableExpr extends Expr {
or
result = any(IsExpr ie |
ie.getExpr() = this and
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral then
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral
then
// E.g. `x is null`
isNull = branch
else (
@@ -326,14 +305,16 @@ 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
if cc.getExpr() instanceof NullLiteral
then
// `case null`
if v.isMatch() then isNull = true else isNull = false
else (
@@ -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. */
@@ -735,9 +707,7 @@ module Internal {
)
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)
)
}
@@ -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
)
)
@@ -931,11 +899,12 @@ 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
@@ -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,14 +968,14 @@ 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
@@ -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,9 +1158,7 @@ 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 |
@@ -1206,8 +1178,7 @@ module Internal {
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 |
@@ -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
@@ -1382,8 +1363,7 @@ module Internal {
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

View File

@@ -16,9 +16,7 @@ module TaintTracking {
* 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
@@ -207,11 +207,15 @@ module TaintTracking {
)
}
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,23 +17,21 @@
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | o |
| arguments.cs: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 |

View File

@@ -17,23 +17,23 @@
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | arguments.cs:33:17:33:17 | o |
| arguments.cs: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 |

View File

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

View File

@@ -0,0 +1,50 @@
import csharp
import semmle.code.csharp.controlflow.Completion
import ControlFlow
import ControlFlow::Internal
query predicate nonUniqueSetRepresentation(Splits s1, Splits s2) {
forex(Nodes::Split s | s = s1.getASplit() | s = s2.getASplit()) and
forex(Nodes::Split s | s = s2.getASplit() | s = s1.getASplit()) and
s1 != s2
}
query predicate breakInvariant2(
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
SplitInternal split, Completion c
) {
succSplits(pred, predSplits, succ, succSplits, c) and
split = predSplits.getASplit() and
split.hasSuccessor(pred, succ, c) and
not split = succSplits.getASplit()
}
query predicate breakInvariant3(
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
SplitInternal split, Completion c
) {
succSplits(pred, predSplits, succ, succSplits, c) and
split = predSplits.getASplit() and
split.hasExit(pred, succ, c) and
split = succSplits.getASplit()
}
query predicate breakInvariant4(
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
SplitInternal split, Completion c
) {
succSplits(pred, predSplits, succ, succSplits, c) and
split.hasEntry(pred, succ, c) and
not split = predSplits.getASplit() and
not split = succSplits.getASplit()
}
query predicate breakInvariant5(
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
SplitInternal split, Completion c
) {
succSplits(pred, predSplits, succ, succSplits, c) and
split = succSplits.getASplit() and
not (split.hasSuccessor(pred, succ, c) and split = predSplits.getASplit()) and
not (split.hasEntry(pred, succ, c) and not split = predSplits.getASplit())
}

View File

@@ -68,6 +68,8 @@
| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false |
| Guards.cs: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 |

View File

@@ -164,6 +164,10 @@
| Guards.cs:205:13:205:13 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true |
| Guards.cs: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