C++: Create a proper class for DataFlowCallable, that includes summarized callables.

This commit is contained in:
Geoffrey White
2024-02-16 10:59:32 +00:00
parent e1a5a84253
commit 1ace9ee50f
5 changed files with 99 additions and 52 deletions

View File

@@ -119,7 +119,10 @@ module SourceSinkInterpretationInput implements
}
/** Gets the callable that this node corresponds to, if any. */
DataFlowCallable asCallable() { result.(Function) = this.asElement() }
DataFlowCallable asCallable() {
result.asSourceCallable() = this.asElement()
// TODO: or summary callable?
}
/** Gets the target of this call, if any. */
Element getCallTarget() { result = this.asCall().getStaticCallTarget() }

View File

@@ -14,7 +14,7 @@ private import DataFlowImplCommon as DataFlowImplCommon
cached
DataFlowCallable defaultViableCallable(DataFlowCall call) {
DataFlowImplCommon::forceCachingInSameStage() and
result = call.getStaticCallTarget()
result = TSourceCallable(call.getStaticCallTarget())
or
// If the target of the call does not have a body in the snapshot, it might
// be because the target is just a header declaration, and the real target
@@ -24,12 +24,12 @@ DataFlowCallable defaultViableCallable(DataFlowCall call) {
// that as a potential callee.
exists(string qualifiedName, int nparams |
callSignatureWithoutBody(qualifiedName, nparams, call.asCallInstruction()) and
functionSignatureWithBody(qualifiedName, nparams, result) and
functionSignatureWithBody(qualifiedName, nparams, result.asSourceCallable()) and
strictcount(Function other | functionSignatureWithBody(qualifiedName, nparams, other)) = 1
)
or
// Virtual dispatch
result = call.(VirtualDispatch::DataSensitiveCall).resolve()
result = TSourceCallable(call.(VirtualDispatch::DataSensitiveCall).resolve())
}
/**
@@ -89,7 +89,7 @@ private module VirtualDispatch {
// Call return
exists(DataFlowCall call, ReturnKind returnKind |
other = getAnOutNode(call, returnKind) and
returnNodeWithKindAndEnclosingCallable(src, returnKind, call.getStaticCallTarget())
returnNodeWithKindAndEnclosingCallable(src, returnKind, TSourceCallable(call.getStaticCallTarget()))
) and
allowFromArg = false
or
@@ -258,12 +258,12 @@ predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable f) {
* value is given as the `arg`'th argument to `f`.
*/
private predicate mayBenefitFromCallContext(
VirtualDispatch::DataSensitiveCall call, Function f, int arg
VirtualDispatch::DataSensitiveCall call, DataFlowCallable f, int arg
) {
f = pragma[only_bind_out](call).getEnclosingCallable() and
exists(InitializeParameterInstruction init |
not exists(call.getStaticCallTarget()) and
init.getEnclosingFunction() = f and
init.getEnclosingFunction() = f.asSourceCallable() and
call.flowsFrom(DataFlow::instructionNode(init), _) and
init.getParameter().getIndex() = arg
)
@@ -275,10 +275,10 @@ private predicate mayBenefitFromCallContext(
*/
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
result = viableCallable(call) and
exists(int i, Function f |
exists(int i, DataFlowCallable f |
mayBenefitFromCallContext(pragma[only_bind_into](call), f, i) and
f = ctx.getStaticCallTarget() and
result = ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
f.asSourceCallable() = ctx.getStaticCallTarget() and
result = TSourceCallable(ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget())
)
}

View File

@@ -104,7 +104,7 @@ class Node0Impl extends TIRDataFlowNode0 {
/**
* INTERNAL: Do not use.
*/
Declaration getEnclosingCallable() { none() } // overridden in subclasses
DataFlowCallable getEnclosingCallable() { none() } // overridden in subclasses
/** Gets the function to which this node belongs, if any. */
Declaration getFunction() { none() } // overridden in subclasses
@@ -174,7 +174,7 @@ abstract class InstructionNode0 extends Node0Impl {
/** Gets the instruction corresponding to this node. */
Instruction getInstruction() { result = instr }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override Declaration getFunction() { result = instr.getEnclosingFunction() }
@@ -219,7 +219,7 @@ abstract class OperandNode0 extends Node0Impl {
/** Gets the operand corresponding to this node. */
Operand getOperand() { result = op }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override Declaration getFunction() { result = op.getUse().getEnclosingFunction() }
@@ -340,7 +340,7 @@ DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCalla
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
p.isParameterOf(c, pos)
p.isParameterOf(c.asSourceCallable(), pos) // TODO: if c is a summary node?
}
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
@@ -941,13 +941,57 @@ class CastNode extends Node {
CastNode() { none() } // stub implementation
}
cached
newtype TDataFlowCallable =
TSourceCallable(Cpp::Declaration decl) { not decl instanceof FlowSummaryImpl::Public::SummarizedCallable } or
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
/**
* A function that may contain code or a variable that may contain itself. When
* flow crosses from one _enclosing callable_ to another, the interprocedural
* data-flow library discards call contexts and inserts a node in the big-step
* relation used for human-readable path explanations.
* A callable, which may be:
* - a function (that may contain code)
* - a summarized function (that may contain only `FlowSummaryNode`s)
* - a variable (this is used as context for global initialization, and also
* for the mid-point in interprocedural data flow between a write and read
* of a global variable in different functions).
* When flow crosses from one _enclosing callable_ to another, the
* interprocedural data-flow library discards call contexts and inserts a node
* in the big-step relation used for human-readable path explanations.
*/
class DataFlowCallable = Cpp::Declaration;
class DataFlowCallable extends TDataFlowCallable {
/** Gets the location of this callable. */
Location getLocation() { none() }
/** Gets a textual representation of this callable. */
string toString() { none() }
Cpp::Declaration asSourceCallable() { this = TSourceCallable(result) }
FlowSummaryImpl::Public::SummarizedCallable asSummarizedCallable() { this = TSummarizedCallable(result) }
/* Callable::TypeRange getUnderlyingCallable() { TODO
result = this.asSummarizedCallable() or result = this.asSourceCallable()
}*/
}
private class SourceCallable extends DataFlowCallable, TSourceCallable {
Cpp::Declaration decl;
SourceCallable() { this = TSourceCallable(decl) }
override string toString() { result = decl.toString() }
override Location getLocation() { result = decl.getLocation() }
}
private class SummarizedCallable extends DataFlowCallable, TSummarizedCallable {
FlowSummaryImpl::Public::SummarizedCallable sc;
SummarizedCallable() { this = TSummarizedCallable(sc) }
override string toString() { result = sc.toString() }
override Location getLocation() { result = sc.getLocation() }
}
class DataFlowExpr = Expr;
@@ -980,7 +1024,7 @@ class DataFlowCall extends TDataFlowCall {
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
Function getStaticCallTarget() { none() }
Function getStaticCallTarget() { none() } // TODO: should this return DataFlowCallable?
/**
* Gets the `index`'th argument operand. The qualifier is considered to have index `-1`.
@@ -1029,7 +1073,7 @@ private class NormalCall extends DataFlowCall, TNormalCall {
result = call.getArgumentOperand(index)
}
override DataFlowCallable getEnclosingCallable() { result = call.getEnclosingFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(call.getEnclosingFunction()) }
override string toString() { result = call.toString() }
@@ -1053,7 +1097,7 @@ class SummaryCall extends DataFlowCall, TSummaryCall {
// override ArgumentOperand getArgumentOperand(int index) TODO
// override DataFlowCallable getEnclosingCallable() { result = TSummarizedCallable(c) } TODO
override DataFlowCallable getEnclosingCallable() { result = TSummarizedCallable(c) }
override string toString() { result = "[summary] call to " + receiver + " in " + c }

View File

@@ -150,7 +150,7 @@ class Node extends TIRDataFlowNode {
/**
* INTERNAL: Do not use.
*/
Declaration getEnclosingCallable() { none() } // overridden in subclasses
DataFlowCallable getEnclosingCallable() { none() } // overridden in subclasses
/** Gets the function to which this node belongs, if any. */
Declaration getFunction() { none() } // overridden in subclasses
@@ -503,7 +503,7 @@ private class Node0 extends Node, TNode0 {
Node0() { this = TNode0(node) }
override Declaration getEnclosingCallable() { result = node.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallable() { result = node.getEnclosingCallable() }
override Declaration getFunction() { result = node.getFunction() }
@@ -568,7 +568,7 @@ class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
override Declaration getFunction() { result = operand.getUse().getEnclosingFunction() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
/** Gets the operand associated with this node. */
Operand getOperand() { result = operand }
@@ -621,7 +621,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
/** Gets the phi node associated with this node. */
Ssa::PhiNode getPhiNode() { result = phi }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
@@ -690,7 +690,7 @@ class SideEffectOperandNode extends Node instanceof IndirectOperand {
int getArgumentIndex() { result = argumentIndex }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override Declaration getFunction() { result = call.getEnclosingFunction() }
@@ -711,7 +711,7 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
/** Gets the underlying SSA use. */
Ssa::GlobalUse getGlobalUse() { result = globalUse }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() }
@@ -741,7 +741,7 @@ class InitialGlobalValue extends Node, TInitialGlobalValue {
/** Gets the underlying SSA definition. */
Ssa::GlobalDef getGlobalDef() { result = globalDef }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override Declaration getFunction() { result = globalDef.getIRFunction().getFunction() }
@@ -778,7 +778,7 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
* TODO: QLDoc.
*/
override DataFlowCallable getEnclosingCallable() {
none() //result.asSummarizedCallable() = this.getSummarizedCallable() TODO
result = TSummarizedCallable(this.getSummarizedCallable())
}
override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }
@@ -801,7 +801,7 @@ class IndirectParameterNode extends Node instanceof IndirectInstruction {
/** Gets the parameter whose indirection is initialized. */
Parameter getParameter() { result = init.getParameter() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override Declaration getFunction() { result = init.getEnclosingFunction() }
@@ -836,7 +836,7 @@ class IndirectReturnNode extends Node {
.hasOperandAndIndirectionIndex(any(ReturnValueInstruction ret).getReturnAddressOperand(), _)
}
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
/**
* Holds if this node represents the value that is returned to the caller
@@ -1031,7 +1031,7 @@ private module RawIndirectNodes {
result = this.getOperand().getDef().getEnclosingFunction()
}
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override DataFlowType getType() {
exists(int sub, DataFlowType type, boolean isGLValue |
@@ -1073,7 +1073,7 @@ private module RawIndirectNodes {
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override DataFlowType getType() {
exists(int sub, DataFlowType type, boolean isGLValue |
@@ -1171,7 +1171,7 @@ class FinalParameterNode extends Node, TFinalParameterNode {
override Declaration getFunction() { result = p.getFunction() }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override DataFlowCallable getEnclosingCallable() { result = TSourceCallable(this.getFunction()) }
override DataFlowType getType() { result = getTypeImpl(p.getUnspecifiedType(), indirectionIndex) }
@@ -1704,7 +1704,7 @@ private predicate indirectParameterNodeHasArgumentIndexAndIndex(
/** A synthetic parameter to model the pointed-to object of a pointer parameter. */
class ParameterIndirectionNode extends ParameterNode instanceof IndirectParameterNode {
override predicate isParameterOf(Function f, ParameterPosition pos) {
IndirectParameterNode.super.getEnclosingCallable() = f and
IndirectParameterNode.super.getEnclosingCallable().asSourceCallable() = f and
exists(int argumentIndex, int indirectionIndex |
indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
@@ -1795,13 +1795,13 @@ class VariableNode extends Node, TVariableNode {
override Declaration getFunction() { none() }
override Declaration getEnclosingCallable() {
override DataFlowCallable getEnclosingCallable() {
// When flow crosses from one _enclosing callable_ to another, the
// interprocedural data-flow library discards call contexts and inserts a
// node in the big-step relation used for human-readable path explanations.
// Therefore we want a distinct enclosing callable for each `VariableNode`,
// and that can be the `Variable` itself.
result = v
result = TSourceCallable(v)
}
override DataFlowType getType() {

View File

@@ -1,14 +1,14 @@
| tests.cpp:115:5:115:19 | [summary param] 0 in madArg0ToReturn | | madArg0ToReturn | |
| tests.cpp:115:5:115:19 | [summary] to write: ReturnValue in madArg0ToReturn | | madArg0ToReturn | |
| tests.cpp:117:5:117:28 | [summary param] 0 in madArg0ToReturnValueFlow | | madArg0ToReturnValueFlow | |
| tests.cpp:117:5:117:28 | [summary] to write: ReturnValue in madArg0ToReturnValueFlow | | madArg0ToReturnValueFlow | |
| tests.cpp:119:6:119:18 | [summary param] 0 in madArg0ToArg1 | | madArg0ToArg1 | |
| tests.cpp:119:6:119:18 | [summary param] 1 in madArg0ToArg1 | | madArg0ToArg1 | |
| tests.cpp:119:6:119:18 | [summary] to write: Argument[1] in madArg0ToArg1 | | madArg0ToArg1 | |
| tests.cpp:180:7:180:19 | [summary param] 0 in madArg0ToSelf | | madArg0ToSelf | |
| tests.cpp:180:7:180:19 | [summary param] this in madArg0ToSelf | | madArg0ToSelf | |
| tests.cpp:180:7:180:19 | [summary] to write: Argument[this] in madArg0ToSelf | | madArg0ToSelf | |
| tests.cpp:181:6:181:20 | [summary param] this in madSelfToReturn | | madSelfToReturn | |
| tests.cpp:181:6:181:20 | [summary] to write: ReturnValue in madSelfToReturn | | madSelfToReturn | |
| tests.cpp:209:7:209:30 | [summary param] this in namespaceMadSelfToReturn | | namespaceMadSelfToReturn | |
| tests.cpp:209:7:209:30 | [summary] to write: ReturnValue in namespaceMadSelfToReturn | | namespaceMadSelfToReturn | |
| tests.cpp:115:5:115:19 | [summary param] 0 in madArg0ToReturn | | madArg0ToReturn | madArg0ToReturn |
| tests.cpp:115:5:115:19 | [summary] to write: ReturnValue in madArg0ToReturn | | madArg0ToReturn | madArg0ToReturn |
| tests.cpp:117:5:117:28 | [summary param] 0 in madArg0ToReturnValueFlow | | madArg0ToReturnValueFlow | madArg0ToReturnValueFlow |
| tests.cpp:117:5:117:28 | [summary] to write: ReturnValue in madArg0ToReturnValueFlow | | madArg0ToReturnValueFlow | madArg0ToReturnValueFlow |
| tests.cpp:119:6:119:18 | [summary param] 0 in madArg0ToArg1 | | madArg0ToArg1 | madArg0ToArg1 |
| tests.cpp:119:6:119:18 | [summary param] 1 in madArg0ToArg1 | | madArg0ToArg1 | madArg0ToArg1 |
| tests.cpp:119:6:119:18 | [summary] to write: Argument[1] in madArg0ToArg1 | | madArg0ToArg1 | madArg0ToArg1 |
| tests.cpp:180:7:180:19 | [summary param] 0 in madArg0ToSelf | | madArg0ToSelf | madArg0ToSelf |
| tests.cpp:180:7:180:19 | [summary param] this in madArg0ToSelf | | madArg0ToSelf | madArg0ToSelf |
| tests.cpp:180:7:180:19 | [summary] to write: Argument[this] in madArg0ToSelf | | madArg0ToSelf | madArg0ToSelf |
| tests.cpp:181:6:181:20 | [summary param] this in madSelfToReturn | | madSelfToReturn | madSelfToReturn |
| tests.cpp:181:6:181:20 | [summary] to write: ReturnValue in madSelfToReturn | | madSelfToReturn | madSelfToReturn |
| tests.cpp:209:7:209:30 | [summary param] this in namespaceMadSelfToReturn | | namespaceMadSelfToReturn | namespaceMadSelfToReturn |
| tests.cpp:209:7:209:30 | [summary] to write: ReturnValue in namespaceMadSelfToReturn | | namespaceMadSelfToReturn | namespaceMadSelfToReturn |