Merge pull request #106 from dave-bartolomeo/dave/LF

Force LF line endings for .ql, .qll, .qlref, and .dbscheme
This commit is contained in:
Pavel Avgustinov
2018-08-27 10:04:53 +01:00
committed by GitHub
111 changed files with 7331 additions and 7312 deletions

View File

@@ -1,41 +1,41 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>In a loop condition, comparison of a value of a narrow type with a value of a wide type may
result in unexpected behavior if the wider value is sufficiently large (or small). This is because
the narrower value may overflow. This can lead to an infinite loop.</p>
</overview>
<recommendation>
<p>Change the types of the compared values so that the value on the narrower side of the
comparison is at least as wide as the value it is being compared with.</p>
</recommendation>
<example>
<p>In this example, <code>bytes_received</code> is compared against <code>max_get</code> in a
<code>while</code> loop. However, <code>bytes_received</code> is an <code>int16_t</code>, and
<code>max_get</code> is an <code>int32_t</code>. Because <code>max_get</code> is larger than
<code>INT16_MAX</code>, the loop condition is always <code>true</code>, so the loop never
terminates.</p>
<p>This problem is avoided in the 'GOOD' case because <code>bytes_received2</code> is an
<code>int32_t</code>, which is as wide as the type of <code>max_get</code>.</p>
<sample src="ComparisonWithWiderType.c" />
</example>
<references>
<li>
<a href="https://docs.microsoft.com/en-us/cpp/cpp/data-type-ranges">Data type ranges</a>
</li>
<li>
<a href="https://wiki.sei.cmu.edu/confluence/display/c/INT18-C.+Evaluate+integer+expressions+in+a+larger+size+before+comparing+or+assigning+to+that+size">INT18-C. Evaluate integer expressions in a larger size before comparing or assigning to that size </a>
</li>
</references>
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>In a loop condition, comparison of a value of a narrow type with a value of a wide type may
result in unexpected behavior if the wider value is sufficiently large (or small). This is because
the narrower value may overflow. This can lead to an infinite loop.</p>
</overview>
<recommendation>
<p>Change the types of the compared values so that the value on the narrower side of the
comparison is at least as wide as the value it is being compared with.</p>
</recommendation>
<example>
<p>In this example, <code>bytes_received</code> is compared against <code>max_get</code> in a
<code>while</code> loop. However, <code>bytes_received</code> is an <code>int16_t</code>, and
<code>max_get</code> is an <code>int32_t</code>. Because <code>max_get</code> is larger than
<code>INT16_MAX</code>, the loop condition is always <code>true</code>, so the loop never
terminates.</p>
<p>This problem is avoided in the 'GOOD' case because <code>bytes_received2</code> is an
<code>int32_t</code>, which is as wide as the type of <code>max_get</code>.</p>
<sample src="ComparisonWithWiderType.c" />
</example>
<references>
<li>
<a href="https://docs.microsoft.com/en-us/cpp/cpp/data-type-ranges">Data type ranges</a>
</li>
<li>
<a href="https://wiki.sei.cmu.edu/confluence/display/c/INT18-C.+Evaluate+integer+expressions+in+a+larger+size+before+comparing+or+assigning+to+that+size">INT18-C. Evaluate integer expressions in a larger size before comparing or assigning to that size </a>
</li>
</references>
</qhelp>

View File

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

View File

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

View File

@@ -1 +1 @@
import internal.IRImpl
import internal.IRImpl

View File

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

View File

@@ -1 +1 @@
import internal.Opcode
import internal.Opcode

View File

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

View File

@@ -1 +1 @@
import internal.PrintIRImpl
import internal.PrintIRImpl

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +1 @@
import IRConstruction as Construction
import IRConstruction as Construction

View File

@@ -1,3 +1,3 @@
private import IRImpl
import InstructionSanity
private import IRImpl
import InstructionSanity

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +1 @@
import internal.aliased_ssa.IRImpl
import internal.aliased_ssa.IRImpl

View File

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

View File

@@ -1 +1 @@
import internal.aliased_ssa.PrintIRImpl
import internal.aliased_ssa.PrintIRImpl

View File

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

View File

@@ -1 +1 @@
import internal.ssa.PrintIRImpl
import internal.ssa.PrintIRImpl

View File

@@ -1 +1 @@
import internal.ssa.IRImpl
import internal.ssa.IRImpl

View File

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

View File

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

View File

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

View File

@@ -1 +1 @@
import semmle.code.cpp.ssa.SSAIR as IR
import semmle.code.cpp.ssa.SSAIR as IR

View File

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

View File

@@ -1 +1 @@
import SSAConstruction as Construction
import SSAConstruction as Construction

View File

@@ -1,3 +1,3 @@
private import IRImpl
import InstructionSanity
private import IRImpl
import InstructionSanity

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +1 @@
import semmle.code.cpp.ir.IR as IR
import semmle.code.cpp.ir.IR as IR

View File

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

View File

@@ -1 +1 @@
import SSAConstruction as Construction
import SSAConstruction as Construction

View File

@@ -1,3 +1,3 @@
private import IRImpl
import InstructionSanity
private import IRImpl
import InstructionSanity

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +1 @@
semmle/code/cpp/ASTSanity.ql
semmle/code/cpp/ASTSanity.ql

View File

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

View File

@@ -1,7 +1,7 @@
/**
* @name InitializerAccesses
*/
import cpp
import cpp
from Initializer i, VariableAccess va
where i.getExpr().getAChild*() = va

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
import cpp
from Expr e
where e.isUnevaluated()
select e
import cpp
from Expr e
where e.isUnevaluated()
select e

View File

@@ -1,5 +1,5 @@
import cpp
from Expr e
where e.hasLValueToRValueConversion()
select e
import cpp
from Expr e
where e.hasLValueToRValueConversion()
select e

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import cpp
from Variable v
select v
import cpp
from Variable v
select v

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import Critical.MemoryFreed
from FreedExpr fe
select fe
import Critical.MemoryFreed
from FreedExpr fe
select fe

View File

@@ -1 +1 @@
Critical/NewArrayDeleteMismatch.ql
Critical/NewArrayDeleteMismatch.ql

View File

@@ -1 +1 @@
Critical/NewDeleteArrayMismatch.ql
Critical/NewDeleteArrayMismatch.ql

View File

@@ -1 +1 @@
Critical/NewFreeMismatch.ql
Critical/NewFreeMismatch.ql

View File

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