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

This commit is contained in:
Geoffrey White
2024-02-14 13:39:29 +00:00
parent 6e13b877bb
commit e1a5a84253
5 changed files with 134 additions and 12 deletions

View File

@@ -114,7 +114,9 @@ module SourceSinkInterpretationInput implements
Node asNode() { this = TNode_(result) }
/** Gets the call that this node corresponds to, if any. */
DataFlowCall asCall() { this.asElement() = result.getUnconvertedResultExpression() }
DataFlowCall asCall() { this.asElement() = result.asCallInstruction().getUnconvertedResultExpression()
// TODO: or summary call?
}
/** Gets the callable that this node corresponds to, if any. */
DataFlowCallable asCallable() { result.(Function) = this.asElement() }

View File

@@ -23,7 +23,7 @@ DataFlowCallable defaultViableCallable(DataFlowCall call) {
// function with the right signature is present in the database, we return
// that as a potential callee.
exists(string qualifiedName, int nparams |
callSignatureWithoutBody(qualifiedName, nparams, call) and
callSignatureWithoutBody(qualifiedName, nparams, call.asCallInstruction()) and
functionSignatureWithBody(qualifiedName, nparams, result) and
strictcount(Function other | functionSignatureWithBody(qualifiedName, nparams, other)) = 1
)
@@ -40,7 +40,7 @@ DataFlowCallable viableCallable(DataFlowCall call) {
result = defaultViableCallable(call)
or
// Additional call targets
result = any(AdditionalCallTarget additional).viableTarget(call.getUnconvertedResultExpression())
result = any(AdditionalCallTarget additional).viableTarget(call.asCallInstruction().getUnconvertedResultExpression())
}
/**
@@ -179,7 +179,7 @@ private module VirtualDispatch {
exists(this.getStaticCallTarget().(VirtualFunction).getAnOverridingFunction())
}
override DataFlow::Node getDispatchValue() { result.asInstruction() = this.getThisArgument() }
override DataFlow::Node getDispatchValue() { result.asInstruction() = this.getArgument(-1) }
override MemberFunction resolve() {
exists(Class overridingClass |

View File

@@ -3,6 +3,7 @@ private import DataFlowUtil
private import semmle.code.cpp.ir.IR
private import DataFlowDispatch
private import semmle.code.cpp.ir.internal.IRCppLanguage
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import SsaInternals as Ssa
private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
@@ -381,12 +382,26 @@ private class SideEffectArgumentNode extends ArgumentNode, SideEffectOperandNode
override predicate argumentOf(DataFlowCall dfCall, ArgumentPosition pos) {
exists(int indirectionIndex |
pos = TIndirectionPosition(argumentIndex, pragma[only_bind_into](indirectionIndex)) and
this.getCallInstruction() = dfCall and
this.getCallInstruction() = dfCall.asCallInstruction() and // TODO: or summarized call?
super.hasAddressOperandAndIndirectionIndex(_, pragma[only_bind_into](indirectionIndex))
)
}
}
class SummaryArgumentNode extends ArgumentNode, FlowSummaryNode {
private SummaryCall call_;
private ArgumentPosition pos_;
SummaryArgumentNode() {
FlowSummaryImpl::Private::summaryArgumentNode(call_.getReceiver(), this.getSummaryNode(), pos_)
}
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
call = call_ and
pos = pos_
}
}
/** A parameter position represented by an integer. */
class ParameterPosition = Position;
@@ -659,19 +674,19 @@ private class DirectCallOutNode extends OutNode {
DirectCallOutNode() { simpleOutNode(this, call) }
override DataFlowCall getCall() { result = call }
override DataFlowCall getCall() { result.asCallInstruction() = call } // TODO: or summarized call?
override ReturnKind getReturnKind() { result = TNormalReturnKind(0) }
}
private class IndirectCallOutNode extends OutNode, IndirectReturnOutNode {
override DataFlowCall getCall() { result = this.getCallInstruction() }
override DataFlowCall getCall() { result.asCallInstruction() = this.getCallInstruction() } // TODO: or summarized call?
override ReturnKind getReturnKind() { result = TNormalReturnKind(this.getIndirectionIndex()) }
}
private class SideEffectOutNode extends OutNode, IndirectArgumentOutNode {
override DataFlowCall getCall() { result = this.getCallInstruction() }
override DataFlowCall getCall() { result.asCallInstruction() = this.getCallInstruction() } // TODO: or summarized call?
override ReturnKind getReturnKind() {
result = TIndirectReturnKind(this.getArgumentIndex(), this.getIndirectionIndex())
@@ -938,9 +953,111 @@ class DataFlowExpr = Expr;
class DataFlowType = Type;
/** A function call relevant for data flow. */
class DataFlowCall extends CallInstruction {
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() }
cached
newtype TDataFlowCall =
TNormalCall(CallInstruction call) or
TSummaryCall(
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
) {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
/**
* A function call relevant for data flow. This includes calls from source
* code and calls inside library callables with a flow summary.
*/
class DataFlowCall extends TDataFlowCall {
/**
* Gets the underlying data flow call instruction, if any.
*/
CallInstruction asCallInstruction() { none() }
/**
* Gets the operand the specifies the target function of the call.
*/
CallTargetOperand getCallTargetOperand() { none() }
/**
* Gets the `Function` that the call targets, if this is statically known.
*/
Function getStaticCallTarget() { none() }
/**
* Gets the `index`'th argument operand. The qualifier is considered to have index `-1`.
*/
ArgumentOperand getArgumentOperand(int index) { none() }
/**
* Gets the argument at the specified index, or `this` if `index` is `-1`.
*/
pragma[noinline]
final Instruction getArgument(int index) { result = this.getArgumentOperand(index).getDef() }
/**
* Gets the number of arguments of the call, including the `this` pointer, if any.
*/
final int getNumberOfArguments() { result = count(this.getArgumentOperand(_)) }
/**
* Gets the enclosing callable, if any.
*/
DataFlowCallable getEnclosingCallable() { none() }
/**
* Gets a textual representation of this call.
*/
string toString() { none() }
/**
* Gets the location of this call.
*/
Location getLocation() { none() }
}
private class NormalCall extends DataFlowCall, TNormalCall {
private CallInstruction call;
NormalCall() { this = TNormalCall(call) }
override CallInstruction asCallInstruction() { result = call }
override CallTargetOperand getCallTargetOperand() { result = call.getCallTargetOperand() }
override Function getStaticCallTarget() { result = call.getStaticCallTarget() }
override ArgumentOperand getArgumentOperand(int index) {
result = call.getArgumentOperand(index)
}
override DataFlowCallable getEnclosingCallable() { result = call.getEnclosingFunction() }
override string toString() { result = call.toString() }
override Location getLocation() { result = call.getLocation() }
}
class SummaryCall extends DataFlowCall, TSummaryCall {
private FlowSummaryImpl::Public::SummarizedCallable c;
private FlowSummaryImpl::Private::SummaryNode receiver;
SummaryCall() { this = TSummaryCall(c, receiver) }
/** Gets the data flow node that this call targets. */
FlowSummaryImpl::Private::SummaryNode getReceiver() { result = receiver }
// override CallTargetOperand getCallTargetOperand() TODO
override Function getStaticCallTarget() { // TODO: should this return DataFlowCallable?
result = c
}
// override ArgumentOperand getArgumentOperand(int index) TODO
// override DataFlowCallable getEnclosingCallable() { result = TSummarizedCallable(c) } TODO
override string toString() { result = "[summary] call to " + receiver + " in " + c }
override UnknownLocation getLocation() { any() }
}
module IsUnreachableInCall {

View File

@@ -877,6 +877,9 @@ class IndirectArgumentOutNode extends PostUpdateNodeImpl {
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() {

View File

@@ -740,7 +740,7 @@ private predicate isArgumentOfCallableInstruction(DataFlowCall call, Instruction
}
private predicate isArgumentOfCallableOperand(DataFlowCall call, Operand operand) {
operand.(ArgumentOperand).getCall() = call
operand = call.getArgumentOperand(_)
or
exists(FieldAddressInstruction fai |
fai.getObjectAddressOperand() = operand and