C++: Make IR dump and AST dump tests use the official graph query format

This commit is contained in:
Dave Bartolomeo
2018-08-07 11:34:37 -07:00
parent 692f416143
commit 3ebb7938f6
52 changed files with 21231 additions and 31544 deletions

View File

@@ -2,6 +2,7 @@
* @name Print AST
* @description Outputs a representation of the Abstract Syntax Tree.
* @id cpp/print-ast
* @kind graph
*/
import cpp

View File

@@ -2,11 +2,18 @@ import cpp
private newtype TPrintASTConfiguration = MkPrintASTConfiguration()
/**
* The query can extend this class to control which functions are printed.
*/
class PrintASTConfiguration extends TPrintASTConfiguration {
string toString() {
result = "PrintASTConfiguration"
}
/**
* Holds if the AST for `func` should be printed. By default, holds for all
* functions.
*/
predicate shouldPrintFunction(Function func) {
any()
}
@@ -18,165 +25,500 @@ private predicate shouldPrintFunction(Function func) {
)
}
private Locatable getAChild(Locatable parent) {
result = getChild(parent, _)
bindingset[s]
private string escapeString(string s) {
result = s.replaceAll("\\", "\\\\").replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll("\t", "\\t")
}
private Function getEnclosingFunction(Locatable ast) {
getAChild*(result) = ast
/**
* Due to extractor issues with ODR violations, a given AST may wind up with
* multiple locations. This predicate returns a single location - the one whose
* string representation comes first in lexicographical order.
*/
private Location getRepresentativeLocation(Locatable ast) {
result = rank[1](Location loc | loc = ast.getLocation() | loc order by loc.toString())
}
private int getEntryPointIndex(Function func) {
if func instanceof Constructor then
result = count(func.(Constructor).getAnInitializer())
else
result = 0
/**
* Most nodes are just a wrapper around `Locatable`, but we do synthesize new
* nodes for things like parameter lists and constructor init lists.
*/
private newtype TPrintASTNode =
TASTNode(Locatable ast) or
TParametersNode(Function func) or
TConstructorInitializersNode(Constructor ctor) {
ctor.hasEntryPoint()
} or
TDestructorDestructionsNode(Destructor dtor) {
dtor.hasEntryPoint()
}
/**
* A node in the output tree.
*/
class PrintASTNode extends TPrintASTNode {
abstract string toString();
/**
* Gets the child node at index `childIndex`. Child indices must be unique,
* but need not be contiguous (but see `getChildByRank`).
*/
abstract PrintASTNode getChild(int childIndex);
/**
* Holds if this node should be printed in the output. By default, all nodes
* within a function are printed, but the query can override
* `PrintASTConfiguration.shouldPrintFunction` to filter the output.
*/
final predicate shouldPrint() {
shouldPrintFunction(getEnclosingFunction())
}
/**
* Gets the children of this node.
*/
final PrintASTNode getAChild() {
result = getChild(_)
}
/**
* Gets the parent of this node, if any.
*/
final PrintASTNode getParent() {
result.getAChild() = this
}
/**
* Gets the location of this node in the source code.
*/
abstract Location getLocation();
/**
* Gets the value of the property of this node, where the name of the property
* is `key`.
*/
string getProperty(string key) {
key = "semmle.label" and
result = toString()
}
/**
* Gets the label for the edge from this node to the specified child. By
* default, this is just the index of the child, but subclasses can override
* this.
*/
string getChildEdgeLabel(int childIndex) {
exists(getChild(childIndex)) and
result = childIndex.toString()
}
/**
* Gets the `Function` that contains this node.
*/
private Function getEnclosingFunction() {
result = getParent*().(FunctionNode).getFunction()
}
}
private Locatable getChild(Locatable parent, int childIndex) {
exists(Function func, Stmt entryPoint |
parent = func and
result = entryPoint and
entryPoint = func.getEntryPoint() and
childIndex = getEntryPointIndex(func)
) or
exists(Function func, Expr childExpr |
parent = func and
result = childExpr and
/**
* A node representing an AST node.
*/
abstract class ASTNode extends PrintASTNode, TASTNode {
Locatable ast;
ASTNode() {
this = TASTNode(ast)
}
override string toString() {
result = ast.toString()
}
override final Location getLocation() {
result = getRepresentativeLocation(ast)
}
/**
* Gets the AST represented by this node.
*/
final Locatable getAST() {
result = ast
}
}
/**
* A node representing an `Expr`.
*/
class ExprNode extends ASTNode {
Expr expr;
ExprNode() {
expr = ast
}
override ASTNode getChild(int childIndex) {
result.getAST() = expr.getChild(childIndex).getFullyConverted()
}
override string getProperty(string key) {
result = super.getProperty(key) or
(
childExpr = func.(Constructor).getInitializer(childIndex) or
childExpr = func.(Destructor).getDestruction(childIndex - 1)
)
) or
exists(Stmt parentStmt |
parentStmt = parent and
key = "Value" and
result = getValue()
) or
(
parentStmt.getChild(childIndex).(Expr).getFullyConverted() = result or
parentStmt.getChild(childIndex).(Stmt) = result
key = "Type" and
result = expr.getType().toString()
) or
(
key = "ValueCategory" and
result = expr.getValueCategoryString()
)
) or
exists(Expr parentExpr, Expr childExpr |
parent = parentExpr and
result = childExpr and
childExpr = parentExpr.getChild(childIndex).getFullyConverted()
) or
exists(Conversion parentConv, Expr childExpr |
parent = parentConv and
result = childExpr and
childExpr = parentConv.getExpr() and
childIndex = 0
) or
exists(DeclStmt declStmt, DeclarationEntry childEntry |
parent = declStmt and
result = childEntry and
childEntry = declStmt.getDeclarationEntry(childIndex)
) or
exists(VariableDeclarationEntry declEntry, Initializer init |
parent = declEntry and
result = init and
init = declEntry.getVariable().getInitializer() and
childIndex = 0
) or
exists(Initializer init, Expr expr |
parent = init and
result = expr and
expr = init.getExpr().getFullyConverted() and
childIndex = 0
)
}
string getValue() {
result = expr.getValue()
}
}
private string getTypeString(Locatable ast) {
if ast instanceof Expr then (
exists(Expr expr |
expr = ast and
result = expr.getValueCategoryString() + ": " + expr.getType().toString()
/**
* A node representing a `StringLiteral`.
*/
class StringLiteralNode extends ExprNode {
StringLiteralNode() {
expr instanceof StringLiteral
}
override string toString() {
result = escapeString(expr.getValue())
}
override string getValue() {
result = "\"" + escapeString(expr.getValue()) + "\""
}
}
/**
* A node representing a `Conversion`.
*/
class ConversionNode extends ExprNode {
Conversion conv;
ConversionNode() {
conv = expr
}
override ASTNode getChild(int childIndex) {
childIndex = 0 and
result.getAST() = conv.getExpr()
}
override string getChildEdgeLabel(int childIndex) {
childIndex = 0 and result = "expr"
}
}
/**
* A node representing a `Cast`.
*/
class CastNode extends ConversionNode {
Cast cast;
CastNode() {
cast = conv
}
override string getProperty(string key) {
result = super.getProperty(key) or
(
key = "Conversion" and
result = cast.getSemanticConversionString()
)
)
else if ast instanceof DeclarationEntry then (
result = ast.(DeclarationEntry).getType().toString()
)
else (
result = ""
)
}
}
private string getExtraInfoString(Locatable ast) {
if ast instanceof Cast then (
result = ast.(Cast).getSemanticConversionString()
)
else (
result = ""
)
}
/**
* A node representing a `DeclarationEntry`.
*/
class DeclarationEntryNode extends ASTNode {
DeclarationEntry entry;
private string getValueString(Locatable ast) {
if exists(ast.(Expr).getValue()) then
result = "=" + ast.(Expr).getValue()
else
result = ""
}
DeclarationEntryNode() {
entry = ast
}
private Locatable getChildByRank(Locatable parent, int rankIndex) {
result = rank[rankIndex + 1](Locatable child, int id |
child = getChild(parent, id) |
child order by id
)
}
override PrintASTNode getChild(int childIndex) {
none()
}
language[monotonicAggregates]
private int getDescendantCount(Locatable ast) {
result = 1 + sum(Locatable child |
child = getChildByRank(ast, _) |
getDescendantCount(child)
)
}
private Locatable getParent(Locatable ast) {
ast = getAChild(result)
}
private int getUniqueId(Locatable ast) {
shouldPrintFunction(getEnclosingFunction(ast)) and
if not exists(getParent(ast)) then
result = 0
else
exists(Locatable parent |
parent = getParent(ast) and
if ast = getChildByRank(parent, 0) then
result = 1 + getUniqueId(parent)
else
exists(int childIndex, Locatable previousChild |
ast = getChildByRank(parent, childIndex) and
previousChild = getChildByRank(parent, childIndex - 1) and
result = getUniqueId(previousChild) +
getDescendantCount(previousChild)
)
override string getProperty(string key) {
result = super.getProperty(key) or
(
key = "Type" and
result = entry.getType().toString()
)
}
}
query predicate printAST(string functionLocation,
string function, int nodeId, int parentId, int childIndex, string ast,
string extra, string value, string type, string astLocation) {
exists(Function func, Locatable astNode |
shouldPrintFunction(func) and
func = getEnclosingFunction(astNode) and
nodeId = getUniqueId(astNode) and
if nodeId = 0 then (
parentId = -1 and
childIndex = 0
)
else (
exists(Locatable parent |
astNode = getChild(parent, childIndex) and
parentId = getUniqueId(parent)
/**
* A node representing a `VariableDeclarationEntry`.
*/
class VariableDeclarationEntryNode extends DeclarationEntryNode {
VariableDeclarationEntry varEntry;
VariableDeclarationEntryNode() {
varEntry = entry
}
override ASTNode getChild(int childIndex) {
childIndex = 0 and
result.getAST() = varEntry.getVariable().getInitializer()
}
override string getChildEdgeLabel(int childIndex) {
childIndex = 0 and result = "init"
}
}
/**
* A node representing a `Stmt`.
*/
class StmtNode extends ASTNode {
Stmt stmt;
StmtNode() {
stmt = ast
}
override ASTNode getChild(int childIndex) {
exists(Locatable child |
child = stmt.getChild(childIndex) and
(
result.getAST() = child.(Expr).getFullyConverted() or
result.getAST() = child.(Stmt)
)
) and
functionLocation = func.getLocation().toString() and
function = func.getFullSignature() and
ast = astNode.toString() and
extra = getExtraInfoString(astNode) and
value = getValueString(astNode) and
type = getTypeString(astNode) and
astLocation = astNode.getLocation().toString()
)
)
}
}
/**
* A node representing a `DeclStmt`.
*/
class DeclStmtNode extends StmtNode {
DeclStmt declStmt;
DeclStmtNode() {
declStmt = stmt
}
override ASTNode getChild(int childIndex) {
result.getAST() = declStmt.getDeclarationEntry(childIndex)
}
}
/**
* A node representing a `Parameter`.
*/
class ParameterNode extends ASTNode {
Parameter param;
ParameterNode() {
param = ast
}
override final PrintASTNode getChild(int childIndex) {
none()
}
override final string getProperty(string key) {
result = super.getProperty(key) or
(
key = "Type" and
result = param.getType().toString()
)
}
}
/**
* A node representing an `Initializer`.
*/
class InitializerNode extends ASTNode {
Initializer init;
InitializerNode() {
init = ast
}
override ASTNode getChild(int childIndex) {
childIndex = 0 and
result.getAST() = init.getExpr().getFullyConverted()
}
override string getChildEdgeLabel(int childIndex) {
childIndex = 0 and
result = "expr"
}
}
/**
* A node representing the parameters of a `Function`.
*/
class ParametersNode extends PrintASTNode, TParametersNode {
Function func;
ParametersNode() {
this = TParametersNode(func)
}
override final string toString() {
result = ""
}
override final Location getLocation() {
result = getRepresentativeLocation(func)
}
override ASTNode getChild(int childIndex) {
result.getAST() = func.getParameter(childIndex)
}
final Function getFunction() {
result = func
}
}
/**
* A node representing the initializer list of a `Constructor`.
*/
class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializersNode {
Constructor ctor;
ConstructorInitializersNode() {
this = TConstructorInitializersNode(ctor)
}
override final string toString() {
result = ""
}
override final Location getLocation() {
result = getRepresentativeLocation(ctor)
}
override final ASTNode getChild(int childIndex) {
result.getAST() = ctor.getInitializer(childIndex)
}
final Constructor getConstructor() {
result = ctor
}
}
/**
* A node representing the destruction list of a `Destructor`.
*/
class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNode {
Destructor dtor;
DestructorDestructionsNode() {
this = TDestructorDestructionsNode(dtor)
}
override final string toString() {
result = ""
}
override final Location getLocation() {
result = getRepresentativeLocation(dtor)
}
override final ASTNode getChild(int childIndex) {
result.getAST() = dtor.getDestruction(childIndex)
}
final Destructor getDestructor() {
result = dtor
}
}
/**
* A node representing a `Function`.
*/
class FunctionNode extends ASTNode {
Function func;
FunctionNode() {
func = ast
}
override string toString() {
result = func.getFullSignature()
}
override PrintASTNode getChild(int childIndex) {
(
childIndex = 0 and
result.(ParametersNode).getFunction() = func
) or
(
childIndex = 1 and
result.(ConstructorInitializersNode).getConstructor() = func
) or
(
childIndex = 2 and
result.(ASTNode).getAST() = func.getEntryPoint()
) or
(
childIndex = 3 and
result.(DestructorDestructionsNode).getDestructor() = func
)
}
override string getChildEdgeLabel(int childIndex) {
childIndex = 0 and result = "params" or
childIndex = 1 and result = "initializations" or
childIndex = 2 and result = "body" or
childIndex = 3 and result = "destructions"
}
private int getOrder() {
this = rank[result](FunctionNode node, Function function, Location loc |
node.getAST() = function and loc = getRepresentativeLocation(function) |
node order by
loc.getFile().toString(),
loc.getStartLine(),
loc.getStartColumn(),
function.getFullSignature()
)
}
override string getProperty(string key) {
result = super.getProperty(key) or
key = "semmle.order" and result = getOrder().toString()
}
final Function getFunction() {
result = func
}
}
query predicate nodes(PrintASTNode node, string key, string value) {
node.shouldPrint() and
value = node.getProperty(key)
}
query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) {
exists(int childIndex |
source.shouldPrint() and
target.shouldPrint() and
target = source.getChild(childIndex) and
(
key = "semmle.label" and value = source.getChildEdgeLabel(childIndex) or
key = "semmle.order" and value = childIndex.toString()
)
)
}
query predicate graphProperties(string key, string value) {
key = "semmle.graphKind" and value = "tree"
}

View File

@@ -0,0 +1,8 @@
/**
* @name Print IR
* @description Outputs a representation of the IR graph
* @id cpp/print-ir
* @kind graph
*/
import PrintIR

View File

@@ -1,81 +1,92 @@
private import IRInternal
private import IRBlockConstruction
import Instruction
import semmle.code.cpp.ir.EdgeKind
class IRBlock extends TIRBlock {
final string toString() {
result = getFirstInstruction(this).toString()
}
final Location getLocation() {
result = getFirstInstruction().getLocation()
}
final string getUniqueId() {
result = getFirstInstruction(this).getUniqueId()
}
final Instruction getInstruction(int index) {
result = getInstruction(this, index)
}
final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
}
final Instruction getAnInstruction() {
result = getInstruction(_) or
result = getAPhiInstruction()
}
final Instruction getFirstInstruction() {
result = getFirstInstruction(this)
}
final Instruction getLastInstruction() {
result = getInstruction(getInstructionCount() - 1)
}
final int getInstructionCount() {
result = strictcount(getInstruction(_))
}
final FunctionIR getFunctionIR() {
result = getFirstInstruction(this).getFunctionIR()
}
final Function getFunction() {
result = getFirstInstruction(this).getFunction()
}
final IRBlock getASuccessor() {
blockSuccessor(this, result)
}
final IRBlock getAPredecessor() {
blockSuccessor(result, this)
}
final IRBlock getSuccessor(EdgeKind kind) {
blockSuccessor(this, result, kind)
}
final predicate immediatelyDominates(IRBlock block) {
blockImmediatelyDominates(this, block)
}
final predicate strictlyDominates(IRBlock block) {
blockImmediatelyDominates+(this, block)
}
final predicate dominates(IRBlock block) {
strictlyDominates(block) or this = block
}
pragma[noinline]
final IRBlock dominanceFrontier() {
dominates(result.getAPredecessor()) and
not strictlyDominates(result)
}
}
private import IRInternal
private import IRBlockConstruction
import Instruction
import semmle.code.cpp.ir.EdgeKind
class IRBlock extends TIRBlock {
final string toString() {
result = getFirstInstruction(this).toString()
}
final Location getLocation() {
result = getFirstInstruction().getLocation()
}
final string getUniqueId() {
result = getFirstInstruction(this).getUniqueId()
}
/**
* Gets the zero-based index of the block within its function. This is used
* by debugging and printing code only.
*/
int getDisplayIndex() {
this = rank[result + 1](IRBlock funcBlock |
funcBlock.getFunction() = getFunction() |
funcBlock order by funcBlock.getUniqueId()
)
}
final Instruction getInstruction(int index) {
result = getInstruction(this, index)
}
final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
}
final Instruction getAnInstruction() {
result = getInstruction(_) or
result = getAPhiInstruction()
}
final Instruction getFirstInstruction() {
result = getFirstInstruction(this)
}
final Instruction getLastInstruction() {
result = getInstruction(getInstructionCount() - 1)
}
final int getInstructionCount() {
result = strictcount(getInstruction(_))
}
final FunctionIR getFunctionIR() {
result = getFirstInstruction(this).getFunctionIR()
}
final Function getFunction() {
result = getFirstInstruction(this).getFunction()
}
final IRBlock getASuccessor() {
blockSuccessor(this, result)
}
final IRBlock getAPredecessor() {
blockSuccessor(result, this)
}
final IRBlock getSuccessor(EdgeKind kind) {
blockSuccessor(this, result, kind)
}
final predicate immediatelyDominates(IRBlock block) {
blockImmediatelyDominates(this, block)
}
final predicate strictlyDominates(IRBlock block) {
blockImmediatelyDominates+(this, block)
}
final predicate dominates(IRBlock block) {
strictlyDominates(block) or this = block
}
pragma[noinline]
final IRBlock dominanceFrontier() {
dominates(result.getAPredecessor()) and
not strictlyDominates(result)
}
}

View File

@@ -90,8 +90,132 @@ class Instruction extends Construction::TInstruction {
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
}
string toString() {
result = opcode.toString()
final string toString() {
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
}
/**
* Gets a string describing the operation of this instruction. This includes
* the opcode and the immediate value, if any. For example:
*
* VariableAddress[x]
*/
final string getOperationString() {
if exists(getImmediateString()) then
result = opcode.toString() + "[" + getImmediateString() + "]"
else
result = opcode.toString()
}
/**
* Gets a string describing the immediate value of this instruction, if any.
*/
string getImmediateString() {
none()
}
private string getResultPrefix() {
if resultType instanceof VoidType then
result = "v"
else if hasMemoryResult() then
if isResultModeled() then
result = "m"
else
result = "mu"
else
result = "r"
}
/**
* Gets the zero-based index of this instruction within its block. This is
* used by debugging and printing code only.
*/
int getDisplayIndexInBlock() {
exists(IRBlock block |
block = getBlock() and
(
exists(int index, int phiCount |
phiCount = count(block.getAPhiInstruction()) and
this = block.getInstruction(index) and
result = index + phiCount
) or
(
this instanceof PhiInstruction and
this = rank[result + 1](PhiInstruction phiInstr |
phiInstr = block.getAPhiInstruction() |
phiInstr order by phiInstr.getUniqueId()
)
)
)
)
}
bindingset[type]
private string getValueCategoryString(string type) {
if isGLValue() then
result = "glval<" + type + ">"
else
result = type
}
private string getResultTypeString() {
exists(string valcat |
valcat = getValueCategoryString(resultType.toString()) and
if resultType instanceof UnknownType and exists(getResultSize()) then
result = valcat + "[" + getResultSize().toString() + "]"
else
result = valcat
)
}
/**
* Gets a human-readable string that uniquely identifies this instruction
* within the function. This string is used to refer to this instruction when
* printing IR dumps.
*
* Example: `r1_1`
*/
string getResultId() {
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
getDisplayIndexInBlock().toString()
}
/**
* Gets a string describing the result of this instruction, suitable for
* display in IR dumps. This consists of the result ID plus the type of the
* result.
*
* Example: `r1_1(int*)`
*/
final string getResultString() {
result = getResultId() + "(" + getResultTypeString() + ")"
}
/**
* Gets a string describing the specified operand, suitable for display in IR
* dumps. This consists of the result ID of the instruction consumed by the
* operand, plus a label identifying the operand kind.
*
* For example: `this:r3_5`
*/
string getOperandString(OperandTag tag) {
exists(Instruction operand |
operand = getOperand(tag) and
result = tag.getLabel() + operand.getResultId()
)
}
/**
* Gets a string describing the operands of this instruction, suitable for
* display in IR dumps.
*
* Example: `func:r3_4, this:r3_5`
*/
string getOperandsString() {
result = concat(OperandTag tag, Instruction operand |
operand = getOperand(tag) |
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
)
}
/**
@@ -312,8 +436,8 @@ class VariableInstruction extends Instruction {
var = Construction::getInstructionVariable(this)
}
override final string toString() {
result = super.toString() + "[" + var.toString() + "]"
override final string getImmediateString() {
result = var.toString()
}
final IRVariable getVariable() {
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
field = Construction::getInstructionField(this)
}
override final string toString() {
result = super.toString() + "[" + field.toString() + "]"
override final string getImmediateString() {
result = field.toString()
}
final Field getField() {
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
funcSymbol = Construction::getInstructionFunction(this)
}
override final string toString() {
result = super.toString() + "[" + funcSymbol.toString() + "]"
override final string getImmediateString() {
result = funcSymbol.toString()
}
final Function getFunctionSymbol() {
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
value = Construction::getInstructionConstantValue(this)
}
override final string toString() {
result = super.toString() + "[" + value + "]"
override final string getImmediateString() {
result = value
}
final string getValue() {
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
value = Construction::getInstructionStringLiteral(this)
}
override final string toString() {
result = super.toString() + "[" +
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
"]"
override final string getImmediateString() {
result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
}
final StringLiteral getValue() {
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
elementSize = Construction::getInstructionElementSize(this)
}
override final string toString() {
result = super.toString() + "[" + elementSize.toString() + "]"
override final string getImmediateString() {
result = elementSize.toString()
}
final int getElementSize() {
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
}
override final string toString() {
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]"
override final string getImmediateString() {
result = derivedClass.toString() + " : " + baseClass.toString()
}
/**
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
exceptionType = Construction::getInstructionExceptionType(this)
}
final override string toString() {
result = super.toString() + "[" + exceptionType.toString() + "]"
final override string getImmediateString() {
result = exceptionType.toString()
}
/**
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
opcode instanceof Opcode::UnmodeledUse
}
override string getOperandsString() {
result = "mu*"
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
tag instanceof UnmodeledUseOperand and
result instanceof UnmodeledMemoryAccess

View File

@@ -1,299 +1,312 @@
private import IRInternal
import Instruction
import IRBlock
import cpp
private newtype TOperandTag =
TLoadStoreAddressOperand() or
TCopySourceOperand() or
TUnaryOperand() or
TLeftOperand() or
TRightOperand() or
TReturnValueOperand() or
TExceptionOperand() or
TConditionOperand() or
TUnmodeledUseOperand() or
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) {
argIndex in [0..Construction::getMaxCallArgIndex()] or
exists(BuiltInOperation op |
exists(op.getChild(argIndex))
)
} or
TPhiOperand(IRBlock predecessorBlock) {
exists(PhiInstruction phi |
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
)
}
/**
* Identifies the kind of operand on an instruction. Each `Instruction` has at
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
* an `Instruction` is determined by the instruction's opcode.
*/
abstract class OperandTag extends TOperandTag {
abstract string toString();
abstract int getSortOrder();
}
// Note: individual subtypes are listed in the order that the operands should
// appear in the operand list of the instruction when printing.
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
override final string toString() {
result = "LoadStoreAddress"
}
override final int getSortOrder() {
result = 0
}
}
LoadStoreAddressOperand loadStoreAddressOperand() {
result = TLoadStoreAddressOperand()
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends OperandTag, TCopySourceOperand {
override final string toString() {
result = "CopySource"
}
override final int getSortOrder() {
result = 1
}
}
CopySourceOperand copySourceOperand() {
result = TCopySourceOperand()
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends OperandTag, TUnaryOperand {
override final string toString() {
result = "Unary"
}
override final int getSortOrder() {
result = 2
}
}
UnaryOperand unaryOperand() {
result = TUnaryOperand()
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends OperandTag, TLeftOperand {
override final string toString() {
result = "Left"
}
override final int getSortOrder() {
result = 3
}
}
LeftOperand leftOperand() {
result = TLeftOperand()
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends OperandTag, TRightOperand {
override final string toString() {
result = "Right"
}
override final int getSortOrder() {
result = 4
}
}
RightOperand rightOperand() {
result = TRightOperand()
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
override final string toString() {
result = "ReturnValue"
}
override final int getSortOrder() {
result = 5
}
}
ReturnValueOperand returnValueOperand() {
result = TReturnValueOperand()
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends OperandTag, TExceptionOperand {
override final string toString() {
result = "Exception"
}
override final int getSortOrder() {
result = 6
}
}
ExceptionOperand exceptionOperand() {
result = TExceptionOperand()
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends OperandTag, TConditionOperand {
override final string toString() {
result = "Condition"
}
override final int getSortOrder() {
result = 7
}
}
ConditionOperand conditionOperand() {
result = TConditionOperand()
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
override final string toString() {
result = "UnmodeledUse"
}
override final int getSortOrder() {
result = 8
}
}
UnmodeledUseOperand unmodeledUseOperand() {
result = TUnmodeledUseOperand()
}
/**
* The operand representing the target function of an `Invoke` instruction.
*/
class CallTargetOperand extends OperandTag, TCallTargetOperand {
override final string toString() {
result = "CallTarget"
}
override final int getSortOrder() {
result = 9
}
}
CallTargetOperand callTargetOperand() {
result = TCallTargetOperand()
}
/**
* An operand representing an argument to a function call. This includes both
* positional arguments (represented by `PositionalArgumentOperand`) and the
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
*/
abstract class ArgumentOperand extends OperandTag {
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
ThisArgumentOperand() {
this = TThisArgumentOperand()
}
override final string toString() {
result = "Arg(this)"
}
override final int getSortOrder() {
result = 10
}
}
ThisArgumentOperand thisArgumentOperand() {
result = TThisArgumentOperand()
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand,
TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
this = TPositionalArgumentOperand(argIndex)
}
override final string toString() {
result = "Arg(" + argIndex + ")"
}
override final int getSortOrder() {
result = 11 + argIndex
}
final int getArgIndex() {
result = argIndex
}
}
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
/**
* An operand of an SSA `Phi` instruction.
*/
class PhiOperand extends OperandTag, TPhiOperand {
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(predecessorBlock)
}
override final string toString() {
result = "Phi"
}
override final int getSortOrder() {
result = 11
}
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
}
PhiOperand phiOperand(IRBlock predecessorBlock) {
result = TPhiOperand(predecessorBlock)
}
private import IRInternal
import Instruction
import IRBlock
import cpp
private newtype TOperandTag =
TLoadStoreAddressOperand() or
TCopySourceOperand() or
TUnaryOperand() or
TLeftOperand() or
TRightOperand() or
TReturnValueOperand() or
TExceptionOperand() or
TConditionOperand() or
TUnmodeledUseOperand() or
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) {
argIndex in [0..Construction::getMaxCallArgIndex()] or
exists(BuiltInOperation op |
exists(op.getChild(argIndex))
)
} or
TPhiOperand(IRBlock predecessorBlock) {
exists(PhiInstruction phi |
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
)
}
/**
* Identifies the kind of operand on an instruction. Each `Instruction` has at
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
* an `Instruction` is determined by the instruction's opcode.
*/
abstract class OperandTag extends TOperandTag {
abstract string toString();
abstract int getSortOrder();
string getLabel() {
result = ""
}
}
// Note: individual subtypes are listed in the order that the operands should
// appear in the operand list of the instruction when printing.
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
override final string toString() {
result = "LoadStoreAddress"
}
override final int getSortOrder() {
result = 0
}
}
LoadStoreAddressOperand loadStoreAddressOperand() {
result = TLoadStoreAddressOperand()
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends OperandTag, TCopySourceOperand {
override final string toString() {
result = "CopySource"
}
override final int getSortOrder() {
result = 1
}
}
CopySourceOperand copySourceOperand() {
result = TCopySourceOperand()
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends OperandTag, TUnaryOperand {
override final string toString() {
result = "Unary"
}
override final int getSortOrder() {
result = 2
}
}
UnaryOperand unaryOperand() {
result = TUnaryOperand()
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends OperandTag, TLeftOperand {
override final string toString() {
result = "Left"
}
override final int getSortOrder() {
result = 3
}
}
LeftOperand leftOperand() {
result = TLeftOperand()
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends OperandTag, TRightOperand {
override final string toString() {
result = "Right"
}
override final int getSortOrder() {
result = 4
}
}
RightOperand rightOperand() {
result = TRightOperand()
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
override final string toString() {
result = "ReturnValue"
}
override final int getSortOrder() {
result = 5
}
}
ReturnValueOperand returnValueOperand() {
result = TReturnValueOperand()
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends OperandTag, TExceptionOperand {
override final string toString() {
result = "Exception"
}
override final int getSortOrder() {
result = 6
}
}
ExceptionOperand exceptionOperand() {
result = TExceptionOperand()
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends OperandTag, TConditionOperand {
override final string toString() {
result = "Condition"
}
override final int getSortOrder() {
result = 7
}
}
ConditionOperand conditionOperand() {
result = TConditionOperand()
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
override final string toString() {
result = "UnmodeledUse"
}
override final int getSortOrder() {
result = 8
}
}
UnmodeledUseOperand unmodeledUseOperand() {
result = TUnmodeledUseOperand()
}
/**
* The operand representing the target function of an `Invoke` instruction.
*/
class CallTargetOperand extends OperandTag, TCallTargetOperand {
override final string toString() {
result = "CallTarget"
}
override final int getSortOrder() {
result = 9
}
}
CallTargetOperand callTargetOperand() {
result = TCallTargetOperand()
}
/**
* An operand representing an argument to a function call. This includes both
* positional arguments (represented by `PositionalArgumentOperand`) and the
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
*/
abstract class ArgumentOperand extends OperandTag {
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
ThisArgumentOperand() {
this = TThisArgumentOperand()
}
override final string toString() {
result = "Arg(this)"
}
override final int getSortOrder() {
result = 10
}
override final string getLabel() {
result = "this:"
}
}
ThisArgumentOperand thisArgumentOperand() {
result = TThisArgumentOperand()
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand,
TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
this = TPositionalArgumentOperand(argIndex)
}
override final string toString() {
result = "Arg(" + argIndex + ")"
}
override final int getSortOrder() {
result = 11 + argIndex
}
final int getArgIndex() {
result = argIndex
}
}
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
/**
* An operand of an SSA `Phi` instruction.
*/
class PhiOperand extends OperandTag, TPhiOperand {
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(predecessorBlock)
}
override final string toString() {
result = "Phi"
}
override final int getSortOrder() {
result = 11 + getPredecessorBlock().getDisplayIndex()
}
override final string getLabel() {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
}
PhiOperand phiOperand(IRBlock predecessorBlock) {
result = TPhiOperand(predecessorBlock)
}

View File

@@ -1,175 +1,239 @@
private import IRImpl
import cpp
private int getInstructionIndexInBlock(Instruction instr) {
exists(IRBlock block |
block = instr.getBlock() and
private newtype TPrintableIRNode =
TPrintableFunctionIR(FunctionIR funcIR) or
TPrintableIRBlock(IRBlock block) or
TPrintableInstruction(Instruction instr)
/**
* A node to be emitted in the IR graph.
*/
abstract class PrintableIRNode extends TPrintableIRNode {
abstract string toString();
/**
* Gets the location to be emitted for the node.
*/
abstract Location getLocation();
/**
* Gets the label to be emitted for the node.
*/
abstract string getLabel();
/**
* Gets the order in which the node appears in its parent node.
*/
abstract int getOrder();
/**
* Gets the parent of this node.
*/
abstract PrintableIRNode getParent();
/**
* Gets the kind of graph represented by this node ("graph" or "tree").
*/
string getGraphKind() {
none()
}
/**
* Holds if this node should always be rendered as text, even in a graphical
* viewer.
*/
predicate forceText() {
none()
}
/**
* Gets the value of the node property with the specified key.
*/
string getProperty(string key) {
key = "semmle.label" and result = getLabel() or
key = "semmle.order" and result = getOrder().toString() or
key = "semmle.graphKind" and result = getGraphKind() or
key = "semmle.forceText" and forceText() and result = "true"
}
}
/**
* An IR graph node representing a `FunctionIR` object.
*/
class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
FunctionIR funcIR;
PrintableFunctionIR() {
this = TPrintableFunctionIR(funcIR)
}
override string toString() {
result = funcIR.toString()
}
override Location getLocation() {
result = funcIR.getLocation()
}
override string getLabel() {
result = funcIR.getFunction().getFullSignature()
}
override int getOrder() {
this = rank[result + 1](PrintableFunctionIR orderedFunc, Location location |
location = orderedFunc.getFunctionIR().getLocation() |
orderedFunc order by location.getFile().getURL(), location.getStartLine(),
location.getStartColumn(), orderedFunc.getLabel()
)
}
override final PrintableIRNode getParent() {
none()
}
final FunctionIR getFunctionIR() {
result = funcIR
}
}
/**
* An IR graph node representing an `IRBlock` object.
*/
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
IRBlock block;
PrintableIRBlock() {
this = TPrintableIRBlock(block)
}
override string toString() {
result = getLabel()
}
override Location getLocation() {
result = block.getLocation()
}
override string getLabel() {
result = "Block " + block.getDisplayIndex().toString()
}
override int getOrder() {
result = block.getDisplayIndex()
}
override final string getGraphKind() {
result = "tree"
}
override final predicate forceText() {
any()
}
override final PrintableFunctionIR getParent() {
result.getFunctionIR() = block.getFunctionIR()
}
final IRBlock getBlock() {
result = block
}
}
/**
* An IR graph node representing an `Instruction`.
*/
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
Instruction instr;
PrintableInstruction() {
this = TPrintableInstruction(instr)
}
override string toString() {
result = instr.toString()
}
override Location getLocation() {
result = instr.getLocation()
}
override string getLabel() {
exists(IRBlock block |
instr = block.getAnInstruction() and
exists(string resultString, string operationString, string operandsString,
int resultWidth, int operationWidth |
resultString = instr.getResultString() and
operationString = instr.getOperationString() and
operandsString = instr.getOperandsString() and
columnWidths(block, resultWidth, operationWidth) and
result = resultString + getPaddingString(resultWidth - resultString.length()) +
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
" : " + operandsString
)
)
}
override int getOrder() {
result = instr.getDisplayIndexInBlock()
}
override final PrintableIRBlock getParent() {
result.getBlock() = instr.getBlock()
}
final Instruction getInstruction() {
result = instr
}
}
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
}
private int maxColumnWidth() {
result = max(Instruction instr, int width |
width = instr.getResultString().length() or
width = instr.getOperationString().length() or
width = instr.getOperandsString().length() |
width)
}
private string getPaddingString(int n) {
n = 0 and result = "" or
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
}
query predicate nodes(PrintableIRNode node, string key, string value) {
value = node.getProperty(key)
}
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
aSucc = pred.getSuccessor(kind) |
aSucc order by kind.toString()
)
}
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
predBlock = pred.getBlock() and
succBlock = succ.getBlock() and
predBlock.getSuccessor(kind) = succBlock and
(
exists(int index, int phiCount |
phiCount = count(block.getAPhiInstruction()) and
instr = block.getInstruction(index) and
result = index + phiCount
(
key = "semmle.label" and
value = kind.toString()
) or
(
instr instanceof PhiInstruction and
instr = rank[result + 1](PhiInstruction phiInstr |
phiInstr = block.getAPhiInstruction() |
phiInstr order by phiInstr.getUniqueId()
)
key = "semmle.order" and
value = getSuccessorIndex(predBlock, succBlock).toString()
)
)
)
}
private string getInstructionResultId(Instruction instr) {
result = getResultPrefix(instr) + getBlockId(instr.getBlock()) + "_" +
getInstructionIndexInBlock(instr).toString()
}
private string getResultPrefix(Instruction instr) {
if instr.hasMemoryResult() then
if instr.isResultModeled() then
result = "@m"
else
result = "@mu"
else
result = "@r"
}
/**
* Gets the identifier of the specified function scope.
* Currently just returns the signature of the function.
*/
private string getScopeId(Function func) {
result = func.getFullSignature()
}
/**
* Gets the unique identifier of the block within its function.
* Currently returns a string representation of an integer in the range
* [0..numBlocks - 1].
*/
private string getBlockId(IRBlock block) {
exists(int rankIndex |
block = rank[rankIndex + 1](IRBlock funcBlock |
funcBlock.getFunction() = block.getFunction() |
funcBlock order by funcBlock.getUniqueId()
) and
result = rankIndex.toString()
)
}
/**
* Prints the full signature and qualified name for each scope. This is primarily
* so that post-processing tools can identify function overloads, which will have
* different signatures but the same qualified name.
*/
query predicate printIRGraphScopes(string scopeId, string qualifiedName) {
exists(FunctionIR ir, Function func |
func = ir.getFunction() and
scopeId = getScopeId(func) and
qualifiedName = func.getQualifiedName()
)
}
query predicate printIRGraphNodes(string scopeId, string blockId, string label, string location) {
exists(IRBlock block |
scopeId = getScopeId(block.getFunction()) and
blockId = getBlockId(block) and
label = "" and
location = ""
)
}
query predicate printIRGraphInstructions(string scopeId, string blockId,
string id, string label, string location) {
exists(IRBlock block, Instruction instr |
instr = block.getAnInstruction() and
label = instr.toString() and
location = instr.getLocation().toString() and
scopeId = getScopeId(block.getFunction()) and
blockId = getBlockId(block) and
id = getInstructionIndexInBlock(instr).toString()
)
}
query predicate printIRGraphEdges(string scopeId,
string predecessorId, string successorId, string label) {
exists(IRBlock predecessor, IRBlock successor, EdgeKind kind |
scopeId = getScopeId(predecessor.getFunction()) and
predecessor.getSuccessor(kind) = successor and
predecessorId = getBlockId(predecessor) and
successorId = getBlockId(successor) and
label = kind.toString()
)
}
private string getValueCategoryString(Instruction instr) {
if instr.isGLValue() then
result = "glval:"
else
result = ""
}
private string getResultTypeString(Instruction instr) {
exists(Type resultType, string valcat |
resultType = instr.getResultType() and
valcat = getValueCategoryString(instr) and
if resultType instanceof UnknownType and exists(instr.getResultSize()) then
result = valcat + resultType.toString() + "[" + instr.getResultSize().toString() + "]"
else
result = valcat + resultType.toString()
)
}
query predicate printIRGraphDestinationOperands(string scopeId, string blockId,
string instructionId, int operandId, string label) {
exists(IRBlock block, Instruction instr |
block.getAnInstruction() = instr and
scopeId = getScopeId(block.getFunction()) and
blockId = getBlockId(block) and
instructionId = getInstructionIndexInBlock(instr).toString() and
not instr.getResultType() instanceof VoidType and
operandId = 0 and
label = getInstructionResultId(instr) +
"(" + getResultTypeString(instr) + ")"
)
}
private string getOperandTagLabel(OperandTag tag) {
(
tag instanceof PhiOperand and
result = "from " + getBlockId(tag.(PhiOperand).getPredecessorBlock()) + ": "
)
or (
tag instanceof ThisArgumentOperand and
result = "this:"
)
or (
not tag instanceof PhiOperand and
not tag instanceof ThisArgumentOperand and
result = ""
)
}
query predicate printIRGraphSourceOperands(string scopeId, string blockId,
string instructionId, int operandId, string label) {
exists(IRBlock block, Instruction instr |
block.getAnInstruction() = instr and
blockId = getBlockId(block) and
scopeId = getScopeId(block.getFunction()) and
instructionId = getInstructionIndexInBlock(instr).toString() and
if (instr instanceof UnmodeledUseInstruction) then (
operandId = 0 and
label = "@mu*"
)
else (
exists(OperandTag tag, Instruction operandInstr |
operandInstr = instr.getOperand(tag) and
operandId = tag.getSortOrder() and
label = getOperandTagLabel(tag) +
getInstructionResultId(operandInstr)
)
)
)
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
parent = child.getParent()
}

View File

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

View File

@@ -0,0 +1,8 @@
/**
* @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,81 +1,92 @@
private import IRInternal
private import IRBlockConstruction
import Instruction
import semmle.code.cpp.ir.EdgeKind
class IRBlock extends TIRBlock {
final string toString() {
result = getFirstInstruction(this).toString()
}
final Location getLocation() {
result = getFirstInstruction().getLocation()
}
final string getUniqueId() {
result = getFirstInstruction(this).getUniqueId()
}
final Instruction getInstruction(int index) {
result = getInstruction(this, index)
}
final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
}
final Instruction getAnInstruction() {
result = getInstruction(_) or
result = getAPhiInstruction()
}
final Instruction getFirstInstruction() {
result = getFirstInstruction(this)
}
final Instruction getLastInstruction() {
result = getInstruction(getInstructionCount() - 1)
}
final int getInstructionCount() {
result = strictcount(getInstruction(_))
}
final FunctionIR getFunctionIR() {
result = getFirstInstruction(this).getFunctionIR()
}
final Function getFunction() {
result = getFirstInstruction(this).getFunction()
}
final IRBlock getASuccessor() {
blockSuccessor(this, result)
}
final IRBlock getAPredecessor() {
blockSuccessor(result, this)
}
final IRBlock getSuccessor(EdgeKind kind) {
blockSuccessor(this, result, kind)
}
final predicate immediatelyDominates(IRBlock block) {
blockImmediatelyDominates(this, block)
}
final predicate strictlyDominates(IRBlock block) {
blockImmediatelyDominates+(this, block)
}
final predicate dominates(IRBlock block) {
strictlyDominates(block) or this = block
}
pragma[noinline]
final IRBlock dominanceFrontier() {
dominates(result.getAPredecessor()) and
not strictlyDominates(result)
}
}
private import IRInternal
private import IRBlockConstruction
import Instruction
import semmle.code.cpp.ir.EdgeKind
class IRBlock extends TIRBlock {
final string toString() {
result = getFirstInstruction(this).toString()
}
final Location getLocation() {
result = getFirstInstruction().getLocation()
}
final string getUniqueId() {
result = getFirstInstruction(this).getUniqueId()
}
/**
* Gets the zero-based index of the block within its function. This is used
* by debugging and printing code only.
*/
int getDisplayIndex() {
this = rank[result + 1](IRBlock funcBlock |
funcBlock.getFunction() = getFunction() |
funcBlock order by funcBlock.getUniqueId()
)
}
final Instruction getInstruction(int index) {
result = getInstruction(this, index)
}
final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
}
final Instruction getAnInstruction() {
result = getInstruction(_) or
result = getAPhiInstruction()
}
final Instruction getFirstInstruction() {
result = getFirstInstruction(this)
}
final Instruction getLastInstruction() {
result = getInstruction(getInstructionCount() - 1)
}
final int getInstructionCount() {
result = strictcount(getInstruction(_))
}
final FunctionIR getFunctionIR() {
result = getFirstInstruction(this).getFunctionIR()
}
final Function getFunction() {
result = getFirstInstruction(this).getFunction()
}
final IRBlock getASuccessor() {
blockSuccessor(this, result)
}
final IRBlock getAPredecessor() {
blockSuccessor(result, this)
}
final IRBlock getSuccessor(EdgeKind kind) {
blockSuccessor(this, result, kind)
}
final predicate immediatelyDominates(IRBlock block) {
blockImmediatelyDominates(this, block)
}
final predicate strictlyDominates(IRBlock block) {
blockImmediatelyDominates+(this, block)
}
final predicate dominates(IRBlock block) {
strictlyDominates(block) or this = block
}
pragma[noinline]
final IRBlock dominanceFrontier() {
dominates(result.getAPredecessor()) and
not strictlyDominates(result)
}
}

View File

@@ -90,8 +90,132 @@ class Instruction extends Construction::TInstruction {
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
}
string toString() {
result = opcode.toString()
final string toString() {
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
}
/**
* Gets a string describing the operation of this instruction. This includes
* the opcode and the immediate value, if any. For example:
*
* VariableAddress[x]
*/
final string getOperationString() {
if exists(getImmediateString()) then
result = opcode.toString() + "[" + getImmediateString() + "]"
else
result = opcode.toString()
}
/**
* Gets a string describing the immediate value of this instruction, if any.
*/
string getImmediateString() {
none()
}
private string getResultPrefix() {
if resultType instanceof VoidType then
result = "v"
else if hasMemoryResult() then
if isResultModeled() then
result = "m"
else
result = "mu"
else
result = "r"
}
/**
* Gets the zero-based index of this instruction within its block. This is
* used by debugging and printing code only.
*/
int getDisplayIndexInBlock() {
exists(IRBlock block |
block = getBlock() and
(
exists(int index, int phiCount |
phiCount = count(block.getAPhiInstruction()) and
this = block.getInstruction(index) and
result = index + phiCount
) or
(
this instanceof PhiInstruction and
this = rank[result + 1](PhiInstruction phiInstr |
phiInstr = block.getAPhiInstruction() |
phiInstr order by phiInstr.getUniqueId()
)
)
)
)
}
bindingset[type]
private string getValueCategoryString(string type) {
if isGLValue() then
result = "glval<" + type + ">"
else
result = type
}
private string getResultTypeString() {
exists(string valcat |
valcat = getValueCategoryString(resultType.toString()) and
if resultType instanceof UnknownType and exists(getResultSize()) then
result = valcat + "[" + getResultSize().toString() + "]"
else
result = valcat
)
}
/**
* Gets a human-readable string that uniquely identifies this instruction
* within the function. This string is used to refer to this instruction when
* printing IR dumps.
*
* Example: `r1_1`
*/
string getResultId() {
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
getDisplayIndexInBlock().toString()
}
/**
* Gets a string describing the result of this instruction, suitable for
* display in IR dumps. This consists of the result ID plus the type of the
* result.
*
* Example: `r1_1(int*)`
*/
final string getResultString() {
result = getResultId() + "(" + getResultTypeString() + ")"
}
/**
* Gets a string describing the specified operand, suitable for display in IR
* dumps. This consists of the result ID of the instruction consumed by the
* operand, plus a label identifying the operand kind.
*
* For example: `this:r3_5`
*/
string getOperandString(OperandTag tag) {
exists(Instruction operand |
operand = getOperand(tag) and
result = tag.getLabel() + operand.getResultId()
)
}
/**
* Gets a string describing the operands of this instruction, suitable for
* display in IR dumps.
*
* Example: `func:r3_4, this:r3_5`
*/
string getOperandsString() {
result = concat(OperandTag tag, Instruction operand |
operand = getOperand(tag) |
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
)
}
/**
@@ -312,8 +436,8 @@ class VariableInstruction extends Instruction {
var = Construction::getInstructionVariable(this)
}
override final string toString() {
result = super.toString() + "[" + var.toString() + "]"
override final string getImmediateString() {
result = var.toString()
}
final IRVariable getVariable() {
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
field = Construction::getInstructionField(this)
}
override final string toString() {
result = super.toString() + "[" + field.toString() + "]"
override final string getImmediateString() {
result = field.toString()
}
final Field getField() {
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
funcSymbol = Construction::getInstructionFunction(this)
}
override final string toString() {
result = super.toString() + "[" + funcSymbol.toString() + "]"
override final string getImmediateString() {
result = funcSymbol.toString()
}
final Function getFunctionSymbol() {
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
value = Construction::getInstructionConstantValue(this)
}
override final string toString() {
result = super.toString() + "[" + value + "]"
override final string getImmediateString() {
result = value
}
final string getValue() {
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
value = Construction::getInstructionStringLiteral(this)
}
override final string toString() {
result = super.toString() + "[" +
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
"]"
override final string getImmediateString() {
result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
}
final StringLiteral getValue() {
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
elementSize = Construction::getInstructionElementSize(this)
}
override final string toString() {
result = super.toString() + "[" + elementSize.toString() + "]"
override final string getImmediateString() {
result = elementSize.toString()
}
final int getElementSize() {
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
}
override final string toString() {
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]"
override final string getImmediateString() {
result = derivedClass.toString() + " : " + baseClass.toString()
}
/**
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
exceptionType = Construction::getInstructionExceptionType(this)
}
final override string toString() {
result = super.toString() + "[" + exceptionType.toString() + "]"
final override string getImmediateString() {
result = exceptionType.toString()
}
/**
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
opcode instanceof Opcode::UnmodeledUse
}
override string getOperandsString() {
result = "mu*"
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
tag instanceof UnmodeledUseOperand and
result instanceof UnmodeledMemoryAccess

View File

@@ -1,299 +1,312 @@
private import IRInternal
import Instruction
import IRBlock
import cpp
private newtype TOperandTag =
TLoadStoreAddressOperand() or
TCopySourceOperand() or
TUnaryOperand() or
TLeftOperand() or
TRightOperand() or
TReturnValueOperand() or
TExceptionOperand() or
TConditionOperand() or
TUnmodeledUseOperand() or
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) {
argIndex in [0..Construction::getMaxCallArgIndex()] or
exists(BuiltInOperation op |
exists(op.getChild(argIndex))
)
} or
TPhiOperand(IRBlock predecessorBlock) {
exists(PhiInstruction phi |
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
)
}
/**
* Identifies the kind of operand on an instruction. Each `Instruction` has at
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
* an `Instruction` is determined by the instruction's opcode.
*/
abstract class OperandTag extends TOperandTag {
abstract string toString();
abstract int getSortOrder();
}
// Note: individual subtypes are listed in the order that the operands should
// appear in the operand list of the instruction when printing.
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
override final string toString() {
result = "LoadStoreAddress"
}
override final int getSortOrder() {
result = 0
}
}
LoadStoreAddressOperand loadStoreAddressOperand() {
result = TLoadStoreAddressOperand()
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends OperandTag, TCopySourceOperand {
override final string toString() {
result = "CopySource"
}
override final int getSortOrder() {
result = 1
}
}
CopySourceOperand copySourceOperand() {
result = TCopySourceOperand()
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends OperandTag, TUnaryOperand {
override final string toString() {
result = "Unary"
}
override final int getSortOrder() {
result = 2
}
}
UnaryOperand unaryOperand() {
result = TUnaryOperand()
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends OperandTag, TLeftOperand {
override final string toString() {
result = "Left"
}
override final int getSortOrder() {
result = 3
}
}
LeftOperand leftOperand() {
result = TLeftOperand()
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends OperandTag, TRightOperand {
override final string toString() {
result = "Right"
}
override final int getSortOrder() {
result = 4
}
}
RightOperand rightOperand() {
result = TRightOperand()
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
override final string toString() {
result = "ReturnValue"
}
override final int getSortOrder() {
result = 5
}
}
ReturnValueOperand returnValueOperand() {
result = TReturnValueOperand()
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends OperandTag, TExceptionOperand {
override final string toString() {
result = "Exception"
}
override final int getSortOrder() {
result = 6
}
}
ExceptionOperand exceptionOperand() {
result = TExceptionOperand()
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends OperandTag, TConditionOperand {
override final string toString() {
result = "Condition"
}
override final int getSortOrder() {
result = 7
}
}
ConditionOperand conditionOperand() {
result = TConditionOperand()
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
override final string toString() {
result = "UnmodeledUse"
}
override final int getSortOrder() {
result = 8
}
}
UnmodeledUseOperand unmodeledUseOperand() {
result = TUnmodeledUseOperand()
}
/**
* The operand representing the target function of an `Invoke` instruction.
*/
class CallTargetOperand extends OperandTag, TCallTargetOperand {
override final string toString() {
result = "CallTarget"
}
override final int getSortOrder() {
result = 9
}
}
CallTargetOperand callTargetOperand() {
result = TCallTargetOperand()
}
/**
* An operand representing an argument to a function call. This includes both
* positional arguments (represented by `PositionalArgumentOperand`) and the
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
*/
abstract class ArgumentOperand extends OperandTag {
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
ThisArgumentOperand() {
this = TThisArgumentOperand()
}
override final string toString() {
result = "Arg(this)"
}
override final int getSortOrder() {
result = 10
}
}
ThisArgumentOperand thisArgumentOperand() {
result = TThisArgumentOperand()
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand,
TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
this = TPositionalArgumentOperand(argIndex)
}
override final string toString() {
result = "Arg(" + argIndex + ")"
}
override final int getSortOrder() {
result = 11 + argIndex
}
final int getArgIndex() {
result = argIndex
}
}
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
/**
* An operand of an SSA `Phi` instruction.
*/
class PhiOperand extends OperandTag, TPhiOperand {
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(predecessorBlock)
}
override final string toString() {
result = "Phi"
}
override final int getSortOrder() {
result = 11
}
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
}
PhiOperand phiOperand(IRBlock predecessorBlock) {
result = TPhiOperand(predecessorBlock)
}
private import IRInternal
import Instruction
import IRBlock
import cpp
private newtype TOperandTag =
TLoadStoreAddressOperand() or
TCopySourceOperand() or
TUnaryOperand() or
TLeftOperand() or
TRightOperand() or
TReturnValueOperand() or
TExceptionOperand() or
TConditionOperand() or
TUnmodeledUseOperand() or
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) {
argIndex in [0..Construction::getMaxCallArgIndex()] or
exists(BuiltInOperation op |
exists(op.getChild(argIndex))
)
} or
TPhiOperand(IRBlock predecessorBlock) {
exists(PhiInstruction phi |
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
)
}
/**
* Identifies the kind of operand on an instruction. Each `Instruction` has at
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
* an `Instruction` is determined by the instruction's opcode.
*/
abstract class OperandTag extends TOperandTag {
abstract string toString();
abstract int getSortOrder();
string getLabel() {
result = ""
}
}
// Note: individual subtypes are listed in the order that the operands should
// appear in the operand list of the instruction when printing.
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
override final string toString() {
result = "LoadStoreAddress"
}
override final int getSortOrder() {
result = 0
}
}
LoadStoreAddressOperand loadStoreAddressOperand() {
result = TLoadStoreAddressOperand()
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends OperandTag, TCopySourceOperand {
override final string toString() {
result = "CopySource"
}
override final int getSortOrder() {
result = 1
}
}
CopySourceOperand copySourceOperand() {
result = TCopySourceOperand()
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends OperandTag, TUnaryOperand {
override final string toString() {
result = "Unary"
}
override final int getSortOrder() {
result = 2
}
}
UnaryOperand unaryOperand() {
result = TUnaryOperand()
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends OperandTag, TLeftOperand {
override final string toString() {
result = "Left"
}
override final int getSortOrder() {
result = 3
}
}
LeftOperand leftOperand() {
result = TLeftOperand()
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends OperandTag, TRightOperand {
override final string toString() {
result = "Right"
}
override final int getSortOrder() {
result = 4
}
}
RightOperand rightOperand() {
result = TRightOperand()
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
override final string toString() {
result = "ReturnValue"
}
override final int getSortOrder() {
result = 5
}
}
ReturnValueOperand returnValueOperand() {
result = TReturnValueOperand()
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends OperandTag, TExceptionOperand {
override final string toString() {
result = "Exception"
}
override final int getSortOrder() {
result = 6
}
}
ExceptionOperand exceptionOperand() {
result = TExceptionOperand()
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends OperandTag, TConditionOperand {
override final string toString() {
result = "Condition"
}
override final int getSortOrder() {
result = 7
}
}
ConditionOperand conditionOperand() {
result = TConditionOperand()
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
override final string toString() {
result = "UnmodeledUse"
}
override final int getSortOrder() {
result = 8
}
}
UnmodeledUseOperand unmodeledUseOperand() {
result = TUnmodeledUseOperand()
}
/**
* The operand representing the target function of an `Invoke` instruction.
*/
class CallTargetOperand extends OperandTag, TCallTargetOperand {
override final string toString() {
result = "CallTarget"
}
override final int getSortOrder() {
result = 9
}
}
CallTargetOperand callTargetOperand() {
result = TCallTargetOperand()
}
/**
* An operand representing an argument to a function call. This includes both
* positional arguments (represented by `PositionalArgumentOperand`) and the
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
*/
abstract class ArgumentOperand extends OperandTag {
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
ThisArgumentOperand() {
this = TThisArgumentOperand()
}
override final string toString() {
result = "Arg(this)"
}
override final int getSortOrder() {
result = 10
}
override final string getLabel() {
result = "this:"
}
}
ThisArgumentOperand thisArgumentOperand() {
result = TThisArgumentOperand()
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand,
TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
this = TPositionalArgumentOperand(argIndex)
}
override final string toString() {
result = "Arg(" + argIndex + ")"
}
override final int getSortOrder() {
result = 11 + argIndex
}
final int getArgIndex() {
result = argIndex
}
}
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
/**
* An operand of an SSA `Phi` instruction.
*/
class PhiOperand extends OperandTag, TPhiOperand {
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(predecessorBlock)
}
override final string toString() {
result = "Phi"
}
override final int getSortOrder() {
result = 11 + getPredecessorBlock().getDisplayIndex()
}
override final string getLabel() {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
}
PhiOperand phiOperand(IRBlock predecessorBlock) {
result = TPhiOperand(predecessorBlock)
}

View File

@@ -1,175 +1,239 @@
private import IRImpl
import cpp
private int getInstructionIndexInBlock(Instruction instr) {
exists(IRBlock block |
block = instr.getBlock() and
private newtype TPrintableIRNode =
TPrintableFunctionIR(FunctionIR funcIR) or
TPrintableIRBlock(IRBlock block) or
TPrintableInstruction(Instruction instr)
/**
* A node to be emitted in the IR graph.
*/
abstract class PrintableIRNode extends TPrintableIRNode {
abstract string toString();
/**
* Gets the location to be emitted for the node.
*/
abstract Location getLocation();
/**
* Gets the label to be emitted for the node.
*/
abstract string getLabel();
/**
* Gets the order in which the node appears in its parent node.
*/
abstract int getOrder();
/**
* Gets the parent of this node.
*/
abstract PrintableIRNode getParent();
/**
* Gets the kind of graph represented by this node ("graph" or "tree").
*/
string getGraphKind() {
none()
}
/**
* Holds if this node should always be rendered as text, even in a graphical
* viewer.
*/
predicate forceText() {
none()
}
/**
* Gets the value of the node property with the specified key.
*/
string getProperty(string key) {
key = "semmle.label" and result = getLabel() or
key = "semmle.order" and result = getOrder().toString() or
key = "semmle.graphKind" and result = getGraphKind() or
key = "semmle.forceText" and forceText() and result = "true"
}
}
/**
* An IR graph node representing a `FunctionIR` object.
*/
class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
FunctionIR funcIR;
PrintableFunctionIR() {
this = TPrintableFunctionIR(funcIR)
}
override string toString() {
result = funcIR.toString()
}
override Location getLocation() {
result = funcIR.getLocation()
}
override string getLabel() {
result = funcIR.getFunction().getFullSignature()
}
override int getOrder() {
this = rank[result + 1](PrintableFunctionIR orderedFunc, Location location |
location = orderedFunc.getFunctionIR().getLocation() |
orderedFunc order by location.getFile().getURL(), location.getStartLine(),
location.getStartColumn(), orderedFunc.getLabel()
)
}
override final PrintableIRNode getParent() {
none()
}
final FunctionIR getFunctionIR() {
result = funcIR
}
}
/**
* An IR graph node representing an `IRBlock` object.
*/
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
IRBlock block;
PrintableIRBlock() {
this = TPrintableIRBlock(block)
}
override string toString() {
result = getLabel()
}
override Location getLocation() {
result = block.getLocation()
}
override string getLabel() {
result = "Block " + block.getDisplayIndex().toString()
}
override int getOrder() {
result = block.getDisplayIndex()
}
override final string getGraphKind() {
result = "tree"
}
override final predicate forceText() {
any()
}
override final PrintableFunctionIR getParent() {
result.getFunctionIR() = block.getFunctionIR()
}
final IRBlock getBlock() {
result = block
}
}
/**
* An IR graph node representing an `Instruction`.
*/
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
Instruction instr;
PrintableInstruction() {
this = TPrintableInstruction(instr)
}
override string toString() {
result = instr.toString()
}
override Location getLocation() {
result = instr.getLocation()
}
override string getLabel() {
exists(IRBlock block |
instr = block.getAnInstruction() and
exists(string resultString, string operationString, string operandsString,
int resultWidth, int operationWidth |
resultString = instr.getResultString() and
operationString = instr.getOperationString() and
operandsString = instr.getOperandsString() and
columnWidths(block, resultWidth, operationWidth) and
result = resultString + getPaddingString(resultWidth - resultString.length()) +
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
" : " + operandsString
)
)
}
override int getOrder() {
result = instr.getDisplayIndexInBlock()
}
override final PrintableIRBlock getParent() {
result.getBlock() = instr.getBlock()
}
final Instruction getInstruction() {
result = instr
}
}
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
}
private int maxColumnWidth() {
result = max(Instruction instr, int width |
width = instr.getResultString().length() or
width = instr.getOperationString().length() or
width = instr.getOperandsString().length() |
width)
}
private string getPaddingString(int n) {
n = 0 and result = "" or
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
}
query predicate nodes(PrintableIRNode node, string key, string value) {
value = node.getProperty(key)
}
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
aSucc = pred.getSuccessor(kind) |
aSucc order by kind.toString()
)
}
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
predBlock = pred.getBlock() and
succBlock = succ.getBlock() and
predBlock.getSuccessor(kind) = succBlock and
(
exists(int index, int phiCount |
phiCount = count(block.getAPhiInstruction()) and
instr = block.getInstruction(index) and
result = index + phiCount
(
key = "semmle.label" and
value = kind.toString()
) or
(
instr instanceof PhiInstruction and
instr = rank[result + 1](PhiInstruction phiInstr |
phiInstr = block.getAPhiInstruction() |
phiInstr order by phiInstr.getUniqueId()
)
key = "semmle.order" and
value = getSuccessorIndex(predBlock, succBlock).toString()
)
)
)
}
private string getInstructionResultId(Instruction instr) {
result = getResultPrefix(instr) + getBlockId(instr.getBlock()) + "_" +
getInstructionIndexInBlock(instr).toString()
}
private string getResultPrefix(Instruction instr) {
if instr.hasMemoryResult() then
if instr.isResultModeled() then
result = "@m"
else
result = "@mu"
else
result = "@r"
}
/**
* Gets the identifier of the specified function scope.
* Currently just returns the signature of the function.
*/
private string getScopeId(Function func) {
result = func.getFullSignature()
}
/**
* Gets the unique identifier of the block within its function.
* Currently returns a string representation of an integer in the range
* [0..numBlocks - 1].
*/
private string getBlockId(IRBlock block) {
exists(int rankIndex |
block = rank[rankIndex + 1](IRBlock funcBlock |
funcBlock.getFunction() = block.getFunction() |
funcBlock order by funcBlock.getUniqueId()
) and
result = rankIndex.toString()
)
}
/**
* Prints the full signature and qualified name for each scope. This is primarily
* so that post-processing tools can identify function overloads, which will have
* different signatures but the same qualified name.
*/
query predicate printIRGraphScopes(string scopeId, string qualifiedName) {
exists(FunctionIR ir, Function func |
func = ir.getFunction() and
scopeId = getScopeId(func) and
qualifiedName = func.getQualifiedName()
)
}
query predicate printIRGraphNodes(string scopeId, string blockId, string label, string location) {
exists(IRBlock block |
scopeId = getScopeId(block.getFunction()) and
blockId = getBlockId(block) and
label = "" and
location = ""
)
}
query predicate printIRGraphInstructions(string scopeId, string blockId,
string id, string label, string location) {
exists(IRBlock block, Instruction instr |
instr = block.getAnInstruction() and
label = instr.toString() and
location = instr.getLocation().toString() and
scopeId = getScopeId(block.getFunction()) and
blockId = getBlockId(block) and
id = getInstructionIndexInBlock(instr).toString()
)
}
query predicate printIRGraphEdges(string scopeId,
string predecessorId, string successorId, string label) {
exists(IRBlock predecessor, IRBlock successor, EdgeKind kind |
scopeId = getScopeId(predecessor.getFunction()) and
predecessor.getSuccessor(kind) = successor and
predecessorId = getBlockId(predecessor) and
successorId = getBlockId(successor) and
label = kind.toString()
)
}
private string getValueCategoryString(Instruction instr) {
if instr.isGLValue() then
result = "glval:"
else
result = ""
}
private string getResultTypeString(Instruction instr) {
exists(Type resultType, string valcat |
resultType = instr.getResultType() and
valcat = getValueCategoryString(instr) and
if resultType instanceof UnknownType and exists(instr.getResultSize()) then
result = valcat + resultType.toString() + "[" + instr.getResultSize().toString() + "]"
else
result = valcat + resultType.toString()
)
}
query predicate printIRGraphDestinationOperands(string scopeId, string blockId,
string instructionId, int operandId, string label) {
exists(IRBlock block, Instruction instr |
block.getAnInstruction() = instr and
scopeId = getScopeId(block.getFunction()) and
blockId = getBlockId(block) and
instructionId = getInstructionIndexInBlock(instr).toString() and
not instr.getResultType() instanceof VoidType and
operandId = 0 and
label = getInstructionResultId(instr) +
"(" + getResultTypeString(instr) + ")"
)
}
private string getOperandTagLabel(OperandTag tag) {
(
tag instanceof PhiOperand and
result = "from " + getBlockId(tag.(PhiOperand).getPredecessorBlock()) + ": "
)
or (
tag instanceof ThisArgumentOperand and
result = "this:"
)
or (
not tag instanceof PhiOperand and
not tag instanceof ThisArgumentOperand and
result = ""
)
}
query predicate printIRGraphSourceOperands(string scopeId, string blockId,
string instructionId, int operandId, string label) {
exists(IRBlock block, Instruction instr |
block.getAnInstruction() = instr and
blockId = getBlockId(block) and
scopeId = getScopeId(block.getFunction()) and
instructionId = getInstructionIndexInBlock(instr).toString() and
if (instr instanceof UnmodeledUseInstruction) then (
operandId = 0 and
label = "@mu*"
)
else (
exists(OperandTag tag, Instruction operandInstr |
operandInstr = instr.getOperand(tag) and
operandId = tag.getSortOrder() and
label = getOperandTagLabel(tag) +
getInstructionResultId(operandInstr)
)
)
)
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
parent = child.getParent()
}

View File

@@ -1,81 +1,92 @@
private import IRInternal
private import IRBlockConstruction
import Instruction
import semmle.code.cpp.ir.EdgeKind
class IRBlock extends TIRBlock {
final string toString() {
result = getFirstInstruction(this).toString()
}
final Location getLocation() {
result = getFirstInstruction().getLocation()
}
final string getUniqueId() {
result = getFirstInstruction(this).getUniqueId()
}
final Instruction getInstruction(int index) {
result = getInstruction(this, index)
}
final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
}
final Instruction getAnInstruction() {
result = getInstruction(_) or
result = getAPhiInstruction()
}
final Instruction getFirstInstruction() {
result = getFirstInstruction(this)
}
final Instruction getLastInstruction() {
result = getInstruction(getInstructionCount() - 1)
}
final int getInstructionCount() {
result = strictcount(getInstruction(_))
}
final FunctionIR getFunctionIR() {
result = getFirstInstruction(this).getFunctionIR()
}
final Function getFunction() {
result = getFirstInstruction(this).getFunction()
}
final IRBlock getASuccessor() {
blockSuccessor(this, result)
}
final IRBlock getAPredecessor() {
blockSuccessor(result, this)
}
final IRBlock getSuccessor(EdgeKind kind) {
blockSuccessor(this, result, kind)
}
final predicate immediatelyDominates(IRBlock block) {
blockImmediatelyDominates(this, block)
}
final predicate strictlyDominates(IRBlock block) {
blockImmediatelyDominates+(this, block)
}
final predicate dominates(IRBlock block) {
strictlyDominates(block) or this = block
}
pragma[noinline]
final IRBlock dominanceFrontier() {
dominates(result.getAPredecessor()) and
not strictlyDominates(result)
}
}
private import IRInternal
private import IRBlockConstruction
import Instruction
import semmle.code.cpp.ir.EdgeKind
class IRBlock extends TIRBlock {
final string toString() {
result = getFirstInstruction(this).toString()
}
final Location getLocation() {
result = getFirstInstruction().getLocation()
}
final string getUniqueId() {
result = getFirstInstruction(this).getUniqueId()
}
/**
* Gets the zero-based index of the block within its function. This is used
* by debugging and printing code only.
*/
int getDisplayIndex() {
this = rank[result + 1](IRBlock funcBlock |
funcBlock.getFunction() = getFunction() |
funcBlock order by funcBlock.getUniqueId()
)
}
final Instruction getInstruction(int index) {
result = getInstruction(this, index)
}
final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
}
final Instruction getAnInstruction() {
result = getInstruction(_) or
result = getAPhiInstruction()
}
final Instruction getFirstInstruction() {
result = getFirstInstruction(this)
}
final Instruction getLastInstruction() {
result = getInstruction(getInstructionCount() - 1)
}
final int getInstructionCount() {
result = strictcount(getInstruction(_))
}
final FunctionIR getFunctionIR() {
result = getFirstInstruction(this).getFunctionIR()
}
final Function getFunction() {
result = getFirstInstruction(this).getFunction()
}
final IRBlock getASuccessor() {
blockSuccessor(this, result)
}
final IRBlock getAPredecessor() {
blockSuccessor(result, this)
}
final IRBlock getSuccessor(EdgeKind kind) {
blockSuccessor(this, result, kind)
}
final predicate immediatelyDominates(IRBlock block) {
blockImmediatelyDominates(this, block)
}
final predicate strictlyDominates(IRBlock block) {
blockImmediatelyDominates+(this, block)
}
final predicate dominates(IRBlock block) {
strictlyDominates(block) or this = block
}
pragma[noinline]
final IRBlock dominanceFrontier() {
dominates(result.getAPredecessor()) and
not strictlyDominates(result)
}
}

View File

@@ -90,8 +90,132 @@ class Instruction extends Construction::TInstruction {
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
}
string toString() {
result = opcode.toString()
final string toString() {
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
}
/**
* Gets a string describing the operation of this instruction. This includes
* the opcode and the immediate value, if any. For example:
*
* VariableAddress[x]
*/
final string getOperationString() {
if exists(getImmediateString()) then
result = opcode.toString() + "[" + getImmediateString() + "]"
else
result = opcode.toString()
}
/**
* Gets a string describing the immediate value of this instruction, if any.
*/
string getImmediateString() {
none()
}
private string getResultPrefix() {
if resultType instanceof VoidType then
result = "v"
else if hasMemoryResult() then
if isResultModeled() then
result = "m"
else
result = "mu"
else
result = "r"
}
/**
* Gets the zero-based index of this instruction within its block. This is
* used by debugging and printing code only.
*/
int getDisplayIndexInBlock() {
exists(IRBlock block |
block = getBlock() and
(
exists(int index, int phiCount |
phiCount = count(block.getAPhiInstruction()) and
this = block.getInstruction(index) and
result = index + phiCount
) or
(
this instanceof PhiInstruction and
this = rank[result + 1](PhiInstruction phiInstr |
phiInstr = block.getAPhiInstruction() |
phiInstr order by phiInstr.getUniqueId()
)
)
)
)
}
bindingset[type]
private string getValueCategoryString(string type) {
if isGLValue() then
result = "glval<" + type + ">"
else
result = type
}
private string getResultTypeString() {
exists(string valcat |
valcat = getValueCategoryString(resultType.toString()) and
if resultType instanceof UnknownType and exists(getResultSize()) then
result = valcat + "[" + getResultSize().toString() + "]"
else
result = valcat
)
}
/**
* Gets a human-readable string that uniquely identifies this instruction
* within the function. This string is used to refer to this instruction when
* printing IR dumps.
*
* Example: `r1_1`
*/
string getResultId() {
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
getDisplayIndexInBlock().toString()
}
/**
* Gets a string describing the result of this instruction, suitable for
* display in IR dumps. This consists of the result ID plus the type of the
* result.
*
* Example: `r1_1(int*)`
*/
final string getResultString() {
result = getResultId() + "(" + getResultTypeString() + ")"
}
/**
* Gets a string describing the specified operand, suitable for display in IR
* dumps. This consists of the result ID of the instruction consumed by the
* operand, plus a label identifying the operand kind.
*
* For example: `this:r3_5`
*/
string getOperandString(OperandTag tag) {
exists(Instruction operand |
operand = getOperand(tag) and
result = tag.getLabel() + operand.getResultId()
)
}
/**
* Gets a string describing the operands of this instruction, suitable for
* display in IR dumps.
*
* Example: `func:r3_4, this:r3_5`
*/
string getOperandsString() {
result = concat(OperandTag tag, Instruction operand |
operand = getOperand(tag) |
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
)
}
/**
@@ -312,8 +436,8 @@ class VariableInstruction extends Instruction {
var = Construction::getInstructionVariable(this)
}
override final string toString() {
result = super.toString() + "[" + var.toString() + "]"
override final string getImmediateString() {
result = var.toString()
}
final IRVariable getVariable() {
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
field = Construction::getInstructionField(this)
}
override final string toString() {
result = super.toString() + "[" + field.toString() + "]"
override final string getImmediateString() {
result = field.toString()
}
final Field getField() {
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
funcSymbol = Construction::getInstructionFunction(this)
}
override final string toString() {
result = super.toString() + "[" + funcSymbol.toString() + "]"
override final string getImmediateString() {
result = funcSymbol.toString()
}
final Function getFunctionSymbol() {
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
value = Construction::getInstructionConstantValue(this)
}
override final string toString() {
result = super.toString() + "[" + value + "]"
override final string getImmediateString() {
result = value
}
final string getValue() {
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
value = Construction::getInstructionStringLiteral(this)
}
override final string toString() {
result = super.toString() + "[" +
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
"]"
override final string getImmediateString() {
result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
}
final StringLiteral getValue() {
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
elementSize = Construction::getInstructionElementSize(this)
}
override final string toString() {
result = super.toString() + "[" + elementSize.toString() + "]"
override final string getImmediateString() {
result = elementSize.toString()
}
final int getElementSize() {
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Construction::getInstructionInheritance(this, baseClass, derivedClass)
}
override final string toString() {
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]"
override final string getImmediateString() {
result = derivedClass.toString() + " : " + baseClass.toString()
}
/**
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
exceptionType = Construction::getInstructionExceptionType(this)
}
final override string toString() {
result = super.toString() + "[" + exceptionType.toString() + "]"
final override string getImmediateString() {
result = exceptionType.toString()
}
/**
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
opcode instanceof Opcode::UnmodeledUse
}
override string getOperandsString() {
result = "mu*"
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
tag instanceof UnmodeledUseOperand and
result instanceof UnmodeledMemoryAccess

View File

@@ -1,299 +1,312 @@
private import IRInternal
import Instruction
import IRBlock
import cpp
private newtype TOperandTag =
TLoadStoreAddressOperand() or
TCopySourceOperand() or
TUnaryOperand() or
TLeftOperand() or
TRightOperand() or
TReturnValueOperand() or
TExceptionOperand() or
TConditionOperand() or
TUnmodeledUseOperand() or
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) {
argIndex in [0..Construction::getMaxCallArgIndex()] or
exists(BuiltInOperation op |
exists(op.getChild(argIndex))
)
} or
TPhiOperand(IRBlock predecessorBlock) {
exists(PhiInstruction phi |
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
)
}
/**
* Identifies the kind of operand on an instruction. Each `Instruction` has at
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
* an `Instruction` is determined by the instruction's opcode.
*/
abstract class OperandTag extends TOperandTag {
abstract string toString();
abstract int getSortOrder();
}
// Note: individual subtypes are listed in the order that the operands should
// appear in the operand list of the instruction when printing.
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
override final string toString() {
result = "LoadStoreAddress"
}
override final int getSortOrder() {
result = 0
}
}
LoadStoreAddressOperand loadStoreAddressOperand() {
result = TLoadStoreAddressOperand()
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends OperandTag, TCopySourceOperand {
override final string toString() {
result = "CopySource"
}
override final int getSortOrder() {
result = 1
}
}
CopySourceOperand copySourceOperand() {
result = TCopySourceOperand()
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends OperandTag, TUnaryOperand {
override final string toString() {
result = "Unary"
}
override final int getSortOrder() {
result = 2
}
}
UnaryOperand unaryOperand() {
result = TUnaryOperand()
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends OperandTag, TLeftOperand {
override final string toString() {
result = "Left"
}
override final int getSortOrder() {
result = 3
}
}
LeftOperand leftOperand() {
result = TLeftOperand()
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends OperandTag, TRightOperand {
override final string toString() {
result = "Right"
}
override final int getSortOrder() {
result = 4
}
}
RightOperand rightOperand() {
result = TRightOperand()
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
override final string toString() {
result = "ReturnValue"
}
override final int getSortOrder() {
result = 5
}
}
ReturnValueOperand returnValueOperand() {
result = TReturnValueOperand()
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends OperandTag, TExceptionOperand {
override final string toString() {
result = "Exception"
}
override final int getSortOrder() {
result = 6
}
}
ExceptionOperand exceptionOperand() {
result = TExceptionOperand()
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends OperandTag, TConditionOperand {
override final string toString() {
result = "Condition"
}
override final int getSortOrder() {
result = 7
}
}
ConditionOperand conditionOperand() {
result = TConditionOperand()
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
override final string toString() {
result = "UnmodeledUse"
}
override final int getSortOrder() {
result = 8
}
}
UnmodeledUseOperand unmodeledUseOperand() {
result = TUnmodeledUseOperand()
}
/**
* The operand representing the target function of an `Invoke` instruction.
*/
class CallTargetOperand extends OperandTag, TCallTargetOperand {
override final string toString() {
result = "CallTarget"
}
override final int getSortOrder() {
result = 9
}
}
CallTargetOperand callTargetOperand() {
result = TCallTargetOperand()
}
/**
* An operand representing an argument to a function call. This includes both
* positional arguments (represented by `PositionalArgumentOperand`) and the
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
*/
abstract class ArgumentOperand extends OperandTag {
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
ThisArgumentOperand() {
this = TThisArgumentOperand()
}
override final string toString() {
result = "Arg(this)"
}
override final int getSortOrder() {
result = 10
}
}
ThisArgumentOperand thisArgumentOperand() {
result = TThisArgumentOperand()
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand,
TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
this = TPositionalArgumentOperand(argIndex)
}
override final string toString() {
result = "Arg(" + argIndex + ")"
}
override final int getSortOrder() {
result = 11 + argIndex
}
final int getArgIndex() {
result = argIndex
}
}
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
/**
* An operand of an SSA `Phi` instruction.
*/
class PhiOperand extends OperandTag, TPhiOperand {
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(predecessorBlock)
}
override final string toString() {
result = "Phi"
}
override final int getSortOrder() {
result = 11
}
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
}
PhiOperand phiOperand(IRBlock predecessorBlock) {
result = TPhiOperand(predecessorBlock)
}
private import IRInternal
import Instruction
import IRBlock
import cpp
private newtype TOperandTag =
TLoadStoreAddressOperand() or
TCopySourceOperand() or
TUnaryOperand() or
TLeftOperand() or
TRightOperand() or
TReturnValueOperand() or
TExceptionOperand() or
TConditionOperand() or
TUnmodeledUseOperand() or
TCallTargetOperand() or
TThisArgumentOperand() or
TPositionalArgumentOperand(int argIndex) {
argIndex in [0..Construction::getMaxCallArgIndex()] or
exists(BuiltInOperation op |
exists(op.getChild(argIndex))
)
} or
TPhiOperand(IRBlock predecessorBlock) {
exists(PhiInstruction phi |
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
)
}
/**
* Identifies the kind of operand on an instruction. Each `Instruction` has at
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
* an `Instruction` is determined by the instruction's opcode.
*/
abstract class OperandTag extends TOperandTag {
abstract string toString();
abstract int getSortOrder();
string getLabel() {
result = ""
}
}
// Note: individual subtypes are listed in the order that the operands should
// appear in the operand list of the instruction when printing.
/**
* The address operand of an instruction that loads or stores a value from
* memory (e.g. `Load`, `Store`).
*/
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
override final string toString() {
result = "LoadStoreAddress"
}
override final int getSortOrder() {
result = 0
}
}
LoadStoreAddressOperand loadStoreAddressOperand() {
result = TLoadStoreAddressOperand()
}
/**
* The source value operand of an instruction that copies this value to its
* result (e.g. `Copy`, `Load`, `Store`).
*/
class CopySourceOperand extends OperandTag, TCopySourceOperand {
override final string toString() {
result = "CopySource"
}
override final int getSortOrder() {
result = 1
}
}
CopySourceOperand copySourceOperand() {
result = TCopySourceOperand()
}
/**
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
*/
class UnaryOperand extends OperandTag, TUnaryOperand {
override final string toString() {
result = "Unary"
}
override final int getSortOrder() {
result = 2
}
}
UnaryOperand unaryOperand() {
result = TUnaryOperand()
}
/**
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class LeftOperand extends OperandTag, TLeftOperand {
override final string toString() {
result = "Left"
}
override final int getSortOrder() {
result = 3
}
}
LeftOperand leftOperand() {
result = TLeftOperand()
}
/**
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
*/
class RightOperand extends OperandTag, TRightOperand {
override final string toString() {
result = "Right"
}
override final int getSortOrder() {
result = 4
}
}
RightOperand rightOperand() {
result = TRightOperand()
}
/**
* The return value operand of a `ReturnValue` instruction.
*/
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
override final string toString() {
result = "ReturnValue"
}
override final int getSortOrder() {
result = 5
}
}
ReturnValueOperand returnValueOperand() {
result = TReturnValueOperand()
}
/**
* The exception thrown by a `ThrowValue` instruction.
*/
class ExceptionOperand extends OperandTag, TExceptionOperand {
override final string toString() {
result = "Exception"
}
override final int getSortOrder() {
result = 6
}
}
ExceptionOperand exceptionOperand() {
result = TExceptionOperand()
}
/**
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
*/
class ConditionOperand extends OperandTag, TConditionOperand {
override final string toString() {
result = "Condition"
}
override final int getSortOrder() {
result = 7
}
}
ConditionOperand conditionOperand() {
result = TConditionOperand()
}
/**
* An operand of the special `UnmodeledUse` instruction, representing a value
* whose set of uses is unknown.
*/
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
override final string toString() {
result = "UnmodeledUse"
}
override final int getSortOrder() {
result = 8
}
}
UnmodeledUseOperand unmodeledUseOperand() {
result = TUnmodeledUseOperand()
}
/**
* The operand representing the target function of an `Invoke` instruction.
*/
class CallTargetOperand extends OperandTag, TCallTargetOperand {
override final string toString() {
result = "CallTarget"
}
override final int getSortOrder() {
result = 9
}
}
CallTargetOperand callTargetOperand() {
result = TCallTargetOperand()
}
/**
* An operand representing an argument to a function call. This includes both
* positional arguments (represented by `PositionalArgumentOperand`) and the
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
*/
abstract class ArgumentOperand extends OperandTag {
}
/**
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
ThisArgumentOperand() {
this = TThisArgumentOperand()
}
override final string toString() {
result = "Arg(this)"
}
override final int getSortOrder() {
result = 10
}
override final string getLabel() {
result = "this:"
}
}
ThisArgumentOperand thisArgumentOperand() {
result = TThisArgumentOperand()
}
/**
* An operand representing an argument to a function call.
*/
class PositionalArgumentOperand extends ArgumentOperand,
TPositionalArgumentOperand {
int argIndex;
PositionalArgumentOperand() {
this = TPositionalArgumentOperand(argIndex)
}
override final string toString() {
result = "Arg(" + argIndex + ")"
}
override final int getSortOrder() {
result = 11 + argIndex
}
final int getArgIndex() {
result = argIndex
}
}
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
result = TPositionalArgumentOperand(argIndex)
}
/**
* An operand of an SSA `Phi` instruction.
*/
class PhiOperand extends OperandTag, TPhiOperand {
IRBlock predecessorBlock;
PhiOperand() {
this = TPhiOperand(predecessorBlock)
}
override final string toString() {
result = "Phi"
}
override final int getSortOrder() {
result = 11 + getPredecessorBlock().getDisplayIndex()
}
override final string getLabel() {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}
final IRBlock getPredecessorBlock() {
result = predecessorBlock
}
}
PhiOperand phiOperand(IRBlock predecessorBlock) {
result = TPhiOperand(predecessorBlock)
}

View File

@@ -1,175 +1,239 @@
private import IRImpl
import cpp
private int getInstructionIndexInBlock(Instruction instr) {
exists(IRBlock block |
block = instr.getBlock() and
private newtype TPrintableIRNode =
TPrintableFunctionIR(FunctionIR funcIR) or
TPrintableIRBlock(IRBlock block) or
TPrintableInstruction(Instruction instr)
/**
* A node to be emitted in the IR graph.
*/
abstract class PrintableIRNode extends TPrintableIRNode {
abstract string toString();
/**
* Gets the location to be emitted for the node.
*/
abstract Location getLocation();
/**
* Gets the label to be emitted for the node.
*/
abstract string getLabel();
/**
* Gets the order in which the node appears in its parent node.
*/
abstract int getOrder();
/**
* Gets the parent of this node.
*/
abstract PrintableIRNode getParent();
/**
* Gets the kind of graph represented by this node ("graph" or "tree").
*/
string getGraphKind() {
none()
}
/**
* Holds if this node should always be rendered as text, even in a graphical
* viewer.
*/
predicate forceText() {
none()
}
/**
* Gets the value of the node property with the specified key.
*/
string getProperty(string key) {
key = "semmle.label" and result = getLabel() or
key = "semmle.order" and result = getOrder().toString() or
key = "semmle.graphKind" and result = getGraphKind() or
key = "semmle.forceText" and forceText() and result = "true"
}
}
/**
* An IR graph node representing a `FunctionIR` object.
*/
class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
FunctionIR funcIR;
PrintableFunctionIR() {
this = TPrintableFunctionIR(funcIR)
}
override string toString() {
result = funcIR.toString()
}
override Location getLocation() {
result = funcIR.getLocation()
}
override string getLabel() {
result = funcIR.getFunction().getFullSignature()
}
override int getOrder() {
this = rank[result + 1](PrintableFunctionIR orderedFunc, Location location |
location = orderedFunc.getFunctionIR().getLocation() |
orderedFunc order by location.getFile().getURL(), location.getStartLine(),
location.getStartColumn(), orderedFunc.getLabel()
)
}
override final PrintableIRNode getParent() {
none()
}
final FunctionIR getFunctionIR() {
result = funcIR
}
}
/**
* An IR graph node representing an `IRBlock` object.
*/
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
IRBlock block;
PrintableIRBlock() {
this = TPrintableIRBlock(block)
}
override string toString() {
result = getLabel()
}
override Location getLocation() {
result = block.getLocation()
}
override string getLabel() {
result = "Block " + block.getDisplayIndex().toString()
}
override int getOrder() {
result = block.getDisplayIndex()
}
override final string getGraphKind() {
result = "tree"
}
override final predicate forceText() {
any()
}
override final PrintableFunctionIR getParent() {
result.getFunctionIR() = block.getFunctionIR()
}
final IRBlock getBlock() {
result = block
}
}
/**
* An IR graph node representing an `Instruction`.
*/
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
Instruction instr;
PrintableInstruction() {
this = TPrintableInstruction(instr)
}
override string toString() {
result = instr.toString()
}
override Location getLocation() {
result = instr.getLocation()
}
override string getLabel() {
exists(IRBlock block |
instr = block.getAnInstruction() and
exists(string resultString, string operationString, string operandsString,
int resultWidth, int operationWidth |
resultString = instr.getResultString() and
operationString = instr.getOperationString() and
operandsString = instr.getOperandsString() and
columnWidths(block, resultWidth, operationWidth) and
result = resultString + getPaddingString(resultWidth - resultString.length()) +
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
" : " + operandsString
)
)
}
override int getOrder() {
result = instr.getDisplayIndexInBlock()
}
override final PrintableIRBlock getParent() {
result.getBlock() = instr.getBlock()
}
final Instruction getInstruction() {
result = instr
}
}
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
}
private int maxColumnWidth() {
result = max(Instruction instr, int width |
width = instr.getResultString().length() or
width = instr.getOperationString().length() or
width = instr.getOperandsString().length() |
width)
}
private string getPaddingString(int n) {
n = 0 and result = "" or
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
}
query predicate nodes(PrintableIRNode node, string key, string value) {
value = node.getProperty(key)
}
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
aSucc = pred.getSuccessor(kind) |
aSucc order by kind.toString()
)
}
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
predBlock = pred.getBlock() and
succBlock = succ.getBlock() and
predBlock.getSuccessor(kind) = succBlock and
(
exists(int index, int phiCount |
phiCount = count(block.getAPhiInstruction()) and
instr = block.getInstruction(index) and
result = index + phiCount
(
key = "semmle.label" and
value = kind.toString()
) or
(
instr instanceof PhiInstruction and
instr = rank[result + 1](PhiInstruction phiInstr |
phiInstr = block.getAPhiInstruction() |
phiInstr order by phiInstr.getUniqueId()
)
key = "semmle.order" and
value = getSuccessorIndex(predBlock, succBlock).toString()
)
)
)
}
private string getInstructionResultId(Instruction instr) {
result = getResultPrefix(instr) + getBlockId(instr.getBlock()) + "_" +
getInstructionIndexInBlock(instr).toString()
}
private string getResultPrefix(Instruction instr) {
if instr.hasMemoryResult() then
if instr.isResultModeled() then
result = "@m"
else
result = "@mu"
else
result = "@r"
}
/**
* Gets the identifier of the specified function scope.
* Currently just returns the signature of the function.
*/
private string getScopeId(Function func) {
result = func.getFullSignature()
}
/**
* Gets the unique identifier of the block within its function.
* Currently returns a string representation of an integer in the range
* [0..numBlocks - 1].
*/
private string getBlockId(IRBlock block) {
exists(int rankIndex |
block = rank[rankIndex + 1](IRBlock funcBlock |
funcBlock.getFunction() = block.getFunction() |
funcBlock order by funcBlock.getUniqueId()
) and
result = rankIndex.toString()
)
}
/**
* Prints the full signature and qualified name for each scope. This is primarily
* so that post-processing tools can identify function overloads, which will have
* different signatures but the same qualified name.
*/
query predicate printIRGraphScopes(string scopeId, string qualifiedName) {
exists(FunctionIR ir, Function func |
func = ir.getFunction() and
scopeId = getScopeId(func) and
qualifiedName = func.getQualifiedName()
)
}
query predicate printIRGraphNodes(string scopeId, string blockId, string label, string location) {
exists(IRBlock block |
scopeId = getScopeId(block.getFunction()) and
blockId = getBlockId(block) and
label = "" and
location = ""
)
}
query predicate printIRGraphInstructions(string scopeId, string blockId,
string id, string label, string location) {
exists(IRBlock block, Instruction instr |
instr = block.getAnInstruction() and
label = instr.toString() and
location = instr.getLocation().toString() and
scopeId = getScopeId(block.getFunction()) and
blockId = getBlockId(block) and
id = getInstructionIndexInBlock(instr).toString()
)
}
query predicate printIRGraphEdges(string scopeId,
string predecessorId, string successorId, string label) {
exists(IRBlock predecessor, IRBlock successor, EdgeKind kind |
scopeId = getScopeId(predecessor.getFunction()) and
predecessor.getSuccessor(kind) = successor and
predecessorId = getBlockId(predecessor) and
successorId = getBlockId(successor) and
label = kind.toString()
)
}
private string getValueCategoryString(Instruction instr) {
if instr.isGLValue() then
result = "glval:"
else
result = ""
}
private string getResultTypeString(Instruction instr) {
exists(Type resultType, string valcat |
resultType = instr.getResultType() and
valcat = getValueCategoryString(instr) and
if resultType instanceof UnknownType and exists(instr.getResultSize()) then
result = valcat + resultType.toString() + "[" + instr.getResultSize().toString() + "]"
else
result = valcat + resultType.toString()
)
}
query predicate printIRGraphDestinationOperands(string scopeId, string blockId,
string instructionId, int operandId, string label) {
exists(IRBlock block, Instruction instr |
block.getAnInstruction() = instr and
scopeId = getScopeId(block.getFunction()) and
blockId = getBlockId(block) and
instructionId = getInstructionIndexInBlock(instr).toString() and
not instr.getResultType() instanceof VoidType and
operandId = 0 and
label = getInstructionResultId(instr) +
"(" + getResultTypeString(instr) + ")"
)
}
private string getOperandTagLabel(OperandTag tag) {
(
tag instanceof PhiOperand and
result = "from " + getBlockId(tag.(PhiOperand).getPredecessorBlock()) + ": "
)
or (
tag instanceof ThisArgumentOperand and
result = "this:"
)
or (
not tag instanceof PhiOperand and
not tag instanceof ThisArgumentOperand and
result = ""
)
}
query predicate printIRGraphSourceOperands(string scopeId, string blockId,
string instructionId, int operandId, string label) {
exists(IRBlock block, Instruction instr |
block.getAnInstruction() = instr and
blockId = getBlockId(block) and
scopeId = getScopeId(block.getFunction()) and
instructionId = getInstructionIndexInBlock(instr).toString() and
if (instr instanceof UnmodeledUseInstruction) then (
operandId = 0 and
label = "@mu*"
)
else (
exists(OperandTag tag, Instruction operandInstr |
operandInstr = instr.getOperand(tag) and
operandId = tag.getSortOrder() and
label = getOperandTagLabel(tag) +
getInstructionResultId(operandInstr)
)
)
)
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
parent = child.getParent()
}

View File

@@ -1,3 +1,3 @@
void v(int i) {
void AddressOf(int i) {
int *j = &i;
}

View File

@@ -2,7 +2,7 @@ struct S {
char* name;
};
void v()
void ArrayToPointer()
{
char c[] = "hello";
struct S s;

View File

@@ -1,3 +1,3 @@
void v(char *c, void *v) {
void Cast(char *c, void *v) {
c = (char *)v;
}

View File

@@ -1,4 +1,4 @@
void v() {
void ConditionDecl() {
int j = 0;
while(int k = j < 5) {
}

View File

@@ -14,7 +14,7 @@ class E {
public:
};
void v(C *c, D *d, E *e) {
void ConstructorCall(C *c, D *d, E *e) {
c = new C(5);
d = new D();
e = new E();

View File

@@ -1,4 +1,4 @@
void v() {
void Conversion1() {
int i = (int)1;
}

View File

@@ -1,3 +1,3 @@
void v(int x) {
void Conversion2(int x) {
x = (int)5 + (int)7;
}

View File

@@ -1,3 +1,3 @@
void v(int x) {
void Conversion3(int x) {
x = (bool)(int)5 + ((int)7);
}

View File

@@ -1,3 +1,3 @@
void v(int x) {
void Conversion4(int x) {
x = ((int)7);
}

View File

@@ -8,7 +8,7 @@ class D {
public:
};
void v(C *c, D *d) {
void DestructorCall(C *c, D *d) {
delete c;
delete d;
}

View File

@@ -5,10 +5,10 @@ class Derived : public Base {
void f() { }
};
void v(Base *bp, Derived *d) {
void DynamicCast(Base *bp, Derived *d) {
d = dynamic_cast<Derived *>(bp);
}
void v_ref(Base &bp, Derived &d) {
void DynamicCastRef(Base &bp, Derived &d) {
d = dynamic_cast<Derived &>(bp);
}

View File

@@ -1,3 +1,3 @@
void v(int i) {
void Parenthesis(int i) {
i = (i + 1) * 2;
}

View File

@@ -1,3 +1,3 @@
void v(int *i, int j) {
void PointerDereference(int *i, int j) {
j = *i;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
there is an implicit compiler-generated dereference node before the access to the variable 'i'
*/
void v(int &i, int j) {
void ReferenceDereference(int &i, int j) {
j = i;
}

View File

@@ -1,3 +1,3 @@
int& v(int *i) {
int& ReferenceTo(int *i) {
return *i;
}

View File

@@ -1,4 +1,4 @@
void v(int array[]) {
void Sizeof(int array[]) {
int i = sizeof(int);
int j = sizeof(array);
}

View File

@@ -1,3 +1,3 @@
void v() {
void StatementExpr() {
int j = ({ int i = 5; i; });
}

View File

@@ -2,7 +2,7 @@ struct X {
static int i;
};
void v(int i, X &xref) {
void StaticMemberAccess(int i, X &xref) {
// i = X::i;
i = xref.i;

View File

@@ -1,3 +1,3 @@
void v(int i[], int j) {
void Subscript(int i[], int j) {
j = i[5];
}

View File

@@ -3,7 +3,7 @@ class F {
public:
F() { }
};
void f(int i) {
void Throw(int i) {
try {
if(i)
throw E();

View File

@@ -15,6 +15,6 @@ class Base {
class Derived : public Base {
};
void v(Base *bp) {
void TypeId(Base *bp) {
const char *name = typeid(bp).name();
}

View File

@@ -1,11 +1,11 @@
template<class T>
void v(T x, T *y) {
void CallDestructor(T x, T *y) {
x.T::~T();
y->T::~T();
}
void f(int i) {
void Vacuous(int i) {
// An int doesn't have a destructor, but we get to call it anyway through a
// template.
v(i, &i);
CallDestructor(i, &i);
}

View File

@@ -5,7 +5,7 @@ typedef __builtin_va_list __gnuc_va_list;
#define va_copy(d,s) __builtin_va_copy(d,s)
typedef __gnuc_va_list va_list;
void output(const char *text, ...) {
void VarArgs(const char *text, ...) {
va_list args;
va_start(args, text);
va_end (args);

View File

@@ -8,4 +8,4 @@ where
resultPointsTo(instr, var, bitOffset) and
pointsTo = var.toString() + getBitOffsetString(bitOffset)
)
select instr, pointsTo
select instr.getLocation().toString(), instr.getOperationString(), pointsTo

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +0,0 @@
import semmle.code.cpp.ssa.AliasedSSAIR
import semmle.code.cpp.ssa.PrintAliasedSSAIR
from Instruction instr
where none()
select instr

View File

@@ -0,0 +1 @@
semmle/code/cpp/ssa/PrintAliasedSSAIR.ql

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +0,0 @@
import default
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.PrintIR
from Instruction instr
where none()
select instr

View File

@@ -0,0 +1 @@
semmle/code/cpp/ir/PrintIR.ql

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +0,0 @@
import semmle.code.cpp.ssa.SSAIR
import semmle.code.cpp.ssa.PrintSSAIR
from Instruction instr
where none()
select instr

View File

@@ -0,0 +1 @@
semmle/code/cpp/ssa/PrintSSAIR.ql