mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
C++: Make IR dump and AST dump tests use the official graph query format
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
* @name Print AST
|
||||
* @description Outputs a representation of the Abstract Syntax Tree.
|
||||
* @id cpp/print-ast
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -2,11 +2,18 @@ import cpp
|
||||
|
||||
private newtype TPrintASTConfiguration = MkPrintASTConfiguration()
|
||||
|
||||
/**
|
||||
* The query can extend this class to control which functions are printed.
|
||||
*/
|
||||
class PrintASTConfiguration extends TPrintASTConfiguration {
|
||||
string toString() {
|
||||
result = "PrintASTConfiguration"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the AST for `func` should be printed. By default, holds for all
|
||||
* functions.
|
||||
*/
|
||||
predicate shouldPrintFunction(Function func) {
|
||||
any()
|
||||
}
|
||||
@@ -18,165 +25,500 @@ private predicate shouldPrintFunction(Function func) {
|
||||
)
|
||||
}
|
||||
|
||||
private Locatable getAChild(Locatable parent) {
|
||||
result = getChild(parent, _)
|
||||
bindingset[s]
|
||||
private string escapeString(string s) {
|
||||
result = s.replaceAll("\\", "\\\\").replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll("\t", "\\t")
|
||||
}
|
||||
|
||||
private Function getEnclosingFunction(Locatable ast) {
|
||||
getAChild*(result) = ast
|
||||
/**
|
||||
* Due to extractor issues with ODR violations, a given AST may wind up with
|
||||
* multiple locations. This predicate returns a single location - the one whose
|
||||
* string representation comes first in lexicographical order.
|
||||
*/
|
||||
private Location getRepresentativeLocation(Locatable ast) {
|
||||
result = rank[1](Location loc | loc = ast.getLocation() | loc order by loc.toString())
|
||||
}
|
||||
|
||||
private int getEntryPointIndex(Function func) {
|
||||
if func instanceof Constructor then
|
||||
result = count(func.(Constructor).getAnInitializer())
|
||||
else
|
||||
result = 0
|
||||
/**
|
||||
* Most nodes are just a wrapper around `Locatable`, but we do synthesize new
|
||||
* nodes for things like parameter lists and constructor init lists.
|
||||
*/
|
||||
private newtype TPrintASTNode =
|
||||
TASTNode(Locatable ast) or
|
||||
TParametersNode(Function func) or
|
||||
TConstructorInitializersNode(Constructor ctor) {
|
||||
ctor.hasEntryPoint()
|
||||
} or
|
||||
TDestructorDestructionsNode(Destructor dtor) {
|
||||
dtor.hasEntryPoint()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node in the output tree.
|
||||
*/
|
||||
class PrintASTNode extends TPrintASTNode {
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the child node at index `childIndex`. Child indices must be unique,
|
||||
* but need not be contiguous (but see `getChildByRank`).
|
||||
*/
|
||||
abstract PrintASTNode getChild(int childIndex);
|
||||
|
||||
/**
|
||||
* Holds if this node should be printed in the output. By default, all nodes
|
||||
* within a function are printed, but the query can override
|
||||
* `PrintASTConfiguration.shouldPrintFunction` to filter the output.
|
||||
*/
|
||||
final predicate shouldPrint() {
|
||||
shouldPrintFunction(getEnclosingFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the children of this node.
|
||||
*/
|
||||
final PrintASTNode getAChild() {
|
||||
result = getChild(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parent of this node, if any.
|
||||
*/
|
||||
final PrintASTNode getParent() {
|
||||
result.getAChild() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of this node in the source code.
|
||||
*/
|
||||
abstract Location getLocation();
|
||||
|
||||
/**
|
||||
* Gets the value of the property of this node, where the name of the property
|
||||
* is `key`.
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and
|
||||
result = toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the label for the edge from this node to the specified child. By
|
||||
* default, this is just the index of the child, but subclasses can override
|
||||
* this.
|
||||
*/
|
||||
string getChildEdgeLabel(int childIndex) {
|
||||
exists(getChild(childIndex)) and
|
||||
result = childIndex.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Function` that contains this node.
|
||||
*/
|
||||
private Function getEnclosingFunction() {
|
||||
result = getParent*().(FunctionNode).getFunction()
|
||||
}
|
||||
}
|
||||
|
||||
private Locatable getChild(Locatable parent, int childIndex) {
|
||||
exists(Function func, Stmt entryPoint |
|
||||
parent = func and
|
||||
result = entryPoint and
|
||||
entryPoint = func.getEntryPoint() and
|
||||
childIndex = getEntryPointIndex(func)
|
||||
) or
|
||||
exists(Function func, Expr childExpr |
|
||||
parent = func and
|
||||
result = childExpr and
|
||||
/**
|
||||
* A node representing an AST node.
|
||||
*/
|
||||
abstract class ASTNode extends PrintASTNode, TASTNode {
|
||||
Locatable ast;
|
||||
|
||||
ASTNode() {
|
||||
this = TASTNode(ast)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = ast.toString()
|
||||
}
|
||||
|
||||
override final Location getLocation() {
|
||||
result = getRepresentativeLocation(ast)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the AST represented by this node.
|
||||
*/
|
||||
final Locatable getAST() {
|
||||
result = ast
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing an `Expr`.
|
||||
*/
|
||||
class ExprNode extends ASTNode {
|
||||
Expr expr;
|
||||
|
||||
ExprNode() {
|
||||
expr = ast
|
||||
}
|
||||
|
||||
override ASTNode getChild(int childIndex) {
|
||||
result.getAST() = expr.getChild(childIndex).getFullyConverted()
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = super.getProperty(key) or
|
||||
(
|
||||
childExpr = func.(Constructor).getInitializer(childIndex) or
|
||||
childExpr = func.(Destructor).getDestruction(childIndex - 1)
|
||||
)
|
||||
) or
|
||||
exists(Stmt parentStmt |
|
||||
parentStmt = parent and
|
||||
key = "Value" and
|
||||
result = getValue()
|
||||
) or
|
||||
(
|
||||
parentStmt.getChild(childIndex).(Expr).getFullyConverted() = result or
|
||||
parentStmt.getChild(childIndex).(Stmt) = result
|
||||
key = "Type" and
|
||||
result = expr.getType().toString()
|
||||
) or
|
||||
(
|
||||
key = "ValueCategory" and
|
||||
result = expr.getValueCategoryString()
|
||||
)
|
||||
) or
|
||||
exists(Expr parentExpr, Expr childExpr |
|
||||
parent = parentExpr and
|
||||
result = childExpr and
|
||||
childExpr = parentExpr.getChild(childIndex).getFullyConverted()
|
||||
) or
|
||||
exists(Conversion parentConv, Expr childExpr |
|
||||
parent = parentConv and
|
||||
result = childExpr and
|
||||
childExpr = parentConv.getExpr() and
|
||||
childIndex = 0
|
||||
) or
|
||||
exists(DeclStmt declStmt, DeclarationEntry childEntry |
|
||||
parent = declStmt and
|
||||
result = childEntry and
|
||||
childEntry = declStmt.getDeclarationEntry(childIndex)
|
||||
) or
|
||||
exists(VariableDeclarationEntry declEntry, Initializer init |
|
||||
parent = declEntry and
|
||||
result = init and
|
||||
init = declEntry.getVariable().getInitializer() and
|
||||
childIndex = 0
|
||||
) or
|
||||
exists(Initializer init, Expr expr |
|
||||
parent = init and
|
||||
result = expr and
|
||||
expr = init.getExpr().getFullyConverted() and
|
||||
childIndex = 0
|
||||
)
|
||||
}
|
||||
|
||||
string getValue() {
|
||||
result = expr.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
private string getTypeString(Locatable ast) {
|
||||
if ast instanceof Expr then (
|
||||
exists(Expr expr |
|
||||
expr = ast and
|
||||
result = expr.getValueCategoryString() + ": " + expr.getType().toString()
|
||||
/**
|
||||
* A node representing a `StringLiteral`.
|
||||
*/
|
||||
class StringLiteralNode extends ExprNode {
|
||||
StringLiteralNode() {
|
||||
expr instanceof StringLiteral
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = escapeString(expr.getValue())
|
||||
}
|
||||
|
||||
override string getValue() {
|
||||
result = "\"" + escapeString(expr.getValue()) + "\""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Conversion`.
|
||||
*/
|
||||
class ConversionNode extends ExprNode {
|
||||
Conversion conv;
|
||||
|
||||
ConversionNode() {
|
||||
conv = expr
|
||||
}
|
||||
|
||||
override ASTNode getChild(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAST() = conv.getExpr()
|
||||
}
|
||||
|
||||
override string getChildEdgeLabel(int childIndex) {
|
||||
childIndex = 0 and result = "expr"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Cast`.
|
||||
*/
|
||||
class CastNode extends ConversionNode {
|
||||
Cast cast;
|
||||
|
||||
CastNode() {
|
||||
cast = conv
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = super.getProperty(key) or
|
||||
(
|
||||
key = "Conversion" and
|
||||
result = cast.getSemanticConversionString()
|
||||
)
|
||||
)
|
||||
else if ast instanceof DeclarationEntry then (
|
||||
result = ast.(DeclarationEntry).getType().toString()
|
||||
)
|
||||
else (
|
||||
result = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private string getExtraInfoString(Locatable ast) {
|
||||
if ast instanceof Cast then (
|
||||
result = ast.(Cast).getSemanticConversionString()
|
||||
)
|
||||
else (
|
||||
result = ""
|
||||
)
|
||||
}
|
||||
/**
|
||||
* A node representing a `DeclarationEntry`.
|
||||
*/
|
||||
class DeclarationEntryNode extends ASTNode {
|
||||
DeclarationEntry entry;
|
||||
|
||||
private string getValueString(Locatable ast) {
|
||||
if exists(ast.(Expr).getValue()) then
|
||||
result = "=" + ast.(Expr).getValue()
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
DeclarationEntryNode() {
|
||||
entry = ast
|
||||
}
|
||||
|
||||
private Locatable getChildByRank(Locatable parent, int rankIndex) {
|
||||
result = rank[rankIndex + 1](Locatable child, int id |
|
||||
child = getChild(parent, id) |
|
||||
child order by id
|
||||
)
|
||||
}
|
||||
override PrintASTNode getChild(int childIndex) {
|
||||
none()
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private int getDescendantCount(Locatable ast) {
|
||||
result = 1 + sum(Locatable child |
|
||||
child = getChildByRank(ast, _) |
|
||||
getDescendantCount(child)
|
||||
)
|
||||
}
|
||||
|
||||
private Locatable getParent(Locatable ast) {
|
||||
ast = getAChild(result)
|
||||
}
|
||||
|
||||
private int getUniqueId(Locatable ast) {
|
||||
shouldPrintFunction(getEnclosingFunction(ast)) and
|
||||
if not exists(getParent(ast)) then
|
||||
result = 0
|
||||
else
|
||||
exists(Locatable parent |
|
||||
parent = getParent(ast) and
|
||||
if ast = getChildByRank(parent, 0) then
|
||||
result = 1 + getUniqueId(parent)
|
||||
else
|
||||
exists(int childIndex, Locatable previousChild |
|
||||
ast = getChildByRank(parent, childIndex) and
|
||||
previousChild = getChildByRank(parent, childIndex - 1) and
|
||||
result = getUniqueId(previousChild) +
|
||||
getDescendantCount(previousChild)
|
||||
)
|
||||
override string getProperty(string key) {
|
||||
result = super.getProperty(key) or
|
||||
(
|
||||
key = "Type" and
|
||||
result = entry.getType().toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate printAST(string functionLocation,
|
||||
string function, int nodeId, int parentId, int childIndex, string ast,
|
||||
string extra, string value, string type, string astLocation) {
|
||||
exists(Function func, Locatable astNode |
|
||||
shouldPrintFunction(func) and
|
||||
func = getEnclosingFunction(astNode) and
|
||||
nodeId = getUniqueId(astNode) and
|
||||
if nodeId = 0 then (
|
||||
parentId = -1 and
|
||||
childIndex = 0
|
||||
)
|
||||
else (
|
||||
exists(Locatable parent |
|
||||
astNode = getChild(parent, childIndex) and
|
||||
parentId = getUniqueId(parent)
|
||||
/**
|
||||
* A node representing a `VariableDeclarationEntry`.
|
||||
*/
|
||||
class VariableDeclarationEntryNode extends DeclarationEntryNode {
|
||||
VariableDeclarationEntry varEntry;
|
||||
|
||||
VariableDeclarationEntryNode() {
|
||||
varEntry = entry
|
||||
}
|
||||
|
||||
override ASTNode getChild(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAST() = varEntry.getVariable().getInitializer()
|
||||
}
|
||||
|
||||
override string getChildEdgeLabel(int childIndex) {
|
||||
childIndex = 0 and result = "init"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Stmt`.
|
||||
*/
|
||||
class StmtNode extends ASTNode {
|
||||
Stmt stmt;
|
||||
|
||||
StmtNode() {
|
||||
stmt = ast
|
||||
}
|
||||
|
||||
override ASTNode getChild(int childIndex) {
|
||||
exists(Locatable child |
|
||||
child = stmt.getChild(childIndex) and
|
||||
(
|
||||
result.getAST() = child.(Expr).getFullyConverted() or
|
||||
result.getAST() = child.(Stmt)
|
||||
)
|
||||
) and
|
||||
functionLocation = func.getLocation().toString() and
|
||||
function = func.getFullSignature() and
|
||||
ast = astNode.toString() and
|
||||
extra = getExtraInfoString(astNode) and
|
||||
value = getValueString(astNode) and
|
||||
type = getTypeString(astNode) and
|
||||
astLocation = astNode.getLocation().toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `DeclStmt`.
|
||||
*/
|
||||
class DeclStmtNode extends StmtNode {
|
||||
DeclStmt declStmt;
|
||||
|
||||
DeclStmtNode() {
|
||||
declStmt = stmt
|
||||
}
|
||||
|
||||
override ASTNode getChild(int childIndex) {
|
||||
result.getAST() = declStmt.getDeclarationEntry(childIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Parameter`.
|
||||
*/
|
||||
class ParameterNode extends ASTNode {
|
||||
Parameter param;
|
||||
|
||||
ParameterNode() {
|
||||
param = ast
|
||||
}
|
||||
|
||||
override final PrintASTNode getChild(int childIndex) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final string getProperty(string key) {
|
||||
result = super.getProperty(key) or
|
||||
(
|
||||
key = "Type" and
|
||||
result = param.getType().toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing an `Initializer`.
|
||||
*/
|
||||
class InitializerNode extends ASTNode {
|
||||
Initializer init;
|
||||
|
||||
InitializerNode() {
|
||||
init = ast
|
||||
}
|
||||
|
||||
override ASTNode getChild(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAST() = init.getExpr().getFullyConverted()
|
||||
}
|
||||
|
||||
override string getChildEdgeLabel(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result = "expr"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the parameters of a `Function`.
|
||||
*/
|
||||
class ParametersNode extends PrintASTNode, TParametersNode {
|
||||
Function func;
|
||||
|
||||
ParametersNode() {
|
||||
this = TParametersNode(func)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
override final Location getLocation() {
|
||||
result = getRepresentativeLocation(func)
|
||||
}
|
||||
|
||||
override ASTNode getChild(int childIndex) {
|
||||
result.getAST() = func.getParameter(childIndex)
|
||||
}
|
||||
|
||||
final Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the initializer list of a `Constructor`.
|
||||
*/
|
||||
class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializersNode {
|
||||
Constructor ctor;
|
||||
|
||||
ConstructorInitializersNode() {
|
||||
this = TConstructorInitializersNode(ctor)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
override final Location getLocation() {
|
||||
result = getRepresentativeLocation(ctor)
|
||||
}
|
||||
|
||||
override final ASTNode getChild(int childIndex) {
|
||||
result.getAST() = ctor.getInitializer(childIndex)
|
||||
}
|
||||
|
||||
final Constructor getConstructor() {
|
||||
result = ctor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the destruction list of a `Destructor`.
|
||||
*/
|
||||
class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNode {
|
||||
Destructor dtor;
|
||||
|
||||
DestructorDestructionsNode() {
|
||||
this = TDestructorDestructionsNode(dtor)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
override final Location getLocation() {
|
||||
result = getRepresentativeLocation(dtor)
|
||||
}
|
||||
|
||||
override final ASTNode getChild(int childIndex) {
|
||||
result.getAST() = dtor.getDestruction(childIndex)
|
||||
}
|
||||
|
||||
final Destructor getDestructor() {
|
||||
result = dtor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Function`.
|
||||
*/
|
||||
class FunctionNode extends ASTNode {
|
||||
Function func;
|
||||
|
||||
FunctionNode() {
|
||||
func = ast
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = func.getFullSignature()
|
||||
}
|
||||
|
||||
override PrintASTNode getChild(int childIndex) {
|
||||
(
|
||||
childIndex = 0 and
|
||||
result.(ParametersNode).getFunction() = func
|
||||
) or
|
||||
(
|
||||
childIndex = 1 and
|
||||
result.(ConstructorInitializersNode).getConstructor() = func
|
||||
) or
|
||||
(
|
||||
childIndex = 2 and
|
||||
result.(ASTNode).getAST() = func.getEntryPoint()
|
||||
) or
|
||||
(
|
||||
childIndex = 3 and
|
||||
result.(DestructorDestructionsNode).getDestructor() = func
|
||||
)
|
||||
}
|
||||
|
||||
override string getChildEdgeLabel(int childIndex) {
|
||||
childIndex = 0 and result = "params" or
|
||||
childIndex = 1 and result = "initializations" or
|
||||
childIndex = 2 and result = "body" or
|
||||
childIndex = 3 and result = "destructions"
|
||||
}
|
||||
|
||||
private int getOrder() {
|
||||
this = rank[result](FunctionNode node, Function function, Location loc |
|
||||
node.getAST() = function and loc = getRepresentativeLocation(function) |
|
||||
node order by
|
||||
loc.getFile().toString(),
|
||||
loc.getStartLine(),
|
||||
loc.getStartColumn(),
|
||||
function.getFullSignature()
|
||||
)
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = super.getProperty(key) or
|
||||
key = "semmle.order" and result = getOrder().toString()
|
||||
}
|
||||
|
||||
final Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
}
|
||||
|
||||
query predicate nodes(PrintASTNode node, string key, string value) {
|
||||
node.shouldPrint() and
|
||||
value = node.getProperty(key)
|
||||
}
|
||||
|
||||
query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) {
|
||||
exists(int childIndex |
|
||||
source.shouldPrint() and
|
||||
target.shouldPrint() and
|
||||
target = source.getChild(childIndex) and
|
||||
(
|
||||
key = "semmle.label" and value = source.getChildEdgeLabel(childIndex) or
|
||||
key = "semmle.order" and value = childIndex.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate graphProperties(string key, string value) {
|
||||
key = "semmle.graphKind" and value = "tree"
|
||||
}
|
||||
|
||||
8
cpp/ql/src/semmle/code/cpp/ir/PrintIR.ql
Normal file
8
cpp/ql/src/semmle/code/cpp/ir/PrintIR.ql
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @name Print IR
|
||||
* @description Outputs a representation of the IR graph
|
||||
* @id cpp/print-ir
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import PrintIR
|
||||
@@ -1,81 +1,92 @@
|
||||
private import IRInternal
|
||||
private import IRBlockConstruction
|
||||
import Instruction
|
||||
import semmle.code.cpp.ir.EdgeKind
|
||||
|
||||
class IRBlock extends TIRBlock {
|
||||
final string toString() {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = getFirstInstruction(this).getUniqueId()
|
||||
}
|
||||
|
||||
final Instruction getInstruction(int index) {
|
||||
result = getInstruction(this, index)
|
||||
}
|
||||
|
||||
final PhiInstruction getAPhiInstruction() {
|
||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||
}
|
||||
|
||||
final Instruction getAnInstruction() {
|
||||
result = getInstruction(_) or
|
||||
result = getAPhiInstruction()
|
||||
}
|
||||
|
||||
final Instruction getFirstInstruction() {
|
||||
result = getFirstInstruction(this)
|
||||
}
|
||||
|
||||
final Instruction getLastInstruction() {
|
||||
result = getInstruction(getInstructionCount() - 1)
|
||||
}
|
||||
|
||||
final int getInstructionCount() {
|
||||
result = strictcount(getInstruction(_))
|
||||
}
|
||||
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = getFirstInstruction(this).getFunctionIR()
|
||||
}
|
||||
|
||||
final Function getFunction() {
|
||||
result = getFirstInstruction(this).getFunction()
|
||||
}
|
||||
|
||||
final IRBlock getASuccessor() {
|
||||
blockSuccessor(this, result)
|
||||
}
|
||||
|
||||
final IRBlock getAPredecessor() {
|
||||
blockSuccessor(result, this)
|
||||
}
|
||||
|
||||
final IRBlock getSuccessor(EdgeKind kind) {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
|
||||
final predicate strictlyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates+(this, block)
|
||||
}
|
||||
|
||||
final predicate dominates(IRBlock block) {
|
||||
strictlyDominates(block) or this = block
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
}
|
||||
private import IRInternal
|
||||
private import IRBlockConstruction
|
||||
import Instruction
|
||||
import semmle.code.cpp.ir.EdgeKind
|
||||
|
||||
class IRBlock extends TIRBlock {
|
||||
final string toString() {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = getFirstInstruction(this).getUniqueId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the block within its function. This is used
|
||||
* by debugging and printing code only.
|
||||
*/
|
||||
int getDisplayIndex() {
|
||||
this = rank[result + 1](IRBlock funcBlock |
|
||||
funcBlock.getFunction() = getFunction() |
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
final Instruction getInstruction(int index) {
|
||||
result = getInstruction(this, index)
|
||||
}
|
||||
|
||||
final PhiInstruction getAPhiInstruction() {
|
||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||
}
|
||||
|
||||
final Instruction getAnInstruction() {
|
||||
result = getInstruction(_) or
|
||||
result = getAPhiInstruction()
|
||||
}
|
||||
|
||||
final Instruction getFirstInstruction() {
|
||||
result = getFirstInstruction(this)
|
||||
}
|
||||
|
||||
final Instruction getLastInstruction() {
|
||||
result = getInstruction(getInstructionCount() - 1)
|
||||
}
|
||||
|
||||
final int getInstructionCount() {
|
||||
result = strictcount(getInstruction(_))
|
||||
}
|
||||
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = getFirstInstruction(this).getFunctionIR()
|
||||
}
|
||||
|
||||
final Function getFunction() {
|
||||
result = getFirstInstruction(this).getFunction()
|
||||
}
|
||||
|
||||
final IRBlock getASuccessor() {
|
||||
blockSuccessor(this, result)
|
||||
}
|
||||
|
||||
final IRBlock getAPredecessor() {
|
||||
blockSuccessor(result, this)
|
||||
}
|
||||
|
||||
final IRBlock getSuccessor(EdgeKind kind) {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
|
||||
final predicate strictlyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates+(this, block)
|
||||
}
|
||||
|
||||
final predicate dominates(IRBlock block) {
|
||||
strictlyDominates(block) or this = block
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +90,132 @@ class Instruction extends Construction::TInstruction {
|
||||
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = opcode.toString()
|
||||
final string toString() {
|
||||
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operation of this instruction. This includes
|
||||
* the opcode and the immediate value, if any. For example:
|
||||
*
|
||||
* VariableAddress[x]
|
||||
*/
|
||||
final string getOperationString() {
|
||||
if exists(getImmediateString()) then
|
||||
result = opcode.toString() + "[" + getImmediateString() + "]"
|
||||
else
|
||||
result = opcode.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the immediate value of this instruction, if any.
|
||||
*/
|
||||
string getImmediateString() {
|
||||
none()
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if resultType instanceof VoidType then
|
||||
result = "v"
|
||||
else if hasMemoryResult() then
|
||||
if isResultModeled() then
|
||||
result = "m"
|
||||
else
|
||||
result = "mu"
|
||||
else
|
||||
result = "r"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of this instruction within its block. This is
|
||||
* used by debugging and printing code only.
|
||||
*/
|
||||
int getDisplayIndexInBlock() {
|
||||
exists(IRBlock block |
|
||||
block = getBlock() and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
this = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
) or
|
||||
(
|
||||
this instanceof PhiInstruction and
|
||||
this = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction() |
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[type]
|
||||
private string getValueCategoryString(string type) {
|
||||
if isGLValue() then
|
||||
result = "glval<" + type + ">"
|
||||
else
|
||||
result = type
|
||||
}
|
||||
|
||||
private string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(resultType.toString()) and
|
||||
if resultType instanceof UnknownType and exists(getResultSize()) then
|
||||
result = valcat + "[" + getResultSize().toString() + "]"
|
||||
else
|
||||
result = valcat
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
* printing IR dumps.
|
||||
*
|
||||
* Example: `r1_1`
|
||||
*/
|
||||
string getResultId() {
|
||||
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||
getDisplayIndexInBlock().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the result of this instruction, suitable for
|
||||
* display in IR dumps. This consists of the result ID plus the type of the
|
||||
* result.
|
||||
*
|
||||
* Example: `r1_1(int*)`
|
||||
*/
|
||||
final string getResultString() {
|
||||
result = getResultId() + "(" + getResultTypeString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the specified operand, suitable for display in IR
|
||||
* dumps. This consists of the result ID of the instruction consumed by the
|
||||
* operand, plus a label identifying the operand kind.
|
||||
*
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
string getOperandString(OperandTag tag) {
|
||||
exists(Instruction operand |
|
||||
operand = getOperand(tag) and
|
||||
result = tag.getLabel() + operand.getResultId()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operands of this instruction, suitable for
|
||||
* display in IR dumps.
|
||||
*
|
||||
* Example: `func:r3_4, this:r3_5`
|
||||
*/
|
||||
string getOperandsString() {
|
||||
result = concat(OperandTag tag, Instruction operand |
|
||||
operand = getOperand(tag) |
|
||||
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,8 +436,8 @@ class VariableInstruction extends Instruction {
|
||||
var = Construction::getInstructionVariable(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + var.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
final IRVariable getVariable() {
|
||||
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
|
||||
field = Construction::getInstructionField(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + field.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = field.toString()
|
||||
}
|
||||
|
||||
final Field getField() {
|
||||
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
|
||||
funcSymbol = Construction::getInstructionFunction(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + funcSymbol.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = funcSymbol.toString()
|
||||
}
|
||||
|
||||
final Function getFunctionSymbol() {
|
||||
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
|
||||
value = Construction::getInstructionConstantValue(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + value + "]"
|
||||
override final string getImmediateString() {
|
||||
result = value
|
||||
}
|
||||
|
||||
final string getValue() {
|
||||
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
|
||||
value = Construction::getInstructionStringLiteral(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" +
|
||||
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
|
||||
"]"
|
||||
override final string getImmediateString() {
|
||||
result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
|
||||
}
|
||||
|
||||
final StringLiteral getValue() {
|
||||
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
elementSize = Construction::getInstructionElementSize(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + elementSize.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = elementSize.toString()
|
||||
}
|
||||
|
||||
final int getElementSize() {
|
||||
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = derivedClass.toString() + " : " + baseClass.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
exceptionType = Construction::getInstructionExceptionType(this)
|
||||
}
|
||||
|
||||
final override string toString() {
|
||||
result = super.toString() + "[" + exceptionType.toString() + "]"
|
||||
final override string getImmediateString() {
|
||||
result = exceptionType.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
|
||||
opcode instanceof Opcode::UnmodeledUse
|
||||
}
|
||||
|
||||
override string getOperandsString() {
|
||||
result = "mu*"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
tag instanceof UnmodeledUseOperand and
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
|
||||
@@ -1,299 +1,312 @@
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
|
||||
private newtype TOperandTag =
|
||||
TLoadStoreAddressOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TReturnValueOperand() or
|
||||
TExceptionOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
} or
|
||||
TPhiOperand(IRBlock predecessorBlock) {
|
||||
exists(PhiInstruction phi |
|
||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
abstract int getSortOrder();
|
||||
}
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
override final string toString() {
|
||||
result = "LoadStoreAddress"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||
result = TLoadStoreAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
override final string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
CopySourceOperand copySourceOperand() {
|
||||
result = TCopySourceOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperand unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends OperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperand leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends OperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
RightOperand rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
override final string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValueOperand returnValueOperand() {
|
||||
result = TReturnValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOperand exceptionOperand() {
|
||||
result = TExceptionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperand conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperand unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Invoke` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperand callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperand extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperand thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + argIndex
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of an SSA `Phi` instruction.
|
||||
*/
|
||||
class PhiOperand extends OperandTag, TPhiOperand {
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11
|
||||
}
|
||||
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
}
|
||||
|
||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||
result = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
|
||||
private newtype TOperandTag =
|
||||
TLoadStoreAddressOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TReturnValueOperand() or
|
||||
TExceptionOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
} or
|
||||
TPhiOperand(IRBlock predecessorBlock) {
|
||||
exists(PhiInstruction phi |
|
||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
|
||||
abstract int getSortOrder();
|
||||
|
||||
string getLabel() {
|
||||
result = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
override final string toString() {
|
||||
result = "LoadStoreAddress"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||
result = TLoadStoreAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
override final string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
CopySourceOperand copySourceOperand() {
|
||||
result = TCopySourceOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperand unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends OperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperand leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends OperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
RightOperand rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
override final string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValueOperand returnValueOperand() {
|
||||
result = TReturnValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOperand exceptionOperand() {
|
||||
result = TExceptionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperand conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperand unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Invoke` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperand callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperand extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "this:"
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperand thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + argIndex
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of an SSA `Phi` instruction.
|
||||
*/
|
||||
class PhiOperand extends OperandTag, TPhiOperand {
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
}
|
||||
|
||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||
result = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
@@ -1,175 +1,239 @@
|
||||
private import IRImpl
|
||||
import cpp
|
||||
|
||||
private int getInstructionIndexInBlock(Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
block = instr.getBlock() and
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableFunctionIR(FunctionIR funcIR) or
|
||||
TPrintableIRBlock(IRBlock block) or
|
||||
TPrintableInstruction(Instruction instr)
|
||||
|
||||
/**
|
||||
* A node to be emitted in the IR graph.
|
||||
*/
|
||||
abstract class PrintableIRNode extends TPrintableIRNode {
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the location to be emitted for the node.
|
||||
*/
|
||||
abstract Location getLocation();
|
||||
|
||||
/**
|
||||
* Gets the label to be emitted for the node.
|
||||
*/
|
||||
abstract string getLabel();
|
||||
|
||||
/**
|
||||
* Gets the order in which the node appears in its parent node.
|
||||
*/
|
||||
abstract int getOrder();
|
||||
|
||||
/**
|
||||
* Gets the parent of this node.
|
||||
*/
|
||||
abstract PrintableIRNode getParent();
|
||||
|
||||
/**
|
||||
* Gets the kind of graph represented by this node ("graph" or "tree").
|
||||
*/
|
||||
string getGraphKind() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node should always be rendered as text, even in a graphical
|
||||
* viewer.
|
||||
*/
|
||||
predicate forceText() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the node property with the specified key.
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and result = getLabel() or
|
||||
key = "semmle.order" and result = getOrder().toString() or
|
||||
key = "semmle.graphKind" and result = getGraphKind() or
|
||||
key = "semmle.forceText" and forceText() and result = "true"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR graph node representing a `FunctionIR` object.
|
||||
*/
|
||||
class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
|
||||
FunctionIR funcIR;
|
||||
|
||||
PrintableFunctionIR() {
|
||||
this = TPrintableFunctionIR(funcIR)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = funcIR.toString()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = funcIR.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = funcIR.getFunction().getFullSignature()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
this = rank[result + 1](PrintableFunctionIR orderedFunc, Location location |
|
||||
location = orderedFunc.getFunctionIR().getLocation() |
|
||||
orderedFunc order by location.getFile().getURL(), location.getStartLine(),
|
||||
location.getStartColumn(), orderedFunc.getLabel()
|
||||
)
|
||||
}
|
||||
|
||||
override final PrintableIRNode getParent() {
|
||||
none()
|
||||
}
|
||||
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR graph node representing an `IRBlock` object.
|
||||
*/
|
||||
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
IRBlock block;
|
||||
|
||||
PrintableIRBlock() {
|
||||
this = TPrintableIRBlock(block)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getLabel()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = block.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = "Block " + block.getDisplayIndex().toString()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
result = block.getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getGraphKind() {
|
||||
result = "tree"
|
||||
}
|
||||
|
||||
override final predicate forceText() {
|
||||
any()
|
||||
}
|
||||
|
||||
override final PrintableFunctionIR getParent() {
|
||||
result.getFunctionIR() = block.getFunctionIR()
|
||||
}
|
||||
|
||||
final IRBlock getBlock() {
|
||||
result = block
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR graph node representing an `Instruction`.
|
||||
*/
|
||||
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
Instruction instr;
|
||||
|
||||
PrintableInstruction() {
|
||||
this = TPrintableInstruction(instr)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = instr.toString()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = instr.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
exists(IRBlock block |
|
||||
instr = block.getAnInstruction() and
|
||||
exists(string resultString, string operationString, string operandsString,
|
||||
int resultWidth, int operationWidth |
|
||||
resultString = instr.getResultString() and
|
||||
operationString = instr.getOperationString() and
|
||||
operandsString = instr.getOperandsString() and
|
||||
columnWidths(block, resultWidth, operationWidth) and
|
||||
result = resultString + getPaddingString(resultWidth - resultString.length()) +
|
||||
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
|
||||
" : " + operandsString
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
result = instr.getDisplayIndexInBlock()
|
||||
}
|
||||
|
||||
override final PrintableIRBlock getParent() {
|
||||
result.getBlock() = instr.getBlock()
|
||||
}
|
||||
|
||||
final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
}
|
||||
|
||||
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
|
||||
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
|
||||
}
|
||||
|
||||
private int maxColumnWidth() {
|
||||
result = max(Instruction instr, int width |
|
||||
width = instr.getResultString().length() or
|
||||
width = instr.getOperationString().length() or
|
||||
width = instr.getOperandsString().length() |
|
||||
width)
|
||||
}
|
||||
|
||||
private string getPaddingString(int n) {
|
||||
n = 0 and result = "" or
|
||||
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
|
||||
}
|
||||
|
||||
query predicate nodes(PrintableIRNode node, string key, string value) {
|
||||
value = node.getProperty(key)
|
||||
}
|
||||
|
||||
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
|
||||
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
|
||||
aSucc = pred.getSuccessor(kind) |
|
||||
aSucc order by kind.toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
|
||||
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
|
||||
predBlock = pred.getBlock() and
|
||||
succBlock = succ.getBlock() and
|
||||
predBlock.getSuccessor(kind) = succBlock and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
instr = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = kind.toString()
|
||||
) or
|
||||
(
|
||||
instr instanceof PhiInstruction and
|
||||
instr = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction() |
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
key = "semmle.order" and
|
||||
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private string getInstructionResultId(Instruction instr) {
|
||||
result = getResultPrefix(instr) + getBlockId(instr.getBlock()) + "_" +
|
||||
getInstructionIndexInBlock(instr).toString()
|
||||
}
|
||||
|
||||
private string getResultPrefix(Instruction instr) {
|
||||
if instr.hasMemoryResult() then
|
||||
if instr.isResultModeled() then
|
||||
result = "@m"
|
||||
else
|
||||
result = "@mu"
|
||||
else
|
||||
result = "@r"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identifier of the specified function scope.
|
||||
* Currently just returns the signature of the function.
|
||||
*/
|
||||
private string getScopeId(Function func) {
|
||||
result = func.getFullSignature()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique identifier of the block within its function.
|
||||
* Currently returns a string representation of an integer in the range
|
||||
* [0..numBlocks - 1].
|
||||
*/
|
||||
private string getBlockId(IRBlock block) {
|
||||
exists(int rankIndex |
|
||||
block = rank[rankIndex + 1](IRBlock funcBlock |
|
||||
funcBlock.getFunction() = block.getFunction() |
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
) and
|
||||
result = rankIndex.toString()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the full signature and qualified name for each scope. This is primarily
|
||||
* so that post-processing tools can identify function overloads, which will have
|
||||
* different signatures but the same qualified name.
|
||||
*/
|
||||
query predicate printIRGraphScopes(string scopeId, string qualifiedName) {
|
||||
exists(FunctionIR ir, Function func |
|
||||
func = ir.getFunction() and
|
||||
scopeId = getScopeId(func) and
|
||||
qualifiedName = func.getQualifiedName()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphNodes(string scopeId, string blockId, string label, string location) {
|
||||
exists(IRBlock block |
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
blockId = getBlockId(block) and
|
||||
label = "" and
|
||||
location = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphInstructions(string scopeId, string blockId,
|
||||
string id, string label, string location) {
|
||||
exists(IRBlock block, Instruction instr |
|
||||
instr = block.getAnInstruction() and
|
||||
label = instr.toString() and
|
||||
location = instr.getLocation().toString() and
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
blockId = getBlockId(block) and
|
||||
id = getInstructionIndexInBlock(instr).toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphEdges(string scopeId,
|
||||
string predecessorId, string successorId, string label) {
|
||||
exists(IRBlock predecessor, IRBlock successor, EdgeKind kind |
|
||||
scopeId = getScopeId(predecessor.getFunction()) and
|
||||
predecessor.getSuccessor(kind) = successor and
|
||||
predecessorId = getBlockId(predecessor) and
|
||||
successorId = getBlockId(successor) and
|
||||
label = kind.toString()
|
||||
)
|
||||
}
|
||||
|
||||
private string getValueCategoryString(Instruction instr) {
|
||||
if instr.isGLValue() then
|
||||
result = "glval:"
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string getResultTypeString(Instruction instr) {
|
||||
exists(Type resultType, string valcat |
|
||||
resultType = instr.getResultType() and
|
||||
valcat = getValueCategoryString(instr) and
|
||||
if resultType instanceof UnknownType and exists(instr.getResultSize()) then
|
||||
result = valcat + resultType.toString() + "[" + instr.getResultSize().toString() + "]"
|
||||
else
|
||||
result = valcat + resultType.toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphDestinationOperands(string scopeId, string blockId,
|
||||
string instructionId, int operandId, string label) {
|
||||
exists(IRBlock block, Instruction instr |
|
||||
block.getAnInstruction() = instr and
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
blockId = getBlockId(block) and
|
||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
||||
not instr.getResultType() instanceof VoidType and
|
||||
operandId = 0 and
|
||||
label = getInstructionResultId(instr) +
|
||||
"(" + getResultTypeString(instr) + ")"
|
||||
)
|
||||
}
|
||||
|
||||
private string getOperandTagLabel(OperandTag tag) {
|
||||
(
|
||||
tag instanceof PhiOperand and
|
||||
result = "from " + getBlockId(tag.(PhiOperand).getPredecessorBlock()) + ": "
|
||||
)
|
||||
or (
|
||||
tag instanceof ThisArgumentOperand and
|
||||
result = "this:"
|
||||
)
|
||||
or (
|
||||
not tag instanceof PhiOperand and
|
||||
not tag instanceof ThisArgumentOperand and
|
||||
result = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphSourceOperands(string scopeId, string blockId,
|
||||
string instructionId, int operandId, string label) {
|
||||
exists(IRBlock block, Instruction instr |
|
||||
block.getAnInstruction() = instr and
|
||||
blockId = getBlockId(block) and
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
||||
if (instr instanceof UnmodeledUseInstruction) then (
|
||||
operandId = 0 and
|
||||
label = "@mu*"
|
||||
)
|
||||
else (
|
||||
exists(OperandTag tag, Instruction operandInstr |
|
||||
operandInstr = instr.getOperand(tag) and
|
||||
operandId = tag.getSortOrder() and
|
||||
label = getOperandTagLabel(tag) +
|
||||
getInstructionResultId(operandInstr)
|
||||
)
|
||||
)
|
||||
)
|
||||
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
|
||||
parent = child.getParent()
|
||||
}
|
||||
|
||||
8
cpp/ql/src/semmle/code/cpp/ssa/PrintAliasedSSAIR.ql
Normal file
8
cpp/ql/src/semmle/code/cpp/ssa/PrintAliasedSSAIR.ql
Normal 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
|
||||
8
cpp/ql/src/semmle/code/cpp/ssa/PrintSSAIR.ql
Normal file
8
cpp/ql/src/semmle/code/cpp/ssa/PrintSSAIR.ql
Normal 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
|
||||
@@ -1,81 +1,92 @@
|
||||
private import IRInternal
|
||||
private import IRBlockConstruction
|
||||
import Instruction
|
||||
import semmle.code.cpp.ir.EdgeKind
|
||||
|
||||
class IRBlock extends TIRBlock {
|
||||
final string toString() {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = getFirstInstruction(this).getUniqueId()
|
||||
}
|
||||
|
||||
final Instruction getInstruction(int index) {
|
||||
result = getInstruction(this, index)
|
||||
}
|
||||
|
||||
final PhiInstruction getAPhiInstruction() {
|
||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||
}
|
||||
|
||||
final Instruction getAnInstruction() {
|
||||
result = getInstruction(_) or
|
||||
result = getAPhiInstruction()
|
||||
}
|
||||
|
||||
final Instruction getFirstInstruction() {
|
||||
result = getFirstInstruction(this)
|
||||
}
|
||||
|
||||
final Instruction getLastInstruction() {
|
||||
result = getInstruction(getInstructionCount() - 1)
|
||||
}
|
||||
|
||||
final int getInstructionCount() {
|
||||
result = strictcount(getInstruction(_))
|
||||
}
|
||||
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = getFirstInstruction(this).getFunctionIR()
|
||||
}
|
||||
|
||||
final Function getFunction() {
|
||||
result = getFirstInstruction(this).getFunction()
|
||||
}
|
||||
|
||||
final IRBlock getASuccessor() {
|
||||
blockSuccessor(this, result)
|
||||
}
|
||||
|
||||
final IRBlock getAPredecessor() {
|
||||
blockSuccessor(result, this)
|
||||
}
|
||||
|
||||
final IRBlock getSuccessor(EdgeKind kind) {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
|
||||
final predicate strictlyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates+(this, block)
|
||||
}
|
||||
|
||||
final predicate dominates(IRBlock block) {
|
||||
strictlyDominates(block) or this = block
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
}
|
||||
private import IRInternal
|
||||
private import IRBlockConstruction
|
||||
import Instruction
|
||||
import semmle.code.cpp.ir.EdgeKind
|
||||
|
||||
class IRBlock extends TIRBlock {
|
||||
final string toString() {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = getFirstInstruction(this).getUniqueId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the block within its function. This is used
|
||||
* by debugging and printing code only.
|
||||
*/
|
||||
int getDisplayIndex() {
|
||||
this = rank[result + 1](IRBlock funcBlock |
|
||||
funcBlock.getFunction() = getFunction() |
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
final Instruction getInstruction(int index) {
|
||||
result = getInstruction(this, index)
|
||||
}
|
||||
|
||||
final PhiInstruction getAPhiInstruction() {
|
||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||
}
|
||||
|
||||
final Instruction getAnInstruction() {
|
||||
result = getInstruction(_) or
|
||||
result = getAPhiInstruction()
|
||||
}
|
||||
|
||||
final Instruction getFirstInstruction() {
|
||||
result = getFirstInstruction(this)
|
||||
}
|
||||
|
||||
final Instruction getLastInstruction() {
|
||||
result = getInstruction(getInstructionCount() - 1)
|
||||
}
|
||||
|
||||
final int getInstructionCount() {
|
||||
result = strictcount(getInstruction(_))
|
||||
}
|
||||
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = getFirstInstruction(this).getFunctionIR()
|
||||
}
|
||||
|
||||
final Function getFunction() {
|
||||
result = getFirstInstruction(this).getFunction()
|
||||
}
|
||||
|
||||
final IRBlock getASuccessor() {
|
||||
blockSuccessor(this, result)
|
||||
}
|
||||
|
||||
final IRBlock getAPredecessor() {
|
||||
blockSuccessor(result, this)
|
||||
}
|
||||
|
||||
final IRBlock getSuccessor(EdgeKind kind) {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
|
||||
final predicate strictlyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates+(this, block)
|
||||
}
|
||||
|
||||
final predicate dominates(IRBlock block) {
|
||||
strictlyDominates(block) or this = block
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +90,132 @@ class Instruction extends Construction::TInstruction {
|
||||
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = opcode.toString()
|
||||
final string toString() {
|
||||
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operation of this instruction. This includes
|
||||
* the opcode and the immediate value, if any. For example:
|
||||
*
|
||||
* VariableAddress[x]
|
||||
*/
|
||||
final string getOperationString() {
|
||||
if exists(getImmediateString()) then
|
||||
result = opcode.toString() + "[" + getImmediateString() + "]"
|
||||
else
|
||||
result = opcode.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the immediate value of this instruction, if any.
|
||||
*/
|
||||
string getImmediateString() {
|
||||
none()
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if resultType instanceof VoidType then
|
||||
result = "v"
|
||||
else if hasMemoryResult() then
|
||||
if isResultModeled() then
|
||||
result = "m"
|
||||
else
|
||||
result = "mu"
|
||||
else
|
||||
result = "r"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of this instruction within its block. This is
|
||||
* used by debugging and printing code only.
|
||||
*/
|
||||
int getDisplayIndexInBlock() {
|
||||
exists(IRBlock block |
|
||||
block = getBlock() and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
this = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
) or
|
||||
(
|
||||
this instanceof PhiInstruction and
|
||||
this = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction() |
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[type]
|
||||
private string getValueCategoryString(string type) {
|
||||
if isGLValue() then
|
||||
result = "glval<" + type + ">"
|
||||
else
|
||||
result = type
|
||||
}
|
||||
|
||||
private string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(resultType.toString()) and
|
||||
if resultType instanceof UnknownType and exists(getResultSize()) then
|
||||
result = valcat + "[" + getResultSize().toString() + "]"
|
||||
else
|
||||
result = valcat
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
* printing IR dumps.
|
||||
*
|
||||
* Example: `r1_1`
|
||||
*/
|
||||
string getResultId() {
|
||||
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||
getDisplayIndexInBlock().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the result of this instruction, suitable for
|
||||
* display in IR dumps. This consists of the result ID plus the type of the
|
||||
* result.
|
||||
*
|
||||
* Example: `r1_1(int*)`
|
||||
*/
|
||||
final string getResultString() {
|
||||
result = getResultId() + "(" + getResultTypeString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the specified operand, suitable for display in IR
|
||||
* dumps. This consists of the result ID of the instruction consumed by the
|
||||
* operand, plus a label identifying the operand kind.
|
||||
*
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
string getOperandString(OperandTag tag) {
|
||||
exists(Instruction operand |
|
||||
operand = getOperand(tag) and
|
||||
result = tag.getLabel() + operand.getResultId()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operands of this instruction, suitable for
|
||||
* display in IR dumps.
|
||||
*
|
||||
* Example: `func:r3_4, this:r3_5`
|
||||
*/
|
||||
string getOperandsString() {
|
||||
result = concat(OperandTag tag, Instruction operand |
|
||||
operand = getOperand(tag) |
|
||||
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,8 +436,8 @@ class VariableInstruction extends Instruction {
|
||||
var = Construction::getInstructionVariable(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + var.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
final IRVariable getVariable() {
|
||||
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
|
||||
field = Construction::getInstructionField(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + field.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = field.toString()
|
||||
}
|
||||
|
||||
final Field getField() {
|
||||
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
|
||||
funcSymbol = Construction::getInstructionFunction(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + funcSymbol.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = funcSymbol.toString()
|
||||
}
|
||||
|
||||
final Function getFunctionSymbol() {
|
||||
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
|
||||
value = Construction::getInstructionConstantValue(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + value + "]"
|
||||
override final string getImmediateString() {
|
||||
result = value
|
||||
}
|
||||
|
||||
final string getValue() {
|
||||
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
|
||||
value = Construction::getInstructionStringLiteral(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" +
|
||||
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
|
||||
"]"
|
||||
override final string getImmediateString() {
|
||||
result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
|
||||
}
|
||||
|
||||
final StringLiteral getValue() {
|
||||
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
elementSize = Construction::getInstructionElementSize(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + elementSize.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = elementSize.toString()
|
||||
}
|
||||
|
||||
final int getElementSize() {
|
||||
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = derivedClass.toString() + " : " + baseClass.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
exceptionType = Construction::getInstructionExceptionType(this)
|
||||
}
|
||||
|
||||
final override string toString() {
|
||||
result = super.toString() + "[" + exceptionType.toString() + "]"
|
||||
final override string getImmediateString() {
|
||||
result = exceptionType.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
|
||||
opcode instanceof Opcode::UnmodeledUse
|
||||
}
|
||||
|
||||
override string getOperandsString() {
|
||||
result = "mu*"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
tag instanceof UnmodeledUseOperand and
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
|
||||
@@ -1,299 +1,312 @@
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
|
||||
private newtype TOperandTag =
|
||||
TLoadStoreAddressOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TReturnValueOperand() or
|
||||
TExceptionOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
} or
|
||||
TPhiOperand(IRBlock predecessorBlock) {
|
||||
exists(PhiInstruction phi |
|
||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
abstract int getSortOrder();
|
||||
}
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
override final string toString() {
|
||||
result = "LoadStoreAddress"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||
result = TLoadStoreAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
override final string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
CopySourceOperand copySourceOperand() {
|
||||
result = TCopySourceOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperand unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends OperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperand leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends OperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
RightOperand rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
override final string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValueOperand returnValueOperand() {
|
||||
result = TReturnValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOperand exceptionOperand() {
|
||||
result = TExceptionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperand conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperand unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Invoke` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperand callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperand extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperand thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + argIndex
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of an SSA `Phi` instruction.
|
||||
*/
|
||||
class PhiOperand extends OperandTag, TPhiOperand {
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11
|
||||
}
|
||||
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
}
|
||||
|
||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||
result = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
|
||||
private newtype TOperandTag =
|
||||
TLoadStoreAddressOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TReturnValueOperand() or
|
||||
TExceptionOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
} or
|
||||
TPhiOperand(IRBlock predecessorBlock) {
|
||||
exists(PhiInstruction phi |
|
||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
|
||||
abstract int getSortOrder();
|
||||
|
||||
string getLabel() {
|
||||
result = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
override final string toString() {
|
||||
result = "LoadStoreAddress"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||
result = TLoadStoreAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
override final string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
CopySourceOperand copySourceOperand() {
|
||||
result = TCopySourceOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperand unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends OperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperand leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends OperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
RightOperand rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
override final string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValueOperand returnValueOperand() {
|
||||
result = TReturnValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOperand exceptionOperand() {
|
||||
result = TExceptionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperand conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperand unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Invoke` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperand callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperand extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "this:"
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperand thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + argIndex
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of an SSA `Phi` instruction.
|
||||
*/
|
||||
class PhiOperand extends OperandTag, TPhiOperand {
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
}
|
||||
|
||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||
result = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
@@ -1,175 +1,239 @@
|
||||
private import IRImpl
|
||||
import cpp
|
||||
|
||||
private int getInstructionIndexInBlock(Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
block = instr.getBlock() and
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableFunctionIR(FunctionIR funcIR) or
|
||||
TPrintableIRBlock(IRBlock block) or
|
||||
TPrintableInstruction(Instruction instr)
|
||||
|
||||
/**
|
||||
* A node to be emitted in the IR graph.
|
||||
*/
|
||||
abstract class PrintableIRNode extends TPrintableIRNode {
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the location to be emitted for the node.
|
||||
*/
|
||||
abstract Location getLocation();
|
||||
|
||||
/**
|
||||
* Gets the label to be emitted for the node.
|
||||
*/
|
||||
abstract string getLabel();
|
||||
|
||||
/**
|
||||
* Gets the order in which the node appears in its parent node.
|
||||
*/
|
||||
abstract int getOrder();
|
||||
|
||||
/**
|
||||
* Gets the parent of this node.
|
||||
*/
|
||||
abstract PrintableIRNode getParent();
|
||||
|
||||
/**
|
||||
* Gets the kind of graph represented by this node ("graph" or "tree").
|
||||
*/
|
||||
string getGraphKind() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node should always be rendered as text, even in a graphical
|
||||
* viewer.
|
||||
*/
|
||||
predicate forceText() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the node property with the specified key.
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and result = getLabel() or
|
||||
key = "semmle.order" and result = getOrder().toString() or
|
||||
key = "semmle.graphKind" and result = getGraphKind() or
|
||||
key = "semmle.forceText" and forceText() and result = "true"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR graph node representing a `FunctionIR` object.
|
||||
*/
|
||||
class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
|
||||
FunctionIR funcIR;
|
||||
|
||||
PrintableFunctionIR() {
|
||||
this = TPrintableFunctionIR(funcIR)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = funcIR.toString()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = funcIR.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = funcIR.getFunction().getFullSignature()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
this = rank[result + 1](PrintableFunctionIR orderedFunc, Location location |
|
||||
location = orderedFunc.getFunctionIR().getLocation() |
|
||||
orderedFunc order by location.getFile().getURL(), location.getStartLine(),
|
||||
location.getStartColumn(), orderedFunc.getLabel()
|
||||
)
|
||||
}
|
||||
|
||||
override final PrintableIRNode getParent() {
|
||||
none()
|
||||
}
|
||||
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR graph node representing an `IRBlock` object.
|
||||
*/
|
||||
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
IRBlock block;
|
||||
|
||||
PrintableIRBlock() {
|
||||
this = TPrintableIRBlock(block)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getLabel()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = block.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = "Block " + block.getDisplayIndex().toString()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
result = block.getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getGraphKind() {
|
||||
result = "tree"
|
||||
}
|
||||
|
||||
override final predicate forceText() {
|
||||
any()
|
||||
}
|
||||
|
||||
override final PrintableFunctionIR getParent() {
|
||||
result.getFunctionIR() = block.getFunctionIR()
|
||||
}
|
||||
|
||||
final IRBlock getBlock() {
|
||||
result = block
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR graph node representing an `Instruction`.
|
||||
*/
|
||||
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
Instruction instr;
|
||||
|
||||
PrintableInstruction() {
|
||||
this = TPrintableInstruction(instr)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = instr.toString()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = instr.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
exists(IRBlock block |
|
||||
instr = block.getAnInstruction() and
|
||||
exists(string resultString, string operationString, string operandsString,
|
||||
int resultWidth, int operationWidth |
|
||||
resultString = instr.getResultString() and
|
||||
operationString = instr.getOperationString() and
|
||||
operandsString = instr.getOperandsString() and
|
||||
columnWidths(block, resultWidth, operationWidth) and
|
||||
result = resultString + getPaddingString(resultWidth - resultString.length()) +
|
||||
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
|
||||
" : " + operandsString
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
result = instr.getDisplayIndexInBlock()
|
||||
}
|
||||
|
||||
override final PrintableIRBlock getParent() {
|
||||
result.getBlock() = instr.getBlock()
|
||||
}
|
||||
|
||||
final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
}
|
||||
|
||||
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
|
||||
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
|
||||
}
|
||||
|
||||
private int maxColumnWidth() {
|
||||
result = max(Instruction instr, int width |
|
||||
width = instr.getResultString().length() or
|
||||
width = instr.getOperationString().length() or
|
||||
width = instr.getOperandsString().length() |
|
||||
width)
|
||||
}
|
||||
|
||||
private string getPaddingString(int n) {
|
||||
n = 0 and result = "" or
|
||||
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
|
||||
}
|
||||
|
||||
query predicate nodes(PrintableIRNode node, string key, string value) {
|
||||
value = node.getProperty(key)
|
||||
}
|
||||
|
||||
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
|
||||
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
|
||||
aSucc = pred.getSuccessor(kind) |
|
||||
aSucc order by kind.toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
|
||||
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
|
||||
predBlock = pred.getBlock() and
|
||||
succBlock = succ.getBlock() and
|
||||
predBlock.getSuccessor(kind) = succBlock and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
instr = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = kind.toString()
|
||||
) or
|
||||
(
|
||||
instr instanceof PhiInstruction and
|
||||
instr = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction() |
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
key = "semmle.order" and
|
||||
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private string getInstructionResultId(Instruction instr) {
|
||||
result = getResultPrefix(instr) + getBlockId(instr.getBlock()) + "_" +
|
||||
getInstructionIndexInBlock(instr).toString()
|
||||
}
|
||||
|
||||
private string getResultPrefix(Instruction instr) {
|
||||
if instr.hasMemoryResult() then
|
||||
if instr.isResultModeled() then
|
||||
result = "@m"
|
||||
else
|
||||
result = "@mu"
|
||||
else
|
||||
result = "@r"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identifier of the specified function scope.
|
||||
* Currently just returns the signature of the function.
|
||||
*/
|
||||
private string getScopeId(Function func) {
|
||||
result = func.getFullSignature()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique identifier of the block within its function.
|
||||
* Currently returns a string representation of an integer in the range
|
||||
* [0..numBlocks - 1].
|
||||
*/
|
||||
private string getBlockId(IRBlock block) {
|
||||
exists(int rankIndex |
|
||||
block = rank[rankIndex + 1](IRBlock funcBlock |
|
||||
funcBlock.getFunction() = block.getFunction() |
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
) and
|
||||
result = rankIndex.toString()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the full signature and qualified name for each scope. This is primarily
|
||||
* so that post-processing tools can identify function overloads, which will have
|
||||
* different signatures but the same qualified name.
|
||||
*/
|
||||
query predicate printIRGraphScopes(string scopeId, string qualifiedName) {
|
||||
exists(FunctionIR ir, Function func |
|
||||
func = ir.getFunction() and
|
||||
scopeId = getScopeId(func) and
|
||||
qualifiedName = func.getQualifiedName()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphNodes(string scopeId, string blockId, string label, string location) {
|
||||
exists(IRBlock block |
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
blockId = getBlockId(block) and
|
||||
label = "" and
|
||||
location = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphInstructions(string scopeId, string blockId,
|
||||
string id, string label, string location) {
|
||||
exists(IRBlock block, Instruction instr |
|
||||
instr = block.getAnInstruction() and
|
||||
label = instr.toString() and
|
||||
location = instr.getLocation().toString() and
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
blockId = getBlockId(block) and
|
||||
id = getInstructionIndexInBlock(instr).toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphEdges(string scopeId,
|
||||
string predecessorId, string successorId, string label) {
|
||||
exists(IRBlock predecessor, IRBlock successor, EdgeKind kind |
|
||||
scopeId = getScopeId(predecessor.getFunction()) and
|
||||
predecessor.getSuccessor(kind) = successor and
|
||||
predecessorId = getBlockId(predecessor) and
|
||||
successorId = getBlockId(successor) and
|
||||
label = kind.toString()
|
||||
)
|
||||
}
|
||||
|
||||
private string getValueCategoryString(Instruction instr) {
|
||||
if instr.isGLValue() then
|
||||
result = "glval:"
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string getResultTypeString(Instruction instr) {
|
||||
exists(Type resultType, string valcat |
|
||||
resultType = instr.getResultType() and
|
||||
valcat = getValueCategoryString(instr) and
|
||||
if resultType instanceof UnknownType and exists(instr.getResultSize()) then
|
||||
result = valcat + resultType.toString() + "[" + instr.getResultSize().toString() + "]"
|
||||
else
|
||||
result = valcat + resultType.toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphDestinationOperands(string scopeId, string blockId,
|
||||
string instructionId, int operandId, string label) {
|
||||
exists(IRBlock block, Instruction instr |
|
||||
block.getAnInstruction() = instr and
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
blockId = getBlockId(block) and
|
||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
||||
not instr.getResultType() instanceof VoidType and
|
||||
operandId = 0 and
|
||||
label = getInstructionResultId(instr) +
|
||||
"(" + getResultTypeString(instr) + ")"
|
||||
)
|
||||
}
|
||||
|
||||
private string getOperandTagLabel(OperandTag tag) {
|
||||
(
|
||||
tag instanceof PhiOperand and
|
||||
result = "from " + getBlockId(tag.(PhiOperand).getPredecessorBlock()) + ": "
|
||||
)
|
||||
or (
|
||||
tag instanceof ThisArgumentOperand and
|
||||
result = "this:"
|
||||
)
|
||||
or (
|
||||
not tag instanceof PhiOperand and
|
||||
not tag instanceof ThisArgumentOperand and
|
||||
result = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphSourceOperands(string scopeId, string blockId,
|
||||
string instructionId, int operandId, string label) {
|
||||
exists(IRBlock block, Instruction instr |
|
||||
block.getAnInstruction() = instr and
|
||||
blockId = getBlockId(block) and
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
||||
if (instr instanceof UnmodeledUseInstruction) then (
|
||||
operandId = 0 and
|
||||
label = "@mu*"
|
||||
)
|
||||
else (
|
||||
exists(OperandTag tag, Instruction operandInstr |
|
||||
operandInstr = instr.getOperand(tag) and
|
||||
operandId = tag.getSortOrder() and
|
||||
label = getOperandTagLabel(tag) +
|
||||
getInstructionResultId(operandInstr)
|
||||
)
|
||||
)
|
||||
)
|
||||
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
|
||||
parent = child.getParent()
|
||||
}
|
||||
|
||||
@@ -1,81 +1,92 @@
|
||||
private import IRInternal
|
||||
private import IRBlockConstruction
|
||||
import Instruction
|
||||
import semmle.code.cpp.ir.EdgeKind
|
||||
|
||||
class IRBlock extends TIRBlock {
|
||||
final string toString() {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = getFirstInstruction(this).getUniqueId()
|
||||
}
|
||||
|
||||
final Instruction getInstruction(int index) {
|
||||
result = getInstruction(this, index)
|
||||
}
|
||||
|
||||
final PhiInstruction getAPhiInstruction() {
|
||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||
}
|
||||
|
||||
final Instruction getAnInstruction() {
|
||||
result = getInstruction(_) or
|
||||
result = getAPhiInstruction()
|
||||
}
|
||||
|
||||
final Instruction getFirstInstruction() {
|
||||
result = getFirstInstruction(this)
|
||||
}
|
||||
|
||||
final Instruction getLastInstruction() {
|
||||
result = getInstruction(getInstructionCount() - 1)
|
||||
}
|
||||
|
||||
final int getInstructionCount() {
|
||||
result = strictcount(getInstruction(_))
|
||||
}
|
||||
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = getFirstInstruction(this).getFunctionIR()
|
||||
}
|
||||
|
||||
final Function getFunction() {
|
||||
result = getFirstInstruction(this).getFunction()
|
||||
}
|
||||
|
||||
final IRBlock getASuccessor() {
|
||||
blockSuccessor(this, result)
|
||||
}
|
||||
|
||||
final IRBlock getAPredecessor() {
|
||||
blockSuccessor(result, this)
|
||||
}
|
||||
|
||||
final IRBlock getSuccessor(EdgeKind kind) {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
|
||||
final predicate strictlyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates+(this, block)
|
||||
}
|
||||
|
||||
final predicate dominates(IRBlock block) {
|
||||
strictlyDominates(block) or this = block
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
}
|
||||
private import IRInternal
|
||||
private import IRBlockConstruction
|
||||
import Instruction
|
||||
import semmle.code.cpp.ir.EdgeKind
|
||||
|
||||
class IRBlock extends TIRBlock {
|
||||
final string toString() {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
final string getUniqueId() {
|
||||
result = getFirstInstruction(this).getUniqueId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of the block within its function. This is used
|
||||
* by debugging and printing code only.
|
||||
*/
|
||||
int getDisplayIndex() {
|
||||
this = rank[result + 1](IRBlock funcBlock |
|
||||
funcBlock.getFunction() = getFunction() |
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
)
|
||||
}
|
||||
|
||||
final Instruction getInstruction(int index) {
|
||||
result = getInstruction(this, index)
|
||||
}
|
||||
|
||||
final PhiInstruction getAPhiInstruction() {
|
||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||
}
|
||||
|
||||
final Instruction getAnInstruction() {
|
||||
result = getInstruction(_) or
|
||||
result = getAPhiInstruction()
|
||||
}
|
||||
|
||||
final Instruction getFirstInstruction() {
|
||||
result = getFirstInstruction(this)
|
||||
}
|
||||
|
||||
final Instruction getLastInstruction() {
|
||||
result = getInstruction(getInstructionCount() - 1)
|
||||
}
|
||||
|
||||
final int getInstructionCount() {
|
||||
result = strictcount(getInstruction(_))
|
||||
}
|
||||
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = getFirstInstruction(this).getFunctionIR()
|
||||
}
|
||||
|
||||
final Function getFunction() {
|
||||
result = getFirstInstruction(this).getFunction()
|
||||
}
|
||||
|
||||
final IRBlock getASuccessor() {
|
||||
blockSuccessor(this, result)
|
||||
}
|
||||
|
||||
final IRBlock getAPredecessor() {
|
||||
blockSuccessor(result, this)
|
||||
}
|
||||
|
||||
final IRBlock getSuccessor(EdgeKind kind) {
|
||||
blockSuccessor(this, result, kind)
|
||||
}
|
||||
|
||||
final predicate immediatelyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates(this, block)
|
||||
}
|
||||
|
||||
final predicate strictlyDominates(IRBlock block) {
|
||||
blockImmediatelyDominates+(this, block)
|
||||
}
|
||||
|
||||
final predicate dominates(IRBlock block) {
|
||||
strictlyDominates(block) or this = block
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +90,132 @@ class Instruction extends Construction::TInstruction {
|
||||
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = opcode.toString()
|
||||
final string toString() {
|
||||
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operation of this instruction. This includes
|
||||
* the opcode and the immediate value, if any. For example:
|
||||
*
|
||||
* VariableAddress[x]
|
||||
*/
|
||||
final string getOperationString() {
|
||||
if exists(getImmediateString()) then
|
||||
result = opcode.toString() + "[" + getImmediateString() + "]"
|
||||
else
|
||||
result = opcode.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the immediate value of this instruction, if any.
|
||||
*/
|
||||
string getImmediateString() {
|
||||
none()
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if resultType instanceof VoidType then
|
||||
result = "v"
|
||||
else if hasMemoryResult() then
|
||||
if isResultModeled() then
|
||||
result = "m"
|
||||
else
|
||||
result = "mu"
|
||||
else
|
||||
result = "r"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of this instruction within its block. This is
|
||||
* used by debugging and printing code only.
|
||||
*/
|
||||
int getDisplayIndexInBlock() {
|
||||
exists(IRBlock block |
|
||||
block = getBlock() and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
this = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
) or
|
||||
(
|
||||
this instanceof PhiInstruction and
|
||||
this = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction() |
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[type]
|
||||
private string getValueCategoryString(string type) {
|
||||
if isGLValue() then
|
||||
result = "glval<" + type + ">"
|
||||
else
|
||||
result = type
|
||||
}
|
||||
|
||||
private string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(resultType.toString()) and
|
||||
if resultType instanceof UnknownType and exists(getResultSize()) then
|
||||
result = valcat + "[" + getResultSize().toString() + "]"
|
||||
else
|
||||
result = valcat
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
* printing IR dumps.
|
||||
*
|
||||
* Example: `r1_1`
|
||||
*/
|
||||
string getResultId() {
|
||||
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||
getDisplayIndexInBlock().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the result of this instruction, suitable for
|
||||
* display in IR dumps. This consists of the result ID plus the type of the
|
||||
* result.
|
||||
*
|
||||
* Example: `r1_1(int*)`
|
||||
*/
|
||||
final string getResultString() {
|
||||
result = getResultId() + "(" + getResultTypeString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the specified operand, suitable for display in IR
|
||||
* dumps. This consists of the result ID of the instruction consumed by the
|
||||
* operand, plus a label identifying the operand kind.
|
||||
*
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
string getOperandString(OperandTag tag) {
|
||||
exists(Instruction operand |
|
||||
operand = getOperand(tag) and
|
||||
result = tag.getLabel() + operand.getResultId()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operands of this instruction, suitable for
|
||||
* display in IR dumps.
|
||||
*
|
||||
* Example: `func:r3_4, this:r3_5`
|
||||
*/
|
||||
string getOperandsString() {
|
||||
result = concat(OperandTag tag, Instruction operand |
|
||||
operand = getOperand(tag) |
|
||||
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,8 +436,8 @@ class VariableInstruction extends Instruction {
|
||||
var = Construction::getInstructionVariable(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + var.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = var.toString()
|
||||
}
|
||||
|
||||
final IRVariable getVariable() {
|
||||
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
|
||||
field = Construction::getInstructionField(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + field.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = field.toString()
|
||||
}
|
||||
|
||||
final Field getField() {
|
||||
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
|
||||
funcSymbol = Construction::getInstructionFunction(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + funcSymbol.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = funcSymbol.toString()
|
||||
}
|
||||
|
||||
final Function getFunctionSymbol() {
|
||||
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
|
||||
value = Construction::getInstructionConstantValue(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + value + "]"
|
||||
override final string getImmediateString() {
|
||||
result = value
|
||||
}
|
||||
|
||||
final string getValue() {
|
||||
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
|
||||
value = Construction::getInstructionStringLiteral(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" +
|
||||
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
|
||||
"]"
|
||||
override final string getImmediateString() {
|
||||
result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
|
||||
}
|
||||
|
||||
final StringLiteral getValue() {
|
||||
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
||||
elementSize = Construction::getInstructionElementSize(this)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + elementSize.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = elementSize.toString()
|
||||
}
|
||||
|
||||
final int getElementSize() {
|
||||
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]"
|
||||
override final string getImmediateString() {
|
||||
result = derivedClass.toString() + " : " + baseClass.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
exceptionType = Construction::getInstructionExceptionType(this)
|
||||
}
|
||||
|
||||
final override string toString() {
|
||||
result = super.toString() + "[" + exceptionType.toString() + "]"
|
||||
final override string getImmediateString() {
|
||||
result = exceptionType.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
|
||||
opcode instanceof Opcode::UnmodeledUse
|
||||
}
|
||||
|
||||
override string getOperandsString() {
|
||||
result = "mu*"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
tag instanceof UnmodeledUseOperand and
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
|
||||
@@ -1,299 +1,312 @@
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
|
||||
private newtype TOperandTag =
|
||||
TLoadStoreAddressOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TReturnValueOperand() or
|
||||
TExceptionOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
} or
|
||||
TPhiOperand(IRBlock predecessorBlock) {
|
||||
exists(PhiInstruction phi |
|
||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
abstract int getSortOrder();
|
||||
}
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
override final string toString() {
|
||||
result = "LoadStoreAddress"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||
result = TLoadStoreAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
override final string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
CopySourceOperand copySourceOperand() {
|
||||
result = TCopySourceOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperand unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends OperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperand leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends OperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
RightOperand rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
override final string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValueOperand returnValueOperand() {
|
||||
result = TReturnValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOperand exceptionOperand() {
|
||||
result = TExceptionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperand conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperand unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Invoke` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperand callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperand extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperand thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + argIndex
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of an SSA `Phi` instruction.
|
||||
*/
|
||||
class PhiOperand extends OperandTag, TPhiOperand {
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11
|
||||
}
|
||||
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
}
|
||||
|
||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||
result = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
private import IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
|
||||
private newtype TOperandTag =
|
||||
TLoadStoreAddressOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TReturnValueOperand() or
|
||||
TExceptionOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
} or
|
||||
TPhiOperand(IRBlock predecessorBlock) {
|
||||
exists(PhiInstruction phi |
|
||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
|
||||
abstract int getSortOrder();
|
||||
|
||||
string getLabel() {
|
||||
result = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
override final string toString() {
|
||||
result = "LoadStoreAddress"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||
result = TLoadStoreAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
override final string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
CopySourceOperand copySourceOperand() {
|
||||
result = TCopySourceOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperand unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends OperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperand leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends OperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
RightOperand rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
override final string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValueOperand returnValueOperand() {
|
||||
result = TReturnValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOperand exceptionOperand() {
|
||||
result = TExceptionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperand conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperand unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Invoke` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperand callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperand extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "this:"
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperand thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + argIndex
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of an SSA `Phi` instruction.
|
||||
*/
|
||||
class PhiOperand extends OperandTag, TPhiOperand {
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
}
|
||||
|
||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||
result = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
@@ -1,175 +1,239 @@
|
||||
private import IRImpl
|
||||
import cpp
|
||||
|
||||
private int getInstructionIndexInBlock(Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
block = instr.getBlock() and
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableFunctionIR(FunctionIR funcIR) or
|
||||
TPrintableIRBlock(IRBlock block) or
|
||||
TPrintableInstruction(Instruction instr)
|
||||
|
||||
/**
|
||||
* A node to be emitted in the IR graph.
|
||||
*/
|
||||
abstract class PrintableIRNode extends TPrintableIRNode {
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the location to be emitted for the node.
|
||||
*/
|
||||
abstract Location getLocation();
|
||||
|
||||
/**
|
||||
* Gets the label to be emitted for the node.
|
||||
*/
|
||||
abstract string getLabel();
|
||||
|
||||
/**
|
||||
* Gets the order in which the node appears in its parent node.
|
||||
*/
|
||||
abstract int getOrder();
|
||||
|
||||
/**
|
||||
* Gets the parent of this node.
|
||||
*/
|
||||
abstract PrintableIRNode getParent();
|
||||
|
||||
/**
|
||||
* Gets the kind of graph represented by this node ("graph" or "tree").
|
||||
*/
|
||||
string getGraphKind() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node should always be rendered as text, even in a graphical
|
||||
* viewer.
|
||||
*/
|
||||
predicate forceText() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the node property with the specified key.
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and result = getLabel() or
|
||||
key = "semmle.order" and result = getOrder().toString() or
|
||||
key = "semmle.graphKind" and result = getGraphKind() or
|
||||
key = "semmle.forceText" and forceText() and result = "true"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR graph node representing a `FunctionIR` object.
|
||||
*/
|
||||
class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
|
||||
FunctionIR funcIR;
|
||||
|
||||
PrintableFunctionIR() {
|
||||
this = TPrintableFunctionIR(funcIR)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = funcIR.toString()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = funcIR.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = funcIR.getFunction().getFullSignature()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
this = rank[result + 1](PrintableFunctionIR orderedFunc, Location location |
|
||||
location = orderedFunc.getFunctionIR().getLocation() |
|
||||
orderedFunc order by location.getFile().getURL(), location.getStartLine(),
|
||||
location.getStartColumn(), orderedFunc.getLabel()
|
||||
)
|
||||
}
|
||||
|
||||
override final PrintableIRNode getParent() {
|
||||
none()
|
||||
}
|
||||
|
||||
final FunctionIR getFunctionIR() {
|
||||
result = funcIR
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR graph node representing an `IRBlock` object.
|
||||
*/
|
||||
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
IRBlock block;
|
||||
|
||||
PrintableIRBlock() {
|
||||
this = TPrintableIRBlock(block)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getLabel()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = block.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
result = "Block " + block.getDisplayIndex().toString()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
result = block.getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getGraphKind() {
|
||||
result = "tree"
|
||||
}
|
||||
|
||||
override final predicate forceText() {
|
||||
any()
|
||||
}
|
||||
|
||||
override final PrintableFunctionIR getParent() {
|
||||
result.getFunctionIR() = block.getFunctionIR()
|
||||
}
|
||||
|
||||
final IRBlock getBlock() {
|
||||
result = block
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR graph node representing an `Instruction`.
|
||||
*/
|
||||
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
Instruction instr;
|
||||
|
||||
PrintableInstruction() {
|
||||
this = TPrintableInstruction(instr)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = instr.toString()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = instr.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
exists(IRBlock block |
|
||||
instr = block.getAnInstruction() and
|
||||
exists(string resultString, string operationString, string operandsString,
|
||||
int resultWidth, int operationWidth |
|
||||
resultString = instr.getResultString() and
|
||||
operationString = instr.getOperationString() and
|
||||
operandsString = instr.getOperandsString() and
|
||||
columnWidths(block, resultWidth, operationWidth) and
|
||||
result = resultString + getPaddingString(resultWidth - resultString.length()) +
|
||||
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
|
||||
" : " + operandsString
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
result = instr.getDisplayIndexInBlock()
|
||||
}
|
||||
|
||||
override final PrintableIRBlock getParent() {
|
||||
result.getBlock() = instr.getBlock()
|
||||
}
|
||||
|
||||
final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
}
|
||||
|
||||
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
|
||||
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
|
||||
}
|
||||
|
||||
private int maxColumnWidth() {
|
||||
result = max(Instruction instr, int width |
|
||||
width = instr.getResultString().length() or
|
||||
width = instr.getOperationString().length() or
|
||||
width = instr.getOperandsString().length() |
|
||||
width)
|
||||
}
|
||||
|
||||
private string getPaddingString(int n) {
|
||||
n = 0 and result = "" or
|
||||
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
|
||||
}
|
||||
|
||||
query predicate nodes(PrintableIRNode node, string key, string value) {
|
||||
value = node.getProperty(key)
|
||||
}
|
||||
|
||||
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
|
||||
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
|
||||
aSucc = pred.getSuccessor(kind) |
|
||||
aSucc order by kind.toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
|
||||
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
|
||||
predBlock = pred.getBlock() and
|
||||
succBlock = succ.getBlock() and
|
||||
predBlock.getSuccessor(kind) = succBlock and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
instr = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = kind.toString()
|
||||
) or
|
||||
(
|
||||
instr instanceof PhiInstruction and
|
||||
instr = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction() |
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
key = "semmle.order" and
|
||||
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private string getInstructionResultId(Instruction instr) {
|
||||
result = getResultPrefix(instr) + getBlockId(instr.getBlock()) + "_" +
|
||||
getInstructionIndexInBlock(instr).toString()
|
||||
}
|
||||
|
||||
private string getResultPrefix(Instruction instr) {
|
||||
if instr.hasMemoryResult() then
|
||||
if instr.isResultModeled() then
|
||||
result = "@m"
|
||||
else
|
||||
result = "@mu"
|
||||
else
|
||||
result = "@r"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identifier of the specified function scope.
|
||||
* Currently just returns the signature of the function.
|
||||
*/
|
||||
private string getScopeId(Function func) {
|
||||
result = func.getFullSignature()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique identifier of the block within its function.
|
||||
* Currently returns a string representation of an integer in the range
|
||||
* [0..numBlocks - 1].
|
||||
*/
|
||||
private string getBlockId(IRBlock block) {
|
||||
exists(int rankIndex |
|
||||
block = rank[rankIndex + 1](IRBlock funcBlock |
|
||||
funcBlock.getFunction() = block.getFunction() |
|
||||
funcBlock order by funcBlock.getUniqueId()
|
||||
) and
|
||||
result = rankIndex.toString()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the full signature and qualified name for each scope. This is primarily
|
||||
* so that post-processing tools can identify function overloads, which will have
|
||||
* different signatures but the same qualified name.
|
||||
*/
|
||||
query predicate printIRGraphScopes(string scopeId, string qualifiedName) {
|
||||
exists(FunctionIR ir, Function func |
|
||||
func = ir.getFunction() and
|
||||
scopeId = getScopeId(func) and
|
||||
qualifiedName = func.getQualifiedName()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphNodes(string scopeId, string blockId, string label, string location) {
|
||||
exists(IRBlock block |
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
blockId = getBlockId(block) and
|
||||
label = "" and
|
||||
location = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphInstructions(string scopeId, string blockId,
|
||||
string id, string label, string location) {
|
||||
exists(IRBlock block, Instruction instr |
|
||||
instr = block.getAnInstruction() and
|
||||
label = instr.toString() and
|
||||
location = instr.getLocation().toString() and
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
blockId = getBlockId(block) and
|
||||
id = getInstructionIndexInBlock(instr).toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphEdges(string scopeId,
|
||||
string predecessorId, string successorId, string label) {
|
||||
exists(IRBlock predecessor, IRBlock successor, EdgeKind kind |
|
||||
scopeId = getScopeId(predecessor.getFunction()) and
|
||||
predecessor.getSuccessor(kind) = successor and
|
||||
predecessorId = getBlockId(predecessor) and
|
||||
successorId = getBlockId(successor) and
|
||||
label = kind.toString()
|
||||
)
|
||||
}
|
||||
|
||||
private string getValueCategoryString(Instruction instr) {
|
||||
if instr.isGLValue() then
|
||||
result = "glval:"
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string getResultTypeString(Instruction instr) {
|
||||
exists(Type resultType, string valcat |
|
||||
resultType = instr.getResultType() and
|
||||
valcat = getValueCategoryString(instr) and
|
||||
if resultType instanceof UnknownType and exists(instr.getResultSize()) then
|
||||
result = valcat + resultType.toString() + "[" + instr.getResultSize().toString() + "]"
|
||||
else
|
||||
result = valcat + resultType.toString()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphDestinationOperands(string scopeId, string blockId,
|
||||
string instructionId, int operandId, string label) {
|
||||
exists(IRBlock block, Instruction instr |
|
||||
block.getAnInstruction() = instr and
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
blockId = getBlockId(block) and
|
||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
||||
not instr.getResultType() instanceof VoidType and
|
||||
operandId = 0 and
|
||||
label = getInstructionResultId(instr) +
|
||||
"(" + getResultTypeString(instr) + ")"
|
||||
)
|
||||
}
|
||||
|
||||
private string getOperandTagLabel(OperandTag tag) {
|
||||
(
|
||||
tag instanceof PhiOperand and
|
||||
result = "from " + getBlockId(tag.(PhiOperand).getPredecessorBlock()) + ": "
|
||||
)
|
||||
or (
|
||||
tag instanceof ThisArgumentOperand and
|
||||
result = "this:"
|
||||
)
|
||||
or (
|
||||
not tag instanceof PhiOperand and
|
||||
not tag instanceof ThisArgumentOperand and
|
||||
result = ""
|
||||
)
|
||||
}
|
||||
|
||||
query predicate printIRGraphSourceOperands(string scopeId, string blockId,
|
||||
string instructionId, int operandId, string label) {
|
||||
exists(IRBlock block, Instruction instr |
|
||||
block.getAnInstruction() = instr and
|
||||
blockId = getBlockId(block) and
|
||||
scopeId = getScopeId(block.getFunction()) and
|
||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
||||
if (instr instanceof UnmodeledUseInstruction) then (
|
||||
operandId = 0 and
|
||||
label = "@mu*"
|
||||
)
|
||||
else (
|
||||
exists(OperandTag tag, Instruction operandInstr |
|
||||
operandInstr = instr.getOperand(tag) and
|
||||
operandId = tag.getSortOrder() and
|
||||
label = getOperandTagLabel(tag) +
|
||||
getInstructionResultId(operandInstr)
|
||||
)
|
||||
)
|
||||
)
|
||||
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
|
||||
parent = child.getParent()
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
void v(int i) {
|
||||
void AddressOf(int i) {
|
||||
int *j = &i;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ struct S {
|
||||
char* name;
|
||||
};
|
||||
|
||||
void v()
|
||||
void ArrayToPointer()
|
||||
{
|
||||
char c[] = "hello";
|
||||
struct S s;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
void v(char *c, void *v) {
|
||||
void Cast(char *c, void *v) {
|
||||
c = (char *)v;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
void v() {
|
||||
void ConditionDecl() {
|
||||
int j = 0;
|
||||
while(int k = j < 5) {
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class E {
|
||||
public:
|
||||
};
|
||||
|
||||
void v(C *c, D *d, E *e) {
|
||||
void ConstructorCall(C *c, D *d, E *e) {
|
||||
c = new C(5);
|
||||
d = new D();
|
||||
e = new E();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
void v() {
|
||||
void Conversion1() {
|
||||
int i = (int)1;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
void v(int x) {
|
||||
void Conversion2(int x) {
|
||||
x = (int)5 + (int)7;
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
void v(int x) {
|
||||
void Conversion3(int x) {
|
||||
x = (bool)(int)5 + ((int)7);
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
void v(int x) {
|
||||
void Conversion4(int x) {
|
||||
x = ((int)7);
|
||||
}
|
||||
@@ -8,7 +8,7 @@ class D {
|
||||
public:
|
||||
};
|
||||
|
||||
void v(C *c, D *d) {
|
||||
void DestructorCall(C *c, D *d) {
|
||||
delete c;
|
||||
delete d;
|
||||
}
|
||||
@@ -5,10 +5,10 @@ class Derived : public Base {
|
||||
void f() { }
|
||||
};
|
||||
|
||||
void v(Base *bp, Derived *d) {
|
||||
void DynamicCast(Base *bp, Derived *d) {
|
||||
d = dynamic_cast<Derived *>(bp);
|
||||
}
|
||||
|
||||
void v_ref(Base &bp, Derived &d) {
|
||||
void DynamicCastRef(Base &bp, Derived &d) {
|
||||
d = dynamic_cast<Derived &>(bp);
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
void v(int i) {
|
||||
void Parenthesis(int i) {
|
||||
i = (i + 1) * 2;
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
void v(int *i, int j) {
|
||||
void PointerDereference(int *i, int j) {
|
||||
j = *i;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
there is an implicit compiler-generated dereference node before the access to the variable 'i'
|
||||
*/
|
||||
void v(int &i, int j) {
|
||||
void ReferenceDereference(int &i, int j) {
|
||||
j = i;
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
int& v(int *i) {
|
||||
int& ReferenceTo(int *i) {
|
||||
return *i;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
void v(int array[]) {
|
||||
void Sizeof(int array[]) {
|
||||
int i = sizeof(int);
|
||||
int j = sizeof(array);
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
void v() {
|
||||
void StatementExpr() {
|
||||
int j = ({ int i = 5; i; });
|
||||
}
|
||||
@@ -2,7 +2,7 @@ struct X {
|
||||
static int i;
|
||||
};
|
||||
|
||||
void v(int i, X &xref) {
|
||||
void StaticMemberAccess(int i, X &xref) {
|
||||
// i = X::i;
|
||||
i = xref.i;
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
void v(int i[], int j) {
|
||||
void Subscript(int i[], int j) {
|
||||
j = i[5];
|
||||
}
|
||||
@@ -3,7 +3,7 @@ class F {
|
||||
public:
|
||||
F() { }
|
||||
};
|
||||
void f(int i) {
|
||||
void Throw(int i) {
|
||||
try {
|
||||
if(i)
|
||||
throw E();
|
||||
|
||||
@@ -15,6 +15,6 @@ class Base {
|
||||
class Derived : public Base {
|
||||
};
|
||||
|
||||
void v(Base *bp) {
|
||||
void TypeId(Base *bp) {
|
||||
const char *name = typeid(bp).name();
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
template<class T>
|
||||
void v(T x, T *y) {
|
||||
void CallDestructor(T x, T *y) {
|
||||
x.T::~T();
|
||||
y->T::~T();
|
||||
}
|
||||
|
||||
void f(int i) {
|
||||
void Vacuous(int i) {
|
||||
// An int doesn't have a destructor, but we get to call it anyway through a
|
||||
// template.
|
||||
v(i, &i);
|
||||
CallDestructor(i, &i);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ typedef __builtin_va_list __gnuc_va_list;
|
||||
#define va_copy(d,s) __builtin_va_copy(d,s)
|
||||
typedef __gnuc_va_list va_list;
|
||||
|
||||
void output(const char *text, ...) {
|
||||
void VarArgs(const char *text, ...) {
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
va_end (args);
|
||||
|
||||
@@ -8,4 +8,4 @@ where
|
||||
resultPointsTo(instr, var, bitOffset) and
|
||||
pointsTo = var.toString() + getBitOffsetString(bitOffset)
|
||||
)
|
||||
select instr, pointsTo
|
||||
select instr.getLocation().toString(), instr.getOperationString(), pointsTo
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
import semmle.code.cpp.ssa.AliasedSSAIR
|
||||
import semmle.code.cpp.ssa.PrintAliasedSSAIR
|
||||
|
||||
from Instruction instr
|
||||
where none()
|
||||
select instr
|
||||
1
cpp/ql/test/library-tests/ir/ir/aliased_ssa_ir.qlref
Normal file
1
cpp/ql/test/library-tests/ir/ir/aliased_ssa_ir.qlref
Normal file
@@ -0,0 +1 @@
|
||||
semmle/code/cpp/ssa/PrintAliasedSSAIR.ql
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
1
cpp/ql/test/library-tests/ir/ir/ir.qlref
Normal file
1
cpp/ql/test/library-tests/ir/ir/ir.qlref
Normal file
@@ -0,0 +1 @@
|
||||
semmle/code/cpp/ir/PrintIR.ql
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
import semmle.code.cpp.ssa.SSAIR
|
||||
import semmle.code.cpp.ssa.PrintSSAIR
|
||||
|
||||
from Instruction instr
|
||||
where none()
|
||||
select instr
|
||||
1
cpp/ql/test/library-tests/ir/ir/ssa_ir.qlref
Normal file
1
cpp/ql/test/library-tests/ir/ir/ssa_ir.qlref
Normal file
@@ -0,0 +1 @@
|
||||
semmle/code/cpp/ssa/PrintSSAIR.ql
|
||||
Reference in New Issue
Block a user