mirror of
https://github.com/github/codeql.git
synced 2026-03-30 20:28:15 +02:00
C++: Move a bunch non-public dataflow node subtypes.
This commit is contained in:
@@ -946,3 +946,859 @@ module Public {
|
||||
}
|
||||
|
||||
private import Public
|
||||
|
||||
/**
|
||||
* A node representing an indirection of a parameter.
|
||||
*/
|
||||
final class IndirectParameterNode = AbstractIndirectParameterNode;
|
||||
|
||||
/**
|
||||
* A class that lifts pre-SSA dataflow nodes to regular dataflow nodes.
|
||||
*/
|
||||
private class Node0 extends Node, TNode0 {
|
||||
Node0Impl node;
|
||||
|
||||
Node0() { this = TNode0(node) }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = node.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override Declaration getFunction() { result = node.getFunction() }
|
||||
|
||||
override Location getLocationImpl() { result = node.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = node.toString() }
|
||||
|
||||
override Type getType() { result = node.getType() }
|
||||
|
||||
override predicate isGLValue() { node.isGLValue() }
|
||||
}
|
||||
|
||||
class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
|
||||
int indirectionIndex;
|
||||
Operand operand;
|
||||
|
||||
PostUpdateNodeImpl() { this = TPostUpdateNodeImpl(operand, indirectionIndex) }
|
||||
|
||||
override Declaration getFunction() { result = operand.getUse().getEnclosingFunction() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result = this.getPreUpdateNode().getEnclosingCallable()
|
||||
}
|
||||
|
||||
/** Gets the operand associated with this node. */
|
||||
Operand getOperand() { result = operand }
|
||||
|
||||
/** Gets the indirection index associated with this node. */
|
||||
override int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Location getLocationImpl() { result = operand.getLocation() }
|
||||
|
||||
final override Node getPreUpdateNode() {
|
||||
indirectionIndex > 0 and
|
||||
hasOperandAndIndex(result, operand, indirectionIndex)
|
||||
or
|
||||
indirectionIndex = 0 and
|
||||
result.asOperand() = operand
|
||||
}
|
||||
|
||||
final override Expr getDefinedExpr() {
|
||||
result = operand.getDef().getUnconvertedResultExpression()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The node representing the value of a field after it has been updated.
|
||||
*/
|
||||
class PostFieldUpdateNode extends PostUpdateNodeImpl {
|
||||
FieldAddress fieldAddress;
|
||||
|
||||
PostFieldUpdateNode() { operand = fieldAddress.getObjectAddressOperand() }
|
||||
|
||||
FieldAddress getFieldAddress() { result = fieldAddress }
|
||||
|
||||
Field getUpdatedField() { result = this.getFieldAddress().getField() }
|
||||
|
||||
override string toStringImpl() { result = this.getPreUpdateNode() + " [post update]" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The base class for nodes that perform "partial definitions".
|
||||
*
|
||||
* In contrast to a normal "definition", which provides a new value for
|
||||
* something, a partial definition is an expression that may affect a
|
||||
* value, but does not necessarily replace it entirely. For example:
|
||||
* ```
|
||||
* x.y = 1; // a partial definition of the object `x`.
|
||||
* x.y.z = 1; // a partial definition of the object `x.y` and `x`.
|
||||
* x.setY(1); // a partial definition of the object `x`.
|
||||
* setY(&x); // a partial definition of the object `x`.
|
||||
* ```
|
||||
*/
|
||||
abstract private class PartialDefinitionNode extends PostUpdateNode {
|
||||
/** Gets the indirection index of this node. */
|
||||
abstract int getIndirectionIndex();
|
||||
|
||||
/** Gets the expression that is partially defined by this node. */
|
||||
abstract Expr getDefinedExpr();
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the indirection of a value after it
|
||||
* has been returned from a function.
|
||||
*/
|
||||
class IndirectArgumentOutNode extends PostUpdateNodeImpl {
|
||||
override ArgumentOperand operand;
|
||||
|
||||
int getArgumentIndex() {
|
||||
exists(CallInstruction call | call.getArgumentOperand(result) = operand)
|
||||
}
|
||||
|
||||
Operand getAddressOperand() { result = operand }
|
||||
|
||||
CallInstruction getCallInstruction() { result.getAnArgumentOperand() = operand }
|
||||
|
||||
/**
|
||||
* Gets the `Function` that the call targets, if this is statically known.
|
||||
*/
|
||||
Function getStaticCallTarget() { result = this.getCallInstruction().getStaticCallTarget() }
|
||||
|
||||
override string toStringImpl() {
|
||||
exists(string prefix | if indirectionIndex > 0 then prefix = "" else prefix = "pointer to " |
|
||||
// This string should be unique enough to be helpful but common enough to
|
||||
// avoid storing too many different strings.
|
||||
result = prefix + this.getStaticCallTarget().getName() + " output argument"
|
||||
or
|
||||
not exists(this.getStaticCallTarget()) and
|
||||
result = prefix + "output argument"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is an indirect operand with columns `(operand, indirectionIndex)`, and
|
||||
* `operand` represents a use of the fully converted value of `call`.
|
||||
*/
|
||||
private predicate hasOperand(Node node, CallInstruction call, int indirectionIndex, Operand operand) {
|
||||
operandForFullyConvertedCall(operand, call) and
|
||||
hasOperandAndIndex(node, operand, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is an indirect instruction with columns `(instr, indirectionIndex)`, and
|
||||
* `instr` represents a use of the fully converted value of `call`.
|
||||
*
|
||||
* Note that `hasOperand(node, _, _, _)` implies `not hasInstruction(node, _, _, _)`.
|
||||
*/
|
||||
private predicate hasInstruction(
|
||||
Node node, CallInstruction call, int indirectionIndex, Instruction instr
|
||||
) {
|
||||
instructionForFullyConvertedCall(instr, call) and
|
||||
hasInstructionAndIndex(node, instr, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the indirect value of a function call (i.e., a value hidden
|
||||
* behind a number of indirections).
|
||||
*/
|
||||
class IndirectReturnOutNode extends Node {
|
||||
CallInstruction call;
|
||||
int indirectionIndex;
|
||||
|
||||
IndirectReturnOutNode() {
|
||||
// Annoyingly, we need to pick the fully converted value as the output of the function to
|
||||
// make flow through in the shared dataflow library work correctly.
|
||||
hasOperand(this, call, indirectionIndex, _)
|
||||
or
|
||||
hasInstruction(this, call, indirectionIndex, _)
|
||||
}
|
||||
|
||||
CallInstruction getCallInstruction() { result = call }
|
||||
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
/** Gets the operand associated with this node, if any. */
|
||||
Operand getOperand() { hasOperand(this, call, indirectionIndex, result) }
|
||||
|
||||
/** Gets the instruction associated with this node, if any. */
|
||||
Instruction getInstruction() { hasInstruction(this, call, indirectionIndex, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An `IndirectReturnOutNode` which is used as a destination of a store operation.
|
||||
* When it's used for a store operation it's useful to have this be a `PostUpdateNode` for
|
||||
* the shared dataflow library's flow-through mechanism to detect flow in cases such as:
|
||||
* ```cpp
|
||||
* struct MyInt {
|
||||
* int i;
|
||||
* int& getRef() { return i; }
|
||||
* };
|
||||
* ...
|
||||
* MyInt mi;
|
||||
* mi.getRef() = source(); // this is detected as a store to `i` via flow-through.
|
||||
* sink(mi.i);
|
||||
* ```
|
||||
*/
|
||||
private class PostIndirectReturnOutNode extends IndirectReturnOutNode, PostUpdateNode {
|
||||
PostIndirectReturnOutNode() {
|
||||
any(StoreInstruction store).getDestinationAddressOperand() = this.getOperand()
|
||||
}
|
||||
|
||||
override Node getPreUpdateNode() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that represents the indirect value of an operand in the IR
|
||||
* after `index` number of loads.
|
||||
*/
|
||||
private class RawIndirectOperand0 extends Node, TRawIndirectOperand0 {
|
||||
Node0Impl node;
|
||||
int indirectionIndex;
|
||||
|
||||
RawIndirectOperand0() { this = TRawIndirectOperand0(node, indirectionIndex) }
|
||||
|
||||
/** Gets the underlying instruction. */
|
||||
Operand getOperand() { result = node.asOperand() }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Declaration getFunction() { result = node.getFunction() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = node.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override predicate isGLValue() { this.getOperand().isGLValue() }
|
||||
|
||||
override Type getType() {
|
||||
exists(int sub, Type type, boolean isGLValue |
|
||||
type = getOperandType(this.getOperand(), isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
|
||||
)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
if exists(this.getOperand().getLocation())
|
||||
then result = this.getOperand().getLocation()
|
||||
else result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
result = stars(this) + operandNode(this.getOperand()).toStringImpl()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that represents the indirect value of an instruction in the IR
|
||||
* after `index` number of loads.
|
||||
*/
|
||||
private class RawIndirectInstruction0 extends Node, TRawIndirectInstruction0 {
|
||||
Node0Impl node;
|
||||
int indirectionIndex;
|
||||
|
||||
RawIndirectInstruction0() { this = TRawIndirectInstruction0(node, indirectionIndex) }
|
||||
|
||||
/** Gets the underlying instruction. */
|
||||
Instruction getInstruction() { result = node.asInstruction() }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Declaration getFunction() { result = node.getFunction() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = node.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override predicate isGLValue() { this.getInstruction().isGLValue() }
|
||||
|
||||
override Type getType() {
|
||||
exists(int sub, Type type, boolean isGLValue |
|
||||
type = getInstructionType(this.getInstruction(), isGLValue) and
|
||||
if isGLValue = true then sub = 1 else sub = 0
|
||||
|
|
||||
result = getTypeImpl(type.getUnderlyingType(), indirectionIndex - sub)
|
||||
)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
if exists(this.getInstruction().getLocation())
|
||||
then result = this.getInstruction().getLocation()
|
||||
else result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
result = stars(this) + instructionNode(this.getInstruction()).toStringImpl()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that represents the indirect value of an operand in the IR
|
||||
* after a number of loads.
|
||||
*/
|
||||
class RawIndirectOperand extends Node {
|
||||
int indirectionIndex;
|
||||
Operand operand;
|
||||
|
||||
RawIndirectOperand() {
|
||||
exists(Node0Impl node | operand = node.asOperand() |
|
||||
this = TRawIndirectOperand0(node, indirectionIndex)
|
||||
or
|
||||
this = TRawIndirectInstruction0(node, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the operand associated with this node. */
|
||||
Operand getOperand() { result = operand }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that represents the indirect value of an instruction in the IR
|
||||
* after a number of loads.
|
||||
*/
|
||||
class RawIndirectInstruction extends Node {
|
||||
int indirectionIndex;
|
||||
Instruction instr;
|
||||
|
||||
RawIndirectInstruction() {
|
||||
exists(Node0Impl node | instr = node.asInstruction() |
|
||||
this = TRawIndirectOperand0(node, indirectionIndex)
|
||||
or
|
||||
this = TRawIndirectInstruction0(node, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the instruction associated with this node. */
|
||||
Instruction getInstruction() { result = instr }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
}
|
||||
|
||||
/**
|
||||
* A synthesized SSA node produced by the shared SSA library, viewed as a node
|
||||
* in a data flow graph.
|
||||
*/
|
||||
class SsaSynthNode extends Node, TSsaSynthNode {
|
||||
SsaImpl::SynthNode node;
|
||||
|
||||
SsaSynthNode() { this = TSsaSynthNode(node) }
|
||||
|
||||
/** Gets the synthesized SSA node associated with this node. */
|
||||
SsaImpl::SynthNode getSynthNode() { result = node }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
}
|
||||
|
||||
override Declaration getFunction() { result = node.getBasicBlock().getEnclosingFunction() }
|
||||
|
||||
override Type getType() { result = node.getSourceVariable().getType() }
|
||||
|
||||
override predicate isGLValue() { node.getSourceVariable().isGLValue() }
|
||||
|
||||
final override Location getLocationImpl() { result = node.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = node.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Dataflow nodes necessary for iterator flow
|
||||
*/
|
||||
class SsaIteratorNode extends Node, TSsaIteratorNode {
|
||||
IteratorFlow::IteratorFlowNode node;
|
||||
|
||||
SsaIteratorNode() { this = TSsaIteratorNode(node) }
|
||||
|
||||
/** Gets the phi node associated with this node. */
|
||||
IteratorFlow::IteratorFlowNode getIteratorFlowNode() { result = node }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
}
|
||||
|
||||
override Declaration getFunction() { result = node.getFunction() }
|
||||
|
||||
override Type getType() { result = node.getType() }
|
||||
|
||||
final override Location getLocationImpl() { result = node.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = node.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a value after leaving a function.
|
||||
*/
|
||||
class SideEffectOperandNode extends Node instanceof IndirectOperand {
|
||||
CallInstruction call;
|
||||
int argumentIndex;
|
||||
ArgumentOperand arg;
|
||||
|
||||
SideEffectOperandNode() {
|
||||
arg = call.getArgumentOperand(argumentIndex) and
|
||||
IndirectOperand.super.hasOperandAndIndirectionIndex(arg, _)
|
||||
}
|
||||
|
||||
CallInstruction getCallInstruction() { result = call }
|
||||
|
||||
/** Gets the underlying operand and the underlying indirection index. */
|
||||
predicate hasAddressOperandAndIndirectionIndex(Operand operand, int indirectionIndex) {
|
||||
IndirectOperand.super.hasOperandAndIndirectionIndex(operand, indirectionIndex)
|
||||
}
|
||||
|
||||
int getArgumentIndex() { result = argumentIndex }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
}
|
||||
|
||||
override Declaration getFunction() { result = call.getEnclosingFunction() }
|
||||
|
||||
Expr getArgument() { result = call.getArgument(argumentIndex).getUnconvertedResultExpression() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the value of a global variable just before returning
|
||||
* from a function body.
|
||||
*/
|
||||
class FinalGlobalValue extends Node, TFinalGlobalValue {
|
||||
SsaImpl::GlobalUse globalUse;
|
||||
|
||||
FinalGlobalValue() { this = TFinalGlobalValue(globalUse) }
|
||||
|
||||
/** Gets the underlying SSA use. */
|
||||
SsaImpl::GlobalUse getGlobalUse() { result = globalUse }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
}
|
||||
|
||||
override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() }
|
||||
|
||||
override Type getType() {
|
||||
exists(int indirectionIndex |
|
||||
indirectionIndex = globalUse.getIndirectionIndex() and
|
||||
result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() { result = globalUse.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = globalUse.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the value of a global variable just after entering
|
||||
* a function body.
|
||||
*/
|
||||
class InitialGlobalValue extends Node, TInitialGlobalValue {
|
||||
SsaImpl::GlobalDef globalDef;
|
||||
|
||||
InitialGlobalValue() { this = TInitialGlobalValue(globalDef) }
|
||||
|
||||
/** Gets the underlying SSA definition. */
|
||||
SsaImpl::GlobalDef getGlobalDef() { result = globalDef }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
}
|
||||
|
||||
override Declaration getFunction() { result = globalDef.getFunction() }
|
||||
|
||||
final override predicate isGLValue() { globalDef.getIndirectionIndex() = 0 }
|
||||
|
||||
override Type getType() { result = globalDef.getUnderlyingType() }
|
||||
|
||||
final override Location getLocationImpl() { result = globalDef.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = globalDef.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a parameter for a function with no body.
|
||||
*/
|
||||
class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
|
||||
Parameter p;
|
||||
int indirectionIndex;
|
||||
|
||||
BodyLessParameterNodeImpl() { this = TBodyLessParameterNodeImpl(p, indirectionIndex) }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
}
|
||||
|
||||
override Declaration getFunction() { result = p.getFunction() }
|
||||
|
||||
/** Gets the indirection index of this node. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Type getType() {
|
||||
result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex())
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
result = unique( | | p.getLocation())
|
||||
or
|
||||
count(p.getLocation()) != 1 and
|
||||
result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
final override string toStringImpl() {
|
||||
exists(string prefix | prefix = stars(this) | result = prefix + p.toString())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node used to model flow summaries. That is, a dataflow node
|
||||
* that is synthesized to represent a parameter, return value, or other part
|
||||
* of a models-as-data modeled function.
|
||||
*/
|
||||
class FlowSummaryNode extends Node, TFlowSummaryNode {
|
||||
/**
|
||||
* Gets the models-as-data `SummaryNode` associated with this dataflow
|
||||
* `FlowSummaryNode`.
|
||||
*/
|
||||
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
|
||||
|
||||
/**
|
||||
* Gets the summarized callable that this node belongs to.
|
||||
*/
|
||||
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
|
||||
result = this.getSummaryNode().getSummarizedCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable. For a `FlowSummaryNode` this is always the
|
||||
* summarized function this node is part of.
|
||||
*/
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSummarizedCallable() = this.getSummarizedCallable()
|
||||
}
|
||||
|
||||
override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }
|
||||
|
||||
override string toStringImpl() { result = this.getSummaryNode().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the indirection of a value that is
|
||||
* about to be returned from a function.
|
||||
*/
|
||||
class IndirectReturnNode extends Node {
|
||||
IndirectReturnNode() {
|
||||
this instanceof FinalParameterNode
|
||||
or
|
||||
this.(IndirectOperand)
|
||||
.hasOperandAndIndirectionIndex(any(ReturnValueInstruction ret).getReturnAddressOperand(), _)
|
||||
}
|
||||
|
||||
override SourceCallable getEnclosingCallable() { result.asSourceCallable() = this.getFunction() }
|
||||
|
||||
/**
|
||||
* Holds if this node represents the value that is returned to the caller
|
||||
* through a `return` statement.
|
||||
*/
|
||||
predicate isNormalReturn() { this instanceof IndirectOperand }
|
||||
|
||||
/**
|
||||
* Holds if this node represents the value that is returned to the caller
|
||||
* by writing to the `argumentIndex`'th argument of the call.
|
||||
*/
|
||||
predicate isParameterReturn(int argumentIndex) {
|
||||
this.(FinalParameterNode).getArgumentIndex() = argumentIndex
|
||||
}
|
||||
|
||||
/** Gets the indirection index of this indirect return node. */
|
||||
int getIndirectionIndex() {
|
||||
result = this.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
this.(IndirectOperand).hasOperandAndIndirectionIndex(_, result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the value of an output parameter
|
||||
* just before reaching the end of a function.
|
||||
*/
|
||||
class FinalParameterNode extends Node, TFinalParameterNode {
|
||||
Parameter p;
|
||||
int indirectionIndex;
|
||||
|
||||
FinalParameterNode() { this = TFinalParameterNode(p, indirectionIndex) }
|
||||
|
||||
/** Gets the parameter associated with this final use. */
|
||||
Parameter getParameter() { result = p }
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
/** Gets the argument index associated with this final use. */
|
||||
final int getArgumentIndex() { result = p.getIndex() }
|
||||
|
||||
override Declaration getFunction() { result = p.getFunction() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
}
|
||||
|
||||
override Type getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
|
||||
|
||||
final override Location getLocationImpl() {
|
||||
// Parameters can have multiple locations. When there's a unique location we use
|
||||
// that one, but if multiple locations exist we default to an unknown location.
|
||||
result = unique( | | p.getLocation())
|
||||
or
|
||||
not exists(unique( | | p.getLocation())) and
|
||||
result instanceof UnknownLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() { result = stars(this) + p.toString() }
|
||||
}
|
||||
|
||||
abstract private class AbstractParameterNode extends Node {
|
||||
/**
|
||||
* Holds if this node is the parameter of `f` at the specified position. The
|
||||
* implicit `this` parameter is considered to have position `-1`, and
|
||||
* pointer-indirection parameters are at further negative positions.
|
||||
*/
|
||||
predicate isSourceParameterOf(Function f, ParameterPosition pos) { none() }
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of `sc` at the specified position. The
|
||||
* implicit `this` parameter is considered to have position `-1`, and
|
||||
* pointer-indirection parameters are at further negative positions.
|
||||
*/
|
||||
predicate isSummaryParameterOf(
|
||||
FlowSummaryImpl::Public::SummarizedCallable sc, ParameterPosition pos
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of `c` at the specified position. The
|
||||
* implicit `this` parameter is considered to have position `-1`, and
|
||||
* pointer-indirection parameters are at further negative positions.
|
||||
*/
|
||||
final predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.isSummaryParameterOf(c.asSummarizedCallable(), pos)
|
||||
or
|
||||
this.isSourceParameterOf(c.asSourceCallable(), pos)
|
||||
}
|
||||
|
||||
/** Gets the `Parameter` associated with this node, if it exists. */
|
||||
Parameter getParameter() { none() } // overridden by subclasses
|
||||
}
|
||||
|
||||
abstract private class AbstractIndirectParameterNode extends AbstractParameterNode {
|
||||
/** Gets the indirection index of this parameter node. */
|
||||
abstract int getIndirectionIndex();
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate indirectParameterNodeHasArgumentIndexAndIndex(
|
||||
IndirectInstructionParameterNode node, int argumentIndex, int indirectionIndex
|
||||
) {
|
||||
node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and
|
||||
node.getArgumentIndex() = argumentIndex
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate indirectPositionHasArgumentIndexAndIndex(
|
||||
IndirectionPosition pos, int argumentIndex, int indirectionIndex
|
||||
) {
|
||||
pos.getArgumentIndex() = argumentIndex and
|
||||
pos.getIndirectionIndex() = indirectionIndex
|
||||
}
|
||||
|
||||
private class IndirectInstructionParameterNode extends AbstractIndirectParameterNode instanceof IndirectInstruction
|
||||
{
|
||||
InitializeParameterInstruction init;
|
||||
|
||||
IndirectInstructionParameterNode() {
|
||||
IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _)
|
||||
}
|
||||
|
||||
int getArgumentIndex() { init.hasIndex(result) }
|
||||
|
||||
override string toStringImpl() {
|
||||
exists(string prefix | prefix = stars(this) |
|
||||
result = prefix + this.getParameter().toString()
|
||||
or
|
||||
not exists(this.getParameter()) and
|
||||
result = prefix + "this"
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the parameter whose indirection is initialized. */
|
||||
override Parameter getParameter() { result = init.getParameter() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asSourceCallable() = this.getFunction()
|
||||
}
|
||||
|
||||
override Declaration getFunction() { result = init.getEnclosingFunction() }
|
||||
|
||||
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
|
||||
this.getFunction() = f and
|
||||
exists(int argumentIndex, int indirectionIndex |
|
||||
indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
|
||||
indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the underlying operand and the underlying indirection index. */
|
||||
predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
|
||||
IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index)
|
||||
}
|
||||
|
||||
final override int getIndirectionIndex() { this.hasInstructionAndIndirectionIndex(init, result) }
|
||||
}
|
||||
|
||||
abstract private class AbstractDirectParameterNode extends AbstractParameterNode { }
|
||||
|
||||
/**
|
||||
* A non-indirect parameter node that is represented as an `Instruction`.
|
||||
*/
|
||||
abstract class InstructionDirectParameterNode extends InstructionNode, AbstractDirectParameterNode {
|
||||
final override InitializeParameterInstruction instr;
|
||||
|
||||
/**
|
||||
* Gets the `IRVariable` that this parameter references.
|
||||
*/
|
||||
final IRVariable getIRVariable() { result = instr.getIRVariable() }
|
||||
}
|
||||
|
||||
abstract private class AbstractExplicitParameterNode extends AbstractDirectParameterNode { }
|
||||
|
||||
/** An explicit positional parameter, not including `this` or `...`. */
|
||||
private class ExplicitParameterInstructionNode extends AbstractExplicitParameterNode,
|
||||
InstructionDirectParameterNode
|
||||
{
|
||||
ExplicitParameterInstructionNode() { exists(instr.getParameter()) }
|
||||
|
||||
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
|
||||
f.getParameter(pos.(DirectPosition).getArgumentIndex()) = instr.getParameter()
|
||||
}
|
||||
|
||||
override string toStringImpl() { result = instr.getParameter().toString() }
|
||||
|
||||
override Parameter getParameter() { result = instr.getParameter() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter node that is part of a summary.
|
||||
*/
|
||||
class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode {
|
||||
SummaryParameterNode() {
|
||||
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _)
|
||||
}
|
||||
|
||||
private ParameterPosition getPosition() {
|
||||
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), result)
|
||||
}
|
||||
|
||||
override predicate isSummaryParameterOf(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition p
|
||||
) {
|
||||
c = this.getSummarizedCallable() and
|
||||
p = this.getPosition()
|
||||
}
|
||||
}
|
||||
|
||||
private class DirectBodyLessParameterNode extends AbstractExplicitParameterNode,
|
||||
BodyLessParameterNodeImpl
|
||||
{
|
||||
DirectBodyLessParameterNode() { indirectionIndex = 0 }
|
||||
|
||||
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
|
||||
this.getFunction() = f and
|
||||
f.getParameter(pos.(DirectPosition).getArgumentIndex()) = p
|
||||
}
|
||||
|
||||
override Parameter getParameter() { result = p }
|
||||
}
|
||||
|
||||
private class IndirectBodyLessParameterNode extends AbstractIndirectParameterNode,
|
||||
BodyLessParameterNodeImpl
|
||||
{
|
||||
IndirectBodyLessParameterNode() { not this instanceof DirectBodyLessParameterNode }
|
||||
|
||||
override predicate isSourceParameterOf(Function f, ParameterPosition pos) {
|
||||
exists(int argumentPosition |
|
||||
this.getFunction() = f and
|
||||
f.getParameter(argumentPosition) = p and
|
||||
indirectPositionHasArgumentIndexAndIndex(pos, argumentPosition, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
override int getIndirectionIndex() {
|
||||
result = BodyLessParameterNodeImpl.super.getIndirectionIndex()
|
||||
}
|
||||
|
||||
override Parameter getParameter() { result = p }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `PostUpdateNode` that is part of a flow summary. These are synthesized,
|
||||
* for example, when a models-as-data summary models a write to a field since
|
||||
* the write needs to target a `PostUpdateNode`.
|
||||
*/
|
||||
class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNode {
|
||||
SummaryPostUpdateNode() {
|
||||
FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(), _)
|
||||
}
|
||||
|
||||
override Node getPreUpdateNode() {
|
||||
FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(),
|
||||
result.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `t`, but stripped of the outermost pointer, reference, etc.
|
||||
*
|
||||
* For example, `stripPointers(int*&)` is `int*` and `stripPointers(int*)` is `int`.
|
||||
*/
|
||||
private Type stripPointer(Type t) {
|
||||
result = any(SsaImpl::Indirection ind | ind.getType() = t).getBaseType()
|
||||
or
|
||||
result = t.(PointerToMemberType).getBaseType()
|
||||
or
|
||||
result = t.(FunctionPointerIshType).getBaseType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `t`, but stripped of the outer-most `indirectionIndex` number of indirections.
|
||||
*/
|
||||
private Type getTypeImpl0(Type t, int indirectionIndex) {
|
||||
indirectionIndex = 0 and
|
||||
result = t
|
||||
or
|
||||
indirectionIndex > 0 and
|
||||
exists(Type stripped |
|
||||
stripped = stripPointer(t.stripTopLevelSpecifiers()) and
|
||||
stripped.getUnspecifiedType() != t.getUnspecifiedType() and
|
||||
result = getTypeImpl0(stripped, indirectionIndex - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `t`, but stripped of the outer-most `indirectionIndex` number of indirections.
|
||||
*
|
||||
* If `indirectionIndex` cannot be stripped off `t`, an `UnknownType` is returned.
|
||||
*/
|
||||
bindingset[t, indirectionIndex]
|
||||
pragma[inline_late]
|
||||
Type getTypeImpl(Type t, int indirectionIndex) {
|
||||
result = getTypeImpl0(t, indirectionIndex)
|
||||
or
|
||||
not exists(getTypeImpl0(t, indirectionIndex)) and
|
||||
result instanceof UnknownType
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user