mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Force LF line endings for .ql, .qll, and .qlref files
This commit is contained in:
13
.gitattributes
vendored
Normal file
13
.gitattributes
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# The following file types will be normalized to LF line endings in the Git
|
||||
# database, and will keep those LF line endings in the working tree even on
|
||||
# Windows. Any other files will have whatever line endings they had when they
|
||||
# were committed. If you add new entires below, you should renormalize the
|
||||
# affected files by running the following from the root of this repo (requires
|
||||
# Git 2.16 or greater):
|
||||
#
|
||||
# git add --renormalize .
|
||||
# git status [just to show what files were renormalized]
|
||||
# git commit -m "Normalize line endings"
|
||||
*.ql eol=lf
|
||||
*.qll eol=lf
|
||||
*.qlref eol=lf
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* @name Print AST
|
||||
* @description Outputs a representation of the Abstract Syntax Tree.
|
||||
* @id cpp/print-ast
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import PrintAST
|
||||
/**
|
||||
* @name Print AST
|
||||
* @description Outputs a representation of the Abstract Syntax Tree.
|
||||
* @id cpp/print-ast
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import PrintAST
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,141 +1,141 @@
|
||||
import cpp
|
||||
|
||||
private newtype TEdgeKind =
|
||||
TGotoEdge() or // Single successor (including fall-through)
|
||||
TTrueEdge() or // 'true' edge of conditional branch
|
||||
TFalseEdge() or // 'false' edge of conditional branch
|
||||
TExceptionEdge() or // Thrown exception
|
||||
TDefaultEdge() or // 'default' label of switch
|
||||
TCaseEdge(string minValue, string maxValue) { // Case label of switch
|
||||
exists(SwitchCase switchCase |
|
||||
hasCaseEdge(switchCase, minValue, maxValue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the kind of an edge in the IR control flow graph. Each
|
||||
* `Instruction` or `IRBlock` has at most one successor of any single
|
||||
* `EdgeKind`.
|
||||
*/
|
||||
abstract class EdgeKind extends TEdgeKind {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A "goto" edge, representing the unconditional successor of an `Instruction`
|
||||
* or `IRBlock`.
|
||||
*/
|
||||
class GotoEdge extends EdgeKind, TGotoEdge {
|
||||
override final string toString() {
|
||||
result = "Goto"
|
||||
}
|
||||
}
|
||||
|
||||
GotoEdge gotoEdge() {
|
||||
result = TGotoEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "true" edge, representing the successor of a conditional branch when the
|
||||
* condition is non-zero.
|
||||
*/
|
||||
class TrueEdge extends EdgeKind, TTrueEdge {
|
||||
override final string toString() {
|
||||
result = "True"
|
||||
}
|
||||
}
|
||||
|
||||
TrueEdge trueEdge() {
|
||||
result = TTrueEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "false" edge, representing the successor of a conditional branch when the
|
||||
* condition is zero.
|
||||
*/
|
||||
class FalseEdge extends EdgeKind, TFalseEdge {
|
||||
override final string toString() {
|
||||
result = "False"
|
||||
}
|
||||
}
|
||||
|
||||
FalseEdge falseEdge() {
|
||||
result = TFalseEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* An "exception" edge, representing the successor of an instruction when that
|
||||
* instruction's evaluation throws an exception.
|
||||
*/
|
||||
class ExceptionEdge extends EdgeKind, TExceptionEdge {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionEdge exceptionEdge() {
|
||||
result = TExceptionEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "default" edge, representing the successor of a `Switch` instruction when
|
||||
* none of the case values matches the condition value.
|
||||
*/
|
||||
class DefaultEdge extends EdgeKind, TDefaultEdge {
|
||||
override final string toString() {
|
||||
result = "Default"
|
||||
}
|
||||
}
|
||||
|
||||
DefaultEdge defaultEdge() {
|
||||
result = TDefaultEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "case" edge, representing the successor of a `Switch` instruction when the
|
||||
* the condition value matches a correponding `case` label.
|
||||
*/
|
||||
class CaseEdge extends EdgeKind, TCaseEdge {
|
||||
string minValue;
|
||||
string maxValue;
|
||||
|
||||
CaseEdge() {
|
||||
this = TCaseEdge(minValue, maxValue)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
if minValue = maxValue then
|
||||
result = "Case[" + minValue + "]"
|
||||
else
|
||||
result = "Case[" + minValue + ".." + maxValue + "]"
|
||||
}
|
||||
|
||||
string getMinValue() {
|
||||
result = minValue
|
||||
}
|
||||
|
||||
string getMaxValue() {
|
||||
result = maxValue
|
||||
}
|
||||
}
|
||||
|
||||
CaseEdge caseEdge(string minValue, string maxValue) {
|
||||
result = TCaseEdge(minValue, maxValue)
|
||||
}
|
||||
|
||||
private predicate hasCaseEdge(SwitchCase switchCase, string minValue,
|
||||
string maxValue) {
|
||||
minValue = switchCase.getExpr().getFullyConverted().getValue() and
|
||||
if exists(switchCase.getEndExpr()) then
|
||||
maxValue = switchCase.getEndExpr().getFullyConverted().getValue()
|
||||
else
|
||||
maxValue = minValue
|
||||
}
|
||||
|
||||
EdgeKind getCaseEdge(SwitchCase switchCase) {
|
||||
exists(CaseEdge edge |
|
||||
result = edge and
|
||||
hasCaseEdge(switchCase, edge.getMinValue(), edge.getMaxValue())
|
||||
) or
|
||||
(switchCase instanceof DefaultCase and result instanceof DefaultEdge)
|
||||
}
|
||||
import cpp
|
||||
|
||||
private newtype TEdgeKind =
|
||||
TGotoEdge() or // Single successor (including fall-through)
|
||||
TTrueEdge() or // 'true' edge of conditional branch
|
||||
TFalseEdge() or // 'false' edge of conditional branch
|
||||
TExceptionEdge() or // Thrown exception
|
||||
TDefaultEdge() or // 'default' label of switch
|
||||
TCaseEdge(string minValue, string maxValue) { // Case label of switch
|
||||
exists(SwitchCase switchCase |
|
||||
hasCaseEdge(switchCase, minValue, maxValue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the kind of an edge in the IR control flow graph. Each
|
||||
* `Instruction` or `IRBlock` has at most one successor of any single
|
||||
* `EdgeKind`.
|
||||
*/
|
||||
abstract class EdgeKind extends TEdgeKind {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A "goto" edge, representing the unconditional successor of an `Instruction`
|
||||
* or `IRBlock`.
|
||||
*/
|
||||
class GotoEdge extends EdgeKind, TGotoEdge {
|
||||
override final string toString() {
|
||||
result = "Goto"
|
||||
}
|
||||
}
|
||||
|
||||
GotoEdge gotoEdge() {
|
||||
result = TGotoEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "true" edge, representing the successor of a conditional branch when the
|
||||
* condition is non-zero.
|
||||
*/
|
||||
class TrueEdge extends EdgeKind, TTrueEdge {
|
||||
override final string toString() {
|
||||
result = "True"
|
||||
}
|
||||
}
|
||||
|
||||
TrueEdge trueEdge() {
|
||||
result = TTrueEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "false" edge, representing the successor of a conditional branch when the
|
||||
* condition is zero.
|
||||
*/
|
||||
class FalseEdge extends EdgeKind, TFalseEdge {
|
||||
override final string toString() {
|
||||
result = "False"
|
||||
}
|
||||
}
|
||||
|
||||
FalseEdge falseEdge() {
|
||||
result = TFalseEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* An "exception" edge, representing the successor of an instruction when that
|
||||
* instruction's evaluation throws an exception.
|
||||
*/
|
||||
class ExceptionEdge extends EdgeKind, TExceptionEdge {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionEdge exceptionEdge() {
|
||||
result = TExceptionEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "default" edge, representing the successor of a `Switch` instruction when
|
||||
* none of the case values matches the condition value.
|
||||
*/
|
||||
class DefaultEdge extends EdgeKind, TDefaultEdge {
|
||||
override final string toString() {
|
||||
result = "Default"
|
||||
}
|
||||
}
|
||||
|
||||
DefaultEdge defaultEdge() {
|
||||
result = TDefaultEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "case" edge, representing the successor of a `Switch` instruction when the
|
||||
* the condition value matches a correponding `case` label.
|
||||
*/
|
||||
class CaseEdge extends EdgeKind, TCaseEdge {
|
||||
string minValue;
|
||||
string maxValue;
|
||||
|
||||
CaseEdge() {
|
||||
this = TCaseEdge(minValue, maxValue)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
if minValue = maxValue then
|
||||
result = "Case[" + minValue + "]"
|
||||
else
|
||||
result = "Case[" + minValue + ".." + maxValue + "]"
|
||||
}
|
||||
|
||||
string getMinValue() {
|
||||
result = minValue
|
||||
}
|
||||
|
||||
string getMaxValue() {
|
||||
result = maxValue
|
||||
}
|
||||
}
|
||||
|
||||
CaseEdge caseEdge(string minValue, string maxValue) {
|
||||
result = TCaseEdge(minValue, maxValue)
|
||||
}
|
||||
|
||||
private predicate hasCaseEdge(SwitchCase switchCase, string minValue,
|
||||
string maxValue) {
|
||||
minValue = switchCase.getExpr().getFullyConverted().getValue() and
|
||||
if exists(switchCase.getEndExpr()) then
|
||||
maxValue = switchCase.getEndExpr().getFullyConverted().getValue()
|
||||
else
|
||||
maxValue = minValue
|
||||
}
|
||||
|
||||
EdgeKind getCaseEdge(SwitchCase switchCase) {
|
||||
exists(CaseEdge edge |
|
||||
result = edge and
|
||||
hasCaseEdge(switchCase, edge.getMinValue(), edge.getMaxValue())
|
||||
) or
|
||||
(switchCase instanceof DefaultCase and result instanceof DefaultEdge)
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
import internal.IRImpl
|
||||
import internal.IRImpl
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
import cpp
|
||||
|
||||
newtype TMemoryAccessKind =
|
||||
TIndirectMemoryAccess() or
|
||||
TEscapedMemoryAccess() or
|
||||
TPhiMemoryAccess() or
|
||||
TUnmodeledMemoryAccess()
|
||||
|
||||
/**
|
||||
* Describes the set of memory locations memory accessed by a memory operand or
|
||||
* memory result.
|
||||
*/
|
||||
class MemoryAccessKind extends TMemoryAccessKind {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses memory at the address specified by the
|
||||
* `LoadStoreAddressOperand` on the same instruction.
|
||||
*/
|
||||
class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
|
||||
override string toString() {
|
||||
result = "indirect"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses all memory whose address has escaped.
|
||||
*/
|
||||
class EscapedMemoryAccess extends MemoryAccessKind, TEscapedMemoryAccess {
|
||||
override string toString() {
|
||||
result = "escaped"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand is a Phi operand, which accesses the same memory as its
|
||||
* definition.
|
||||
*/
|
||||
class PhiMemoryAccess extends MemoryAccessKind, TPhiMemoryAccess {
|
||||
override string toString() {
|
||||
result = "phi"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand accesses memory not modeled in SSA. Used only on the result of
|
||||
* `UnmodeledDefinition` and on the operands of `UnmodeledUse`.
|
||||
*/
|
||||
class UnmodeledMemoryAccess extends MemoryAccessKind, TUnmodeledMemoryAccess {
|
||||
override string toString() {
|
||||
result = "unmodeled"
|
||||
}
|
||||
}
|
||||
import cpp
|
||||
|
||||
newtype TMemoryAccessKind =
|
||||
TIndirectMemoryAccess() or
|
||||
TEscapedMemoryAccess() or
|
||||
TPhiMemoryAccess() or
|
||||
TUnmodeledMemoryAccess()
|
||||
|
||||
/**
|
||||
* Describes the set of memory locations memory accessed by a memory operand or
|
||||
* memory result.
|
||||
*/
|
||||
class MemoryAccessKind extends TMemoryAccessKind {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses memory at the address specified by the
|
||||
* `LoadStoreAddressOperand` on the same instruction.
|
||||
*/
|
||||
class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
|
||||
override string toString() {
|
||||
result = "indirect"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses all memory whose address has escaped.
|
||||
*/
|
||||
class EscapedMemoryAccess extends MemoryAccessKind, TEscapedMemoryAccess {
|
||||
override string toString() {
|
||||
result = "escaped"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand is a Phi operand, which accesses the same memory as its
|
||||
* definition.
|
||||
*/
|
||||
class PhiMemoryAccess extends MemoryAccessKind, TPhiMemoryAccess {
|
||||
override string toString() {
|
||||
result = "phi"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand accesses memory not modeled in SSA. Used only on the result of
|
||||
* `UnmodeledDefinition` and on the operands of `UnmodeledUse`.
|
||||
*/
|
||||
class UnmodeledMemoryAccess extends MemoryAccessKind, TUnmodeledMemoryAccess {
|
||||
override string toString() {
|
||||
result = "unmodeled"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
import internal.Opcode
|
||||
import internal.Opcode
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @name Print IR
|
||||
* @description Outputs a representation of the IR graph
|
||||
* @id cpp/print-ir
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import PrintIR
|
||||
/**
|
||||
* @name Print IR
|
||||
* @description Outputs a representation of the IR graph
|
||||
* @id cpp/print-ir
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import PrintIR
|
||||
|
||||
@@ -1 +1 @@
|
||||
import internal.PrintIRImpl
|
||||
import internal.PrintIRImpl
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import cpp
|
||||
private import internal.TempVariableTag
|
||||
|
||||
class TempVariableTag extends TTempVariableTag {
|
||||
string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
}
|
||||
import cpp
|
||||
private import internal.TempVariableTag
|
||||
|
||||
class TempVariableTag extends TTempVariableTag {
|
||||
string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
import cpp
|
||||
|
||||
private newtype TValueCategory =
|
||||
TLValue() or
|
||||
TXValue() or
|
||||
TPRValue()
|
||||
|
||||
abstract class ValueCategory extends TValueCategory {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
abstract class GLValue extends ValueCategory {
|
||||
}
|
||||
|
||||
abstract class RValue extends ValueCategory {
|
||||
}
|
||||
|
||||
class LValue extends GLValue, TLValue {
|
||||
override string toString() {
|
||||
result = "lvalue"
|
||||
}
|
||||
}
|
||||
|
||||
class XValue extends GLValue, RValue, TXValue {
|
||||
override string toString() {
|
||||
result = "xvalue"
|
||||
}
|
||||
}
|
||||
|
||||
class PRValue extends RValue, TPRValue {
|
||||
override string toString() {
|
||||
result = "prvalue"
|
||||
}
|
||||
}
|
||||
|
||||
ValueCategory getExprValueCategory(Expr expr) {
|
||||
(
|
||||
expr.isLValueCategory() and result instanceof LValue
|
||||
) or (
|
||||
expr.isXValueCategory() and result instanceof XValue
|
||||
) or (
|
||||
expr.isPRValueCategory() and result instanceof PRValue
|
||||
)
|
||||
}
|
||||
import cpp
|
||||
|
||||
private newtype TValueCategory =
|
||||
TLValue() or
|
||||
TXValue() or
|
||||
TPRValue()
|
||||
|
||||
abstract class ValueCategory extends TValueCategory {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
abstract class GLValue extends ValueCategory {
|
||||
}
|
||||
|
||||
abstract class RValue extends ValueCategory {
|
||||
}
|
||||
|
||||
class LValue extends GLValue, TLValue {
|
||||
override string toString() {
|
||||
result = "lvalue"
|
||||
}
|
||||
}
|
||||
|
||||
class XValue extends GLValue, RValue, TXValue {
|
||||
override string toString() {
|
||||
result = "xvalue"
|
||||
}
|
||||
}
|
||||
|
||||
class PRValue extends RValue, TPRValue {
|
||||
override string toString() {
|
||||
result = "prvalue"
|
||||
}
|
||||
}
|
||||
|
||||
ValueCategory getExprValueCategory(Expr expr) {
|
||||
(
|
||||
expr.isLValueCategory() and result instanceof LValue
|
||||
) or (
|
||||
expr.isXValueCategory() and result instanceof XValue
|
||||
) or (
|
||||
expr.isPRValueCategory() and result instanceof PRValue
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import cpp
|
||||
|
||||
private newtype TFunctionIR =
|
||||
MkFunctionIR(Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
*/
|
||||
class FunctionIR extends TFunctionIR {
|
||||
Function func;
|
||||
|
||||
FunctionIR() {
|
||||
this = MkFunctionIR(func)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final EnterFunctionInstruction getEnterFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exit point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ExitFunctionInstruction getExitFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ReturnInstruction getReturnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable used to hold the return value of this function. If this
|
||||
* function does not return a value, this predicate does not hold.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRReturnVariable getReturnVariable() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block containing the entry point of this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock getEntryBlock() {
|
||||
result.getFirstInstruction() = getEnterFunctionInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instructions in this function.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
}
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import cpp
|
||||
|
||||
private newtype TFunctionIR =
|
||||
MkFunctionIR(Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
*/
|
||||
class FunctionIR extends TFunctionIR {
|
||||
Function func;
|
||||
|
||||
FunctionIR() {
|
||||
this = MkFunctionIR(func)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final EnterFunctionInstruction getEnterFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exit point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ExitFunctionInstruction getExitFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ReturnInstruction getReturnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable used to hold the return value of this function. If this
|
||||
* function does not return a value, this predicate does not hold.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRReturnVariable getReturnVariable() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block containing the entry point of this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock getEntryBlock() {
|
||||
result.getFirstInstruction() = getEnterFunctionInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instructions in this function.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,165 +1,165 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
private import InstructionTag
|
||||
private import TempVariableTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedFunction
|
||||
|
||||
class InstructionTagType extends TInstructionTag {
|
||||
final string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
}
|
||||
|
||||
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(), _)
|
||||
}
|
||||
|
||||
import Cached
|
||||
cached private module Cached {
|
||||
cached predicate functionHasIR(Function func) {
|
||||
exists(getTranslatedFunction(func))
|
||||
}
|
||||
|
||||
cached int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(FunctionCall call |
|
||||
exists(call.getArgument(argIndex))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
||||
Type type) {
|
||||
exists(TranslatedElement element |
|
||||
element.getAST() = ast and
|
||||
func = element.getFunction() and
|
||||
element.hasTempVariable(tag, type)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
none()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
|
||||
instruction.getTag(), tag)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
none()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionSuccessor(
|
||||
instruction.getTag(), kind)
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionVariable(
|
||||
instruction.getTag())
|
||||
}
|
||||
|
||||
cached Field getInstructionField(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionField(tag)
|
||||
)
|
||||
}
|
||||
|
||||
cached Function getInstructionFunction(Instruction instruction) {
|
||||
exists(InstructionTag tag |
|
||||
result = getInstructionTranslatedElementAndTag(instruction, tag)
|
||||
.getInstructionFunction(tag)
|
||||
)
|
||||
}
|
||||
|
||||
cached string getInstructionConstantValue(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction).getInstructionConstantValue(
|
||||
instruction.getTag())
|
||||
}
|
||||
|
||||
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction).getInstructionStringLiteral(
|
||||
instruction.getTag())
|
||||
}
|
||||
|
||||
cached Type getInstructionExceptionType(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction).getInstructionExceptionType(
|
||||
instruction.getTag())
|
||||
}
|
||||
|
||||
cached predicate getInstructionInheritance(Instruction instruction,
|
||||
Class baseClass, Class derivedClass) {
|
||||
getInstructionTranslatedElement(instruction).getInstructionInheritance(
|
||||
instruction.getTag(), baseClass, derivedClass)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate instructionOrigin(Instruction instruction,
|
||||
TranslatedElement element, InstructionTag tag) {
|
||||
element = getInstructionTranslatedElement(instruction) and
|
||||
tag = instruction.getTag()
|
||||
}
|
||||
|
||||
cached int getInstructionElementSize(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionElementSize(tag)
|
||||
)
|
||||
}
|
||||
|
||||
cached int getInstructionResultSize(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionResultSize(tag)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import CachedForDebugging
|
||||
cached private module CachedForDebugging {
|
||||
cached string getTempVariableUniqueId(IRTempVariable var) {
|
||||
result = getTempVariableTranslatedElement(var).getId() + ":" +
|
||||
getTempVariableTagId(var.getTag())
|
||||
}
|
||||
|
||||
cached string getInstructionUniqueId(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction).getId() + ":" +
|
||||
getInstructionTagId(instruction.getTag())
|
||||
}
|
||||
}
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
private import InstructionTag
|
||||
private import TempVariableTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedFunction
|
||||
|
||||
class InstructionTagType extends TInstructionTag {
|
||||
final string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
}
|
||||
|
||||
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(), _)
|
||||
}
|
||||
|
||||
import Cached
|
||||
cached private module Cached {
|
||||
cached predicate functionHasIR(Function func) {
|
||||
exists(getTranslatedFunction(func))
|
||||
}
|
||||
|
||||
cached int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(FunctionCall call |
|
||||
exists(call.getArgument(argIndex))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
||||
Type type) {
|
||||
exists(TranslatedElement element |
|
||||
element.getAST() = ast and
|
||||
func = element.getFunction() and
|
||||
element.hasTempVariable(tag, type)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
none()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
|
||||
instruction.getTag(), tag)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
none()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionSuccessor(
|
||||
instruction.getTag(), kind)
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionVariable(
|
||||
instruction.getTag())
|
||||
}
|
||||
|
||||
cached Field getInstructionField(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionField(tag)
|
||||
)
|
||||
}
|
||||
|
||||
cached Function getInstructionFunction(Instruction instruction) {
|
||||
exists(InstructionTag tag |
|
||||
result = getInstructionTranslatedElementAndTag(instruction, tag)
|
||||
.getInstructionFunction(tag)
|
||||
)
|
||||
}
|
||||
|
||||
cached string getInstructionConstantValue(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction).getInstructionConstantValue(
|
||||
instruction.getTag())
|
||||
}
|
||||
|
||||
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction).getInstructionStringLiteral(
|
||||
instruction.getTag())
|
||||
}
|
||||
|
||||
cached Type getInstructionExceptionType(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction).getInstructionExceptionType(
|
||||
instruction.getTag())
|
||||
}
|
||||
|
||||
cached predicate getInstructionInheritance(Instruction instruction,
|
||||
Class baseClass, Class derivedClass) {
|
||||
getInstructionTranslatedElement(instruction).getInstructionInheritance(
|
||||
instruction.getTag(), baseClass, derivedClass)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate instructionOrigin(Instruction instruction,
|
||||
TranslatedElement element, InstructionTag tag) {
|
||||
element = getInstructionTranslatedElement(instruction) and
|
||||
tag = instruction.getTag()
|
||||
}
|
||||
|
||||
cached int getInstructionElementSize(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionElementSize(tag)
|
||||
)
|
||||
}
|
||||
|
||||
cached int getInstructionResultSize(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getInstructionResultSize(tag)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import CachedForDebugging
|
||||
cached private module CachedForDebugging {
|
||||
cached string getTempVariableUniqueId(IRTempVariable var) {
|
||||
result = getTempVariableTranslatedElement(var).getId() + ":" +
|
||||
getTempVariableTagId(var.getTag())
|
||||
}
|
||||
|
||||
cached string getInstructionUniqueId(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction).getId() + ":" +
|
||||
getInstructionTagId(instruction.getTag())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
import IRConstruction as Construction
|
||||
import IRConstruction as Construction
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
private import IRImpl
|
||||
import InstructionSanity
|
||||
|
||||
private import IRImpl
|
||||
import InstructionSanity
|
||||
|
||||
|
||||
@@ -1,202 +1,202 @@
|
||||
private import IRInternal
|
||||
import FunctionIR
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.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)
|
||||
}
|
||||
|
||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
result.getVariable() = var and
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
FunctionIR funcIR;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Type getType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Locatable getAST();
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
abstract class IRUserVariable extends IRVariable {
|
||||
Variable var;
|
||||
|
||||
override final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = var.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = var
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = var.toString() + " " + var.getLocation().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
final Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
TIRAutomaticUserVariable {
|
||||
LocalScopeVariable localVar;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
||||
var = localVar
|
||||
}
|
||||
|
||||
final LocalScopeVariable getLocalVariable() {
|
||||
result = localVar
|
||||
}
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, funcIR)
|
||||
}
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
|
||||
result.getAST() = ast and
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Locatable ast;
|
||||
TempVariableTag tag;
|
||||
Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = type
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = ast
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = "Temp: " + Construction::getTempVariableUniqueId(this)
|
||||
}
|
||||
|
||||
final TempVariableTag getTag() {
|
||||
result = tag
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
}
|
||||
|
||||
string getBaseString() {
|
||||
result = "#temp"
|
||||
}
|
||||
}
|
||||
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() {
|
||||
tag = ReturnValueTempVar()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "#return"
|
||||
}
|
||||
}
|
||||
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() {
|
||||
tag = ThrowTempVar()
|
||||
}
|
||||
|
||||
override string getBaseString() {
|
||||
result = "#throw"
|
||||
}
|
||||
}
|
||||
private import IRInternal
|
||||
import FunctionIR
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.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)
|
||||
}
|
||||
|
||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
result.getVariable() = var and
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
FunctionIR funcIR;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Type getType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Locatable getAST();
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
abstract class IRUserVariable extends IRVariable {
|
||||
Variable var;
|
||||
|
||||
override final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = var.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = var
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = var.toString() + " " + var.getLocation().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
final Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
TIRAutomaticUserVariable {
|
||||
LocalScopeVariable localVar;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
||||
var = localVar
|
||||
}
|
||||
|
||||
final LocalScopeVariable getLocalVariable() {
|
||||
result = localVar
|
||||
}
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, funcIR)
|
||||
}
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
|
||||
result.getAST() = ast and
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Locatable ast;
|
||||
TempVariableTag tag;
|
||||
Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = type
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = ast
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = "Temp: " + Construction::getTempVariableUniqueId(this)
|
||||
}
|
||||
|
||||
final TempVariableTag getTag() {
|
||||
result = tag
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
}
|
||||
|
||||
string getBaseString() {
|
||||
result = "#temp"
|
||||
}
|
||||
}
|
||||
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() {
|
||||
tag = ReturnValueTempVar()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "#return"
|
||||
}
|
||||
}
|
||||
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() {
|
||||
tag = ThrowTempVar()
|
||||
}
|
||||
|
||||
override string getBaseString() {
|
||||
result = "#throw"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,152 +1,152 @@
|
||||
import cpp
|
||||
|
||||
private predicate fieldIsInitialized(Field field) {
|
||||
exists(ClassAggregateLiteral initList |
|
||||
initList.isInitialized(field)
|
||||
) or
|
||||
exists(ConstructorFieldInit init |
|
||||
field = init.getTarget()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate elementIsInitialized(int elementIndex) {
|
||||
exists(ArrayAggregateLiteral initList |
|
||||
initList.isInitialized(elementIndex)
|
||||
)
|
||||
}
|
||||
|
||||
newtype TInstructionTag =
|
||||
OnlyInstructionTag() or // Single instruction (not including implicit Load)
|
||||
InitializeThisTag() or
|
||||
InitializerVariableAddressTag() or
|
||||
InitializerLoadStringTag() or
|
||||
InitializerStoreTag() or
|
||||
ZeroPadStringConstantTag() or
|
||||
ZeroPadStringElementIndexTag() or
|
||||
ZeroPadStringElementAddressTag() or
|
||||
ZeroPadStringStoreTag() or
|
||||
AssignOperationLoadTag() or
|
||||
AssignOperationConvertLeftTag() or
|
||||
AssignOperationOpTag() or
|
||||
AssignOperationConvertResultTag() or
|
||||
AssignmentStoreTag() or
|
||||
CrementLoadTag() or
|
||||
CrementConstantTag() or
|
||||
CrementOpTag() or
|
||||
CrementStoreTag() or
|
||||
EnterFunctionTag() or
|
||||
ReturnValueAddressTag() or
|
||||
ReturnTag() or
|
||||
ExitFunctionTag() or
|
||||
UnmodeledDefinitionTag() or
|
||||
UnmodeledUseTag() or
|
||||
SwitchBranchTag() or
|
||||
CallTargetTag() or
|
||||
CallTag() or
|
||||
AllocationSizeTag() or
|
||||
AllocationElementSizeTag() or
|
||||
AllocationExtentConvertTag() or
|
||||
ValueConditionConditionalBranchTag() or
|
||||
ConditionValueTrueTempAddressTag() or
|
||||
ConditionValueTrueConstantTag() or
|
||||
ConditionValueTrueStoreTag() or
|
||||
ConditionValueFalseTempAddressTag() or
|
||||
ConditionValueFalseConstantTag() or
|
||||
ConditionValueFalseStoreTag() or
|
||||
ConditionValueResultTempAddressTag() or
|
||||
ConditionValueResultLoadTag() or
|
||||
BoolConversionConstantTag() or
|
||||
BoolConversionCompareTag() or
|
||||
LoadTag() or // Implicit load due to lvalue-to-rvalue conversion
|
||||
CatchTag() or
|
||||
ThrowTag() or
|
||||
UnwindTag() or
|
||||
InitializerFieldAddressTag(Field field) {
|
||||
fieldIsInitialized(field)
|
||||
} or
|
||||
InitializerFieldDefaultValueTag(Field field) {
|
||||
fieldIsInitialized(field)
|
||||
} or
|
||||
InitializerFieldDefaultValueStoreTag(Field field) {
|
||||
fieldIsInitialized(field)
|
||||
} or
|
||||
InitializerElementIndexTag(int elementIndex) {
|
||||
elementIsInitialized(elementIndex)
|
||||
} or
|
||||
InitializerElementAddressTag(int elementIndex) {
|
||||
elementIsInitialized(elementIndex)
|
||||
} or
|
||||
InitializerElementDefaultValueTag(int elementIndex) {
|
||||
elementIsInitialized(elementIndex)
|
||||
} or
|
||||
InitializerElementDefaultValueStoreTag(int elementIndex) {
|
||||
elementIsInitialized(elementIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a unique string for the instruction tag. Primarily used for generating
|
||||
* instruction IDs to ensure stable IR dumps.
|
||||
*/
|
||||
string getInstructionTagId(TInstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and result = "Only" or // Single instruction (not including implicit Load)
|
||||
tag = InitializerVariableAddressTag() and result = "InitVarAddr" or
|
||||
tag = InitializerStoreTag() and result = "InitStore" or
|
||||
tag = ZeroPadStringConstantTag() and result = "ZeroPadConst" or
|
||||
tag = ZeroPadStringElementIndexTag() and result = "ZeroPadElemIndex" or
|
||||
tag = ZeroPadStringElementAddressTag() and result = "ZeroPadElemAddr" or
|
||||
tag = ZeroPadStringStoreTag() and result = "ZeroPadStore" or
|
||||
tag = AssignOperationLoadTag() and result = "AssignOpLoad" or
|
||||
tag = AssignOperationConvertLeftTag() and result = "AssignOpConvLeft" or
|
||||
tag = AssignOperationOpTag() and result = "AssignOpOp" or
|
||||
tag = AssignOperationConvertResultTag() and result = "AssignOpConvRes" or
|
||||
tag = AssignmentStoreTag() and result = "AssignStore" or
|
||||
tag = CrementLoadTag() and result = "CrementLoad" or
|
||||
tag = CrementConstantTag() and result = "CrementConst" or
|
||||
tag = CrementOpTag() and result = "CrementOp" or
|
||||
tag = CrementStoreTag() and result = "CrementStore" or
|
||||
tag = EnterFunctionTag() and result = "EnterFunc" or
|
||||
tag = ReturnValueAddressTag() and result = "RetValAddr" or
|
||||
tag = ReturnTag() and result = "Ret" or
|
||||
tag = ExitFunctionTag() and result = "ExitFunc" or
|
||||
tag = UnmodeledDefinitionTag() and result = "UnmodeledDef" or
|
||||
tag = UnmodeledUseTag() and result = "UnmodeledUse" or
|
||||
tag = SwitchBranchTag() and result = "SwitchBranch" or
|
||||
tag = CallTargetTag() and result = "CallTarget" or
|
||||
tag = CallTag() and result = "Call" or
|
||||
tag = AllocationSizeTag() and result = "AllocSize" or
|
||||
tag = AllocationElementSizeTag() and result = "AllocElemSize" or
|
||||
tag = AllocationExtentConvertTag() and result = "AllocExtConv" or
|
||||
tag = ValueConditionConditionalBranchTag() and result = "ValCondCondBranch" or
|
||||
tag = ConditionValueTrueTempAddressTag() and result = "CondValTrueTempAddr" or
|
||||
tag = ConditionValueTrueConstantTag() and result = "CondValTrueConst" or
|
||||
tag = ConditionValueTrueStoreTag() and result = "CondValTrueStore" or
|
||||
tag = ConditionValueFalseTempAddressTag() and result = "CondValFalseTempAddr" or
|
||||
tag = ConditionValueFalseConstantTag() and result = "CondValFalseConst" or
|
||||
tag = ConditionValueFalseStoreTag() and result = "CondValFalseStore" or
|
||||
tag = ConditionValueResultTempAddressTag() and result = "CondValResTempAddr" or
|
||||
tag = ConditionValueResultLoadTag() and result = "CondValResLoad" or
|
||||
tag = BoolConversionConstantTag() and result = "BoolConvConst" or
|
||||
tag = BoolConversionCompareTag() and result = "BoolConvComp" or
|
||||
tag = LoadTag() and result = "Load" or // Implicit load due to lvalue-to-rvalue conversion
|
||||
tag = CatchTag() and result = "Catch" or
|
||||
tag = ThrowTag() and result = "Throw" or
|
||||
tag = UnwindTag() and result = "Unwind" or
|
||||
exists(Field field, Class cls, int index, string tagName |
|
||||
field = cls.getCanonicalMember(index) and
|
||||
(
|
||||
tag = InitializerFieldAddressTag(field) and tagName = "InitFieldAddr" or
|
||||
tag = InitializerFieldDefaultValueTag(field) and tagName = "InitFieldDefVal" or
|
||||
tag = InitializerFieldDefaultValueStoreTag(field) and tagName = "InitFieldDefValStore"
|
||||
) and
|
||||
result = tagName + "(" + index + ")"
|
||||
) or
|
||||
exists(int index, string tagName |
|
||||
(
|
||||
tag = InitializerElementIndexTag(index) and tagName = "InitElemIndex" or
|
||||
tag = InitializerElementAddressTag(index) and tagName = "InitElemAddr" or
|
||||
tag = InitializerElementDefaultValueTag(index) and tagName = "InitElemDefVal" or
|
||||
tag = InitializerElementDefaultValueStoreTag(index) and tagName = "InitElemDefValStore"
|
||||
) and
|
||||
result = tagName + "(" + index + ")"
|
||||
)
|
||||
}
|
||||
import cpp
|
||||
|
||||
private predicate fieldIsInitialized(Field field) {
|
||||
exists(ClassAggregateLiteral initList |
|
||||
initList.isInitialized(field)
|
||||
) or
|
||||
exists(ConstructorFieldInit init |
|
||||
field = init.getTarget()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate elementIsInitialized(int elementIndex) {
|
||||
exists(ArrayAggregateLiteral initList |
|
||||
initList.isInitialized(elementIndex)
|
||||
)
|
||||
}
|
||||
|
||||
newtype TInstructionTag =
|
||||
OnlyInstructionTag() or // Single instruction (not including implicit Load)
|
||||
InitializeThisTag() or
|
||||
InitializerVariableAddressTag() or
|
||||
InitializerLoadStringTag() or
|
||||
InitializerStoreTag() or
|
||||
ZeroPadStringConstantTag() or
|
||||
ZeroPadStringElementIndexTag() or
|
||||
ZeroPadStringElementAddressTag() or
|
||||
ZeroPadStringStoreTag() or
|
||||
AssignOperationLoadTag() or
|
||||
AssignOperationConvertLeftTag() or
|
||||
AssignOperationOpTag() or
|
||||
AssignOperationConvertResultTag() or
|
||||
AssignmentStoreTag() or
|
||||
CrementLoadTag() or
|
||||
CrementConstantTag() or
|
||||
CrementOpTag() or
|
||||
CrementStoreTag() or
|
||||
EnterFunctionTag() or
|
||||
ReturnValueAddressTag() or
|
||||
ReturnTag() or
|
||||
ExitFunctionTag() or
|
||||
UnmodeledDefinitionTag() or
|
||||
UnmodeledUseTag() or
|
||||
SwitchBranchTag() or
|
||||
CallTargetTag() or
|
||||
CallTag() or
|
||||
AllocationSizeTag() or
|
||||
AllocationElementSizeTag() or
|
||||
AllocationExtentConvertTag() or
|
||||
ValueConditionConditionalBranchTag() or
|
||||
ConditionValueTrueTempAddressTag() or
|
||||
ConditionValueTrueConstantTag() or
|
||||
ConditionValueTrueStoreTag() or
|
||||
ConditionValueFalseTempAddressTag() or
|
||||
ConditionValueFalseConstantTag() or
|
||||
ConditionValueFalseStoreTag() or
|
||||
ConditionValueResultTempAddressTag() or
|
||||
ConditionValueResultLoadTag() or
|
||||
BoolConversionConstantTag() or
|
||||
BoolConversionCompareTag() or
|
||||
LoadTag() or // Implicit load due to lvalue-to-rvalue conversion
|
||||
CatchTag() or
|
||||
ThrowTag() or
|
||||
UnwindTag() or
|
||||
InitializerFieldAddressTag(Field field) {
|
||||
fieldIsInitialized(field)
|
||||
} or
|
||||
InitializerFieldDefaultValueTag(Field field) {
|
||||
fieldIsInitialized(field)
|
||||
} or
|
||||
InitializerFieldDefaultValueStoreTag(Field field) {
|
||||
fieldIsInitialized(field)
|
||||
} or
|
||||
InitializerElementIndexTag(int elementIndex) {
|
||||
elementIsInitialized(elementIndex)
|
||||
} or
|
||||
InitializerElementAddressTag(int elementIndex) {
|
||||
elementIsInitialized(elementIndex)
|
||||
} or
|
||||
InitializerElementDefaultValueTag(int elementIndex) {
|
||||
elementIsInitialized(elementIndex)
|
||||
} or
|
||||
InitializerElementDefaultValueStoreTag(int elementIndex) {
|
||||
elementIsInitialized(elementIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a unique string for the instruction tag. Primarily used for generating
|
||||
* instruction IDs to ensure stable IR dumps.
|
||||
*/
|
||||
string getInstructionTagId(TInstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and result = "Only" or // Single instruction (not including implicit Load)
|
||||
tag = InitializerVariableAddressTag() and result = "InitVarAddr" or
|
||||
tag = InitializerStoreTag() and result = "InitStore" or
|
||||
tag = ZeroPadStringConstantTag() and result = "ZeroPadConst" or
|
||||
tag = ZeroPadStringElementIndexTag() and result = "ZeroPadElemIndex" or
|
||||
tag = ZeroPadStringElementAddressTag() and result = "ZeroPadElemAddr" or
|
||||
tag = ZeroPadStringStoreTag() and result = "ZeroPadStore" or
|
||||
tag = AssignOperationLoadTag() and result = "AssignOpLoad" or
|
||||
tag = AssignOperationConvertLeftTag() and result = "AssignOpConvLeft" or
|
||||
tag = AssignOperationOpTag() and result = "AssignOpOp" or
|
||||
tag = AssignOperationConvertResultTag() and result = "AssignOpConvRes" or
|
||||
tag = AssignmentStoreTag() and result = "AssignStore" or
|
||||
tag = CrementLoadTag() and result = "CrementLoad" or
|
||||
tag = CrementConstantTag() and result = "CrementConst" or
|
||||
tag = CrementOpTag() and result = "CrementOp" or
|
||||
tag = CrementStoreTag() and result = "CrementStore" or
|
||||
tag = EnterFunctionTag() and result = "EnterFunc" or
|
||||
tag = ReturnValueAddressTag() and result = "RetValAddr" or
|
||||
tag = ReturnTag() and result = "Ret" or
|
||||
tag = ExitFunctionTag() and result = "ExitFunc" or
|
||||
tag = UnmodeledDefinitionTag() and result = "UnmodeledDef" or
|
||||
tag = UnmodeledUseTag() and result = "UnmodeledUse" or
|
||||
tag = SwitchBranchTag() and result = "SwitchBranch" or
|
||||
tag = CallTargetTag() and result = "CallTarget" or
|
||||
tag = CallTag() and result = "Call" or
|
||||
tag = AllocationSizeTag() and result = "AllocSize" or
|
||||
tag = AllocationElementSizeTag() and result = "AllocElemSize" or
|
||||
tag = AllocationExtentConvertTag() and result = "AllocExtConv" or
|
||||
tag = ValueConditionConditionalBranchTag() and result = "ValCondCondBranch" or
|
||||
tag = ConditionValueTrueTempAddressTag() and result = "CondValTrueTempAddr" or
|
||||
tag = ConditionValueTrueConstantTag() and result = "CondValTrueConst" or
|
||||
tag = ConditionValueTrueStoreTag() and result = "CondValTrueStore" or
|
||||
tag = ConditionValueFalseTempAddressTag() and result = "CondValFalseTempAddr" or
|
||||
tag = ConditionValueFalseConstantTag() and result = "CondValFalseConst" or
|
||||
tag = ConditionValueFalseStoreTag() and result = "CondValFalseStore" or
|
||||
tag = ConditionValueResultTempAddressTag() and result = "CondValResTempAddr" or
|
||||
tag = ConditionValueResultLoadTag() and result = "CondValResLoad" or
|
||||
tag = BoolConversionConstantTag() and result = "BoolConvConst" or
|
||||
tag = BoolConversionCompareTag() and result = "BoolConvComp" or
|
||||
tag = LoadTag() and result = "Load" or // Implicit load due to lvalue-to-rvalue conversion
|
||||
tag = CatchTag() and result = "Catch" or
|
||||
tag = ThrowTag() and result = "Throw" or
|
||||
tag = UnwindTag() and result = "Unwind" or
|
||||
exists(Field field, Class cls, int index, string tagName |
|
||||
field = cls.getCanonicalMember(index) and
|
||||
(
|
||||
tag = InitializerFieldAddressTag(field) and tagName = "InitFieldAddr" or
|
||||
tag = InitializerFieldDefaultValueTag(field) and tagName = "InitFieldDefVal" or
|
||||
tag = InitializerFieldDefaultValueStoreTag(field) and tagName = "InitFieldDefValStore"
|
||||
) and
|
||||
result = tagName + "(" + index + ")"
|
||||
) or
|
||||
exists(int index, string tagName |
|
||||
(
|
||||
tag = InitializerElementIndexTag(index) and tagName = "InitElemIndex" or
|
||||
tag = InitializerElementAddressTag(index) and tagName = "InitElemAddr" or
|
||||
tag = InitializerElementDefaultValueTag(index) and tagName = "InitElemDefVal" or
|
||||
tag = InitializerElementDefaultValueStoreTag(index) and tagName = "InitElemDefValStore"
|
||||
) and
|
||||
result = tagName + "(" + index + ")"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,154 +1,154 @@
|
||||
private newtype TOpcode =
|
||||
TNoOp() or
|
||||
TUninitialized() or
|
||||
TInitializeParameter() or
|
||||
TInitializeThis() or
|
||||
TEnterFunction() or
|
||||
TExitFunction() or
|
||||
TReturnValue() or
|
||||
TReturnVoid() or
|
||||
TCopyValue() or
|
||||
TLoad() or
|
||||
TStore() or
|
||||
TAdd() or
|
||||
TSub() or
|
||||
TMul() or
|
||||
TDiv() or
|
||||
TRem() or
|
||||
TNegate() or
|
||||
TShiftLeft() or
|
||||
TShiftRight() or
|
||||
TBitAnd() or
|
||||
TBitOr() or
|
||||
TBitXor() or
|
||||
TBitComplement() or
|
||||
TLogicalNot() or
|
||||
TCompareEQ() or
|
||||
TCompareNE() or
|
||||
TCompareLT() or
|
||||
TCompareGT() or
|
||||
TCompareLE() or
|
||||
TCompareGE() or
|
||||
TPointerAdd() or
|
||||
TPointerSub() or
|
||||
TPointerDiff() or
|
||||
TConvert() or
|
||||
TConvertToBase() or
|
||||
TConvertToVirtualBase() or
|
||||
TConvertToDerived() or
|
||||
TCheckedConvertOrNull() or
|
||||
TCheckedConvertOrThrow() or
|
||||
TDynamicCastToVoid() or
|
||||
TVariableAddress() or
|
||||
TFieldAddress() or
|
||||
TFunctionAddress() or
|
||||
TConstant() or
|
||||
TStringConstant() or
|
||||
TConditionalBranch() or
|
||||
TSwitch() or
|
||||
TInvoke() or
|
||||
TCatchByType() or
|
||||
TCatchAny() or
|
||||
TThrowValue() or
|
||||
TReThrow() or
|
||||
TUnwind() or
|
||||
TUnmodeledDefinition() or
|
||||
TUnmodeledUse() or
|
||||
TPhi() or
|
||||
TVarArgsStart() or
|
||||
TVarArgsEnd() or
|
||||
TVarArg() or
|
||||
TVarArgCopy()
|
||||
|
||||
class Opcode extends TOpcode {
|
||||
string toString() {
|
||||
result = "UnknownOpcode"
|
||||
}
|
||||
}
|
||||
|
||||
abstract class UnaryOpcode extends Opcode {}
|
||||
|
||||
abstract class BinaryOpcode extends Opcode {}
|
||||
|
||||
abstract class PointerArithmeticOpcode extends BinaryOpcode {}
|
||||
|
||||
abstract class PointerOffsetOpcode extends PointerArithmeticOpcode {}
|
||||
|
||||
abstract class CompareOpcode extends BinaryOpcode {}
|
||||
|
||||
abstract class CopyOpcode extends Opcode {}
|
||||
|
||||
abstract class MemoryAccessOpcode extends Opcode {}
|
||||
|
||||
abstract class ReturnOpcode extends Opcode {}
|
||||
|
||||
abstract class ThrowOpcode extends Opcode {}
|
||||
|
||||
abstract class CatchOpcode extends Opcode {}
|
||||
|
||||
abstract class OpcodeWithCondition extends Opcode {}
|
||||
|
||||
abstract class BuiltInOpcode extends Opcode {}
|
||||
|
||||
module Opcode {
|
||||
class NoOp extends Opcode, TNoOp { override final string toString() { result = "NoOp" } }
|
||||
class Uninitialized extends MemoryAccessOpcode, TUninitialized { override final string toString() { result = "Uninitialized" } }
|
||||
class InitializeParameter extends MemoryAccessOpcode, TInitializeParameter { override final string toString() { result = "InitializeParameter" } }
|
||||
class InitializeThis extends Opcode, TInitializeThis { override final string toString() { result = "InitializeThis" } }
|
||||
class EnterFunction extends Opcode, TEnterFunction { override final string toString() { result = "EnterFunction" } }
|
||||
class ExitFunction extends Opcode, TExitFunction { override final string toString() { result = "ExitFunction" } }
|
||||
class ReturnValue extends ReturnOpcode, MemoryAccessOpcode, TReturnValue { override final string toString() { result = "ReturnValue" } }
|
||||
class ReturnVoid extends ReturnOpcode, TReturnVoid { override final string toString() { result = "ReturnVoid" } }
|
||||
class CopyValue extends CopyOpcode, TCopyValue { override final string toString() { result = "CopyValue" } }
|
||||
class Load extends CopyOpcode, MemoryAccessOpcode, TLoad { override final string toString() { result = "Load" } }
|
||||
class Store extends CopyOpcode, MemoryAccessOpcode, TStore { override final string toString() { result = "Store" } }
|
||||
class Add extends BinaryOpcode, TAdd { override final string toString() { result = "Add" } }
|
||||
class Sub extends BinaryOpcode, TSub { override final string toString() { result = "Sub" } }
|
||||
class Mul extends BinaryOpcode, TMul { override final string toString() { result = "Mul" } }
|
||||
class Div extends BinaryOpcode, TDiv { override final string toString() { result = "Div" } }
|
||||
class Rem extends BinaryOpcode, TRem { override final string toString() { result = "Rem" } }
|
||||
class Negate extends UnaryOpcode, TNegate { override final string toString() { result = "Negate" } }
|
||||
class ShiftLeft extends BinaryOpcode, TShiftLeft { override final string toString() { result = "ShiftLeft" } }
|
||||
class ShiftRight extends BinaryOpcode, TShiftRight { override final string toString() { result = "ShiftRight" } }
|
||||
class BitAnd extends BinaryOpcode, TBitAnd { override final string toString() { result = "BitAnd" } }
|
||||
class BitOr extends BinaryOpcode, TBitOr { override final string toString() { result = "BitOr" } }
|
||||
class BitXor extends BinaryOpcode, TBitXor { override final string toString() { result = "BitXor" } }
|
||||
class BitComplement extends UnaryOpcode, TBitComplement { override final string toString() { result = "BitComplement" } }
|
||||
class LogicalNot extends UnaryOpcode, TLogicalNot { override final string toString() { result = "LogicalNot" } }
|
||||
class CompareEQ extends CompareOpcode, TCompareEQ { override final string toString() { result = "CompareEQ" } }
|
||||
class CompareNE extends CompareOpcode, TCompareNE { override final string toString() { result = "CompareNE" } }
|
||||
class CompareLT extends CompareOpcode, TCompareLT { override final string toString() { result = "CompareLT" } }
|
||||
class CompareGT extends CompareOpcode, TCompareGT { override final string toString() { result = "CompareGT" } }
|
||||
class CompareLE extends CompareOpcode, TCompareLE { override final string toString() { result = "CompareLE" } }
|
||||
class CompareGE extends CompareOpcode, TCompareGE { override final string toString() { result = "CompareGE" } }
|
||||
class PointerAdd extends PointerOffsetOpcode, TPointerAdd { override final string toString() { result = "PointerAdd" } }
|
||||
class PointerSub extends PointerOffsetOpcode, TPointerSub { override final string toString() { result = "PointerSub" } }
|
||||
class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { override final string toString() { result = "PointerDiff" } }
|
||||
class Convert extends UnaryOpcode, TConvert { override final string toString() { result = "Convert" } }
|
||||
class ConvertToBase extends UnaryOpcode, TConvertToBase { override final string toString() { result = "ConvertToBase" } }
|
||||
class ConvertToVirtualBase extends UnaryOpcode, TConvertToVirtualBase { override final string toString() { result = "ConvertToVirtualBase" } }
|
||||
class ConvertToDerived extends UnaryOpcode, TConvertToDerived { override final string toString() { result = "ConvertToDerived" } }
|
||||
class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { override final string toString() { result = "CheckedConvertOrNull" } }
|
||||
class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { override final string toString() { result = "CheckedConvertOrThrow" } }
|
||||
class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { override final string toString() { result = "DynamicCastToVoid" } }
|
||||
class VariableAddress extends Opcode, TVariableAddress { override final string toString() { result = "VariableAddress" } }
|
||||
class FieldAddress extends UnaryOpcode, TFieldAddress { override final string toString() { result = "FieldAddress" } }
|
||||
class FunctionAddress extends Opcode, TFunctionAddress { override final string toString() { result = "FunctionAddress" } }
|
||||
class Constant extends Opcode, TConstant { override final string toString() { result = "Constant" } }
|
||||
class StringConstant extends Opcode, TStringConstant { override final string toString() { result = "StringConstant" } }
|
||||
class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { override final string toString() { result = "ConditionalBranch" } }
|
||||
class Switch extends OpcodeWithCondition, TSwitch { override final string toString() { result = "Switch" } }
|
||||
class Invoke extends Opcode, TInvoke { override final string toString() { result = "Invoke" } }
|
||||
class CatchByType extends CatchOpcode, TCatchByType { override final string toString() { result = "CatchByType" } }
|
||||
class CatchAny extends CatchOpcode, TCatchAny { override final string toString() { result = "CatchAny" } }
|
||||
class ThrowValue extends ThrowOpcode, MemoryAccessOpcode, TThrowValue { override final string toString() { result = "ThrowValue" } }
|
||||
class ReThrow extends ThrowOpcode, TReThrow { override final string toString() { result = "ReThrow" } }
|
||||
class Unwind extends Opcode, TUnwind { override final string toString() { result = "Unwind" } }
|
||||
class UnmodeledDefinition extends Opcode, TUnmodeledDefinition { override final string toString() { result = "UnmodeledDefinition" } }
|
||||
class UnmodeledUse extends Opcode, TUnmodeledUse { override final string toString() { result = "UnmodeledUse" } }
|
||||
class Phi extends Opcode, TPhi { override final string toString() { result = "Phi" } }
|
||||
class VarArgsStart extends BuiltInOpcode, TVarArgsStart { override final string toString() { result = "VarArgsStart" } }
|
||||
class VarArgsEnd extends BuiltInOpcode, TVarArgsEnd { override final string toString() { result = "VarArgsEnd" } }
|
||||
class VarArg extends BuiltInOpcode, TVarArg { override final string toString() { result = "VarArg" } }
|
||||
class VarArgCopy extends BuiltInOpcode, TVarArgCopy { override final string toString() { result = "VarArgCopy" } }
|
||||
}
|
||||
private newtype TOpcode =
|
||||
TNoOp() or
|
||||
TUninitialized() or
|
||||
TInitializeParameter() or
|
||||
TInitializeThis() or
|
||||
TEnterFunction() or
|
||||
TExitFunction() or
|
||||
TReturnValue() or
|
||||
TReturnVoid() or
|
||||
TCopyValue() or
|
||||
TLoad() or
|
||||
TStore() or
|
||||
TAdd() or
|
||||
TSub() or
|
||||
TMul() or
|
||||
TDiv() or
|
||||
TRem() or
|
||||
TNegate() or
|
||||
TShiftLeft() or
|
||||
TShiftRight() or
|
||||
TBitAnd() or
|
||||
TBitOr() or
|
||||
TBitXor() or
|
||||
TBitComplement() or
|
||||
TLogicalNot() or
|
||||
TCompareEQ() or
|
||||
TCompareNE() or
|
||||
TCompareLT() or
|
||||
TCompareGT() or
|
||||
TCompareLE() or
|
||||
TCompareGE() or
|
||||
TPointerAdd() or
|
||||
TPointerSub() or
|
||||
TPointerDiff() or
|
||||
TConvert() or
|
||||
TConvertToBase() or
|
||||
TConvertToVirtualBase() or
|
||||
TConvertToDerived() or
|
||||
TCheckedConvertOrNull() or
|
||||
TCheckedConvertOrThrow() or
|
||||
TDynamicCastToVoid() or
|
||||
TVariableAddress() or
|
||||
TFieldAddress() or
|
||||
TFunctionAddress() or
|
||||
TConstant() or
|
||||
TStringConstant() or
|
||||
TConditionalBranch() or
|
||||
TSwitch() or
|
||||
TInvoke() or
|
||||
TCatchByType() or
|
||||
TCatchAny() or
|
||||
TThrowValue() or
|
||||
TReThrow() or
|
||||
TUnwind() or
|
||||
TUnmodeledDefinition() or
|
||||
TUnmodeledUse() or
|
||||
TPhi() or
|
||||
TVarArgsStart() or
|
||||
TVarArgsEnd() or
|
||||
TVarArg() or
|
||||
TVarArgCopy()
|
||||
|
||||
class Opcode extends TOpcode {
|
||||
string toString() {
|
||||
result = "UnknownOpcode"
|
||||
}
|
||||
}
|
||||
|
||||
abstract class UnaryOpcode extends Opcode {}
|
||||
|
||||
abstract class BinaryOpcode extends Opcode {}
|
||||
|
||||
abstract class PointerArithmeticOpcode extends BinaryOpcode {}
|
||||
|
||||
abstract class PointerOffsetOpcode extends PointerArithmeticOpcode {}
|
||||
|
||||
abstract class CompareOpcode extends BinaryOpcode {}
|
||||
|
||||
abstract class CopyOpcode extends Opcode {}
|
||||
|
||||
abstract class MemoryAccessOpcode extends Opcode {}
|
||||
|
||||
abstract class ReturnOpcode extends Opcode {}
|
||||
|
||||
abstract class ThrowOpcode extends Opcode {}
|
||||
|
||||
abstract class CatchOpcode extends Opcode {}
|
||||
|
||||
abstract class OpcodeWithCondition extends Opcode {}
|
||||
|
||||
abstract class BuiltInOpcode extends Opcode {}
|
||||
|
||||
module Opcode {
|
||||
class NoOp extends Opcode, TNoOp { override final string toString() { result = "NoOp" } }
|
||||
class Uninitialized extends MemoryAccessOpcode, TUninitialized { override final string toString() { result = "Uninitialized" } }
|
||||
class InitializeParameter extends MemoryAccessOpcode, TInitializeParameter { override final string toString() { result = "InitializeParameter" } }
|
||||
class InitializeThis extends Opcode, TInitializeThis { override final string toString() { result = "InitializeThis" } }
|
||||
class EnterFunction extends Opcode, TEnterFunction { override final string toString() { result = "EnterFunction" } }
|
||||
class ExitFunction extends Opcode, TExitFunction { override final string toString() { result = "ExitFunction" } }
|
||||
class ReturnValue extends ReturnOpcode, MemoryAccessOpcode, TReturnValue { override final string toString() { result = "ReturnValue" } }
|
||||
class ReturnVoid extends ReturnOpcode, TReturnVoid { override final string toString() { result = "ReturnVoid" } }
|
||||
class CopyValue extends CopyOpcode, TCopyValue { override final string toString() { result = "CopyValue" } }
|
||||
class Load extends CopyOpcode, MemoryAccessOpcode, TLoad { override final string toString() { result = "Load" } }
|
||||
class Store extends CopyOpcode, MemoryAccessOpcode, TStore { override final string toString() { result = "Store" } }
|
||||
class Add extends BinaryOpcode, TAdd { override final string toString() { result = "Add" } }
|
||||
class Sub extends BinaryOpcode, TSub { override final string toString() { result = "Sub" } }
|
||||
class Mul extends BinaryOpcode, TMul { override final string toString() { result = "Mul" } }
|
||||
class Div extends BinaryOpcode, TDiv { override final string toString() { result = "Div" } }
|
||||
class Rem extends BinaryOpcode, TRem { override final string toString() { result = "Rem" } }
|
||||
class Negate extends UnaryOpcode, TNegate { override final string toString() { result = "Negate" } }
|
||||
class ShiftLeft extends BinaryOpcode, TShiftLeft { override final string toString() { result = "ShiftLeft" } }
|
||||
class ShiftRight extends BinaryOpcode, TShiftRight { override final string toString() { result = "ShiftRight" } }
|
||||
class BitAnd extends BinaryOpcode, TBitAnd { override final string toString() { result = "BitAnd" } }
|
||||
class BitOr extends BinaryOpcode, TBitOr { override final string toString() { result = "BitOr" } }
|
||||
class BitXor extends BinaryOpcode, TBitXor { override final string toString() { result = "BitXor" } }
|
||||
class BitComplement extends UnaryOpcode, TBitComplement { override final string toString() { result = "BitComplement" } }
|
||||
class LogicalNot extends UnaryOpcode, TLogicalNot { override final string toString() { result = "LogicalNot" } }
|
||||
class CompareEQ extends CompareOpcode, TCompareEQ { override final string toString() { result = "CompareEQ" } }
|
||||
class CompareNE extends CompareOpcode, TCompareNE { override final string toString() { result = "CompareNE" } }
|
||||
class CompareLT extends CompareOpcode, TCompareLT { override final string toString() { result = "CompareLT" } }
|
||||
class CompareGT extends CompareOpcode, TCompareGT { override final string toString() { result = "CompareGT" } }
|
||||
class CompareLE extends CompareOpcode, TCompareLE { override final string toString() { result = "CompareLE" } }
|
||||
class CompareGE extends CompareOpcode, TCompareGE { override final string toString() { result = "CompareGE" } }
|
||||
class PointerAdd extends PointerOffsetOpcode, TPointerAdd { override final string toString() { result = "PointerAdd" } }
|
||||
class PointerSub extends PointerOffsetOpcode, TPointerSub { override final string toString() { result = "PointerSub" } }
|
||||
class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { override final string toString() { result = "PointerDiff" } }
|
||||
class Convert extends UnaryOpcode, TConvert { override final string toString() { result = "Convert" } }
|
||||
class ConvertToBase extends UnaryOpcode, TConvertToBase { override final string toString() { result = "ConvertToBase" } }
|
||||
class ConvertToVirtualBase extends UnaryOpcode, TConvertToVirtualBase { override final string toString() { result = "ConvertToVirtualBase" } }
|
||||
class ConvertToDerived extends UnaryOpcode, TConvertToDerived { override final string toString() { result = "ConvertToDerived" } }
|
||||
class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { override final string toString() { result = "CheckedConvertOrNull" } }
|
||||
class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { override final string toString() { result = "CheckedConvertOrThrow" } }
|
||||
class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { override final string toString() { result = "DynamicCastToVoid" } }
|
||||
class VariableAddress extends Opcode, TVariableAddress { override final string toString() { result = "VariableAddress" } }
|
||||
class FieldAddress extends UnaryOpcode, TFieldAddress { override final string toString() { result = "FieldAddress" } }
|
||||
class FunctionAddress extends Opcode, TFunctionAddress { override final string toString() { result = "FunctionAddress" } }
|
||||
class Constant extends Opcode, TConstant { override final string toString() { result = "Constant" } }
|
||||
class StringConstant extends Opcode, TStringConstant { override final string toString() { result = "StringConstant" } }
|
||||
class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { override final string toString() { result = "ConditionalBranch" } }
|
||||
class Switch extends OpcodeWithCondition, TSwitch { override final string toString() { result = "Switch" } }
|
||||
class Invoke extends Opcode, TInvoke { override final string toString() { result = "Invoke" } }
|
||||
class CatchByType extends CatchOpcode, TCatchByType { override final string toString() { result = "CatchByType" } }
|
||||
class CatchAny extends CatchOpcode, TCatchAny { override final string toString() { result = "CatchAny" } }
|
||||
class ThrowValue extends ThrowOpcode, MemoryAccessOpcode, TThrowValue { override final string toString() { result = "ThrowValue" } }
|
||||
class ReThrow extends ThrowOpcode, TReThrow { override final string toString() { result = "ReThrow" } }
|
||||
class Unwind extends Opcode, TUnwind { override final string toString() { result = "Unwind" } }
|
||||
class UnmodeledDefinition extends Opcode, TUnmodeledDefinition { override final string toString() { result = "UnmodeledDefinition" } }
|
||||
class UnmodeledUse extends Opcode, TUnmodeledUse { override final string toString() { result = "UnmodeledUse" } }
|
||||
class Phi extends Opcode, TPhi { override final string toString() { result = "Phi" } }
|
||||
class VarArgsStart extends BuiltInOpcode, TVarArgsStart { override final string toString() { result = "VarArgsStart" } }
|
||||
class VarArgsEnd extends BuiltInOpcode, TVarArgsEnd { override final string toString() { result = "VarArgsEnd" } }
|
||||
class VarArg extends BuiltInOpcode, TVarArg { override final string toString() { result = "VarArg" } }
|
||||
class VarArgCopy extends BuiltInOpcode, TVarArgCopy { override final string toString() { result = "VarArgCopy" } }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import cpp
|
||||
|
||||
newtype TTempVariableTag =
|
||||
ConditionValueTempVar() or
|
||||
ReturnValueTempVar() or
|
||||
ThrowTempVar()
|
||||
|
||||
string getTempVariableTagId(TTempVariableTag tag) {
|
||||
tag = ConditionValueTempVar() and result = "CondVal" or
|
||||
tag = ReturnValueTempVar() and result = "Ret" or
|
||||
tag = ThrowTempVar() and result = "Throw"
|
||||
}
|
||||
import cpp
|
||||
|
||||
newtype TTempVariableTag =
|
||||
ConditionValueTempVar() or
|
||||
ReturnValueTempVar() or
|
||||
ThrowTempVar()
|
||||
|
||||
string getTempVariableTagId(TTempVariableTag tag) {
|
||||
tag = ConditionValueTempVar() and result = "CondVal" or
|
||||
tag = ReturnValueTempVar() and result = "Ret" or
|
||||
tag = ThrowTempVar() and result = "Throw"
|
||||
}
|
||||
|
||||
@@ -1,263 +1,263 @@
|
||||
import cpp
|
||||
private import InstructionTag
|
||||
private import Opcode
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
|
||||
abstract class ConditionContext extends TranslatedElement {
|
||||
abstract Instruction getChildTrueSuccessor(TranslatedCondition child);
|
||||
|
||||
abstract Instruction getChildFalseSuccessor(TranslatedCondition child);
|
||||
}
|
||||
|
||||
TranslatedCondition getTranslatedCondition(Expr expr) {
|
||||
result.getExpr() = expr
|
||||
}
|
||||
|
||||
abstract class TranslatedCondition extends TranslatedElement {
|
||||
Expr expr;
|
||||
|
||||
override final string toString() {
|
||||
result = expr.toString()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = expr
|
||||
}
|
||||
|
||||
final ConditionContext getConditionContext() {
|
||||
result = getParent()
|
||||
}
|
||||
|
||||
final Expr getExpr() {
|
||||
result = expr
|
||||
}
|
||||
|
||||
override final Function getFunction() {
|
||||
result = expr.getEnclosingFunction()
|
||||
}
|
||||
|
||||
final Type getResultType() {
|
||||
result = expr.getType().getUnspecifiedType()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TranslatedFlexibleCondition extends TranslatedCondition,
|
||||
ConditionContext, TTranslatedFlexibleCondition {
|
||||
TranslatedFlexibleCondition() {
|
||||
this = TTranslatedFlexibleCondition(expr)
|
||||
}
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getOperand()
|
||||
}
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
result = getOperand().getFirstInstruction()
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final Instruction getChildSuccessor(TranslatedElement child) {
|
||||
none()
|
||||
}
|
||||
|
||||
abstract TranslatedCondition getOperand();
|
||||
}
|
||||
|
||||
class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
||||
ParenthesisExpr paren;
|
||||
|
||||
TranslatedParenthesisCondition() {
|
||||
paren = expr
|
||||
}
|
||||
|
||||
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
}
|
||||
|
||||
final override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
|
||||
final override TranslatedCondition getOperand() {
|
||||
result = getTranslatedCondition(paren.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedNotCondition extends TranslatedFlexibleCondition {
|
||||
NotExpr notExpr;
|
||||
|
||||
TranslatedNotCondition() {
|
||||
notExpr = expr
|
||||
}
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
}
|
||||
|
||||
override TranslatedCondition getOperand() {
|
||||
result = getTranslatedCondition(notExpr.getOperand().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TranslatedNativeCondition extends TranslatedCondition,
|
||||
TTranslatedNativeCondition {
|
||||
TranslatedNativeCondition() {
|
||||
this = TTranslatedNativeCondition(expr)
|
||||
}
|
||||
|
||||
override final Instruction getChildSuccessor(TranslatedElement child) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TranslatedBinaryLogicalOperation extends
|
||||
TranslatedNativeCondition, ConditionContext {
|
||||
BinaryLogicalOperation op;
|
||||
|
||||
TranslatedBinaryLogicalOperation() {
|
||||
op = expr
|
||||
}
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getLeftOperand() or
|
||||
id = 1 and result = getRightOperand()
|
||||
}
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
result = getLeftOperand().getFirstInstruction()
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
none()
|
||||
}
|
||||
|
||||
final TranslatedCondition getLeftOperand() {
|
||||
result = getTranslatedCondition(op.getLeftOperand().getFullyConverted())
|
||||
}
|
||||
|
||||
final TranslatedCondition getRightOperand() {
|
||||
result = getTranslatedCondition(op.getRightOperand().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
|
||||
TranslatedLogicalAndExpr() {
|
||||
op instanceof LogicalAndExpr
|
||||
}
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
(
|
||||
child = getLeftOperand() and
|
||||
result = getRightOperand().getFirstInstruction()
|
||||
) or
|
||||
(
|
||||
child = getRightOperand() and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
(child = getLeftOperand() or child = getRightOperand()) and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
|
||||
TranslatedLogicalOrExpr() {
|
||||
op instanceof LogicalOrExpr
|
||||
}
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
(child = getLeftOperand() or child = getRightOperand()) and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
(
|
||||
child = getLeftOperand() and
|
||||
result = getRightOperand().getFirstInstruction()
|
||||
) or
|
||||
(
|
||||
child = getRightOperand() and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedValueCondition extends TranslatedCondition,
|
||||
TTranslatedValueCondition {
|
||||
TranslatedValueCondition() {
|
||||
this = TTranslatedValueCondition(expr)
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getValueExpr()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getValueExpr().getFirstInstruction()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
opcode instanceof Opcode::ConditionalBranch and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getValueExpr() and
|
||||
result = getInstruction(ValueConditionConditionalBranchTag())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
(
|
||||
(
|
||||
kind instanceof TrueEdge and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
) or
|
||||
(
|
||||
kind instanceof FalseEdge and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
operandTag instanceof ConditionOperand and
|
||||
result = getValueExpr().getResult()
|
||||
}
|
||||
|
||||
private TranslatedExpr getValueExpr() {
|
||||
result = getTranslatedExpr(expr)
|
||||
}
|
||||
}
|
||||
import cpp
|
||||
private import InstructionTag
|
||||
private import Opcode
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
|
||||
abstract class ConditionContext extends TranslatedElement {
|
||||
abstract Instruction getChildTrueSuccessor(TranslatedCondition child);
|
||||
|
||||
abstract Instruction getChildFalseSuccessor(TranslatedCondition child);
|
||||
}
|
||||
|
||||
TranslatedCondition getTranslatedCondition(Expr expr) {
|
||||
result.getExpr() = expr
|
||||
}
|
||||
|
||||
abstract class TranslatedCondition extends TranslatedElement {
|
||||
Expr expr;
|
||||
|
||||
override final string toString() {
|
||||
result = expr.toString()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = expr
|
||||
}
|
||||
|
||||
final ConditionContext getConditionContext() {
|
||||
result = getParent()
|
||||
}
|
||||
|
||||
final Expr getExpr() {
|
||||
result = expr
|
||||
}
|
||||
|
||||
override final Function getFunction() {
|
||||
result = expr.getEnclosingFunction()
|
||||
}
|
||||
|
||||
final Type getResultType() {
|
||||
result = expr.getType().getUnspecifiedType()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TranslatedFlexibleCondition extends TranslatedCondition,
|
||||
ConditionContext, TTranslatedFlexibleCondition {
|
||||
TranslatedFlexibleCondition() {
|
||||
this = TTranslatedFlexibleCondition(expr)
|
||||
}
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getOperand()
|
||||
}
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
result = getOperand().getFirstInstruction()
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final Instruction getChildSuccessor(TranslatedElement child) {
|
||||
none()
|
||||
}
|
||||
|
||||
abstract TranslatedCondition getOperand();
|
||||
}
|
||||
|
||||
class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
||||
ParenthesisExpr paren;
|
||||
|
||||
TranslatedParenthesisCondition() {
|
||||
paren = expr
|
||||
}
|
||||
|
||||
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
}
|
||||
|
||||
final override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
|
||||
final override TranslatedCondition getOperand() {
|
||||
result = getTranslatedCondition(paren.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedNotCondition extends TranslatedFlexibleCondition {
|
||||
NotExpr notExpr;
|
||||
|
||||
TranslatedNotCondition() {
|
||||
notExpr = expr
|
||||
}
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
child = getOperand() and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
}
|
||||
|
||||
override TranslatedCondition getOperand() {
|
||||
result = getTranslatedCondition(notExpr.getOperand().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TranslatedNativeCondition extends TranslatedCondition,
|
||||
TTranslatedNativeCondition {
|
||||
TranslatedNativeCondition() {
|
||||
this = TTranslatedNativeCondition(expr)
|
||||
}
|
||||
|
||||
override final Instruction getChildSuccessor(TranslatedElement child) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TranslatedBinaryLogicalOperation extends
|
||||
TranslatedNativeCondition, ConditionContext {
|
||||
BinaryLogicalOperation op;
|
||||
|
||||
TranslatedBinaryLogicalOperation() {
|
||||
op = expr
|
||||
}
|
||||
|
||||
override final TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getLeftOperand() or
|
||||
id = 1 and result = getRightOperand()
|
||||
}
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
result = getLeftOperand().getFirstInstruction()
|
||||
}
|
||||
|
||||
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
none()
|
||||
}
|
||||
|
||||
final TranslatedCondition getLeftOperand() {
|
||||
result = getTranslatedCondition(op.getLeftOperand().getFullyConverted())
|
||||
}
|
||||
|
||||
final TranslatedCondition getRightOperand() {
|
||||
result = getTranslatedCondition(op.getRightOperand().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
|
||||
TranslatedLogicalAndExpr() {
|
||||
op instanceof LogicalAndExpr
|
||||
}
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
(
|
||||
child = getLeftOperand() and
|
||||
result = getRightOperand().getFirstInstruction()
|
||||
) or
|
||||
(
|
||||
child = getRightOperand() and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
(child = getLeftOperand() or child = getRightOperand()) and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
|
||||
TranslatedLogicalOrExpr() {
|
||||
op instanceof LogicalOrExpr
|
||||
}
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
(child = getLeftOperand() or child = getRightOperand()) and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
(
|
||||
child = getLeftOperand() and
|
||||
result = getRightOperand().getFirstInstruction()
|
||||
) or
|
||||
(
|
||||
child = getRightOperand() and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedValueCondition extends TranslatedCondition,
|
||||
TTranslatedValueCondition {
|
||||
TranslatedValueCondition() {
|
||||
this = TTranslatedValueCondition(expr)
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getValueExpr()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getValueExpr().getFirstInstruction()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
opcode instanceof Opcode::ConditionalBranch and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getValueExpr() and
|
||||
result = getInstruction(ValueConditionConditionalBranchTag())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
(
|
||||
(
|
||||
kind instanceof TrueEdge and
|
||||
result = getConditionContext().getChildTrueSuccessor(this)
|
||||
) or
|
||||
(
|
||||
kind instanceof FalseEdge and
|
||||
result = getConditionContext().getChildFalseSuccessor(this)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
operandTag instanceof ConditionOperand and
|
||||
result = getValueExpr().getResult()
|
||||
}
|
||||
|
||||
private TranslatedExpr getValueExpr() {
|
||||
result = getTranslatedExpr(expr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,226 +1,226 @@
|
||||
import cpp
|
||||
private import InstructionTag
|
||||
private import Opcode
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import TranslatedInitialization
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedDeclarationEntry` that represents the declaration
|
||||
* `entry`.
|
||||
*/
|
||||
TranslatedDeclarationEntry getTranslatedDeclarationEntry(
|
||||
DeclarationEntry entry) {
|
||||
result.getAST() = entry
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a declaration within the body of a function.
|
||||
* Most often, this is the declaration of an automatic local variable, although
|
||||
* it can also be the declaration of a static local variable, an extern
|
||||
* variable, or an extern function.
|
||||
*/
|
||||
abstract class TranslatedDeclarationEntry extends TranslatedElement,
|
||||
TTranslatedDeclarationEntry {
|
||||
DeclarationEntry entry;
|
||||
|
||||
TranslatedDeclarationEntry() {
|
||||
this = TTranslatedDeclarationEntry(entry)
|
||||
}
|
||||
|
||||
override final Function getFunction() {
|
||||
exists(DeclStmt stmt |
|
||||
stmt.getADeclarationEntry() = entry and
|
||||
result = stmt.getEnclosingFunction()
|
||||
)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = entry.toString()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = entry
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a declaration within the body of a function,
|
||||
* for declarations other than local variables. Since these have no semantic
|
||||
* effect, they are translated as `NoOp`.
|
||||
*/
|
||||
class TranslatedNonVariableDeclaration extends
|
||||
TranslatedDeclarationEntry {
|
||||
TranslatedNonVariableDeclaration() {
|
||||
not entry.getDeclaration() instanceof LocalVariable
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
opcode instanceof Opcode::NoOp and
|
||||
tag = OnlyInstructionTag() and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of the declaration of a local variable,
|
||||
* including its initialization, if any.
|
||||
*/
|
||||
abstract class TranslatedVariableDeclaration extends
|
||||
TranslatedDeclarationEntry {
|
||||
LocalVariable var;
|
||||
|
||||
TranslatedVariableDeclaration() {
|
||||
entry.getDeclaration() = var
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a local variable with no initializer. The
|
||||
* generated IR stores into the variable using an `Uninitialized` instruction,
|
||||
* rather than a `Store`.
|
||||
*/
|
||||
class TranslatedUninitializedVariable extends
|
||||
TranslatedVariableDeclaration {
|
||||
TranslatedUninitializedVariable() {
|
||||
not exists(Initializer init |
|
||||
init.getDeclaration() = var
|
||||
)
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = var.getType().getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
) or
|
||||
(
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = var.getType().getUnspecifiedType() and
|
||||
isGLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
kind instanceof GotoEdge and
|
||||
(
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getInstruction(InitializerStoreTag())
|
||||
) or
|
||||
(
|
||||
tag = InitializerStoreTag() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getIRUserVariable(var.getFunction(), var)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a local variable with an initializer.
|
||||
*/
|
||||
class TranslatedInitializedVariable extends
|
||||
TranslatedVariableDeclaration, InitializationContext {
|
||||
Initializer init;
|
||||
|
||||
TranslatedInitializedVariable() {
|
||||
init.getDeclaration() = var
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getInitialization()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = var.getType().getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getInitialization().getFirstInstruction() and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getIRUserVariable(var.getFunction(), var)
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override Type getTargetType() {
|
||||
result = var.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
private TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(init.getExpr().getFullyConverted())
|
||||
}
|
||||
}
|
||||
import cpp
|
||||
private import InstructionTag
|
||||
private import Opcode
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import TranslatedInitialization
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedDeclarationEntry` that represents the declaration
|
||||
* `entry`.
|
||||
*/
|
||||
TranslatedDeclarationEntry getTranslatedDeclarationEntry(
|
||||
DeclarationEntry entry) {
|
||||
result.getAST() = entry
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a declaration within the body of a function.
|
||||
* Most often, this is the declaration of an automatic local variable, although
|
||||
* it can also be the declaration of a static local variable, an extern
|
||||
* variable, or an extern function.
|
||||
*/
|
||||
abstract class TranslatedDeclarationEntry extends TranslatedElement,
|
||||
TTranslatedDeclarationEntry {
|
||||
DeclarationEntry entry;
|
||||
|
||||
TranslatedDeclarationEntry() {
|
||||
this = TTranslatedDeclarationEntry(entry)
|
||||
}
|
||||
|
||||
override final Function getFunction() {
|
||||
exists(DeclStmt stmt |
|
||||
stmt.getADeclarationEntry() = entry and
|
||||
result = stmt.getEnclosingFunction()
|
||||
)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = entry.toString()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = entry
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a declaration within the body of a function,
|
||||
* for declarations other than local variables. Since these have no semantic
|
||||
* effect, they are translated as `NoOp`.
|
||||
*/
|
||||
class TranslatedNonVariableDeclaration extends
|
||||
TranslatedDeclarationEntry {
|
||||
TranslatedNonVariableDeclaration() {
|
||||
not entry.getDeclaration() instanceof LocalVariable
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
opcode instanceof Opcode::NoOp and
|
||||
tag = OnlyInstructionTag() and
|
||||
resultType instanceof VoidType and
|
||||
isGLValue = false
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of the declaration of a local variable,
|
||||
* including its initialization, if any.
|
||||
*/
|
||||
abstract class TranslatedVariableDeclaration extends
|
||||
TranslatedDeclarationEntry {
|
||||
LocalVariable var;
|
||||
|
||||
TranslatedVariableDeclaration() {
|
||||
entry.getDeclaration() = var
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a local variable with no initializer. The
|
||||
* generated IR stores into the variable using an `Uninitialized` instruction,
|
||||
* rather than a `Store`.
|
||||
*/
|
||||
class TranslatedUninitializedVariable extends
|
||||
TranslatedVariableDeclaration {
|
||||
TranslatedUninitializedVariable() {
|
||||
not exists(Initializer init |
|
||||
init.getDeclaration() = var
|
||||
)
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = var.getType().getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
) or
|
||||
(
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = var.getType().getUnspecifiedType() and
|
||||
isGLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
kind instanceof GotoEdge and
|
||||
(
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getInstruction(InitializerStoreTag())
|
||||
) or
|
||||
(
|
||||
tag = InitializerStoreTag() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getIRUserVariable(var.getFunction(), var)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of a local variable with an initializer.
|
||||
*/
|
||||
class TranslatedInitializedVariable extends
|
||||
TranslatedVariableDeclaration, InitializationContext {
|
||||
Initializer init;
|
||||
|
||||
TranslatedInitializedVariable() {
|
||||
init.getDeclaration() = var
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getInitialization()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = var.getType().getUnspecifiedType() and
|
||||
isGLValue = true
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getInitialization().getFirstInstruction() and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
result = getIRUserVariable(var.getFunction(), var)
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override Type getTargetType() {
|
||||
result = var.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
private TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(init.getExpr().getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
* Gets the type of the result produced by this expression.
|
||||
*/
|
||||
final Type getResultType() {
|
||||
result = expr.getType().getUnspecifiedType()
|
||||
result = expr.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
@@ -303,7 +303,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Load of " + expr.toString()
|
||||
result = "Load of " + expr.toString()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
@@ -1945,7 +1945,7 @@ abstract class TranslatedAllocationSize extends TranslatedExpr,
|
||||
}
|
||||
|
||||
override final predicate producesExprResult() {
|
||||
none()
|
||||
none()
|
||||
}
|
||||
|
||||
override final Instruction getResult() {
|
||||
@@ -2144,7 +2144,7 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
|
||||
}
|
||||
|
||||
override final predicate producesExprResult() {
|
||||
none()
|
||||
none()
|
||||
}
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
private import implementations.Inet
|
||||
private import implementations.Memcpy
|
||||
private import implementations.Printf
|
||||
private import implementations.Pure
|
||||
private import implementations.Strcat
|
||||
private import implementations.Strcpy
|
||||
private import implementations.Strftime
|
||||
private import implementations.Inet
|
||||
private import implementations.Memcpy
|
||||
private import implementations.Printf
|
||||
private import implementations.Pure
|
||||
private import implementations.Strcat
|
||||
private import implementations.Strcpy
|
||||
private import implementations.Strftime
|
||||
|
||||
@@ -1 +1 @@
|
||||
import internal.aliased_ssa.IRImpl
|
||||
import internal.aliased_ssa.IRImpl
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @name Print Aliased SSA IR
|
||||
* @description Outputs a representation of the Aliased SSA IR graph
|
||||
* @id cpp/print-aliased-ssa-ir
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import PrintAliasedSSAIR
|
||||
/**
|
||||
* @name Print Aliased SSA IR
|
||||
* @description Outputs a representation of the Aliased SSA IR graph
|
||||
* @id cpp/print-aliased-ssa-ir
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import PrintAliasedSSAIR
|
||||
|
||||
@@ -1 +1 @@
|
||||
import internal.aliased_ssa.PrintIRImpl
|
||||
import internal.aliased_ssa.PrintIRImpl
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @name Print SSA IR
|
||||
* @description Outputs a representation of the SSA IR graph
|
||||
* @id cpp/print-ssa-ir
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import PrintSSAIR
|
||||
/**
|
||||
* @name Print SSA IR
|
||||
* @description Outputs a representation of the SSA IR graph
|
||||
* @id cpp/print-ssa-ir
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import PrintSSAIR
|
||||
|
||||
@@ -1 +1 @@
|
||||
import internal.ssa.PrintIRImpl
|
||||
import internal.ssa.PrintIRImpl
|
||||
|
||||
@@ -1 +1 @@
|
||||
import internal.ssa.IRImpl
|
||||
import internal.ssa.IRImpl
|
||||
|
||||
@@ -1,111 +1,111 @@
|
||||
import cpp
|
||||
|
||||
class IntValue = int;
|
||||
|
||||
/**
|
||||
* Returns the value of the maximum representable integer.
|
||||
*/
|
||||
int maxValue() {
|
||||
result = 2147483647
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the minimum representable integer.
|
||||
*/
|
||||
int minValue() {
|
||||
result = -2147483647
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value representing an unknown integer.
|
||||
*/
|
||||
IntValue unknown() {
|
||||
result = -2147483648
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` has a known value.
|
||||
*/
|
||||
bindingset[n]
|
||||
predicate hasValue(IntValue n) {
|
||||
n != unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value `f` is within the range of representable integers.
|
||||
*/
|
||||
pragma[inline]
|
||||
bindingset[f]
|
||||
private predicate isRepresentable(float f) {
|
||||
(f >= minValue()) and (f <= maxValue())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of `n`. Holds only if `n` has a known value.
|
||||
*/
|
||||
bindingset[n]
|
||||
int getValue(IntValue n) {
|
||||
hasValue(n) and result = n
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `a + b`. If either input is unknown, or if the addition overflows,
|
||||
* the result is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
IntValue add(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) and isRepresentable((float)a + (float)b) then
|
||||
result = a + b
|
||||
else
|
||||
result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `a - b`. If either input is unknown, or if the subtraction overflows,
|
||||
* the result is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
IntValue sub(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) and isRepresentable((float)a - (float)b) then
|
||||
result = a - b
|
||||
else
|
||||
result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `a * b`. If the multiplication overflows, the result is unknown. If
|
||||
* either input is unknown and the other input is non-zero, the result is
|
||||
* unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
IntValue mul(IntValue a, IntValue b) {
|
||||
if (a = 0) or (b = 0) then
|
||||
result = 0
|
||||
else if hasValue(a) and hasValue(b) and isRepresentable((float)a * (float)b) then
|
||||
result = a * b
|
||||
else
|
||||
result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `a / b`. If either input is unknown, or if `b` is zero, the result is
|
||||
* unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
IntValue div(IntValue a, IntValue b) {
|
||||
// Normally, integer division has to worry about overflow for INT_MIN/-1.
|
||||
// However, since we use INT_MIN to represent an unknown value anyway, we only
|
||||
// have to worry about division by zero.
|
||||
if hasValue(a) and hasValue(b) and (b != 0) then
|
||||
result = a / b
|
||||
else
|
||||
result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `-a`. If `a` is unknown, the result is unknown.
|
||||
*/
|
||||
bindingset[a]
|
||||
IntValue neg(IntValue a) {
|
||||
result = -a // -INT_MIN = INT_MIN, so this preserves unknown
|
||||
}
|
||||
import cpp
|
||||
|
||||
class IntValue = int;
|
||||
|
||||
/**
|
||||
* Returns the value of the maximum representable integer.
|
||||
*/
|
||||
int maxValue() {
|
||||
result = 2147483647
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the minimum representable integer.
|
||||
*/
|
||||
int minValue() {
|
||||
result = -2147483647
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value representing an unknown integer.
|
||||
*/
|
||||
IntValue unknown() {
|
||||
result = -2147483648
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` has a known value.
|
||||
*/
|
||||
bindingset[n]
|
||||
predicate hasValue(IntValue n) {
|
||||
n != unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value `f` is within the range of representable integers.
|
||||
*/
|
||||
pragma[inline]
|
||||
bindingset[f]
|
||||
private predicate isRepresentable(float f) {
|
||||
(f >= minValue()) and (f <= maxValue())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of `n`. Holds only if `n` has a known value.
|
||||
*/
|
||||
bindingset[n]
|
||||
int getValue(IntValue n) {
|
||||
hasValue(n) and result = n
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `a + b`. If either input is unknown, or if the addition overflows,
|
||||
* the result is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
IntValue add(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) and isRepresentable((float)a + (float)b) then
|
||||
result = a + b
|
||||
else
|
||||
result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `a - b`. If either input is unknown, or if the subtraction overflows,
|
||||
* the result is unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
IntValue sub(IntValue a, IntValue b) {
|
||||
if hasValue(a) and hasValue(b) and isRepresentable((float)a - (float)b) then
|
||||
result = a - b
|
||||
else
|
||||
result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `a * b`. If the multiplication overflows, the result is unknown. If
|
||||
* either input is unknown and the other input is non-zero, the result is
|
||||
* unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
IntValue mul(IntValue a, IntValue b) {
|
||||
if (a = 0) or (b = 0) then
|
||||
result = 0
|
||||
else if hasValue(a) and hasValue(b) and isRepresentable((float)a * (float)b) then
|
||||
result = a * b
|
||||
else
|
||||
result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `a / b`. If either input is unknown, or if `b` is zero, the result is
|
||||
* unknown.
|
||||
*/
|
||||
bindingset[a, b]
|
||||
IntValue div(IntValue a, IntValue b) {
|
||||
// Normally, integer division has to worry about overflow for INT_MIN/-1.
|
||||
// However, since we use INT_MIN to represent an unknown value anyway, we only
|
||||
// have to worry about division by zero.
|
||||
if hasValue(a) and hasValue(b) and (b != 0) then
|
||||
result = a / b
|
||||
else
|
||||
result = unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `-a`. If `a` is unknown, the result is unknown.
|
||||
*/
|
||||
bindingset[a]
|
||||
IntValue neg(IntValue a) {
|
||||
result = -a // -INT_MIN = INT_MIN, so this preserves unknown
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import cpp
|
||||
|
||||
private newtype TOverlap =
|
||||
TMayPartiallyOverlap() or
|
||||
TMustTotallyOverlap() or
|
||||
TMustExactlyOverlap()
|
||||
|
||||
abstract class Overlap extends TOverlap {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
class MayPartiallyOverlap extends Overlap, TMayPartiallyOverlap {
|
||||
override final string toString() {
|
||||
result = "MayPartiallyOverlap"
|
||||
}
|
||||
}
|
||||
|
||||
class MustTotallyOverlap extends Overlap, TMustTotallyOverlap {
|
||||
override final string toString() {
|
||||
result = "MustTotallyOverlap"
|
||||
}
|
||||
}
|
||||
|
||||
class MustExactlyOverlap extends Overlap, TMustExactlyOverlap {
|
||||
override final string toString() {
|
||||
result = "MustExactlyOverlap"
|
||||
}
|
||||
}
|
||||
import cpp
|
||||
|
||||
private newtype TOverlap =
|
||||
TMayPartiallyOverlap() or
|
||||
TMustTotallyOverlap() or
|
||||
TMustExactlyOverlap()
|
||||
|
||||
abstract class Overlap extends TOverlap {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
class MayPartiallyOverlap extends Overlap, TMayPartiallyOverlap {
|
||||
override final string toString() {
|
||||
result = "MayPartiallyOverlap"
|
||||
}
|
||||
}
|
||||
|
||||
class MustTotallyOverlap extends Overlap, TMustTotallyOverlap {
|
||||
override final string toString() {
|
||||
result = "MustTotallyOverlap"
|
||||
}
|
||||
}
|
||||
|
||||
class MustExactlyOverlap extends Overlap, TMustExactlyOverlap {
|
||||
override final string toString() {
|
||||
result = "MustExactlyOverlap"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,214 +1,214 @@
|
||||
private import AliasAnalysisInternal
|
||||
import cpp
|
||||
private import IR
|
||||
private import semmle.code.cpp.ssa.internal.IntegerConstant as Ints
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
/**
|
||||
* Converts the bit count in `bits` to a byte count and a bit count in the form
|
||||
* bytes:bits.
|
||||
*/
|
||||
bindingset[bits]
|
||||
string bitsToBytesAndBits(int bits) {
|
||||
result = (bits / 8).toString() + ":" + (bits % 8).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a printable string for a bit offset with possibly unknown value.
|
||||
*/
|
||||
bindingset[bitOffset]
|
||||
string getBitOffsetString(IntValue bitOffset) {
|
||||
if Ints::hasValue(bitOffset) then
|
||||
if bitOffset >= 0 then
|
||||
result = "+" + bitsToBytesAndBits(bitOffset)
|
||||
else
|
||||
result = "-" + bitsToBytesAndBits(Ints::neg(bitOffset))
|
||||
else
|
||||
result = "+?"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of field `field` in bits.
|
||||
*/
|
||||
private IntValue getFieldBitOffset(Field field) {
|
||||
if (field instanceof BitField) then (
|
||||
result = Ints::add(Ints::mul(field.getByteOffset(), 8),
|
||||
field.(BitField).getBitOffset())
|
||||
)
|
||||
else (
|
||||
result = Ints::mul(field.getByteOffset(), 8)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand `tag` of instruction `instr` is used in a way that does
|
||||
* not result in any address held in that operand from escaping beyond the
|
||||
* instruction.
|
||||
*/
|
||||
predicate operandIsConsumedWithoutEscaping(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// The source/destination address of a Load/Store does not escape (but the
|
||||
// loaded/stored value could).
|
||||
tag instanceof LoadStoreAddressOperand or
|
||||
// Neither operand of a Compare escapes.
|
||||
instr instanceof CompareInstruction or
|
||||
// Neither operand of a PointerDiff escapes.
|
||||
instr instanceof PointerDiffInstruction or
|
||||
// Converting an address to a `bool` does not escape the address.
|
||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* If the result of instruction `instr` is an integer constant, returns the
|
||||
* value of that constant. Otherwise, returns unknown.
|
||||
*/
|
||||
IntValue getConstantValue(Instruction instr) {
|
||||
if instr instanceof IntegerConstantInstruction then
|
||||
result = instr.(IntegerConstantInstruction).getValue().toInt()
|
||||
else
|
||||
result = Ints::unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the offset, in bits, by which the result of `instr` differs from the
|
||||
* pointer argument to `instr`, if that offset is a constant. Otherwise, returns
|
||||
* unknown.
|
||||
*/
|
||||
IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
||||
exists(IntValue bitOffset |
|
||||
(
|
||||
bitOffset = Ints::mul(Ints::mul(getConstantValue(instr.getRightOperand()),
|
||||
instr.getElementSize()), 8)
|
||||
) and
|
||||
(
|
||||
instr instanceof PointerAddInstruction and result = bitOffset or
|
||||
instr instanceof PointerSubInstruction and result = Ints::neg(bitOffset)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand `tag` of instruction `instr` is
|
||||
* propagated to the result of `instr`, offset by the number of bits in
|
||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||
* a constant, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate operandIsPropagated(Instruction instr, OperandTag tag,
|
||||
IntValue bitOffset) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
) or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
) or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
(
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
) or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, Type resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultType() and
|
||||
(
|
||||
resultType instanceof PointerType or
|
||||
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
|
||||
) and
|
||||
bitOffset = 0
|
||||
) or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||
// A copy propagates the source value.
|
||||
tag instanceof CopySourceOperand and bitOffset = 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand number `tag` of instruction `instr`
|
||||
* escapes outside the domain of the analysis.
|
||||
*/
|
||||
predicate operandEscapes(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
// Conservatively assume that the address escapes unless one of the following
|
||||
// holds:
|
||||
not (
|
||||
// The operand is used in a way that does not escape the instruction
|
||||
operandIsConsumedWithoutEscaping(instr, tag) or
|
||||
// The address is propagated to the result of the instruction, but that
|
||||
// result does not itself escape.
|
||||
operandIsPropagated(instr, tag, _) and not resultEscapes(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in the result of instruction `instr` escapes
|
||||
* outside the domain of the analysis.
|
||||
*/
|
||||
predicate resultEscapes(Instruction instr) {
|
||||
// The result escapes if it has at least one use that escapes.
|
||||
exists(Instruction useInstr, OperandTag useOperandTag |
|
||||
useInstr.getOperand(useOperandTag) = instr and
|
||||
operandEscapes(useInstr, useOperandTag)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of the specified local variable or parameter escapes the
|
||||
* domain of the analysis.
|
||||
*/
|
||||
private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = var.getFunctionIR() and
|
||||
// The variable's address escapes if the result of any
|
||||
// VariableAddressInstruction that computes the variable's address escapes.
|
||||
exists(VariableAddressInstruction instr |
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var and
|
||||
resultEscapes(instr)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of the specified variable escapes the domain of the
|
||||
* analysis.
|
||||
*/
|
||||
predicate variableAddressEscapes(IRVariable var) {
|
||||
automaticVariableAddressEscapes(var.(IRAutomaticVariable)) or
|
||||
// All variables with static storage duration have their address escape.
|
||||
not var instanceof IRAutomaticVariable
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the result of instruction `instr` points within variable `var`, at
|
||||
* bit offset `bitOffset` within the variable. If the result points within
|
||||
* `var`, but at an unknown or non-constant offset, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) {
|
||||
(
|
||||
// The address of a variable points to that variable, at offset 0.
|
||||
instr.(VariableAddressInstruction).getVariable() = var and
|
||||
bitOffset = 0
|
||||
) or
|
||||
exists(OperandTag operandTag, IntValue originalBitOffset,
|
||||
IntValue propagatedBitOffset |
|
||||
// If an operand is propagated, then the result points to the same variable,
|
||||
// offset by the bit offset from the propagation.
|
||||
resultPointsTo(instr.getOperand(operandTag), var, originalBitOffset) and
|
||||
operandIsPropagated(instr, operandTag, propagatedBitOffset) and
|
||||
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
||||
)
|
||||
}
|
||||
private import AliasAnalysisInternal
|
||||
import cpp
|
||||
private import IR
|
||||
private import semmle.code.cpp.ssa.internal.IntegerConstant as Ints
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
/**
|
||||
* Converts the bit count in `bits` to a byte count and a bit count in the form
|
||||
* bytes:bits.
|
||||
*/
|
||||
bindingset[bits]
|
||||
string bitsToBytesAndBits(int bits) {
|
||||
result = (bits / 8).toString() + ":" + (bits % 8).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a printable string for a bit offset with possibly unknown value.
|
||||
*/
|
||||
bindingset[bitOffset]
|
||||
string getBitOffsetString(IntValue bitOffset) {
|
||||
if Ints::hasValue(bitOffset) then
|
||||
if bitOffset >= 0 then
|
||||
result = "+" + bitsToBytesAndBits(bitOffset)
|
||||
else
|
||||
result = "-" + bitsToBytesAndBits(Ints::neg(bitOffset))
|
||||
else
|
||||
result = "+?"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of field `field` in bits.
|
||||
*/
|
||||
private IntValue getFieldBitOffset(Field field) {
|
||||
if (field instanceof BitField) then (
|
||||
result = Ints::add(Ints::mul(field.getByteOffset(), 8),
|
||||
field.(BitField).getBitOffset())
|
||||
)
|
||||
else (
|
||||
result = Ints::mul(field.getByteOffset(), 8)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand `tag` of instruction `instr` is used in a way that does
|
||||
* not result in any address held in that operand from escaping beyond the
|
||||
* instruction.
|
||||
*/
|
||||
predicate operandIsConsumedWithoutEscaping(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// The source/destination address of a Load/Store does not escape (but the
|
||||
// loaded/stored value could).
|
||||
tag instanceof LoadStoreAddressOperand or
|
||||
// Neither operand of a Compare escapes.
|
||||
instr instanceof CompareInstruction or
|
||||
// Neither operand of a PointerDiff escapes.
|
||||
instr instanceof PointerDiffInstruction or
|
||||
// Converting an address to a `bool` does not escape the address.
|
||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* If the result of instruction `instr` is an integer constant, returns the
|
||||
* value of that constant. Otherwise, returns unknown.
|
||||
*/
|
||||
IntValue getConstantValue(Instruction instr) {
|
||||
if instr instanceof IntegerConstantInstruction then
|
||||
result = instr.(IntegerConstantInstruction).getValue().toInt()
|
||||
else
|
||||
result = Ints::unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the offset, in bits, by which the result of `instr` differs from the
|
||||
* pointer argument to `instr`, if that offset is a constant. Otherwise, returns
|
||||
* unknown.
|
||||
*/
|
||||
IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
||||
exists(IntValue bitOffset |
|
||||
(
|
||||
bitOffset = Ints::mul(Ints::mul(getConstantValue(instr.getRightOperand()),
|
||||
instr.getElementSize()), 8)
|
||||
) and
|
||||
(
|
||||
instr instanceof PointerAddInstruction and result = bitOffset or
|
||||
instr instanceof PointerSubInstruction and result = Ints::neg(bitOffset)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand `tag` of instruction `instr` is
|
||||
* propagated to the result of `instr`, offset by the number of bits in
|
||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||
* a constant, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate operandIsPropagated(Instruction instr, OperandTag tag,
|
||||
IntValue bitOffset) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
) or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
) or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
(
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
) or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, Type resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultType() and
|
||||
(
|
||||
resultType instanceof PointerType or
|
||||
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
|
||||
) and
|
||||
bitOffset = 0
|
||||
) or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||
// A copy propagates the source value.
|
||||
tag instanceof CopySourceOperand and bitOffset = 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand number `tag` of instruction `instr`
|
||||
* escapes outside the domain of the analysis.
|
||||
*/
|
||||
predicate operandEscapes(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
// Conservatively assume that the address escapes unless one of the following
|
||||
// holds:
|
||||
not (
|
||||
// The operand is used in a way that does not escape the instruction
|
||||
operandIsConsumedWithoutEscaping(instr, tag) or
|
||||
// The address is propagated to the result of the instruction, but that
|
||||
// result does not itself escape.
|
||||
operandIsPropagated(instr, tag, _) and not resultEscapes(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in the result of instruction `instr` escapes
|
||||
* outside the domain of the analysis.
|
||||
*/
|
||||
predicate resultEscapes(Instruction instr) {
|
||||
// The result escapes if it has at least one use that escapes.
|
||||
exists(Instruction useInstr, OperandTag useOperandTag |
|
||||
useInstr.getOperand(useOperandTag) = instr and
|
||||
operandEscapes(useInstr, useOperandTag)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of the specified local variable or parameter escapes the
|
||||
* domain of the analysis.
|
||||
*/
|
||||
private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = var.getFunctionIR() and
|
||||
// The variable's address escapes if the result of any
|
||||
// VariableAddressInstruction that computes the variable's address escapes.
|
||||
exists(VariableAddressInstruction instr |
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var and
|
||||
resultEscapes(instr)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of the specified variable escapes the domain of the
|
||||
* analysis.
|
||||
*/
|
||||
predicate variableAddressEscapes(IRVariable var) {
|
||||
automaticVariableAddressEscapes(var.(IRAutomaticVariable)) or
|
||||
// All variables with static storage duration have their address escape.
|
||||
not var instanceof IRAutomaticVariable
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the result of instruction `instr` points within variable `var`, at
|
||||
* bit offset `bitOffset` within the variable. If the result points within
|
||||
* `var`, but at an unknown or non-constant offset, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) {
|
||||
(
|
||||
// The address of a variable points to that variable, at offset 0.
|
||||
instr.(VariableAddressInstruction).getVariable() = var and
|
||||
bitOffset = 0
|
||||
) or
|
||||
exists(OperandTag operandTag, IntValue originalBitOffset,
|
||||
IntValue propagatedBitOffset |
|
||||
// If an operand is propagated, then the result points to the same variable,
|
||||
// offset by the bit offset from the propagation.
|
||||
resultPointsTo(instr.getOperand(operandTag), var, originalBitOffset) and
|
||||
operandIsPropagated(instr, operandTag, propagatedBitOffset) and
|
||||
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
import semmle.code.cpp.ssa.SSAIR as IR
|
||||
import semmle.code.cpp.ssa.SSAIR as IR
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import cpp
|
||||
|
||||
private newtype TFunctionIR =
|
||||
MkFunctionIR(Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
*/
|
||||
class FunctionIR extends TFunctionIR {
|
||||
Function func;
|
||||
|
||||
FunctionIR() {
|
||||
this = MkFunctionIR(func)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final EnterFunctionInstruction getEnterFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exit point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ExitFunctionInstruction getExitFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ReturnInstruction getReturnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable used to hold the return value of this function. If this
|
||||
* function does not return a value, this predicate does not hold.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRReturnVariable getReturnVariable() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block containing the entry point of this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock getEntryBlock() {
|
||||
result.getFirstInstruction() = getEnterFunctionInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instructions in this function.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
}
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import cpp
|
||||
|
||||
private newtype TFunctionIR =
|
||||
MkFunctionIR(Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
*/
|
||||
class FunctionIR extends TFunctionIR {
|
||||
Function func;
|
||||
|
||||
FunctionIR() {
|
||||
this = MkFunctionIR(func)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final EnterFunctionInstruction getEnterFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exit point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ExitFunctionInstruction getExitFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ReturnInstruction getReturnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable used to hold the return value of this function. If this
|
||||
* function does not return a value, this predicate does not hold.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRReturnVariable getReturnVariable() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block containing the entry point of this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock getEntryBlock() {
|
||||
result.getFirstInstruction() = getEnterFunctionInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instructions in this function.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
import SSAConstruction as Construction
|
||||
import SSAConstruction as Construction
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
private import IRImpl
|
||||
import InstructionSanity
|
||||
|
||||
private import IRImpl
|
||||
import InstructionSanity
|
||||
|
||||
|
||||
@@ -1,202 +1,202 @@
|
||||
private import IRInternal
|
||||
import FunctionIR
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.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)
|
||||
}
|
||||
|
||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
result.getVariable() = var and
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
FunctionIR funcIR;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Type getType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Locatable getAST();
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
abstract class IRUserVariable extends IRVariable {
|
||||
Variable var;
|
||||
|
||||
override final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = var.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = var
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = var.toString() + " " + var.getLocation().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
final Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
TIRAutomaticUserVariable {
|
||||
LocalScopeVariable localVar;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
||||
var = localVar
|
||||
}
|
||||
|
||||
final LocalScopeVariable getLocalVariable() {
|
||||
result = localVar
|
||||
}
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, funcIR)
|
||||
}
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
|
||||
result.getAST() = ast and
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Locatable ast;
|
||||
TempVariableTag tag;
|
||||
Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = type
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = ast
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = "Temp: " + Construction::getTempVariableUniqueId(this)
|
||||
}
|
||||
|
||||
final TempVariableTag getTag() {
|
||||
result = tag
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
}
|
||||
|
||||
string getBaseString() {
|
||||
result = "#temp"
|
||||
}
|
||||
}
|
||||
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() {
|
||||
tag = ReturnValueTempVar()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "#return"
|
||||
}
|
||||
}
|
||||
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() {
|
||||
tag = ThrowTempVar()
|
||||
}
|
||||
|
||||
override string getBaseString() {
|
||||
result = "#throw"
|
||||
}
|
||||
}
|
||||
private import IRInternal
|
||||
import FunctionIR
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.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)
|
||||
}
|
||||
|
||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
result.getVariable() = var and
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
FunctionIR funcIR;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Type getType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Locatable getAST();
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
abstract class IRUserVariable extends IRVariable {
|
||||
Variable var;
|
||||
|
||||
override final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = var.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = var
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = var.toString() + " " + var.getLocation().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
final Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
TIRAutomaticUserVariable {
|
||||
LocalScopeVariable localVar;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
||||
var = localVar
|
||||
}
|
||||
|
||||
final LocalScopeVariable getLocalVariable() {
|
||||
result = localVar
|
||||
}
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, funcIR)
|
||||
}
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
|
||||
result.getAST() = ast and
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Locatable ast;
|
||||
TempVariableTag tag;
|
||||
Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = type
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = ast
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = "Temp: " + Construction::getTempVariableUniqueId(this)
|
||||
}
|
||||
|
||||
final TempVariableTag getTag() {
|
||||
result = tag
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
}
|
||||
|
||||
string getBaseString() {
|
||||
result = "#temp"
|
||||
}
|
||||
}
|
||||
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() {
|
||||
tag = ReturnValueTempVar()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "#return"
|
||||
}
|
||||
}
|
||||
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() {
|
||||
tag = ThrowTempVar()
|
||||
}
|
||||
|
||||
override string getBaseString() {
|
||||
result = "#throw"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,424 +1,424 @@
|
||||
import SSAConstructionInternal
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.internal.Opcode
|
||||
import NewIR
|
||||
|
||||
import Cached
|
||||
cached private module Cached {
|
||||
|
||||
private OldIR::OperandTag getOldOperandTag(OperandTag newTag) {
|
||||
newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or
|
||||
newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or
|
||||
newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or
|
||||
newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or
|
||||
newTag instanceof RightOperand and result instanceof OldIR::RightOperand or
|
||||
newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or
|
||||
newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or
|
||||
newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or
|
||||
newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or
|
||||
newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or
|
||||
newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or
|
||||
exists(PositionalArgumentOperand newArg |
|
||||
newArg = newTag and
|
||||
result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex()
|
||||
)
|
||||
}
|
||||
|
||||
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
|
||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
}
|
||||
|
||||
cached newtype TInstructionTag =
|
||||
WrappedInstructionTag(OldIR::Instruction oldInstruction) or
|
||||
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
hasPhiNode(vvar, block)
|
||||
}
|
||||
|
||||
cached class InstructionTagType extends TInstructionTag {
|
||||
cached final string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
}
|
||||
|
||||
cached predicate functionHasIR(Function func) {
|
||||
exists(OldIR::FunctionIR funcIR |
|
||||
funcIR.getFunction() = func
|
||||
)
|
||||
}
|
||||
|
||||
cached int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(OldIR::PositionalArgumentOperand oldOperand |
|
||||
argIndex = oldOperand.getArgIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached OldIR::Instruction getOldInstruction(Instruction instr) {
|
||||
instr.getTag() = WrappedInstructionTag(result)
|
||||
}
|
||||
|
||||
private Instruction getNewInstruction(OldIR::Instruction instr) {
|
||||
getOldInstruction(result) = instr
|
||||
}
|
||||
|
||||
private PhiInstruction getPhiInstruction(Function func, OldIR::IRBlock oldBlock,
|
||||
Alias::VirtualVariable vvar) {
|
||||
result.getFunction() = func and
|
||||
result.getAST() = oldBlock.getFirstInstruction().getAST() and
|
||||
result.getTag() = PhiTag(vvar, oldBlock)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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(OldIR::Instruction 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(OldIR::IRBlock 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
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
||||
Type type) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
var.getFunction() = func and
|
||||
var.getAST() = ast and
|
||||
var.getTag() = tag and
|
||||
var.getType() = type
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
exists(Alias::getResultMemoryAccess(getOldInstruction(instruction))) or
|
||||
instruction instanceof PhiInstruction // Phis always have modeled results
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag |
|
||||
oldUse = getOldInstruction(instruction) and
|
||||
oldTag = getOldOperandTag(tag) and
|
||||
if oldUse.isMemoryOperand(oldTag) then (
|
||||
(
|
||||
if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then (
|
||||
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex |
|
||||
vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldUse) and
|
||||
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instruction.getFunction(), defBlock, vvar)
|
||||
)
|
||||
)
|
||||
else (
|
||||
result = instruction.getFunctionIR().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
) or
|
||||
// Connect any definitions that are not being modeled in SSA to the
|
||||
// `UnmodeledUse` instruction.
|
||||
exists(OldIR::Instruction oldDefinition |
|
||||
instruction instanceof UnmodeledUseInstruction and
|
||||
tag instanceof UnmodeledUseOperand and
|
||||
oldDefinition = oldUse.getOperand(oldTag) and
|
||||
not exists(Alias::getResultMemoryAccess(oldDefinition)) and
|
||||
result = getNewInstruction(oldDefinition)
|
||||
)
|
||||
)
|
||||
else
|
||||
result = getNewInstruction(oldUse.getOperand(oldTag))
|
||||
) or
|
||||
result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand))
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) {
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
|
||||
hasPhiNode(vvar, phiBlock) and
|
||||
predBlock = phiBlock.getAPredecessor() and
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
tag.getPredecessorBlock() = getNewBlock(predBlock) and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instr.getFunction(), defBlock, vvar)
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
exists(OldIR::IRBlock oldBlock |
|
||||
instr.getTag() = PhiTag(_, oldBlock) and
|
||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||
}
|
||||
|
||||
cached Field getInstructionField(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
|
||||
}
|
||||
|
||||
cached Function getInstructionFunction(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
cached string getInstructionConstantValue(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
|
||||
}
|
||||
|
||||
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
|
||||
}
|
||||
|
||||
cached Type getInstructionExceptionType(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
|
||||
}
|
||||
|
||||
cached int getInstructionElementSize(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
|
||||
}
|
||||
|
||||
cached int getInstructionResultSize(Instruction instruction) {
|
||||
// Only return a result for instructions that needed an explicit result size.
|
||||
instruction.getResultType() instanceof UnknownType and
|
||||
result = getOldInstruction(instruction).getResultSize()
|
||||
}
|
||||
|
||||
cached predicate getInstructionInheritance(Instruction instruction, Class baseClass,
|
||||
Class derivedClass) {
|
||||
exists(OldIR::InheritanceConversionInstruction oldInstr |
|
||||
oldInstr = getOldInstruction(instruction) and
|
||||
baseClass = oldInstr.getBaseClass() and
|
||||
derivedClass = oldInstr.getDerivedClass()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
|
||||
block.getInstruction(index) = instr and
|
||||
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
|
||||
}
|
||||
|
||||
private predicate hasDefinition(Alias::VirtualVariable vvar, OldIR::IRBlock block, int index) {
|
||||
(
|
||||
hasPhiNode(vvar, block) and
|
||||
index = -1
|
||||
) or
|
||||
exists(Alias::MemoryAccess access, OldIR::Instruction def |
|
||||
access = Alias::getResultMemoryAccess(def) and
|
||||
block.getInstruction(index) = def and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate defUseRank(Alias::VirtualVariable vvar, OldIR::IRBlock block, int rankIndex, int index) {
|
||||
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
|
||||
}
|
||||
|
||||
private predicate hasUse(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction use, OldIR::IRBlock block, int index) {
|
||||
exists(Alias::MemoryAccess access |
|
||||
access = Alias::getOperandMemoryAccess(use, _) and
|
||||
block.getInstruction(index) = use and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldIR::IRBlock 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, _))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
variableLiveOnEntryToBlock(vvar, block.getASuccessor())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank index of a hyphothetical use one instruction past the end of
|
||||
* the block. This index can be used to determine if a definition reaches the
|
||||
* end of the block, even if the definition is the last instruction in the
|
||||
* block.
|
||||
*/
|
||||
private int exitRank(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
result = max(int rankIndex | defUseRank(vvar, block, rankIndex, _)) + 1
|
||||
}
|
||||
|
||||
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock block, int rankIndex, int instructionIndex) {
|
||||
hasDefinition(vvar, block, instructionIndex) and
|
||||
defUseRank(vvar, block, rankIndex, instructionIndex)
|
||||
}
|
||||
|
||||
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldIR::IRBlock block,
|
||||
int rankIndex, OldIR::Instruction use) {
|
||||
exists(int index |
|
||||
hasUse(vvar, use, block, index) and
|
||||
defUseRank(vvar, block, rankIndex, index)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition of `vvar` at `(block, defRank)` reaches the rank
|
||||
* index `reachesRank` in block `block`.
|
||||
*/
|
||||
private predicate definitionReachesRank(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock block, int defRank, int reachesRank) {
|
||||
hasDefinitionAtRank(vvar, block, defRank, _) and
|
||||
reachesRank <= exitRank(vvar, block) and // Without this, the predicate would be infinite.
|
||||
(
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
reachesRank = defRank + 1 or
|
||||
(
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
definitionReachesRank(vvar, block, defRank, reachesRank - 1) and
|
||||
not hasDefinitionAtRank(vvar, block, reachesRank - 1, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition of `vvar` at `(defBlock, defRank)` reaches the end of
|
||||
* block `block`.
|
||||
*/
|
||||
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock block) {
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
|
||||
(
|
||||
(
|
||||
// If we're looking at the def's own block, just see if it reaches the exit
|
||||
// rank of the block.
|
||||
block = defBlock and
|
||||
variableLiveOnExitFromBlock(vvar, defBlock) and
|
||||
definitionReachesRank(vvar, defBlock, defRank, exitRank(vvar, defBlock))
|
||||
) or
|
||||
exists(OldIR::IRBlock idom |
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, idom) and
|
||||
noDefinitionsSinceIDominator(vvar, idom, block)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock idom, OldIR::IRBlock block) {
|
||||
idom.immediatelyDominates(block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
|
||||
variableLiveOnExitFromBlock(vvar, block) and
|
||||
not hasDefinition(vvar, block, _)
|
||||
}
|
||||
|
||||
private predicate definitionReachesUseWithinBlock(
|
||||
Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank,
|
||||
OldIR::IRBlock useBlock, int useRank) {
|
||||
defBlock = useBlock and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, _) and
|
||||
definitionReachesRank(vvar, defBlock, defRank, useRank)
|
||||
}
|
||||
|
||||
private predicate definitionReachesUse(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock useBlock, int useRank) {
|
||||
hasUseAtRank(vvar, useBlock, useRank, _) and
|
||||
(
|
||||
definitionReachesUseWithinBlock(vvar, defBlock, defRank, useBlock,
|
||||
useRank) or
|
||||
(
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank,
|
||||
useBlock.getAPredecessor()) and
|
||||
not definitionReachesUseWithinBlock(vvar, useBlock, _, useBlock, useRank)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock phiBlock) {
|
||||
exists(OldIR::IRBlock defBlock |
|
||||
phiBlock = defBlock.dominanceFrontier() and
|
||||
hasDefinition(vvar, defBlock, _) and
|
||||
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
||||
variableLiveOnEntryToBlock(vvar, phiBlock)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasPhiNode(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock phiBlock) {
|
||||
hasFrontierPhiNode(vvar, phiBlock)
|
||||
//or ssa_sanitized_custom_phi_node(vvar, block)
|
||||
}
|
||||
}
|
||||
|
||||
import CachedForDebugging
|
||||
cached private module CachedForDebugging {
|
||||
cached string getTempVariableUniqueId(IRTempVariable var) {
|
||||
result = getOldTempVariable(var).getUniqueId()
|
||||
}
|
||||
|
||||
cached string getInstructionUniqueId(Instruction instr) {
|
||||
exists(OldIR::Instruction oldInstr |
|
||||
oldInstr = getOldInstruction(instr) and
|
||||
result = "NonSSA: " + oldInstr.getUniqueId()
|
||||
) or
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock |
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {
|
||||
result.getFunction() = var.getFunction() and
|
||||
result.getAST() = var.getAST() and
|
||||
result.getTag() = var.getTag()
|
||||
}
|
||||
}
|
||||
import SSAConstructionInternal
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.internal.Opcode
|
||||
import NewIR
|
||||
|
||||
import Cached
|
||||
cached private module Cached {
|
||||
|
||||
private OldIR::OperandTag getOldOperandTag(OperandTag newTag) {
|
||||
newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or
|
||||
newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or
|
||||
newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or
|
||||
newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or
|
||||
newTag instanceof RightOperand and result instanceof OldIR::RightOperand or
|
||||
newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or
|
||||
newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or
|
||||
newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or
|
||||
newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or
|
||||
newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or
|
||||
newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or
|
||||
exists(PositionalArgumentOperand newArg |
|
||||
newArg = newTag and
|
||||
result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex()
|
||||
)
|
||||
}
|
||||
|
||||
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
|
||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
}
|
||||
|
||||
cached newtype TInstructionTag =
|
||||
WrappedInstructionTag(OldIR::Instruction oldInstruction) or
|
||||
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
hasPhiNode(vvar, block)
|
||||
}
|
||||
|
||||
cached class InstructionTagType extends TInstructionTag {
|
||||
cached final string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
}
|
||||
|
||||
cached predicate functionHasIR(Function func) {
|
||||
exists(OldIR::FunctionIR funcIR |
|
||||
funcIR.getFunction() = func
|
||||
)
|
||||
}
|
||||
|
||||
cached int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(OldIR::PositionalArgumentOperand oldOperand |
|
||||
argIndex = oldOperand.getArgIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached OldIR::Instruction getOldInstruction(Instruction instr) {
|
||||
instr.getTag() = WrappedInstructionTag(result)
|
||||
}
|
||||
|
||||
private Instruction getNewInstruction(OldIR::Instruction instr) {
|
||||
getOldInstruction(result) = instr
|
||||
}
|
||||
|
||||
private PhiInstruction getPhiInstruction(Function func, OldIR::IRBlock oldBlock,
|
||||
Alias::VirtualVariable vvar) {
|
||||
result.getFunction() = func and
|
||||
result.getAST() = oldBlock.getFirstInstruction().getAST() and
|
||||
result.getTag() = PhiTag(vvar, oldBlock)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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(OldIR::Instruction 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(OldIR::IRBlock 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
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
||||
Type type) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
var.getFunction() = func and
|
||||
var.getAST() = ast and
|
||||
var.getTag() = tag and
|
||||
var.getType() = type
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
exists(Alias::getResultMemoryAccess(getOldInstruction(instruction))) or
|
||||
instruction instanceof PhiInstruction // Phis always have modeled results
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag |
|
||||
oldUse = getOldInstruction(instruction) and
|
||||
oldTag = getOldOperandTag(tag) and
|
||||
if oldUse.isMemoryOperand(oldTag) then (
|
||||
(
|
||||
if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then (
|
||||
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex |
|
||||
vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldUse) and
|
||||
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instruction.getFunction(), defBlock, vvar)
|
||||
)
|
||||
)
|
||||
else (
|
||||
result = instruction.getFunctionIR().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
) or
|
||||
// Connect any definitions that are not being modeled in SSA to the
|
||||
// `UnmodeledUse` instruction.
|
||||
exists(OldIR::Instruction oldDefinition |
|
||||
instruction instanceof UnmodeledUseInstruction and
|
||||
tag instanceof UnmodeledUseOperand and
|
||||
oldDefinition = oldUse.getOperand(oldTag) and
|
||||
not exists(Alias::getResultMemoryAccess(oldDefinition)) and
|
||||
result = getNewInstruction(oldDefinition)
|
||||
)
|
||||
)
|
||||
else
|
||||
result = getNewInstruction(oldUse.getOperand(oldTag))
|
||||
) or
|
||||
result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand))
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) {
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
|
||||
hasPhiNode(vvar, phiBlock) and
|
||||
predBlock = phiBlock.getAPredecessor() and
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
tag.getPredecessorBlock() = getNewBlock(predBlock) and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instr.getFunction(), defBlock, vvar)
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
exists(OldIR::IRBlock oldBlock |
|
||||
instr.getTag() = PhiTag(_, oldBlock) and
|
||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||
}
|
||||
|
||||
cached Field getInstructionField(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
|
||||
}
|
||||
|
||||
cached Function getInstructionFunction(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
cached string getInstructionConstantValue(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
|
||||
}
|
||||
|
||||
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
|
||||
}
|
||||
|
||||
cached Type getInstructionExceptionType(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
|
||||
}
|
||||
|
||||
cached int getInstructionElementSize(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
|
||||
}
|
||||
|
||||
cached int getInstructionResultSize(Instruction instruction) {
|
||||
// Only return a result for instructions that needed an explicit result size.
|
||||
instruction.getResultType() instanceof UnknownType and
|
||||
result = getOldInstruction(instruction).getResultSize()
|
||||
}
|
||||
|
||||
cached predicate getInstructionInheritance(Instruction instruction, Class baseClass,
|
||||
Class derivedClass) {
|
||||
exists(OldIR::InheritanceConversionInstruction oldInstr |
|
||||
oldInstr = getOldInstruction(instruction) and
|
||||
baseClass = oldInstr.getBaseClass() and
|
||||
derivedClass = oldInstr.getDerivedClass()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
|
||||
block.getInstruction(index) = instr and
|
||||
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
|
||||
}
|
||||
|
||||
private predicate hasDefinition(Alias::VirtualVariable vvar, OldIR::IRBlock block, int index) {
|
||||
(
|
||||
hasPhiNode(vvar, block) and
|
||||
index = -1
|
||||
) or
|
||||
exists(Alias::MemoryAccess access, OldIR::Instruction def |
|
||||
access = Alias::getResultMemoryAccess(def) and
|
||||
block.getInstruction(index) = def and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate defUseRank(Alias::VirtualVariable vvar, OldIR::IRBlock block, int rankIndex, int index) {
|
||||
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
|
||||
}
|
||||
|
||||
private predicate hasUse(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction use, OldIR::IRBlock block, int index) {
|
||||
exists(Alias::MemoryAccess access |
|
||||
access = Alias::getOperandMemoryAccess(use, _) and
|
||||
block.getInstruction(index) = use and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldIR::IRBlock 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, _))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
variableLiveOnEntryToBlock(vvar, block.getASuccessor())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank index of a hyphothetical use one instruction past the end of
|
||||
* the block. This index can be used to determine if a definition reaches the
|
||||
* end of the block, even if the definition is the last instruction in the
|
||||
* block.
|
||||
*/
|
||||
private int exitRank(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
result = max(int rankIndex | defUseRank(vvar, block, rankIndex, _)) + 1
|
||||
}
|
||||
|
||||
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock block, int rankIndex, int instructionIndex) {
|
||||
hasDefinition(vvar, block, instructionIndex) and
|
||||
defUseRank(vvar, block, rankIndex, instructionIndex)
|
||||
}
|
||||
|
||||
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldIR::IRBlock block,
|
||||
int rankIndex, OldIR::Instruction use) {
|
||||
exists(int index |
|
||||
hasUse(vvar, use, block, index) and
|
||||
defUseRank(vvar, block, rankIndex, index)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition of `vvar` at `(block, defRank)` reaches the rank
|
||||
* index `reachesRank` in block `block`.
|
||||
*/
|
||||
private predicate definitionReachesRank(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock block, int defRank, int reachesRank) {
|
||||
hasDefinitionAtRank(vvar, block, defRank, _) and
|
||||
reachesRank <= exitRank(vvar, block) and // Without this, the predicate would be infinite.
|
||||
(
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
reachesRank = defRank + 1 or
|
||||
(
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
definitionReachesRank(vvar, block, defRank, reachesRank - 1) and
|
||||
not hasDefinitionAtRank(vvar, block, reachesRank - 1, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition of `vvar` at `(defBlock, defRank)` reaches the end of
|
||||
* block `block`.
|
||||
*/
|
||||
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock block) {
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
|
||||
(
|
||||
(
|
||||
// If we're looking at the def's own block, just see if it reaches the exit
|
||||
// rank of the block.
|
||||
block = defBlock and
|
||||
variableLiveOnExitFromBlock(vvar, defBlock) and
|
||||
definitionReachesRank(vvar, defBlock, defRank, exitRank(vvar, defBlock))
|
||||
) or
|
||||
exists(OldIR::IRBlock idom |
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, idom) and
|
||||
noDefinitionsSinceIDominator(vvar, idom, block)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock idom, OldIR::IRBlock block) {
|
||||
idom.immediatelyDominates(block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
|
||||
variableLiveOnExitFromBlock(vvar, block) and
|
||||
not hasDefinition(vvar, block, _)
|
||||
}
|
||||
|
||||
private predicate definitionReachesUseWithinBlock(
|
||||
Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank,
|
||||
OldIR::IRBlock useBlock, int useRank) {
|
||||
defBlock = useBlock and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, _) and
|
||||
definitionReachesRank(vvar, defBlock, defRank, useRank)
|
||||
}
|
||||
|
||||
private predicate definitionReachesUse(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock useBlock, int useRank) {
|
||||
hasUseAtRank(vvar, useBlock, useRank, _) and
|
||||
(
|
||||
definitionReachesUseWithinBlock(vvar, defBlock, defRank, useBlock,
|
||||
useRank) or
|
||||
(
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank,
|
||||
useBlock.getAPredecessor()) and
|
||||
not definitionReachesUseWithinBlock(vvar, useBlock, _, useBlock, useRank)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock phiBlock) {
|
||||
exists(OldIR::IRBlock defBlock |
|
||||
phiBlock = defBlock.dominanceFrontier() and
|
||||
hasDefinition(vvar, defBlock, _) and
|
||||
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
||||
variableLiveOnEntryToBlock(vvar, phiBlock)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasPhiNode(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock phiBlock) {
|
||||
hasFrontierPhiNode(vvar, phiBlock)
|
||||
//or ssa_sanitized_custom_phi_node(vvar, block)
|
||||
}
|
||||
}
|
||||
|
||||
import CachedForDebugging
|
||||
cached private module CachedForDebugging {
|
||||
cached string getTempVariableUniqueId(IRTempVariable var) {
|
||||
result = getOldTempVariable(var).getUniqueId()
|
||||
}
|
||||
|
||||
cached string getInstructionUniqueId(Instruction instr) {
|
||||
exists(OldIR::Instruction oldInstr |
|
||||
oldInstr = getOldInstruction(instr) and
|
||||
result = "NonSSA: " + oldInstr.getUniqueId()
|
||||
) or
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock |
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {
|
||||
result.getFunction() = var.getFunction() and
|
||||
result.getAST() = var.getAST() and
|
||||
result.getTag() = var.getTag()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import semmle.code.cpp.ssa.SSAIR as OldIR
|
||||
import semmle.code.cpp.ssa.AliasedSSAIR as NewIR
|
||||
import SimpleSSA as Alias
|
||||
import semmle.code.cpp.ssa.SSAIR as OldIR
|
||||
import semmle.code.cpp.ssa.AliasedSSAIR as NewIR
|
||||
import SimpleSSA as Alias
|
||||
|
||||
@@ -1,83 +1,83 @@
|
||||
import SimpleSSAInternal
|
||||
import cpp
|
||||
import Alias
|
||||
import IR
|
||||
import semmle.code.cpp.ssa.internal.Overlap
|
||||
|
||||
private newtype TVirtualVariable =
|
||||
MkVirtualVariable(IRVariable var) {
|
||||
not variableAddressEscapes(var)
|
||||
}
|
||||
|
||||
private VirtualVariable getVirtualVariable(IRVariable var) {
|
||||
result.getIRVariable() = var
|
||||
}
|
||||
|
||||
class VirtualVariable extends TVirtualVariable {
|
||||
IRVariable var;
|
||||
|
||||
VirtualVariable() {
|
||||
this = MkVirtualVariable(var)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
final IRVariable getIRVariable() {
|
||||
result = var
|
||||
}
|
||||
|
||||
// REVIEW: This should just be on MemoryAccess
|
||||
final Type getType() {
|
||||
result = var.getType()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = var.getUniqueId()
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TMemoryAccess =
|
||||
MkMemoryAccess(VirtualVariable vvar)
|
||||
|
||||
private MemoryAccess getMemoryAccess(IRVariable var) {
|
||||
result.getVirtualVariable() = getVirtualVariable(var)
|
||||
}
|
||||
|
||||
class MemoryAccess extends TMemoryAccess {
|
||||
VirtualVariable vvar;
|
||||
|
||||
MemoryAccess() {
|
||||
this = MkMemoryAccess(vvar)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = vvar.toString()
|
||||
}
|
||||
|
||||
VirtualVariable getVirtualVariable() {
|
||||
result = vvar
|
||||
}
|
||||
}
|
||||
|
||||
Overlap getOverlap(MemoryAccess def, MemoryAccess use) {
|
||||
def.getVirtualVariable() = use.getVirtualVariable() and
|
||||
result instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
MemoryAccess getResultMemoryAccess(Instruction instr) {
|
||||
exists(IRVariable var |
|
||||
instr.getResultMemoryAccess() instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
MemoryAccess getOperandMemoryAccess(Instruction instr, OperandTag tag) {
|
||||
exists(IRVariable var |
|
||||
instr.getOperandMemoryAccess(tag) instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
import SimpleSSAInternal
|
||||
import cpp
|
||||
import Alias
|
||||
import IR
|
||||
import semmle.code.cpp.ssa.internal.Overlap
|
||||
|
||||
private newtype TVirtualVariable =
|
||||
MkVirtualVariable(IRVariable var) {
|
||||
not variableAddressEscapes(var)
|
||||
}
|
||||
|
||||
private VirtualVariable getVirtualVariable(IRVariable var) {
|
||||
result.getIRVariable() = var
|
||||
}
|
||||
|
||||
class VirtualVariable extends TVirtualVariable {
|
||||
IRVariable var;
|
||||
|
||||
VirtualVariable() {
|
||||
this = MkVirtualVariable(var)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
final IRVariable getIRVariable() {
|
||||
result = var
|
||||
}
|
||||
|
||||
// REVIEW: This should just be on MemoryAccess
|
||||
final Type getType() {
|
||||
result = var.getType()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = var.getUniqueId()
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TMemoryAccess =
|
||||
MkMemoryAccess(VirtualVariable vvar)
|
||||
|
||||
private MemoryAccess getMemoryAccess(IRVariable var) {
|
||||
result.getVirtualVariable() = getVirtualVariable(var)
|
||||
}
|
||||
|
||||
class MemoryAccess extends TMemoryAccess {
|
||||
VirtualVariable vvar;
|
||||
|
||||
MemoryAccess() {
|
||||
this = MkMemoryAccess(vvar)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = vvar.toString()
|
||||
}
|
||||
|
||||
VirtualVariable getVirtualVariable() {
|
||||
result = vvar
|
||||
}
|
||||
}
|
||||
|
||||
Overlap getOverlap(MemoryAccess def, MemoryAccess use) {
|
||||
def.getVirtualVariable() = use.getVirtualVariable() and
|
||||
result instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
MemoryAccess getResultMemoryAccess(Instruction instr) {
|
||||
exists(IRVariable var |
|
||||
instr.getResultMemoryAccess() instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
MemoryAccess getOperandMemoryAccess(Instruction instr, OperandTag tag) {
|
||||
exists(IRVariable var |
|
||||
instr.getOperandMemoryAccess(tag) instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import AliasAnalysis as Alias
|
||||
import semmle.code.cpp.ssa.SSAIR as IR
|
||||
|
||||
import AliasAnalysis as Alias
|
||||
import semmle.code.cpp.ssa.SSAIR as IR
|
||||
|
||||
|
||||
@@ -1,214 +1,214 @@
|
||||
private import AliasAnalysisInternal
|
||||
import cpp
|
||||
private import IR
|
||||
private import semmle.code.cpp.ssa.internal.IntegerConstant as Ints
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
/**
|
||||
* Converts the bit count in `bits` to a byte count and a bit count in the form
|
||||
* bytes:bits.
|
||||
*/
|
||||
bindingset[bits]
|
||||
string bitsToBytesAndBits(int bits) {
|
||||
result = (bits / 8).toString() + ":" + (bits % 8).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a printable string for a bit offset with possibly unknown value.
|
||||
*/
|
||||
bindingset[bitOffset]
|
||||
string getBitOffsetString(IntValue bitOffset) {
|
||||
if Ints::hasValue(bitOffset) then
|
||||
if bitOffset >= 0 then
|
||||
result = "+" + bitsToBytesAndBits(bitOffset)
|
||||
else
|
||||
result = "-" + bitsToBytesAndBits(Ints::neg(bitOffset))
|
||||
else
|
||||
result = "+?"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of field `field` in bits.
|
||||
*/
|
||||
private IntValue getFieldBitOffset(Field field) {
|
||||
if (field instanceof BitField) then (
|
||||
result = Ints::add(Ints::mul(field.getByteOffset(), 8),
|
||||
field.(BitField).getBitOffset())
|
||||
)
|
||||
else (
|
||||
result = Ints::mul(field.getByteOffset(), 8)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand `tag` of instruction `instr` is used in a way that does
|
||||
* not result in any address held in that operand from escaping beyond the
|
||||
* instruction.
|
||||
*/
|
||||
predicate operandIsConsumedWithoutEscaping(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// The source/destination address of a Load/Store does not escape (but the
|
||||
// loaded/stored value could).
|
||||
tag instanceof LoadStoreAddressOperand or
|
||||
// Neither operand of a Compare escapes.
|
||||
instr instanceof CompareInstruction or
|
||||
// Neither operand of a PointerDiff escapes.
|
||||
instr instanceof PointerDiffInstruction or
|
||||
// Converting an address to a `bool` does not escape the address.
|
||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* If the result of instruction `instr` is an integer constant, returns the
|
||||
* value of that constant. Otherwise, returns unknown.
|
||||
*/
|
||||
IntValue getConstantValue(Instruction instr) {
|
||||
if instr instanceof IntegerConstantInstruction then
|
||||
result = instr.(IntegerConstantInstruction).getValue().toInt()
|
||||
else
|
||||
result = Ints::unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the offset, in bits, by which the result of `instr` differs from the
|
||||
* pointer argument to `instr`, if that offset is a constant. Otherwise, returns
|
||||
* unknown.
|
||||
*/
|
||||
IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
||||
exists(IntValue bitOffset |
|
||||
(
|
||||
bitOffset = Ints::mul(Ints::mul(getConstantValue(instr.getRightOperand()),
|
||||
instr.getElementSize()), 8)
|
||||
) and
|
||||
(
|
||||
instr instanceof PointerAddInstruction and result = bitOffset or
|
||||
instr instanceof PointerSubInstruction and result = Ints::neg(bitOffset)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand `tag` of instruction `instr` is
|
||||
* propagated to the result of `instr`, offset by the number of bits in
|
||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||
* a constant, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate operandIsPropagated(Instruction instr, OperandTag tag,
|
||||
IntValue bitOffset) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
) or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
) or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
(
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
) or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, Type resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultType() and
|
||||
(
|
||||
resultType instanceof PointerType or
|
||||
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
|
||||
) and
|
||||
bitOffset = 0
|
||||
) or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||
// A copy propagates the source value.
|
||||
tag instanceof CopySourceOperand and bitOffset = 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand number `tag` of instruction `instr`
|
||||
* escapes outside the domain of the analysis.
|
||||
*/
|
||||
predicate operandEscapes(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
// Conservatively assume that the address escapes unless one of the following
|
||||
// holds:
|
||||
not (
|
||||
// The operand is used in a way that does not escape the instruction
|
||||
operandIsConsumedWithoutEscaping(instr, tag) or
|
||||
// The address is propagated to the result of the instruction, but that
|
||||
// result does not itself escape.
|
||||
operandIsPropagated(instr, tag, _) and not resultEscapes(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in the result of instruction `instr` escapes
|
||||
* outside the domain of the analysis.
|
||||
*/
|
||||
predicate resultEscapes(Instruction instr) {
|
||||
// The result escapes if it has at least one use that escapes.
|
||||
exists(Instruction useInstr, OperandTag useOperandTag |
|
||||
useInstr.getOperand(useOperandTag) = instr and
|
||||
operandEscapes(useInstr, useOperandTag)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of the specified local variable or parameter escapes the
|
||||
* domain of the analysis.
|
||||
*/
|
||||
private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = var.getFunctionIR() and
|
||||
// The variable's address escapes if the result of any
|
||||
// VariableAddressInstruction that computes the variable's address escapes.
|
||||
exists(VariableAddressInstruction instr |
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var and
|
||||
resultEscapes(instr)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of the specified variable escapes the domain of the
|
||||
* analysis.
|
||||
*/
|
||||
predicate variableAddressEscapes(IRVariable var) {
|
||||
automaticVariableAddressEscapes(var.(IRAutomaticVariable)) or
|
||||
// All variables with static storage duration have their address escape.
|
||||
not var instanceof IRAutomaticVariable
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the result of instruction `instr` points within variable `var`, at
|
||||
* bit offset `bitOffset` within the variable. If the result points within
|
||||
* `var`, but at an unknown or non-constant offset, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) {
|
||||
(
|
||||
// The address of a variable points to that variable, at offset 0.
|
||||
instr.(VariableAddressInstruction).getVariable() = var and
|
||||
bitOffset = 0
|
||||
) or
|
||||
exists(OperandTag operandTag, IntValue originalBitOffset,
|
||||
IntValue propagatedBitOffset |
|
||||
// If an operand is propagated, then the result points to the same variable,
|
||||
// offset by the bit offset from the propagation.
|
||||
resultPointsTo(instr.getOperand(operandTag), var, originalBitOffset) and
|
||||
operandIsPropagated(instr, operandTag, propagatedBitOffset) and
|
||||
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
||||
)
|
||||
}
|
||||
private import AliasAnalysisInternal
|
||||
import cpp
|
||||
private import IR
|
||||
private import semmle.code.cpp.ssa.internal.IntegerConstant as Ints
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
/**
|
||||
* Converts the bit count in `bits` to a byte count and a bit count in the form
|
||||
* bytes:bits.
|
||||
*/
|
||||
bindingset[bits]
|
||||
string bitsToBytesAndBits(int bits) {
|
||||
result = (bits / 8).toString() + ":" + (bits % 8).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a printable string for a bit offset with possibly unknown value.
|
||||
*/
|
||||
bindingset[bitOffset]
|
||||
string getBitOffsetString(IntValue bitOffset) {
|
||||
if Ints::hasValue(bitOffset) then
|
||||
if bitOffset >= 0 then
|
||||
result = "+" + bitsToBytesAndBits(bitOffset)
|
||||
else
|
||||
result = "-" + bitsToBytesAndBits(Ints::neg(bitOffset))
|
||||
else
|
||||
result = "+?"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of field `field` in bits.
|
||||
*/
|
||||
private IntValue getFieldBitOffset(Field field) {
|
||||
if (field instanceof BitField) then (
|
||||
result = Ints::add(Ints::mul(field.getByteOffset(), 8),
|
||||
field.(BitField).getBitOffset())
|
||||
)
|
||||
else (
|
||||
result = Ints::mul(field.getByteOffset(), 8)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand `tag` of instruction `instr` is used in a way that does
|
||||
* not result in any address held in that operand from escaping beyond the
|
||||
* instruction.
|
||||
*/
|
||||
predicate operandIsConsumedWithoutEscaping(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// The source/destination address of a Load/Store does not escape (but the
|
||||
// loaded/stored value could).
|
||||
tag instanceof LoadStoreAddressOperand or
|
||||
// Neither operand of a Compare escapes.
|
||||
instr instanceof CompareInstruction or
|
||||
// Neither operand of a PointerDiff escapes.
|
||||
instr instanceof PointerDiffInstruction or
|
||||
// Converting an address to a `bool` does not escape the address.
|
||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* If the result of instruction `instr` is an integer constant, returns the
|
||||
* value of that constant. Otherwise, returns unknown.
|
||||
*/
|
||||
IntValue getConstantValue(Instruction instr) {
|
||||
if instr instanceof IntegerConstantInstruction then
|
||||
result = instr.(IntegerConstantInstruction).getValue().toInt()
|
||||
else
|
||||
result = Ints::unknown()
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the offset, in bits, by which the result of `instr` differs from the
|
||||
* pointer argument to `instr`, if that offset is a constant. Otherwise, returns
|
||||
* unknown.
|
||||
*/
|
||||
IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
||||
exists(IntValue bitOffset |
|
||||
(
|
||||
bitOffset = Ints::mul(Ints::mul(getConstantValue(instr.getRightOperand()),
|
||||
instr.getElementSize()), 8)
|
||||
) and
|
||||
(
|
||||
instr instanceof PointerAddInstruction and result = bitOffset or
|
||||
instr instanceof PointerSubInstruction and result = Ints::neg(bitOffset)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand `tag` of instruction `instr` is
|
||||
* propagated to the result of `instr`, offset by the number of bits in
|
||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||
* a constant, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate operandIsPropagated(Instruction instr, OperandTag tag,
|
||||
IntValue bitOffset) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
) or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
) or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
(
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
) or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, Type resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultType() and
|
||||
(
|
||||
resultType instanceof PointerType or
|
||||
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
|
||||
) and
|
||||
bitOffset = 0
|
||||
) or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||
// A copy propagates the source value.
|
||||
tag instanceof CopySourceOperand and bitOffset = 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand number `tag` of instruction `instr`
|
||||
* escapes outside the domain of the analysis.
|
||||
*/
|
||||
predicate operandEscapes(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
// Conservatively assume that the address escapes unless one of the following
|
||||
// holds:
|
||||
not (
|
||||
// The operand is used in a way that does not escape the instruction
|
||||
operandIsConsumedWithoutEscaping(instr, tag) or
|
||||
// The address is propagated to the result of the instruction, but that
|
||||
// result does not itself escape.
|
||||
operandIsPropagated(instr, tag, _) and not resultEscapes(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in the result of instruction `instr` escapes
|
||||
* outside the domain of the analysis.
|
||||
*/
|
||||
predicate resultEscapes(Instruction instr) {
|
||||
// The result escapes if it has at least one use that escapes.
|
||||
exists(Instruction useInstr, OperandTag useOperandTag |
|
||||
useInstr.getOperand(useOperandTag) = instr and
|
||||
operandEscapes(useInstr, useOperandTag)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of the specified local variable or parameter escapes the
|
||||
* domain of the analysis.
|
||||
*/
|
||||
private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = var.getFunctionIR() and
|
||||
// The variable's address escapes if the result of any
|
||||
// VariableAddressInstruction that computes the variable's address escapes.
|
||||
exists(VariableAddressInstruction instr |
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var and
|
||||
resultEscapes(instr)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of the specified variable escapes the domain of the
|
||||
* analysis.
|
||||
*/
|
||||
predicate variableAddressEscapes(IRVariable var) {
|
||||
automaticVariableAddressEscapes(var.(IRAutomaticVariable)) or
|
||||
// All variables with static storage duration have their address escape.
|
||||
not var instanceof IRAutomaticVariable
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the result of instruction `instr` points within variable `var`, at
|
||||
* bit offset `bitOffset` within the variable. If the result points within
|
||||
* `var`, but at an unknown or non-constant offset, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) {
|
||||
(
|
||||
// The address of a variable points to that variable, at offset 0.
|
||||
instr.(VariableAddressInstruction).getVariable() = var and
|
||||
bitOffset = 0
|
||||
) or
|
||||
exists(OperandTag operandTag, IntValue originalBitOffset,
|
||||
IntValue propagatedBitOffset |
|
||||
// If an operand is propagated, then the result points to the same variable,
|
||||
// offset by the bit offset from the propagation.
|
||||
resultPointsTo(instr.getOperand(operandTag), var, originalBitOffset) and
|
||||
operandIsPropagated(instr, operandTag, propagatedBitOffset) and
|
||||
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import cpp
|
||||
|
||||
private newtype TFunctionIR =
|
||||
MkFunctionIR(Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
*/
|
||||
class FunctionIR extends TFunctionIR {
|
||||
Function func;
|
||||
|
||||
FunctionIR() {
|
||||
this = MkFunctionIR(func)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final EnterFunctionInstruction getEnterFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exit point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ExitFunctionInstruction getExitFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ReturnInstruction getReturnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable used to hold the return value of this function. If this
|
||||
* function does not return a value, this predicate does not hold.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRReturnVariable getReturnVariable() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block containing the entry point of this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock getEntryBlock() {
|
||||
result.getFirstInstruction() = getEnterFunctionInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instructions in this function.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
}
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import cpp
|
||||
|
||||
private newtype TFunctionIR =
|
||||
MkFunctionIR(Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
*/
|
||||
class FunctionIR extends TFunctionIR {
|
||||
Function func;
|
||||
|
||||
FunctionIR() {
|
||||
this = MkFunctionIR(func)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entry point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final EnterFunctionInstruction getEnterFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exit point for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ExitFunctionInstruction getExitFunctionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single return instruction for this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final ReturnInstruction getReturnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable used to hold the return value of this function. If this
|
||||
* function does not return a value, this predicate does not hold.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRReturnVariable getReturnVariable() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block containing the entry point of this function.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock getEntryBlock() {
|
||||
result.getFirstInstruction() = getEnterFunctionInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instructions in this function.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all blocks in this function.
|
||||
*/
|
||||
final IRBlock getABlock() {
|
||||
result.getFunctionIR() = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
import SSAConstruction as Construction
|
||||
import SSAConstruction as Construction
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
private import IRImpl
|
||||
import InstructionSanity
|
||||
|
||||
private import IRImpl
|
||||
import InstructionSanity
|
||||
|
||||
|
||||
@@ -1,202 +1,202 @@
|
||||
private import IRInternal
|
||||
import FunctionIR
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.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)
|
||||
}
|
||||
|
||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
result.getVariable() = var and
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
FunctionIR funcIR;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Type getType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Locatable getAST();
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
abstract class IRUserVariable extends IRVariable {
|
||||
Variable var;
|
||||
|
||||
override final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = var.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = var
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = var.toString() + " " + var.getLocation().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
final Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
TIRAutomaticUserVariable {
|
||||
LocalScopeVariable localVar;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
||||
var = localVar
|
||||
}
|
||||
|
||||
final LocalScopeVariable getLocalVariable() {
|
||||
result = localVar
|
||||
}
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, funcIR)
|
||||
}
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
|
||||
result.getAST() = ast and
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Locatable ast;
|
||||
TempVariableTag tag;
|
||||
Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = type
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = ast
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = "Temp: " + Construction::getTempVariableUniqueId(this)
|
||||
}
|
||||
|
||||
final TempVariableTag getTag() {
|
||||
result = tag
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
}
|
||||
|
||||
string getBaseString() {
|
||||
result = "#temp"
|
||||
}
|
||||
}
|
||||
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() {
|
||||
tag = ReturnValueTempVar()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "#return"
|
||||
}
|
||||
}
|
||||
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() {
|
||||
tag = ThrowTempVar()
|
||||
}
|
||||
|
||||
override string getBaseString() {
|
||||
result = "#throw"
|
||||
}
|
||||
}
|
||||
private import IRInternal
|
||||
import FunctionIR
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.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)
|
||||
}
|
||||
|
||||
IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
result.getVariable() = var and
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable referenced by the IR for a function. The variable may
|
||||
* be a user-declared variable (`IRUserVariable`) or a temporary variable
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
FunctionIR funcIR;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Type getType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Locatable getAST();
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Function getFunction() {
|
||||
result = funcIR.getFunction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
abstract class IRUserVariable extends IRVariable {
|
||||
Variable var;
|
||||
|
||||
override final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = var.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = var
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = var.toString() + " " + var.getLocation().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
final Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a variable (user-declared or temporary) that is allocated on the
|
||||
* stack. This includes all parameters, non-static local variables, and
|
||||
* temporary variables.
|
||||
*/
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
TIRAutomaticUserVariable {
|
||||
LocalScopeVariable localVar;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, funcIR) and
|
||||
var = localVar
|
||||
}
|
||||
|
||||
final LocalScopeVariable getLocalVariable() {
|
||||
result = localVar
|
||||
}
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, funcIR)
|
||||
}
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
|
||||
result.getAST() = ast and
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Locatable ast;
|
||||
TempVariableTag tag;
|
||||
Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(funcIR, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = type
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
result = ast
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = "Temp: " + Construction::getTempVariableUniqueId(this)
|
||||
}
|
||||
|
||||
final TempVariableTag getTag() {
|
||||
result = tag
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
|
||||
ast.getLocation().getStartColumn().toString()
|
||||
}
|
||||
|
||||
string getBaseString() {
|
||||
result = "#temp"
|
||||
}
|
||||
}
|
||||
|
||||
class IRReturnVariable extends IRTempVariable {
|
||||
IRReturnVariable() {
|
||||
tag = ReturnValueTempVar()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "#return"
|
||||
}
|
||||
}
|
||||
|
||||
class IRThrowVariable extends IRTempVariable {
|
||||
IRThrowVariable() {
|
||||
tag = ThrowTempVar()
|
||||
}
|
||||
|
||||
override string getBaseString() {
|
||||
result = "#throw"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,424 +1,424 @@
|
||||
import SSAConstructionInternal
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.internal.Opcode
|
||||
import NewIR
|
||||
|
||||
import Cached
|
||||
cached private module Cached {
|
||||
|
||||
private OldIR::OperandTag getOldOperandTag(OperandTag newTag) {
|
||||
newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or
|
||||
newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or
|
||||
newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or
|
||||
newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or
|
||||
newTag instanceof RightOperand and result instanceof OldIR::RightOperand or
|
||||
newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or
|
||||
newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or
|
||||
newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or
|
||||
newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or
|
||||
newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or
|
||||
newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or
|
||||
exists(PositionalArgumentOperand newArg |
|
||||
newArg = newTag and
|
||||
result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex()
|
||||
)
|
||||
}
|
||||
|
||||
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
|
||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
}
|
||||
|
||||
cached newtype TInstructionTag =
|
||||
WrappedInstructionTag(OldIR::Instruction oldInstruction) or
|
||||
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
hasPhiNode(vvar, block)
|
||||
}
|
||||
|
||||
cached class InstructionTagType extends TInstructionTag {
|
||||
cached final string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
}
|
||||
|
||||
cached predicate functionHasIR(Function func) {
|
||||
exists(OldIR::FunctionIR funcIR |
|
||||
funcIR.getFunction() = func
|
||||
)
|
||||
}
|
||||
|
||||
cached int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(OldIR::PositionalArgumentOperand oldOperand |
|
||||
argIndex = oldOperand.getArgIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached OldIR::Instruction getOldInstruction(Instruction instr) {
|
||||
instr.getTag() = WrappedInstructionTag(result)
|
||||
}
|
||||
|
||||
private Instruction getNewInstruction(OldIR::Instruction instr) {
|
||||
getOldInstruction(result) = instr
|
||||
}
|
||||
|
||||
private PhiInstruction getPhiInstruction(Function func, OldIR::IRBlock oldBlock,
|
||||
Alias::VirtualVariable vvar) {
|
||||
result.getFunction() = func and
|
||||
result.getAST() = oldBlock.getFirstInstruction().getAST() and
|
||||
result.getTag() = PhiTag(vvar, oldBlock)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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(OldIR::Instruction 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(OldIR::IRBlock 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
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
||||
Type type) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
var.getFunction() = func and
|
||||
var.getAST() = ast and
|
||||
var.getTag() = tag and
|
||||
var.getType() = type
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
exists(Alias::getResultMemoryAccess(getOldInstruction(instruction))) or
|
||||
instruction instanceof PhiInstruction // Phis always have modeled results
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag |
|
||||
oldUse = getOldInstruction(instruction) and
|
||||
oldTag = getOldOperandTag(tag) and
|
||||
if oldUse.isMemoryOperand(oldTag) then (
|
||||
(
|
||||
if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then (
|
||||
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex |
|
||||
vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldUse) and
|
||||
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instruction.getFunction(), defBlock, vvar)
|
||||
)
|
||||
)
|
||||
else (
|
||||
result = instruction.getFunctionIR().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
) or
|
||||
// Connect any definitions that are not being modeled in SSA to the
|
||||
// `UnmodeledUse` instruction.
|
||||
exists(OldIR::Instruction oldDefinition |
|
||||
instruction instanceof UnmodeledUseInstruction and
|
||||
tag instanceof UnmodeledUseOperand and
|
||||
oldDefinition = oldUse.getOperand(oldTag) and
|
||||
not exists(Alias::getResultMemoryAccess(oldDefinition)) and
|
||||
result = getNewInstruction(oldDefinition)
|
||||
)
|
||||
)
|
||||
else
|
||||
result = getNewInstruction(oldUse.getOperand(oldTag))
|
||||
) or
|
||||
result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand))
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) {
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
|
||||
hasPhiNode(vvar, phiBlock) and
|
||||
predBlock = phiBlock.getAPredecessor() and
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
tag.getPredecessorBlock() = getNewBlock(predBlock) and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instr.getFunction(), defBlock, vvar)
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
exists(OldIR::IRBlock oldBlock |
|
||||
instr.getTag() = PhiTag(_, oldBlock) and
|
||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||
}
|
||||
|
||||
cached Field getInstructionField(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
|
||||
}
|
||||
|
||||
cached Function getInstructionFunction(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
cached string getInstructionConstantValue(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
|
||||
}
|
||||
|
||||
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
|
||||
}
|
||||
|
||||
cached Type getInstructionExceptionType(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
|
||||
}
|
||||
|
||||
cached int getInstructionElementSize(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
|
||||
}
|
||||
|
||||
cached int getInstructionResultSize(Instruction instruction) {
|
||||
// Only return a result for instructions that needed an explicit result size.
|
||||
instruction.getResultType() instanceof UnknownType and
|
||||
result = getOldInstruction(instruction).getResultSize()
|
||||
}
|
||||
|
||||
cached predicate getInstructionInheritance(Instruction instruction, Class baseClass,
|
||||
Class derivedClass) {
|
||||
exists(OldIR::InheritanceConversionInstruction oldInstr |
|
||||
oldInstr = getOldInstruction(instruction) and
|
||||
baseClass = oldInstr.getBaseClass() and
|
||||
derivedClass = oldInstr.getDerivedClass()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
|
||||
block.getInstruction(index) = instr and
|
||||
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
|
||||
}
|
||||
|
||||
private predicate hasDefinition(Alias::VirtualVariable vvar, OldIR::IRBlock block, int index) {
|
||||
(
|
||||
hasPhiNode(vvar, block) and
|
||||
index = -1
|
||||
) or
|
||||
exists(Alias::MemoryAccess access, OldIR::Instruction def |
|
||||
access = Alias::getResultMemoryAccess(def) and
|
||||
block.getInstruction(index) = def and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate defUseRank(Alias::VirtualVariable vvar, OldIR::IRBlock block, int rankIndex, int index) {
|
||||
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
|
||||
}
|
||||
|
||||
private predicate hasUse(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction use, OldIR::IRBlock block, int index) {
|
||||
exists(Alias::MemoryAccess access |
|
||||
access = Alias::getOperandMemoryAccess(use, _) and
|
||||
block.getInstruction(index) = use and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldIR::IRBlock 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, _))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
variableLiveOnEntryToBlock(vvar, block.getASuccessor())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank index of a hyphothetical use one instruction past the end of
|
||||
* the block. This index can be used to determine if a definition reaches the
|
||||
* end of the block, even if the definition is the last instruction in the
|
||||
* block.
|
||||
*/
|
||||
private int exitRank(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
result = max(int rankIndex | defUseRank(vvar, block, rankIndex, _)) + 1
|
||||
}
|
||||
|
||||
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock block, int rankIndex, int instructionIndex) {
|
||||
hasDefinition(vvar, block, instructionIndex) and
|
||||
defUseRank(vvar, block, rankIndex, instructionIndex)
|
||||
}
|
||||
|
||||
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldIR::IRBlock block,
|
||||
int rankIndex, OldIR::Instruction use) {
|
||||
exists(int index |
|
||||
hasUse(vvar, use, block, index) and
|
||||
defUseRank(vvar, block, rankIndex, index)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition of `vvar` at `(block, defRank)` reaches the rank
|
||||
* index `reachesRank` in block `block`.
|
||||
*/
|
||||
private predicate definitionReachesRank(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock block, int defRank, int reachesRank) {
|
||||
hasDefinitionAtRank(vvar, block, defRank, _) and
|
||||
reachesRank <= exitRank(vvar, block) and // Without this, the predicate would be infinite.
|
||||
(
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
reachesRank = defRank + 1 or
|
||||
(
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
definitionReachesRank(vvar, block, defRank, reachesRank - 1) and
|
||||
not hasDefinitionAtRank(vvar, block, reachesRank - 1, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition of `vvar` at `(defBlock, defRank)` reaches the end of
|
||||
* block `block`.
|
||||
*/
|
||||
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock block) {
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
|
||||
(
|
||||
(
|
||||
// If we're looking at the def's own block, just see if it reaches the exit
|
||||
// rank of the block.
|
||||
block = defBlock and
|
||||
variableLiveOnExitFromBlock(vvar, defBlock) and
|
||||
definitionReachesRank(vvar, defBlock, defRank, exitRank(vvar, defBlock))
|
||||
) or
|
||||
exists(OldIR::IRBlock idom |
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, idom) and
|
||||
noDefinitionsSinceIDominator(vvar, idom, block)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock idom, OldIR::IRBlock block) {
|
||||
idom.immediatelyDominates(block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
|
||||
variableLiveOnExitFromBlock(vvar, block) and
|
||||
not hasDefinition(vvar, block, _)
|
||||
}
|
||||
|
||||
private predicate definitionReachesUseWithinBlock(
|
||||
Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank,
|
||||
OldIR::IRBlock useBlock, int useRank) {
|
||||
defBlock = useBlock and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, _) and
|
||||
definitionReachesRank(vvar, defBlock, defRank, useRank)
|
||||
}
|
||||
|
||||
private predicate definitionReachesUse(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock useBlock, int useRank) {
|
||||
hasUseAtRank(vvar, useBlock, useRank, _) and
|
||||
(
|
||||
definitionReachesUseWithinBlock(vvar, defBlock, defRank, useBlock,
|
||||
useRank) or
|
||||
(
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank,
|
||||
useBlock.getAPredecessor()) and
|
||||
not definitionReachesUseWithinBlock(vvar, useBlock, _, useBlock, useRank)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock phiBlock) {
|
||||
exists(OldIR::IRBlock defBlock |
|
||||
phiBlock = defBlock.dominanceFrontier() and
|
||||
hasDefinition(vvar, defBlock, _) and
|
||||
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
||||
variableLiveOnEntryToBlock(vvar, phiBlock)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasPhiNode(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock phiBlock) {
|
||||
hasFrontierPhiNode(vvar, phiBlock)
|
||||
//or ssa_sanitized_custom_phi_node(vvar, block)
|
||||
}
|
||||
}
|
||||
|
||||
import CachedForDebugging
|
||||
cached private module CachedForDebugging {
|
||||
cached string getTempVariableUniqueId(IRTempVariable var) {
|
||||
result = getOldTempVariable(var).getUniqueId()
|
||||
}
|
||||
|
||||
cached string getInstructionUniqueId(Instruction instr) {
|
||||
exists(OldIR::Instruction oldInstr |
|
||||
oldInstr = getOldInstruction(instr) and
|
||||
result = "NonSSA: " + oldInstr.getUniqueId()
|
||||
) or
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock |
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {
|
||||
result.getFunction() = var.getFunction() and
|
||||
result.getAST() = var.getAST() and
|
||||
result.getTag() = var.getTag()
|
||||
}
|
||||
}
|
||||
import SSAConstructionInternal
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.internal.Opcode
|
||||
import NewIR
|
||||
|
||||
import Cached
|
||||
cached private module Cached {
|
||||
|
||||
private OldIR::OperandTag getOldOperandTag(OperandTag newTag) {
|
||||
newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or
|
||||
newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or
|
||||
newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or
|
||||
newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or
|
||||
newTag instanceof RightOperand and result instanceof OldIR::RightOperand or
|
||||
newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or
|
||||
newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or
|
||||
newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or
|
||||
newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or
|
||||
newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or
|
||||
newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or
|
||||
exists(PositionalArgumentOperand newArg |
|
||||
newArg = newTag and
|
||||
result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex()
|
||||
)
|
||||
}
|
||||
|
||||
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
|
||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
}
|
||||
|
||||
cached newtype TInstructionTag =
|
||||
WrappedInstructionTag(OldIR::Instruction oldInstruction) or
|
||||
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
hasPhiNode(vvar, block)
|
||||
}
|
||||
|
||||
cached class InstructionTagType extends TInstructionTag {
|
||||
cached final string toString() {
|
||||
result = "Tag"
|
||||
}
|
||||
}
|
||||
|
||||
cached predicate functionHasIR(Function func) {
|
||||
exists(OldIR::FunctionIR funcIR |
|
||||
funcIR.getFunction() = func
|
||||
)
|
||||
}
|
||||
|
||||
cached int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(OldIR::PositionalArgumentOperand oldOperand |
|
||||
argIndex = oldOperand.getArgIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached OldIR::Instruction getOldInstruction(Instruction instr) {
|
||||
instr.getTag() = WrappedInstructionTag(result)
|
||||
}
|
||||
|
||||
private Instruction getNewInstruction(OldIR::Instruction instr) {
|
||||
getOldInstruction(result) = instr
|
||||
}
|
||||
|
||||
private PhiInstruction getPhiInstruction(Function func, OldIR::IRBlock oldBlock,
|
||||
Alias::VirtualVariable vvar) {
|
||||
result.getFunction() = func and
|
||||
result.getAST() = oldBlock.getFirstInstruction().getAST() and
|
||||
result.getTag() = PhiTag(vvar, oldBlock)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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(OldIR::Instruction 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(OldIR::IRBlock 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
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag,
|
||||
Type type) {
|
||||
exists(OldIR::IRTempVariable var |
|
||||
var.getFunction() = func and
|
||||
var.getAST() = ast and
|
||||
var.getTag() = tag and
|
||||
var.getType() = type
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
exists(Alias::getResultMemoryAccess(getOldInstruction(instruction))) or
|
||||
instruction instanceof PhiInstruction // Phis always have modeled results
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag |
|
||||
oldUse = getOldInstruction(instruction) and
|
||||
oldTag = getOldOperandTag(tag) and
|
||||
if oldUse.isMemoryOperand(oldTag) then (
|
||||
(
|
||||
if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then (
|
||||
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex |
|
||||
vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldUse) and
|
||||
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instruction.getFunction(), defBlock, vvar)
|
||||
)
|
||||
)
|
||||
else (
|
||||
result = instruction.getFunctionIR().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
) or
|
||||
// Connect any definitions that are not being modeled in SSA to the
|
||||
// `UnmodeledUse` instruction.
|
||||
exists(OldIR::Instruction oldDefinition |
|
||||
instruction instanceof UnmodeledUseInstruction and
|
||||
tag instanceof UnmodeledUseOperand and
|
||||
oldDefinition = oldUse.getOperand(oldTag) and
|
||||
not exists(Alias::getResultMemoryAccess(oldDefinition)) and
|
||||
result = getNewInstruction(oldDefinition)
|
||||
)
|
||||
)
|
||||
else
|
||||
result = getNewInstruction(oldUse.getOperand(oldTag))
|
||||
) or
|
||||
result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand))
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) {
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
|
||||
hasPhiNode(vvar, phiBlock) and
|
||||
predBlock = phiBlock.getAPredecessor() and
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
tag.getPredecessorBlock() = getNewBlock(predBlock) and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
else
|
||||
result = getPhiInstruction(instr.getFunction(), defBlock, vvar)
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
exists(OldIR::IRBlock oldBlock |
|
||||
instr.getTag() = PhiTag(_, oldBlock) and
|
||||
result = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
|
||||
}
|
||||
|
||||
cached IRVariable getInstructionVariable(Instruction instruction) {
|
||||
result = getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getVariable())
|
||||
}
|
||||
|
||||
cached Field getInstructionField(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
|
||||
}
|
||||
|
||||
cached Function getInstructionFunction(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
cached string getInstructionConstantValue(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
|
||||
}
|
||||
|
||||
cached StringLiteral getInstructionStringLiteral(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
|
||||
}
|
||||
|
||||
cached Type getInstructionExceptionType(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
|
||||
}
|
||||
|
||||
cached int getInstructionElementSize(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize()
|
||||
}
|
||||
|
||||
cached int getInstructionResultSize(Instruction instruction) {
|
||||
// Only return a result for instructions that needed an explicit result size.
|
||||
instruction.getResultType() instanceof UnknownType and
|
||||
result = getOldInstruction(instruction).getResultSize()
|
||||
}
|
||||
|
||||
cached predicate getInstructionInheritance(Instruction instruction, Class baseClass,
|
||||
Class derivedClass) {
|
||||
exists(OldIR::InheritanceConversionInstruction oldInstr |
|
||||
oldInstr = getOldInstruction(instruction) and
|
||||
baseClass = oldInstr.getBaseClass() and
|
||||
derivedClass = oldInstr.getDerivedClass()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
|
||||
block.getInstruction(index) = instr and
|
||||
Alias::getResultMemoryAccess(instr).getVirtualVariable() = vvar
|
||||
}
|
||||
|
||||
private predicate hasDefinition(Alias::VirtualVariable vvar, OldIR::IRBlock block, int index) {
|
||||
(
|
||||
hasPhiNode(vvar, block) and
|
||||
index = -1
|
||||
) or
|
||||
exists(Alias::MemoryAccess access, OldIR::Instruction def |
|
||||
access = Alias::getResultMemoryAccess(def) and
|
||||
block.getInstruction(index) = def and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate defUseRank(Alias::VirtualVariable vvar, OldIR::IRBlock block, int rankIndex, int index) {
|
||||
index = rank[rankIndex](int j | hasDefinition(vvar, block, j) or hasUse(vvar, _, block, j))
|
||||
}
|
||||
|
||||
private predicate hasUse(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction use, OldIR::IRBlock block, int index) {
|
||||
exists(Alias::MemoryAccess access |
|
||||
access = Alias::getOperandMemoryAccess(use, _) and
|
||||
block.getInstruction(index) = use and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate variableLiveOnEntryToBlock(Alias::VirtualVariable vvar, OldIR::IRBlock 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, _))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate variableLiveOnExitFromBlock(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
variableLiveOnEntryToBlock(vvar, block.getASuccessor())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank index of a hyphothetical use one instruction past the end of
|
||||
* the block. This index can be used to determine if a definition reaches the
|
||||
* end of the block, even if the definition is the last instruction in the
|
||||
* block.
|
||||
*/
|
||||
private int exitRank(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
result = max(int rankIndex | defUseRank(vvar, block, rankIndex, _)) + 1
|
||||
}
|
||||
|
||||
private predicate hasDefinitionAtRank(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock block, int rankIndex, int instructionIndex) {
|
||||
hasDefinition(vvar, block, instructionIndex) and
|
||||
defUseRank(vvar, block, rankIndex, instructionIndex)
|
||||
}
|
||||
|
||||
private predicate hasUseAtRank(Alias::VirtualVariable vvar, OldIR::IRBlock block,
|
||||
int rankIndex, OldIR::Instruction use) {
|
||||
exists(int index |
|
||||
hasUse(vvar, use, block, index) and
|
||||
defUseRank(vvar, block, rankIndex, index)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition of `vvar` at `(block, defRank)` reaches the rank
|
||||
* index `reachesRank` in block `block`.
|
||||
*/
|
||||
private predicate definitionReachesRank(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock block, int defRank, int reachesRank) {
|
||||
hasDefinitionAtRank(vvar, block, defRank, _) and
|
||||
reachesRank <= exitRank(vvar, block) and // Without this, the predicate would be infinite.
|
||||
(
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
reachesRank = defRank + 1 or
|
||||
(
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
definitionReachesRank(vvar, block, defRank, reachesRank - 1) and
|
||||
not hasDefinitionAtRank(vvar, block, reachesRank - 1, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition of `vvar` at `(defBlock, defRank)` reaches the end of
|
||||
* block `block`.
|
||||
*/
|
||||
private predicate definitionReachesEndOfBlock(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock block) {
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
|
||||
(
|
||||
(
|
||||
// If we're looking at the def's own block, just see if it reaches the exit
|
||||
// rank of the block.
|
||||
block = defBlock and
|
||||
variableLiveOnExitFromBlock(vvar, defBlock) and
|
||||
definitionReachesRank(vvar, defBlock, defRank, exitRank(vvar, defBlock))
|
||||
) or
|
||||
exists(OldIR::IRBlock idom |
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, idom) and
|
||||
noDefinitionsSinceIDominator(vvar, idom, block)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate noDefinitionsSinceIDominator(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock idom, OldIR::IRBlock block) {
|
||||
idom.immediatelyDominates(block) and // It is sufficient to traverse the dominator graph, cf. discussion above.
|
||||
variableLiveOnExitFromBlock(vvar, block) and
|
||||
not hasDefinition(vvar, block, _)
|
||||
}
|
||||
|
||||
private predicate definitionReachesUseWithinBlock(
|
||||
Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank,
|
||||
OldIR::IRBlock useBlock, int useRank) {
|
||||
defBlock = useBlock and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, _) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, _) and
|
||||
definitionReachesRank(vvar, defBlock, defRank, useRank)
|
||||
}
|
||||
|
||||
private predicate definitionReachesUse(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, OldIR::IRBlock useBlock, int useRank) {
|
||||
hasUseAtRank(vvar, useBlock, useRank, _) and
|
||||
(
|
||||
definitionReachesUseWithinBlock(vvar, defBlock, defRank, useBlock,
|
||||
useRank) or
|
||||
(
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank,
|
||||
useBlock.getAPredecessor()) and
|
||||
not definitionReachesUseWithinBlock(vvar, useBlock, _, useBlock, useRank)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFrontierPhiNode(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock phiBlock) {
|
||||
exists(OldIR::IRBlock defBlock |
|
||||
phiBlock = defBlock.dominanceFrontier() and
|
||||
hasDefinition(vvar, defBlock, _) and
|
||||
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
||||
variableLiveOnEntryToBlock(vvar, phiBlock)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasPhiNode(Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock phiBlock) {
|
||||
hasFrontierPhiNode(vvar, phiBlock)
|
||||
//or ssa_sanitized_custom_phi_node(vvar, block)
|
||||
}
|
||||
}
|
||||
|
||||
import CachedForDebugging
|
||||
cached private module CachedForDebugging {
|
||||
cached string getTempVariableUniqueId(IRTempVariable var) {
|
||||
result = getOldTempVariable(var).getUniqueId()
|
||||
}
|
||||
|
||||
cached string getInstructionUniqueId(Instruction instr) {
|
||||
exists(OldIR::Instruction oldInstr |
|
||||
oldInstr = getOldInstruction(instr) and
|
||||
result = "NonSSA: " + oldInstr.getUniqueId()
|
||||
) or
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock |
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
result = "Phi Block(" + phiBlock.getUniqueId() + "): " + vvar.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {
|
||||
result.getFunction() = var.getFunction() and
|
||||
result.getAST() = var.getAST() and
|
||||
result.getTag() = var.getTag()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import semmle.code.cpp.ir.IR as OldIR
|
||||
import semmle.code.cpp.ssa.SSAIR as NewIR
|
||||
import SimpleSSA as Alias
|
||||
import semmle.code.cpp.ir.IR as OldIR
|
||||
import semmle.code.cpp.ssa.SSAIR as NewIR
|
||||
import SimpleSSA as Alias
|
||||
|
||||
@@ -1,83 +1,83 @@
|
||||
import SimpleSSAInternal
|
||||
import cpp
|
||||
import Alias
|
||||
import IR
|
||||
import semmle.code.cpp.ssa.internal.Overlap
|
||||
|
||||
private newtype TVirtualVariable =
|
||||
MkVirtualVariable(IRVariable var) {
|
||||
not variableAddressEscapes(var)
|
||||
}
|
||||
|
||||
private VirtualVariable getVirtualVariable(IRVariable var) {
|
||||
result.getIRVariable() = var
|
||||
}
|
||||
|
||||
class VirtualVariable extends TVirtualVariable {
|
||||
IRVariable var;
|
||||
|
||||
VirtualVariable() {
|
||||
this = MkVirtualVariable(var)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
final IRVariable getIRVariable() {
|
||||
result = var
|
||||
}
|
||||
|
||||
// REVIEW: This should just be on MemoryAccess
|
||||
final Type getType() {
|
||||
result = var.getType()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = var.getUniqueId()
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TMemoryAccess =
|
||||
MkMemoryAccess(VirtualVariable vvar)
|
||||
|
||||
private MemoryAccess getMemoryAccess(IRVariable var) {
|
||||
result.getVirtualVariable() = getVirtualVariable(var)
|
||||
}
|
||||
|
||||
class MemoryAccess extends TMemoryAccess {
|
||||
VirtualVariable vvar;
|
||||
|
||||
MemoryAccess() {
|
||||
this = MkMemoryAccess(vvar)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = vvar.toString()
|
||||
}
|
||||
|
||||
VirtualVariable getVirtualVariable() {
|
||||
result = vvar
|
||||
}
|
||||
}
|
||||
|
||||
Overlap getOverlap(MemoryAccess def, MemoryAccess use) {
|
||||
def.getVirtualVariable() = use.getVirtualVariable() and
|
||||
result instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
MemoryAccess getResultMemoryAccess(Instruction instr) {
|
||||
exists(IRVariable var |
|
||||
instr.getResultMemoryAccess() instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
MemoryAccess getOperandMemoryAccess(Instruction instr, OperandTag tag) {
|
||||
exists(IRVariable var |
|
||||
instr.getOperandMemoryAccess(tag) instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
import SimpleSSAInternal
|
||||
import cpp
|
||||
import Alias
|
||||
import IR
|
||||
import semmle.code.cpp.ssa.internal.Overlap
|
||||
|
||||
private newtype TVirtualVariable =
|
||||
MkVirtualVariable(IRVariable var) {
|
||||
not variableAddressEscapes(var)
|
||||
}
|
||||
|
||||
private VirtualVariable getVirtualVariable(IRVariable var) {
|
||||
result.getIRVariable() = var
|
||||
}
|
||||
|
||||
class VirtualVariable extends TVirtualVariable {
|
||||
IRVariable var;
|
||||
|
||||
VirtualVariable() {
|
||||
this = MkVirtualVariable(var)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
final IRVariable getIRVariable() {
|
||||
result = var
|
||||
}
|
||||
|
||||
// REVIEW: This should just be on MemoryAccess
|
||||
final Type getType() {
|
||||
result = var.getType()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = var.getUniqueId()
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TMemoryAccess =
|
||||
MkMemoryAccess(VirtualVariable vvar)
|
||||
|
||||
private MemoryAccess getMemoryAccess(IRVariable var) {
|
||||
result.getVirtualVariable() = getVirtualVariable(var)
|
||||
}
|
||||
|
||||
class MemoryAccess extends TMemoryAccess {
|
||||
VirtualVariable vvar;
|
||||
|
||||
MemoryAccess() {
|
||||
this = MkMemoryAccess(vvar)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = vvar.toString()
|
||||
}
|
||||
|
||||
VirtualVariable getVirtualVariable() {
|
||||
result = vvar
|
||||
}
|
||||
}
|
||||
|
||||
Overlap getOverlap(MemoryAccess def, MemoryAccess use) {
|
||||
def.getVirtualVariable() = use.getVirtualVariable() and
|
||||
result instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
MemoryAccess getResultMemoryAccess(Instruction instr) {
|
||||
exists(IRVariable var |
|
||||
instr.getResultMemoryAccess() instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
MemoryAccess getOperandMemoryAccess(Instruction instr, OperandTag tag) {
|
||||
exists(IRVariable var |
|
||||
instr.getOperandMemoryAccess(tag) instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import AliasAnalysis as Alias
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
|
||||
import AliasAnalysis as Alias
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ssa.internal.IntegerConstant as Ints
|
||||
|
||||
bindingset[n]
|
||||
string resultString(int n) {
|
||||
if Ints::hasValue(n) then
|
||||
result = n.toString()
|
||||
else
|
||||
result = "unknown"
|
||||
}
|
||||
|
||||
from string expr, int res
|
||||
where
|
||||
expr = "0 + 0" and res = Ints::add(0, 0) or
|
||||
expr = "0 + INT_MAX" and res = Ints::add(0, Ints::maxValue()) or
|
||||
expr = "0 + -INT_MAX" and res = Ints::add(0, Ints::minValue()) or
|
||||
expr = "1 + INT_MAX" and res = Ints::add(1, Ints::maxValue()) or
|
||||
expr = "1 + -INT_MAX" and res = Ints::add(1, Ints::minValue()) or
|
||||
expr = "unknown + unknown" and res = Ints::add(Ints::unknown(), Ints::unknown()) or
|
||||
expr = "5 + unknown" and res = Ints::add(5, Ints::unknown()) or
|
||||
expr = "unknown + 5" and res = Ints::add(Ints::unknown(), 5) or
|
||||
expr = "0 - INT_MAX" and res = Ints::sub(0, Ints::maxValue()) or
|
||||
expr = "0 - -INT_MAX" and res = Ints::sub(0, Ints::minValue()) or
|
||||
expr = "-1 - INT_MAX" and res = Ints::sub(-1, Ints::maxValue()) or
|
||||
expr = "-1 - -INT_MAX" and res = Ints::sub(-1, Ints::minValue()) or
|
||||
expr = "unknown - unknown" and res = Ints::sub(Ints::unknown(), Ints::unknown()) or
|
||||
expr = "5 - unknown" and res = Ints::sub(5, Ints::unknown()) or
|
||||
expr = "unknown - 5" and res = Ints::sub(Ints::unknown(), 5) or
|
||||
expr = "0 * 0" and res = Ints::mul(0, 0) or
|
||||
expr = "5 * 7" and res = Ints::mul(5, 7) or
|
||||
expr = "0 * INT_MAX" and res = Ints::mul(0, Ints::maxValue()) or
|
||||
expr = "2 * INT_MAX" and res = Ints::mul(2, Ints::maxValue()) or
|
||||
expr = "-1 * -INT_MAX" and res = Ints::mul(-1, Ints::minValue()) or
|
||||
expr = "INT_MAX * INT_MAX" and res = Ints::mul(Ints::maxValue(), Ints::maxValue()) or
|
||||
expr = "0 * unknown" and res = Ints::mul(0, Ints::unknown()) or
|
||||
expr = "35 / 7" and res = Ints::div(35, 7) or
|
||||
expr = "35 / 8" and res = Ints::div(35, 8) or
|
||||
expr = "35 / -7" and res = Ints::div(35, -7) or
|
||||
expr = "35 / -8" and res = Ints::div(35, -8) or
|
||||
expr = "-35 / 7" and res = Ints::div(-35, 7) or
|
||||
expr = "-35 / 8" and res = Ints::div(-35, 8) or
|
||||
expr = "-35 / -7" and res = Ints::div(-35, -7) or
|
||||
expr = "-35 / -8" and res = Ints::div(-35, -8) or
|
||||
expr = "0 / -INT_MAX" and res = Ints::div(0, Ints::minValue()) or
|
||||
expr = "INT_MAX / 0" and res = Ints::div(Ints::maxValue(), 0) or
|
||||
expr = "0 / unknown" and res = Ints::div(0, Ints::unknown()) or
|
||||
expr = "unknown / 3" and res = Ints::div(Ints::unknown(), 3) or
|
||||
expr = "unknown / unknown" and res = Ints::div(Ints::unknown(), Ints::unknown())
|
||||
select expr, resultString(res)
|
||||
import cpp
|
||||
import semmle.code.cpp.ssa.internal.IntegerConstant as Ints
|
||||
|
||||
bindingset[n]
|
||||
string resultString(int n) {
|
||||
if Ints::hasValue(n) then
|
||||
result = n.toString()
|
||||
else
|
||||
result = "unknown"
|
||||
}
|
||||
|
||||
from string expr, int res
|
||||
where
|
||||
expr = "0 + 0" and res = Ints::add(0, 0) or
|
||||
expr = "0 + INT_MAX" and res = Ints::add(0, Ints::maxValue()) or
|
||||
expr = "0 + -INT_MAX" and res = Ints::add(0, Ints::minValue()) or
|
||||
expr = "1 + INT_MAX" and res = Ints::add(1, Ints::maxValue()) or
|
||||
expr = "1 + -INT_MAX" and res = Ints::add(1, Ints::minValue()) or
|
||||
expr = "unknown + unknown" and res = Ints::add(Ints::unknown(), Ints::unknown()) or
|
||||
expr = "5 + unknown" and res = Ints::add(5, Ints::unknown()) or
|
||||
expr = "unknown + 5" and res = Ints::add(Ints::unknown(), 5) or
|
||||
expr = "0 - INT_MAX" and res = Ints::sub(0, Ints::maxValue()) or
|
||||
expr = "0 - -INT_MAX" and res = Ints::sub(0, Ints::minValue()) or
|
||||
expr = "-1 - INT_MAX" and res = Ints::sub(-1, Ints::maxValue()) or
|
||||
expr = "-1 - -INT_MAX" and res = Ints::sub(-1, Ints::minValue()) or
|
||||
expr = "unknown - unknown" and res = Ints::sub(Ints::unknown(), Ints::unknown()) or
|
||||
expr = "5 - unknown" and res = Ints::sub(5, Ints::unknown()) or
|
||||
expr = "unknown - 5" and res = Ints::sub(Ints::unknown(), 5) or
|
||||
expr = "0 * 0" and res = Ints::mul(0, 0) or
|
||||
expr = "5 * 7" and res = Ints::mul(5, 7) or
|
||||
expr = "0 * INT_MAX" and res = Ints::mul(0, Ints::maxValue()) or
|
||||
expr = "2 * INT_MAX" and res = Ints::mul(2, Ints::maxValue()) or
|
||||
expr = "-1 * -INT_MAX" and res = Ints::mul(-1, Ints::minValue()) or
|
||||
expr = "INT_MAX * INT_MAX" and res = Ints::mul(Ints::maxValue(), Ints::maxValue()) or
|
||||
expr = "0 * unknown" and res = Ints::mul(0, Ints::unknown()) or
|
||||
expr = "35 / 7" and res = Ints::div(35, 7) or
|
||||
expr = "35 / 8" and res = Ints::div(35, 8) or
|
||||
expr = "35 / -7" and res = Ints::div(35, -7) or
|
||||
expr = "35 / -8" and res = Ints::div(35, -8) or
|
||||
expr = "-35 / 7" and res = Ints::div(-35, 7) or
|
||||
expr = "-35 / 8" and res = Ints::div(-35, 8) or
|
||||
expr = "-35 / -7" and res = Ints::div(-35, -7) or
|
||||
expr = "-35 / -8" and res = Ints::div(-35, -8) or
|
||||
expr = "0 / -INT_MAX" and res = Ints::div(0, Ints::minValue()) or
|
||||
expr = "INT_MAX / 0" and res = Ints::div(Ints::maxValue(), 0) or
|
||||
expr = "0 / unknown" and res = Ints::div(0, Ints::unknown()) or
|
||||
expr = "unknown / 3" and res = Ints::div(Ints::unknown(), 3) or
|
||||
expr = "unknown / unknown" and res = Ints::div(Ints::unknown(), Ints::unknown())
|
||||
select expr, resultString(res)
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import default
|
||||
import semmle.code.cpp.ssa.internal.ssa.AliasAnalysis
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
predicate shouldEscape(IRAutomaticUserVariable var) {
|
||||
exists(string name |
|
||||
name = var.getVariable().getName() and
|
||||
name.matches("no_%") and
|
||||
not name.matches("no_ssa_%")
|
||||
)
|
||||
}
|
||||
|
||||
from IRAutomaticUserVariable var
|
||||
where
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = var.getFunctionIR() and
|
||||
(
|
||||
(shouldEscape(var) and variableAddressEscapes(var)) or
|
||||
(not shouldEscape(var) and not variableAddressEscapes(var))
|
||||
)
|
||||
)
|
||||
select var
|
||||
import default
|
||||
import semmle.code.cpp.ssa.internal.ssa.AliasAnalysis
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
predicate shouldEscape(IRAutomaticUserVariable var) {
|
||||
exists(string name |
|
||||
name = var.getVariable().getName() and
|
||||
name.matches("no_%") and
|
||||
not name.matches("no_ssa_%")
|
||||
)
|
||||
}
|
||||
|
||||
from IRAutomaticUserVariable var
|
||||
where
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = var.getFunctionIR() and
|
||||
(
|
||||
(shouldEscape(var) and variableAddressEscapes(var)) or
|
||||
(not shouldEscape(var) and not variableAddressEscapes(var))
|
||||
)
|
||||
)
|
||||
select var
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import default
|
||||
import semmle.code.cpp.ssa.internal.ssa.AliasAnalysis
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
from Instruction instr, string pointsTo
|
||||
where
|
||||
exists(IRVariable var, int bitOffset |
|
||||
resultPointsTo(instr, var, bitOffset) and
|
||||
pointsTo = var.toString() + getBitOffsetString(bitOffset)
|
||||
)
|
||||
select instr.getLocation().toString(), instr.getOperationString(), pointsTo
|
||||
import default
|
||||
import semmle.code.cpp.ssa.internal.ssa.AliasAnalysis
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
from Instruction instr, string pointsTo
|
||||
where
|
||||
exists(IRVariable var, int bitOffset |
|
||||
resultPointsTo(instr, var, bitOffset) and
|
||||
pointsTo = var.toString() + getBitOffsetString(bitOffset)
|
||||
)
|
||||
select instr.getLocation().toString(), instr.getOperationString(), pointsTo
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import default
|
||||
import semmle.code.cpp.ssa.internal.aliased_ssa.AliasAnalysis
|
||||
import semmle.code.cpp.ssa.SSAIR
|
||||
|
||||
predicate shouldEscape(IRAutomaticUserVariable var) {
|
||||
exists(string name |
|
||||
name = var.getVariable().getName() and
|
||||
name.matches("no_%")
|
||||
)
|
||||
}
|
||||
|
||||
from IRAutomaticUserVariable var
|
||||
where
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = var.getFunctionIR() and
|
||||
(
|
||||
(shouldEscape(var) and variableAddressEscapes(var)) or
|
||||
(not shouldEscape(var) and not variableAddressEscapes(var))
|
||||
)
|
||||
)
|
||||
select var
|
||||
import default
|
||||
import semmle.code.cpp.ssa.internal.aliased_ssa.AliasAnalysis
|
||||
import semmle.code.cpp.ssa.SSAIR
|
||||
|
||||
predicate shouldEscape(IRAutomaticUserVariable var) {
|
||||
exists(string name |
|
||||
name = var.getVariable().getName() and
|
||||
name.matches("no_%")
|
||||
)
|
||||
}
|
||||
|
||||
from IRAutomaticUserVariable var
|
||||
where
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = var.getFunctionIR() and
|
||||
(
|
||||
(shouldEscape(var) and variableAddressEscapes(var)) or
|
||||
(not shouldEscape(var) and not variableAddressEscapes(var))
|
||||
)
|
||||
)
|
||||
select var
|
||||
|
||||
@@ -1,89 +1,89 @@
|
||||
import default
|
||||
|
||||
query predicate newExprs(NewExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function allocator, Type allocatedType |
|
||||
expr.getAllocator() = allocator and
|
||||
sig = allocator.getFullSignature() and
|
||||
allocatedType = expr.getAllocatedType() and
|
||||
type = allocatedType.toString() and
|
||||
size = allocatedType.getSize() and
|
||||
alignment = allocatedType.getAlignment() and
|
||||
if expr.hasAlignedAllocation() then form = "aligned" else form = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate newArrayExprs(NewArrayExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function allocator, Type elementType |
|
||||
expr.getAllocator() = allocator and
|
||||
sig = allocator.getFullSignature() and
|
||||
elementType = expr.getAllocatedElementType() and
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
if expr.hasAlignedAllocation() then form = "aligned" else form = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate newExprDeallocators(NewExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function deallocator, Type allocatedType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
allocatedType = expr.getAllocatedType() and
|
||||
type = allocatedType.toString() and
|
||||
size = allocatedType.getSize() and
|
||||
alignment = allocatedType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate newArrayExprDeallocators(NewArrayExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function deallocator, Type elementType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
elementType = expr.getAllocatedElementType() and
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate deleteExprs(DeleteExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function deallocator, Type deletedType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
deletedType = expr.getDeletedObjectType() and
|
||||
type = deletedType.toString() and
|
||||
size = deletedType.getSize() and
|
||||
alignment = deletedType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate deleteArrayExprs(DeleteArrayExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function deallocator, Type elementType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
elementType = expr.getDeletedElementType() and
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
)
|
||||
)
|
||||
}
|
||||
import default
|
||||
|
||||
query predicate newExprs(NewExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function allocator, Type allocatedType |
|
||||
expr.getAllocator() = allocator and
|
||||
sig = allocator.getFullSignature() and
|
||||
allocatedType = expr.getAllocatedType() and
|
||||
type = allocatedType.toString() and
|
||||
size = allocatedType.getSize() and
|
||||
alignment = allocatedType.getAlignment() and
|
||||
if expr.hasAlignedAllocation() then form = "aligned" else form = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate newArrayExprs(NewArrayExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function allocator, Type elementType |
|
||||
expr.getAllocator() = allocator and
|
||||
sig = allocator.getFullSignature() and
|
||||
elementType = expr.getAllocatedElementType() and
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
if expr.hasAlignedAllocation() then form = "aligned" else form = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate newExprDeallocators(NewExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function deallocator, Type allocatedType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
allocatedType = expr.getAllocatedType() and
|
||||
type = allocatedType.toString() and
|
||||
size = allocatedType.getSize() and
|
||||
alignment = allocatedType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate newArrayExprDeallocators(NewArrayExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function deallocator, Type elementType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
elementType = expr.getAllocatedElementType() and
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate deleteExprs(DeleteExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function deallocator, Type deletedType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
deletedType = expr.getDeletedObjectType() and
|
||||
type = deletedType.toString() and
|
||||
size = deletedType.getSize() and
|
||||
alignment = deletedType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate deleteArrayExprs(DeleteArrayExpr expr, string type, string sig, int size, int alignment, string form) {
|
||||
exists(Function deallocator, Type elementType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
elementType = expr.getDeletedElementType() and
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
alignment = elementType.getAlignment() and
|
||||
exists(string sized, string aligned |
|
||||
(if expr.hasAlignedDeallocation() then aligned = "aligned" else aligned = "") and
|
||||
(if expr.hasSizedDeallocation() then sized = "sized" else sized = "") and
|
||||
form = sized + " " + aligned
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
from GuardCondition guard
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
from GuardCondition guard
|
||||
select guard
|
||||
@@ -1,15 +1,15 @@
|
||||
import default
|
||||
|
||||
string getValueCategoryString(Expr expr) {
|
||||
if expr.isLValueCategory() then
|
||||
result = "lval"
|
||||
else if expr.isXValueCategory() then
|
||||
result = "xval"
|
||||
else if expr.hasLValueToRValueConversion() then
|
||||
result = "prval(load)"
|
||||
else
|
||||
result = "prval"
|
||||
}
|
||||
|
||||
from Cast cast
|
||||
select cast, cast.getSemanticConversionString(), getValueCategoryString(cast), cast.getType().toString(), cast.getExpr().getType().toString()
|
||||
import default
|
||||
|
||||
string getValueCategoryString(Expr expr) {
|
||||
if expr.isLValueCategory() then
|
||||
result = "lval"
|
||||
else if expr.isXValueCategory() then
|
||||
result = "xval"
|
||||
else if expr.hasLValueToRValueConversion() then
|
||||
result = "prval(load)"
|
||||
else
|
||||
result = "prval"
|
||||
}
|
||||
|
||||
from Cast cast
|
||||
select cast, cast.getSemanticConversionString(), getValueCategoryString(cast), cast.getType().toString(), cast.getExpr().getType().toString()
|
||||
|
||||
@@ -1 +1 @@
|
||||
semmle/code/cpp/ASTSanity.ql
|
||||
semmle/code/cpp/ASTSanity.ql
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from Expr e, Variable v
|
||||
where varbind(unresolveElement(e), unresolveElement(v))
|
||||
select e, v
|
||||
import cpp
|
||||
|
||||
from Expr e, Variable v
|
||||
where varbind(unresolveElement(e), unresolveElement(v))
|
||||
select e, v
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @name InitializerAccesses
|
||||
*/
|
||||
import cpp
|
||||
import cpp
|
||||
|
||||
from Initializer i, VariableAccess va
|
||||
where i.getExpr().getAChild*() = va
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cpp
|
||||
|
||||
//this query should find the baseType of CC* to be CC, not C.
|
||||
from DerivedType t, Type baseType
|
||||
where t.getBaseType() = baseType
|
||||
select t, baseType
|
||||
import cpp
|
||||
|
||||
//this query should find the baseType of CC* to be CC, not C.
|
||||
from DerivedType t, Type baseType
|
||||
where t.getBaseType() = baseType
|
||||
select t, baseType
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import cpp
|
||||
|
||||
from ComparisonOperation co, string s
|
||||
where
|
||||
(
|
||||
co instanceof EqualityOperation and s = "EqualityOperation"
|
||||
) or (
|
||||
co instanceof EQExpr and s = "EQExpr"
|
||||
) or (
|
||||
co instanceof NEExpr and s = "NEExpr"
|
||||
) or (
|
||||
co instanceof RelationalOperation and s = "RelationalOperation"
|
||||
) or (
|
||||
s = "getGreaterOperand() = " + co.(RelationalOperation).getGreaterOperand().toString()
|
||||
) or (
|
||||
s = "getLesserOperand() = " + co.(RelationalOperation).getLesserOperand().toString()
|
||||
) or (
|
||||
co instanceof GTExpr and s = "GTExpr"
|
||||
) or (
|
||||
co instanceof LTExpr and s = "LTExpr"
|
||||
) or (
|
||||
co instanceof GEExpr and s = "GEExpr"
|
||||
) or (
|
||||
co instanceof LEExpr and s = "LEExpr"
|
||||
)
|
||||
select co, s
|
||||
import cpp
|
||||
|
||||
from ComparisonOperation co, string s
|
||||
where
|
||||
(
|
||||
co instanceof EqualityOperation and s = "EqualityOperation"
|
||||
) or (
|
||||
co instanceof EQExpr and s = "EQExpr"
|
||||
) or (
|
||||
co instanceof NEExpr and s = "NEExpr"
|
||||
) or (
|
||||
co instanceof RelationalOperation and s = "RelationalOperation"
|
||||
) or (
|
||||
s = "getGreaterOperand() = " + co.(RelationalOperation).getGreaterOperand().toString()
|
||||
) or (
|
||||
s = "getLesserOperand() = " + co.(RelationalOperation).getLesserOperand().toString()
|
||||
) or (
|
||||
co instanceof GTExpr and s = "GTExpr"
|
||||
) or (
|
||||
co instanceof LTExpr and s = "LTExpr"
|
||||
) or (
|
||||
co instanceof GEExpr and s = "GEExpr"
|
||||
) or (
|
||||
co instanceof LEExpr and s = "LEExpr"
|
||||
)
|
||||
select co, s
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
import cpp
|
||||
|
||||
predicate describe(UnaryOperation uo, string s)
|
||||
{
|
||||
(
|
||||
uo instanceof UnaryArithmeticOperation and s = "UnaryArithmeticOperation"
|
||||
) or (
|
||||
uo instanceof UnaryMinusExpr and s = "UnaryMinusExpr"
|
||||
) or (
|
||||
uo instanceof UnaryPlusExpr and s = "UnaryPlusExpr"
|
||||
) or (
|
||||
uo instanceof ConjugationExpr and s = "ConjugationExpr"
|
||||
) or (
|
||||
uo instanceof CrementOperation and s = "CrementOperation"
|
||||
) or (
|
||||
uo instanceof IncrementOperation and s = "IncrementOperation"
|
||||
) or (
|
||||
uo instanceof DecrementOperation and s = "DecrementOperation"
|
||||
) or (
|
||||
uo instanceof PrefixCrementOperation and s = "PrefixCrementOperation"
|
||||
) or (
|
||||
uo instanceof PostfixCrementOperation and s = "PostfixCrementOperation"
|
||||
) or (
|
||||
uo instanceof AddressOfExpr and s = "AddressOfExpr"
|
||||
) or (
|
||||
s = "getAddressable() = " + uo.(AddressOfExpr).getAddressable().toString()
|
||||
) or (
|
||||
uo instanceof PointerDereferenceExpr and s = "PointerDereferenceExpr"
|
||||
) or (
|
||||
uo instanceof UnaryLogicalOperation and s = "UnaryLogicalOperation"
|
||||
) or (
|
||||
uo instanceof NotExpr and s = "NotExpr"
|
||||
)
|
||||
}
|
||||
|
||||
from UnaryOperation uo
|
||||
select uo, uo.getOperator(), concat(string s | describe(uo, s) | s, ", ")
|
||||
import cpp
|
||||
|
||||
predicate describe(UnaryOperation uo, string s)
|
||||
{
|
||||
(
|
||||
uo instanceof UnaryArithmeticOperation and s = "UnaryArithmeticOperation"
|
||||
) or (
|
||||
uo instanceof UnaryMinusExpr and s = "UnaryMinusExpr"
|
||||
) or (
|
||||
uo instanceof UnaryPlusExpr and s = "UnaryPlusExpr"
|
||||
) or (
|
||||
uo instanceof ConjugationExpr and s = "ConjugationExpr"
|
||||
) or (
|
||||
uo instanceof CrementOperation and s = "CrementOperation"
|
||||
) or (
|
||||
uo instanceof IncrementOperation and s = "IncrementOperation"
|
||||
) or (
|
||||
uo instanceof DecrementOperation and s = "DecrementOperation"
|
||||
) or (
|
||||
uo instanceof PrefixCrementOperation and s = "PrefixCrementOperation"
|
||||
) or (
|
||||
uo instanceof PostfixCrementOperation and s = "PostfixCrementOperation"
|
||||
) or (
|
||||
uo instanceof AddressOfExpr and s = "AddressOfExpr"
|
||||
) or (
|
||||
s = "getAddressable() = " + uo.(AddressOfExpr).getAddressable().toString()
|
||||
) or (
|
||||
uo instanceof PointerDereferenceExpr and s = "PointerDereferenceExpr"
|
||||
) or (
|
||||
uo instanceof UnaryLogicalOperation and s = "UnaryLogicalOperation"
|
||||
) or (
|
||||
uo instanceof NotExpr and s = "NotExpr"
|
||||
)
|
||||
}
|
||||
|
||||
from UnaryOperation uo
|
||||
select uo, uo.getOperator(), concat(string s | describe(uo, s) | s, ", ")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from Expr e
|
||||
where e.isUnevaluated()
|
||||
select e
|
||||
import cpp
|
||||
|
||||
from Expr e
|
||||
where e.isUnevaluated()
|
||||
select e
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from Expr e
|
||||
where e.hasLValueToRValueConversion()
|
||||
select e
|
||||
import cpp
|
||||
|
||||
from Expr e
|
||||
where e.hasLValueToRValueConversion()
|
||||
select e
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cpp
|
||||
|
||||
from Expr e, string valcat
|
||||
where
|
||||
e.isLValueCategory() and valcat = "lvalue" or
|
||||
e.isXValueCategory() and valcat = "xvalue"
|
||||
select e, e.getType().toString(), valcat
|
||||
import cpp
|
||||
|
||||
from Expr e, string valcat
|
||||
where
|
||||
e.isLValueCategory() and valcat = "lvalue" or
|
||||
e.isXValueCategory() and valcat = "xvalue"
|
||||
select e, e.getType().toString(), valcat
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* @name EnumConst
|
||||
* @kind table
|
||||
*/
|
||||
import cpp
|
||||
|
||||
from Enum e, Declaration c, string reason
|
||||
where (c.(EnumConstant).getDeclaringEnum() = e and reason = "getDeclaringEnum()") or
|
||||
(c.(EnumConstant).getType() = e and reason = "getType()") or
|
||||
(c.(Field).getDeclaringType() = e and reason = "getDeclaringType()")
|
||||
select e, c, reason
|
||||
/**
|
||||
* @name EnumConst
|
||||
* @kind table
|
||||
*/
|
||||
import cpp
|
||||
|
||||
from Enum e, Declaration c, string reason
|
||||
where (c.(EnumConstant).getDeclaringEnum() = e and reason = "getDeclaringEnum()") or
|
||||
(c.(EnumConstant).getType() = e and reason = "getType()") or
|
||||
(c.(Field).getDeclaringType() = e and reason = "getDeclaringType()")
|
||||
select e, c, reason
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
/**
|
||||
* @name Fields
|
||||
* @kind table
|
||||
*/
|
||||
import cpp
|
||||
|
||||
predicate nameCheck(Declaration d) {
|
||||
count(d.toString()) = 1 and
|
||||
count(string s | d.hasName(s)) = 1 and
|
||||
d.hasName(d.toString())
|
||||
}
|
||||
|
||||
string accessType(Field f) {
|
||||
(f.isPublic() and result = "public") or
|
||||
(f.isProtected() and result = "protected") or
|
||||
(f.isPrivate() and result = "private")
|
||||
}
|
||||
|
||||
string fieldType(Field f) {
|
||||
result = f.getType().getAQlClass() and
|
||||
(
|
||||
result.matches("%Type") or
|
||||
result = "Enum"
|
||||
)
|
||||
}
|
||||
|
||||
string pointedType(Field f) {
|
||||
if f.getType() instanceof PointerType then (
|
||||
result = f.getType().(PointerType).getBaseType().toString()
|
||||
) else (
|
||||
result = ""
|
||||
)
|
||||
}
|
||||
|
||||
from Class c, Field f
|
||||
where f.getDeclaringType() = c and
|
||||
c.getAField() = f and
|
||||
nameCheck(c) and
|
||||
nameCheck(f)
|
||||
select c, f, accessType(f), fieldType(f), pointedType(f)
|
||||
/**
|
||||
* @name Fields
|
||||
* @kind table
|
||||
*/
|
||||
import cpp
|
||||
|
||||
predicate nameCheck(Declaration d) {
|
||||
count(d.toString()) = 1 and
|
||||
count(string s | d.hasName(s)) = 1 and
|
||||
d.hasName(d.toString())
|
||||
}
|
||||
|
||||
string accessType(Field f) {
|
||||
(f.isPublic() and result = "public") or
|
||||
(f.isProtected() and result = "protected") or
|
||||
(f.isPrivate() and result = "private")
|
||||
}
|
||||
|
||||
string fieldType(Field f) {
|
||||
result = f.getType().getAQlClass() and
|
||||
(
|
||||
result.matches("%Type") or
|
||||
result = "Enum"
|
||||
)
|
||||
}
|
||||
|
||||
string pointedType(Field f) {
|
||||
if f.getType() instanceof PointerType then (
|
||||
result = f.getType().(PointerType).getBaseType().toString()
|
||||
) else (
|
||||
result = ""
|
||||
)
|
||||
}
|
||||
|
||||
from Class c, Field f
|
||||
where f.getDeclaringType() = c and
|
||||
c.getAField() = f and
|
||||
nameCheck(c) and
|
||||
nameCheck(f)
|
||||
select c, f, accessType(f), fieldType(f), pointedType(f)
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import default
|
||||
import semmle.code.cpp.ssa.SSAIR
|
||||
import semmle.code.cpp.ssa.internal.IntegerConstant
|
||||
|
||||
language[monotonicAggregates]
|
||||
IntValue getConstantValue(Instruction instr) {
|
||||
result = instr.(IntegerConstantInstruction).getValue().toInt() or
|
||||
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
|
||||
binInstr = instr and
|
||||
left = getConstantValue(binInstr.getLeftOperand()) and
|
||||
right = getConstantValue(binInstr.getRightOperand()) and
|
||||
(
|
||||
binInstr instanceof AddInstruction and result = add(left, right) or
|
||||
binInstr instanceof SubInstruction and result = sub(left, right) or
|
||||
binInstr instanceof MulInstruction and result = mul(left, right) or
|
||||
binInstr instanceof DivInstruction and result = div(left, right)
|
||||
)
|
||||
) or
|
||||
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
|
||||
exists(PhiInstruction phi |
|
||||
phi = instr and
|
||||
result = max(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand)) and
|
||||
result = min(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand))
|
||||
)
|
||||
}
|
||||
|
||||
from FunctionIR funcIR, int value
|
||||
where
|
||||
value = getValue(getConstantValue(funcIR.getReturnInstruction().(ReturnValueInstruction).getReturnValue()))
|
||||
select funcIR, value
|
||||
import default
|
||||
import semmle.code.cpp.ssa.SSAIR
|
||||
import semmle.code.cpp.ssa.internal.IntegerConstant
|
||||
|
||||
language[monotonicAggregates]
|
||||
IntValue getConstantValue(Instruction instr) {
|
||||
result = instr.(IntegerConstantInstruction).getValue().toInt() or
|
||||
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
|
||||
binInstr = instr and
|
||||
left = getConstantValue(binInstr.getLeftOperand()) and
|
||||
right = getConstantValue(binInstr.getRightOperand()) and
|
||||
(
|
||||
binInstr instanceof AddInstruction and result = add(left, right) or
|
||||
binInstr instanceof SubInstruction and result = sub(left, right) or
|
||||
binInstr instanceof MulInstruction and result = mul(left, right) or
|
||||
binInstr instanceof DivInstruction and result = div(left, right)
|
||||
)
|
||||
) or
|
||||
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
|
||||
exists(PhiInstruction phi |
|
||||
phi = instr and
|
||||
result = max(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand)) and
|
||||
result = min(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand))
|
||||
)
|
||||
}
|
||||
|
||||
from FunctionIR funcIR, int value
|
||||
where
|
||||
value = getValue(getConstantValue(funcIR.getReturnInstruction().(ReturnValueInstruction).getReturnValue()))
|
||||
select funcIR, value
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import default
|
||||
import semmle.code.cpp.ssa.SSAIR
|
||||
|
||||
from FunctionIR funcIR
|
||||
select funcIR.toString(), count(funcIR.getABlock())
|
||||
import default
|
||||
import semmle.code.cpp.ssa.SSAIR
|
||||
|
||||
from FunctionIR funcIR
|
||||
select funcIR.toString(), count(funcIR.getABlock())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from ArrayType a, ArrayAggregateLiteral al, int i
|
||||
where a = al.getType()
|
||||
select al, a, i, al.getElementExpr(i)
|
||||
import cpp
|
||||
|
||||
from ArrayType a, ArrayAggregateLiteral al, int i
|
||||
where a = al.getType()
|
||||
select al, a, i, al.getElementExpr(i)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cpp
|
||||
|
||||
from ArrayType a, ArrayAggregateLiteral al, int i
|
||||
where a = al.getType()
|
||||
and al.isValueInitialized(i)
|
||||
select al, a, i
|
||||
import cpp
|
||||
|
||||
from ArrayType a, ArrayAggregateLiteral al, int i
|
||||
where a = al.getType()
|
||||
and al.isValueInitialized(i)
|
||||
select al, a, i
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cpp
|
||||
|
||||
from Class c, ClassAggregateLiteral al, Field f
|
||||
where c = al.getType()
|
||||
and f = c.getAField()
|
||||
select al, c, f, al.getFieldExpr(f)
|
||||
import cpp
|
||||
|
||||
from Class c, ClassAggregateLiteral al, Field f
|
||||
where c = al.getType()
|
||||
and f = c.getAField()
|
||||
select al, c, f, al.getFieldExpr(f)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cpp
|
||||
|
||||
from Class c, ClassAggregateLiteral al, Field f
|
||||
where c = al.getType()
|
||||
and al.isValueInitialized(f)
|
||||
select al, c, f
|
||||
import cpp
|
||||
|
||||
from Class c, ClassAggregateLiteral al, Field f
|
||||
where c = al.getType()
|
||||
and al.isValueInitialized(f)
|
||||
select al, c, f
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
* @name Parameters3
|
||||
* @kind table
|
||||
*/
|
||||
import cpp
|
||||
|
||||
from Function f, int i, Parameter p, string pname, boolean named
|
||||
import cpp
|
||||
|
||||
from Function f, int i, Parameter p, string pname, boolean named
|
||||
where f.hasName("Dispatch")
|
||||
and f.getParameter(i) = p
|
||||
and p.getName() = pname
|
||||
and (
|
||||
p.isNamed() and named = true
|
||||
or not p.isNamed() and named = false)
|
||||
or not p.isNamed() and named = false)
|
||||
select f, i, pname, named
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from BreakStmt b, Stmt s
|
||||
where b.getBreakable() = s
|
||||
select b, s
|
||||
import cpp
|
||||
|
||||
from BreakStmt b, Stmt s
|
||||
where b.getBreakable() = s
|
||||
select b, s
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import cpp
|
||||
|
||||
from Variable v
|
||||
select v
|
||||
import cpp
|
||||
|
||||
from Variable v
|
||||
select v
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from Variable v, Class t
|
||||
where t = v.getType().(PointerType).getBaseType()
|
||||
select v, t, count(t.getAMember())
|
||||
import cpp
|
||||
|
||||
from Variable v, Class t
|
||||
where t = v.getType().(PointerType).getBaseType()
|
||||
select v, t, count(t.getAMember())
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import cpp
|
||||
|
||||
class MutexTypeForTest extends MutexType {
|
||||
MutexTypeForTest() {
|
||||
this.(Class).getName() = "Mutex7"
|
||||
}
|
||||
|
||||
override predicate mustlockAccess(FunctionCall fc, Expr arg) {
|
||||
exists(Function f |
|
||||
f = fc.getTarget() and
|
||||
f.getName() = "custom_l" and
|
||||
f.getDeclaringType() = this and
|
||||
arg = fc.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate trylockAccess(FunctionCall fc, Expr arg) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate unlockAccess(FunctionCall fc, Expr arg) {
|
||||
exists(Function f |
|
||||
f = fc.getTarget() and
|
||||
f.getName() = "custom_ul" and
|
||||
f.getDeclaringType() = this and
|
||||
arg = fc.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
import cpp
|
||||
|
||||
class MutexTypeForTest extends MutexType {
|
||||
MutexTypeForTest() {
|
||||
this.(Class).getName() = "Mutex7"
|
||||
}
|
||||
|
||||
override predicate mustlockAccess(FunctionCall fc, Expr arg) {
|
||||
exists(Function f |
|
||||
f = fc.getTarget() and
|
||||
f.getName() = "custom_l" and
|
||||
f.getDeclaringType() = this and
|
||||
arg = fc.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate trylockAccess(FunctionCall fc, Expr arg) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate unlockAccess(FunctionCall fc, Expr arg) {
|
||||
exists(Function f |
|
||||
f = fc.getTarget() and
|
||||
f.getName() = "custom_ul" and
|
||||
f.getDeclaringType() = this and
|
||||
arg = fc.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Critical.MemoryFreed
|
||||
|
||||
from FreedExpr fe
|
||||
select fe
|
||||
import Critical.MemoryFreed
|
||||
|
||||
from FreedExpr fe
|
||||
select fe
|
||||
|
||||
@@ -1 +1 @@
|
||||
Critical/NewArrayDeleteMismatch.ql
|
||||
Critical/NewArrayDeleteMismatch.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Critical/NewDeleteArrayMismatch.ql
|
||||
Critical/NewDeleteArrayMismatch.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Critical/NewFreeMismatch.ql
|
||||
Critical/NewFreeMismatch.ql
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from ControlFlowNode n
|
||||
select n.getLocation().getStartLine(), n.getControlFlowScope(), n,
|
||||
count(n.getAPredecessor()), count(n.getASuccessor())
|
||||
import cpp
|
||||
|
||||
from ControlFlowNode n
|
||||
select n.getLocation().getStartLine(), n.getControlFlowScope(), n,
|
||||
count(n.getAPredecessor()), count(n.getASuccessor())
|
||||
|
||||
@@ -1 +1 @@
|
||||
Bad Practices/Comments/CommentedOutCode.ql
|
||||
Bad Practices/Comments/CommentedOutCode.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Bad Practices/Comments/TodoComments.ql
|
||||
Bad Practices/Comments/TodoComments.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Bad Practices/Naming Conventions/ConfusingMethodNames.ql
|
||||
Bad Practices/Naming Conventions/ConfusingMethodNames.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Documentation/XmldocExtraParam.ql
|
||||
Documentation/XmldocExtraParam.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Documentation/XmldocMissingException.ql
|
||||
Documentation/XmldocMissingException.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Documentation/XmldocMissingParam.ql
|
||||
Documentation/XmldocMissingParam.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Documentation/XmldocMissingReturn.ql
|
||||
Documentation/XmldocMissingReturn.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Documentation/XmldocMissingSummary.ql
|
||||
Documentation/XmldocMissingSummary.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Documentation/XmldocMissingTypeParam.ql
|
||||
Documentation/XmldocMissingTypeParam.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Likely Bugs/Statements/EmptyBlock.ql
|
||||
Likely Bugs/Statements/EmptyBlock.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Language Abuse/ChainedIs.ql
|
||||
Language Abuse/ChainedIs.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Language Abuse/ForeachCapture.ql
|
||||
Language Abuse/ForeachCapture.ql
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user