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 * @name Print AST
* @description Outputs a representation of the Abstract Syntax Tree. * @description Outputs a representation of the Abstract Syntax Tree.
* @id cpp/print-ast * @id cpp/print-ast
* @kind graph
*/ */
import cpp import cpp

View File

@@ -2,11 +2,18 @@ import cpp
private newtype TPrintASTConfiguration = MkPrintASTConfiguration() private newtype TPrintASTConfiguration = MkPrintASTConfiguration()
/**
* The query can extend this class to control which functions are printed.
*/
class PrintASTConfiguration extends TPrintASTConfiguration { class PrintASTConfiguration extends TPrintASTConfiguration {
string toString() { string toString() {
result = "PrintASTConfiguration" result = "PrintASTConfiguration"
} }
/**
* Holds if the AST for `func` should be printed. By default, holds for all
* functions.
*/
predicate shouldPrintFunction(Function func) { predicate shouldPrintFunction(Function func) {
any() any()
} }
@@ -18,165 +25,500 @@ private predicate shouldPrintFunction(Function func) {
) )
} }
private Locatable getAChild(Locatable parent) { bindingset[s]
result = getChild(parent, _) 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 * Most nodes are just a wrapper around `Locatable`, but we do synthesize new
result = count(func.(Constructor).getAnInitializer()) * nodes for things like parameter lists and constructor init lists.
else */
result = 0 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 | * A node representing an AST node.
parent = func and */
result = entryPoint and abstract class ASTNode extends PrintASTNode, TASTNode {
entryPoint = func.getEntryPoint() and Locatable ast;
childIndex = getEntryPointIndex(func)
) or ASTNode() {
exists(Function func, Expr childExpr | this = TASTNode(ast)
parent = func and }
result = childExpr and
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 key = "Value" and
childExpr = func.(Destructor).getDestruction(childIndex - 1) result = getValue()
) ) or
) or
exists(Stmt parentStmt |
parentStmt = parent and
( (
parentStmt.getChild(childIndex).(Expr).getFullyConverted() = result or key = "Type" and
parentStmt.getChild(childIndex).(Stmt) = result result = expr.getType().toString()
) or
(
key = "ValueCategory" and
result = expr.getValueCategoryString()
) )
) or }
exists(Expr parentExpr, Expr childExpr |
parent = parentExpr and string getValue() {
result = childExpr and result = expr.getValue()
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
)
} }
private string getTypeString(Locatable ast) { /**
if ast instanceof Expr then ( * A node representing a `StringLiteral`.
exists(Expr expr | */
expr = ast and class StringLiteralNode extends ExprNode {
result = expr.getValueCategoryString() + ": " + expr.getType().toString() 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 ( * A node representing a `DeclarationEntry`.
result = ast.(Cast).getSemanticConversionString() */
) class DeclarationEntryNode extends ASTNode {
else ( DeclarationEntry entry;
result = ""
)
}
private string getValueString(Locatable ast) { DeclarationEntryNode() {
if exists(ast.(Expr).getValue()) then entry = ast
result = "=" + ast.(Expr).getValue() }
else
result = ""
}
private Locatable getChildByRank(Locatable parent, int rankIndex) { override PrintASTNode getChild(int childIndex) {
result = rank[rankIndex + 1](Locatable child, int id | none()
child = getChild(parent, id) | }
child order by id
)
}
language[monotonicAggregates] override string getProperty(string key) {
private int getDescendantCount(Locatable ast) { result = super.getProperty(key) or
result = 1 + sum(Locatable child | (
child = getChildByRank(ast, _) | key = "Type" and
getDescendantCount(child) result = entry.getType().toString()
)
}
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)
)
) )
}
} }
query predicate printAST(string functionLocation, /**
string function, int nodeId, int parentId, int childIndex, string ast, * A node representing a `VariableDeclarationEntry`.
string extra, string value, string type, string astLocation) { */
exists(Function func, Locatable astNode | class VariableDeclarationEntryNode extends DeclarationEntryNode {
shouldPrintFunction(func) and VariableDeclarationEntry varEntry;
func = getEnclosingFunction(astNode) and
nodeId = getUniqueId(astNode) and VariableDeclarationEntryNode() {
if nodeId = 0 then ( varEntry = entry
parentId = -1 and }
childIndex = 0
) override ASTNode getChild(int childIndex) {
else ( childIndex = 0 and
exists(Locatable parent | result.getAST() = varEntry.getVariable().getInitializer()
astNode = getChild(parent, childIndex) and }
parentId = getUniqueId(parent)
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 * A node representing a `DeclStmt`.
type = getTypeString(astNode) and */
astLocation = astNode.getLocation().toString() 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 IRInternal
private import IRBlockConstruction private import IRBlockConstruction
import Instruction import Instruction
import semmle.code.cpp.ir.EdgeKind import semmle.code.cpp.ir.EdgeKind
class IRBlock extends TIRBlock { class IRBlock extends TIRBlock {
final string toString() { final string toString() {
result = getFirstInstruction(this).toString() result = getFirstInstruction(this).toString()
} }
final Location getLocation() { final Location getLocation() {
result = getFirstInstruction().getLocation() result = getFirstInstruction().getLocation()
} }
final string getUniqueId() { final string getUniqueId() {
result = getFirstInstruction(this).getUniqueId() result = getFirstInstruction(this).getUniqueId()
} }
final Instruction getInstruction(int index) { /**
result = getInstruction(this, index) * Gets the zero-based index of the block within its function. This is used
} * by debugging and printing code only.
*/
final PhiInstruction getAPhiInstruction() { int getDisplayIndex() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() this = rank[result + 1](IRBlock funcBlock |
} funcBlock.getFunction() = getFunction() |
funcBlock order by funcBlock.getUniqueId()
final Instruction getAnInstruction() { )
result = getInstruction(_) or }
result = getAPhiInstruction()
} final Instruction getInstruction(int index) {
result = getInstruction(this, index)
final Instruction getFirstInstruction() { }
result = getFirstInstruction(this)
} final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
final Instruction getLastInstruction() { }
result = getInstruction(getInstructionCount() - 1)
} final Instruction getAnInstruction() {
result = getInstruction(_) or
final int getInstructionCount() { result = getAPhiInstruction()
result = strictcount(getInstruction(_)) }
}
final Instruction getFirstInstruction() {
final FunctionIR getFunctionIR() { result = getFirstInstruction(this)
result = getFirstInstruction(this).getFunctionIR() }
}
final Instruction getLastInstruction() {
final Function getFunction() { result = getInstruction(getInstructionCount() - 1)
result = getFirstInstruction(this).getFunction() }
}
final int getInstructionCount() {
final IRBlock getASuccessor() { result = strictcount(getInstruction(_))
blockSuccessor(this, result) }
}
final FunctionIR getFunctionIR() {
final IRBlock getAPredecessor() { result = getFirstInstruction(this).getFunctionIR()
blockSuccessor(result, this) }
}
final Function getFunction() {
final IRBlock getSuccessor(EdgeKind kind) { result = getFirstInstruction(this).getFunction()
blockSuccessor(this, result, kind) }
}
final IRBlock getASuccessor() {
final predicate immediatelyDominates(IRBlock block) { blockSuccessor(this, result)
blockImmediatelyDominates(this, block) }
}
final IRBlock getAPredecessor() {
final predicate strictlyDominates(IRBlock block) { blockSuccessor(result, this)
blockImmediatelyDominates+(this, block) }
}
final IRBlock getSuccessor(EdgeKind kind) {
final predicate dominates(IRBlock block) { blockSuccessor(this, result, kind)
strictlyDominates(block) or this = block }
}
final predicate immediatelyDominates(IRBlock block) {
pragma[noinline] blockImmediatelyDominates(this, block)
final IRBlock dominanceFrontier() { }
dominates(result.getAPredecessor()) and
not strictlyDominates(result) 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) this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
} }
string toString() { final string toString() {
result = opcode.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) var = Construction::getInstructionVariable(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + var.toString() + "]" result = var.toString()
} }
final IRVariable getVariable() { final IRVariable getVariable() {
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
field = Construction::getInstructionField(this) field = Construction::getInstructionField(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + field.toString() + "]" result = field.toString()
} }
final Field getField() { final Field getField() {
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
funcSymbol = Construction::getInstructionFunction(this) funcSymbol = Construction::getInstructionFunction(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + funcSymbol.toString() + "]" result = funcSymbol.toString()
} }
final Function getFunctionSymbol() { final Function getFunctionSymbol() {
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
value = Construction::getInstructionConstantValue(this) value = Construction::getInstructionConstantValue(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + value + "]" result = value
} }
final string getValue() { final string getValue() {
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
value = Construction::getInstructionStringLiteral(this) value = Construction::getInstructionStringLiteral(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
"]"
} }
final StringLiteral getValue() { final StringLiteral getValue() {
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
elementSize = Construction::getInstructionElementSize(this) elementSize = Construction::getInstructionElementSize(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + elementSize.toString() + "]" result = elementSize.toString()
} }
final int getElementSize() { final int getElementSize() {
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Construction::getInstructionInheritance(this, baseClass, derivedClass) Construction::getInstructionInheritance(this, baseClass, derivedClass)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]" result = derivedClass.toString() + " : " + baseClass.toString()
} }
/** /**
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
exceptionType = Construction::getInstructionExceptionType(this) exceptionType = Construction::getInstructionExceptionType(this)
} }
final override string toString() { final override string getImmediateString() {
result = super.toString() + "[" + exceptionType.toString() + "]" result = exceptionType.toString()
} }
/** /**
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
opcode instanceof Opcode::UnmodeledUse opcode instanceof Opcode::UnmodeledUse
} }
override string getOperandsString() {
result = "mu*"
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) { override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
tag instanceof UnmodeledUseOperand and tag instanceof UnmodeledUseOperand and
result instanceof UnmodeledMemoryAccess result instanceof UnmodeledMemoryAccess

View File

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

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 IRInternal
private import IRBlockConstruction private import IRBlockConstruction
import Instruction import Instruction
import semmle.code.cpp.ir.EdgeKind import semmle.code.cpp.ir.EdgeKind
class IRBlock extends TIRBlock { class IRBlock extends TIRBlock {
final string toString() { final string toString() {
result = getFirstInstruction(this).toString() result = getFirstInstruction(this).toString()
} }
final Location getLocation() { final Location getLocation() {
result = getFirstInstruction().getLocation() result = getFirstInstruction().getLocation()
} }
final string getUniqueId() { final string getUniqueId() {
result = getFirstInstruction(this).getUniqueId() result = getFirstInstruction(this).getUniqueId()
} }
final Instruction getInstruction(int index) { /**
result = getInstruction(this, index) * Gets the zero-based index of the block within its function. This is used
} * by debugging and printing code only.
*/
final PhiInstruction getAPhiInstruction() { int getDisplayIndex() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() this = rank[result + 1](IRBlock funcBlock |
} funcBlock.getFunction() = getFunction() |
funcBlock order by funcBlock.getUniqueId()
final Instruction getAnInstruction() { )
result = getInstruction(_) or }
result = getAPhiInstruction()
} final Instruction getInstruction(int index) {
result = getInstruction(this, index)
final Instruction getFirstInstruction() { }
result = getFirstInstruction(this)
} final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
final Instruction getLastInstruction() { }
result = getInstruction(getInstructionCount() - 1)
} final Instruction getAnInstruction() {
result = getInstruction(_) or
final int getInstructionCount() { result = getAPhiInstruction()
result = strictcount(getInstruction(_)) }
}
final Instruction getFirstInstruction() {
final FunctionIR getFunctionIR() { result = getFirstInstruction(this)
result = getFirstInstruction(this).getFunctionIR() }
}
final Instruction getLastInstruction() {
final Function getFunction() { result = getInstruction(getInstructionCount() - 1)
result = getFirstInstruction(this).getFunction() }
}
final int getInstructionCount() {
final IRBlock getASuccessor() { result = strictcount(getInstruction(_))
blockSuccessor(this, result) }
}
final FunctionIR getFunctionIR() {
final IRBlock getAPredecessor() { result = getFirstInstruction(this).getFunctionIR()
blockSuccessor(result, this) }
}
final Function getFunction() {
final IRBlock getSuccessor(EdgeKind kind) { result = getFirstInstruction(this).getFunction()
blockSuccessor(this, result, kind) }
}
final IRBlock getASuccessor() {
final predicate immediatelyDominates(IRBlock block) { blockSuccessor(this, result)
blockImmediatelyDominates(this, block) }
}
final IRBlock getAPredecessor() {
final predicate strictlyDominates(IRBlock block) { blockSuccessor(result, this)
blockImmediatelyDominates+(this, block) }
}
final IRBlock getSuccessor(EdgeKind kind) {
final predicate dominates(IRBlock block) { blockSuccessor(this, result, kind)
strictlyDominates(block) or this = block }
}
final predicate immediatelyDominates(IRBlock block) {
pragma[noinline] blockImmediatelyDominates(this, block)
final IRBlock dominanceFrontier() { }
dominates(result.getAPredecessor()) and
not strictlyDominates(result) 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) this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
} }
string toString() { final string toString() {
result = opcode.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) var = Construction::getInstructionVariable(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + var.toString() + "]" result = var.toString()
} }
final IRVariable getVariable() { final IRVariable getVariable() {
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
field = Construction::getInstructionField(this) field = Construction::getInstructionField(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + field.toString() + "]" result = field.toString()
} }
final Field getField() { final Field getField() {
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
funcSymbol = Construction::getInstructionFunction(this) funcSymbol = Construction::getInstructionFunction(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + funcSymbol.toString() + "]" result = funcSymbol.toString()
} }
final Function getFunctionSymbol() { final Function getFunctionSymbol() {
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
value = Construction::getInstructionConstantValue(this) value = Construction::getInstructionConstantValue(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + value + "]" result = value
} }
final string getValue() { final string getValue() {
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
value = Construction::getInstructionStringLiteral(this) value = Construction::getInstructionStringLiteral(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
"]"
} }
final StringLiteral getValue() { final StringLiteral getValue() {
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
elementSize = Construction::getInstructionElementSize(this) elementSize = Construction::getInstructionElementSize(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + elementSize.toString() + "]" result = elementSize.toString()
} }
final int getElementSize() { final int getElementSize() {
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Construction::getInstructionInheritance(this, baseClass, derivedClass) Construction::getInstructionInheritance(this, baseClass, derivedClass)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]" result = derivedClass.toString() + " : " + baseClass.toString()
} }
/** /**
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
exceptionType = Construction::getInstructionExceptionType(this) exceptionType = Construction::getInstructionExceptionType(this)
} }
final override string toString() { final override string getImmediateString() {
result = super.toString() + "[" + exceptionType.toString() + "]" result = exceptionType.toString()
} }
/** /**
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
opcode instanceof Opcode::UnmodeledUse opcode instanceof Opcode::UnmodeledUse
} }
override string getOperandsString() {
result = "mu*"
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) { override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
tag instanceof UnmodeledUseOperand and tag instanceof UnmodeledUseOperand and
result instanceof UnmodeledMemoryAccess result instanceof UnmodeledMemoryAccess

View File

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

View File

@@ -1,81 +1,92 @@
private import IRInternal private import IRInternal
private import IRBlockConstruction private import IRBlockConstruction
import Instruction import Instruction
import semmle.code.cpp.ir.EdgeKind import semmle.code.cpp.ir.EdgeKind
class IRBlock extends TIRBlock { class IRBlock extends TIRBlock {
final string toString() { final string toString() {
result = getFirstInstruction(this).toString() result = getFirstInstruction(this).toString()
} }
final Location getLocation() { final Location getLocation() {
result = getFirstInstruction().getLocation() result = getFirstInstruction().getLocation()
} }
final string getUniqueId() { final string getUniqueId() {
result = getFirstInstruction(this).getUniqueId() result = getFirstInstruction(this).getUniqueId()
} }
final Instruction getInstruction(int index) { /**
result = getInstruction(this, index) * Gets the zero-based index of the block within its function. This is used
} * by debugging and printing code only.
*/
final PhiInstruction getAPhiInstruction() { int getDisplayIndex() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() this = rank[result + 1](IRBlock funcBlock |
} funcBlock.getFunction() = getFunction() |
funcBlock order by funcBlock.getUniqueId()
final Instruction getAnInstruction() { )
result = getInstruction(_) or }
result = getAPhiInstruction()
} final Instruction getInstruction(int index) {
result = getInstruction(this, index)
final Instruction getFirstInstruction() { }
result = getFirstInstruction(this)
} final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
final Instruction getLastInstruction() { }
result = getInstruction(getInstructionCount() - 1)
} final Instruction getAnInstruction() {
result = getInstruction(_) or
final int getInstructionCount() { result = getAPhiInstruction()
result = strictcount(getInstruction(_)) }
}
final Instruction getFirstInstruction() {
final FunctionIR getFunctionIR() { result = getFirstInstruction(this)
result = getFirstInstruction(this).getFunctionIR() }
}
final Instruction getLastInstruction() {
final Function getFunction() { result = getInstruction(getInstructionCount() - 1)
result = getFirstInstruction(this).getFunction() }
}
final int getInstructionCount() {
final IRBlock getASuccessor() { result = strictcount(getInstruction(_))
blockSuccessor(this, result) }
}
final FunctionIR getFunctionIR() {
final IRBlock getAPredecessor() { result = getFirstInstruction(this).getFunctionIR()
blockSuccessor(result, this) }
}
final Function getFunction() {
final IRBlock getSuccessor(EdgeKind kind) { result = getFirstInstruction(this).getFunction()
blockSuccessor(this, result, kind) }
}
final IRBlock getASuccessor() {
final predicate immediatelyDominates(IRBlock block) { blockSuccessor(this, result)
blockImmediatelyDominates(this, block) }
}
final IRBlock getAPredecessor() {
final predicate strictlyDominates(IRBlock block) { blockSuccessor(result, this)
blockImmediatelyDominates+(this, block) }
}
final IRBlock getSuccessor(EdgeKind kind) {
final predicate dominates(IRBlock block) { blockSuccessor(this, result, kind)
strictlyDominates(block) or this = block }
}
final predicate immediatelyDominates(IRBlock block) {
pragma[noinline] blockImmediatelyDominates(this, block)
final IRBlock dominanceFrontier() { }
dominates(result.getAPredecessor()) and
not strictlyDominates(result) 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) this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
} }
string toString() { final string toString() {
result = opcode.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) var = Construction::getInstructionVariable(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + var.toString() + "]" result = var.toString()
} }
final IRVariable getVariable() { final IRVariable getVariable() {
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
field = Construction::getInstructionField(this) field = Construction::getInstructionField(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + field.toString() + "]" result = field.toString()
} }
final Field getField() { final Field getField() {
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
funcSymbol = Construction::getInstructionFunction(this) funcSymbol = Construction::getInstructionFunction(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + funcSymbol.toString() + "]" result = funcSymbol.toString()
} }
final Function getFunctionSymbol() { final Function getFunctionSymbol() {
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
value = Construction::getInstructionConstantValue(this) value = Construction::getInstructionConstantValue(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + value + "]" result = value
} }
final string getValue() { final string getValue() {
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
value = Construction::getInstructionStringLiteral(this) value = Construction::getInstructionStringLiteral(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
"]"
} }
final StringLiteral getValue() { final StringLiteral getValue() {
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
elementSize = Construction::getInstructionElementSize(this) elementSize = Construction::getInstructionElementSize(this)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + elementSize.toString() + "]" result = elementSize.toString()
} }
final int getElementSize() { final int getElementSize() {
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
Construction::getInstructionInheritance(this, baseClass, derivedClass) Construction::getInstructionInheritance(this, baseClass, derivedClass)
} }
override final string toString() { override final string getImmediateString() {
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]" result = derivedClass.toString() + " : " + baseClass.toString()
} }
/** /**
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
exceptionType = Construction::getInstructionExceptionType(this) exceptionType = Construction::getInstructionExceptionType(this)
} }
final override string toString() { final override string getImmediateString() {
result = super.toString() + "[" + exceptionType.toString() + "]" result = exceptionType.toString()
} }
/** /**
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
opcode instanceof Opcode::UnmodeledUse opcode instanceof Opcode::UnmodeledUse
} }
override string getOperandsString() {
result = "mu*"
}
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) { override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
tag instanceof UnmodeledUseOperand and tag instanceof UnmodeledUseOperand and
result instanceof UnmodeledMemoryAccess result instanceof UnmodeledMemoryAccess

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,3 @@
void v(int x) { void Conversion2(int x) {
x = (int)5 + (int)7; 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); x = (bool)(int)5 + ((int)7);
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,3 @@
void v(int *i, int j) { void PointerDereference(int *i, int j) {
j = *i; 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' 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; j = i;
} }

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,7 @@ struct X {
static int i; static int i;
}; };
void v(int i, X &xref) { void StaticMemberAccess(int i, X &xref) {
// i = X::i; // i = X::i;
i = xref.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]; j = i[5];
} }

View File

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

View File

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

View File

@@ -1,11 +1,11 @@
template<class T> template<class T>
void v(T x, T *y) { void CallDestructor(T x, T *y) {
x.T::~T(); x.T::~T();
y->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 // An int doesn't have a destructor, but we get to call it anyway through a
// template. // 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) #define va_copy(d,s) __builtin_va_copy(d,s)
typedef __gnuc_va_list va_list; typedef __gnuc_va_list va_list;
void output(const char *text, ...) { void VarArgs(const char *text, ...) {
va_list args; va_list args;
va_start(args, text); va_start(args, text);
va_end (args); va_end (args);

View File

@@ -8,4 +8,4 @@ where
resultPointsTo(instr, var, bitOffset) and resultPointsTo(instr, var, bitOffset) and
pointsTo = var.toString() + getBitOffsetString(bitOffset) 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