C++: Use CallInstruction as DataFlowCall

This commit is contained in:
Robert Marsh
2019-04-29 14:18:09 -07:00
parent 5f6e9121b3
commit 514d405630
3 changed files with 89 additions and 24 deletions

View File

@@ -0,0 +1,80 @@
private import semmle.code.cpp.ir.IR
Function viableImpl(CallInstruction call) { result = viableCallable(call) }
/**
* Gets a function that might be called by `call`.
*/
Function viableCallable(CallInstruction call) {
result = 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
// will be determined at run time when the caller and callee are linked
// together by the operating system's dynamic linker. In case a _unique_
// 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
functionSignatureWithBody(qualifiedName, nparams, result) and
strictcount(Function other | functionSignatureWithBody(qualifiedName, nparams, other)) = 1
)
}
/**
* Holds if `f` is a function with a body that has name `qualifiedName` and
* `nparams` parameter count. See `functionSignature`.
*/
private predicate functionSignatureWithBody(string qualifiedName, int nparams, Function f) {
functionSignature(f, qualifiedName, nparams) and
exists(f.getBlock())
}
/**
* Holds if the target of `call` is a function _with no definition_ that has
* name `qualifiedName` and `nparams` parameter count. See `functionSignature`.
*/
pragma[noinline]
private predicate callSignatureWithoutBody(string qualifiedName, int nparams, CallInstruction call) {
exists(Function target |
target = call.getStaticCallTarget() and
not exists(target.getBlock()) and
functionSignature(target, qualifiedName, nparams)
)
}
/**
* Holds if `f` has name `qualifiedName` and `nparams` parameter count. This is
* an approximation of its signature for the purpose of matching functions that
* might be the same across link targets.
*/
private predicate functionSignature(Function f, string qualifiedName, int nparams) {
qualifiedName = f.getQualifiedName() and
nparams = f.getNumberOfParameters() and
not f.isStatic()
}
/**
* Holds if the call context `ctx` reduces the set of viable dispatch
* targets of `ma` in `c`.
*/
predicate reducedViableImplInCallContext(CallInstruction call, Function f, CallInstruction ctx) { none() }
/**
* Gets a viable dispatch target of `ma` in the context `ctx`. This is
* restricted to those `ma`s for which the context makes a difference.
*/
Function prunedViableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() }
/**
* Holds if flow returning from `m` to `ma` might return further and if
* this path restricts the set of call sites that can be returned to.
*/
predicate reducedViableImplInReturn(Function f, CallInstruction call) { none() }
/**
* Gets a viable dispatch target of `ma` in the context `ctx`. This is
* restricted to those `ma`s and results for which the return flow from the
* result to `ma` restricts the possible context `ctx`.
*/
Function prunedViableImplInCallContextReverse(CallInstruction call, CallInstruction ctx) { none() }

View File

@@ -3,7 +3,7 @@
*/
module Private {
import DataFlowPrivate
import semmle.code.cpp.dataflow.internal.DataFlowDispatch
import DataFlowDispatch
}
module Public {

View File

@@ -1,7 +1,7 @@
private import cpp
private import DataFlowUtil
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.dataflow.internal.DataFlowDispatch
private import DataFlowDispatch
/**
* A data flow node that occurs as the argument of a call and is passed as-is
@@ -15,14 +15,9 @@ class ArgumentNode extends Node {
* The instance argument is considered to have index `-1`.
*/
predicate argumentOf(DataFlowCall call, int pos) {
exists(CallInstruction callInstr |
callInstr.getAST() = call and
(
this = callInstr.getPositionalArgument(pos)
or
this = callInstr.getThisArgument() and pos = -1
)
)
this = call.getPositionalArgument(pos)
or
this = call.getThisArgument() and pos = -1
}
/** Gets the call in which this node is an argument. */
@@ -52,11 +47,9 @@ class ReturnNode extends Node {
}
/** A data flow node that represents a call. */
class OutNode extends ExprNode {
OutNode() { this.getExpr() instanceof FunctionCall }
class OutNode extends Node, CallInstruction {
/** Gets the underlying call. */
DataFlowCall getCall() { result = this.getExpr() }
DataFlowCall getCall() { result = this }
}
/** Gets a node that can read the value returned at position `pos`. */
@@ -198,19 +191,11 @@ class DataFlowType = Type;
class DataFlowLocation = Location;
/** A function call relevant for data flow. */
class DataFlowCall extends Expr {
DataFlowCall() { this instanceof Call }
class DataFlowCall extends CallInstruction, Node {
/**
* Gets the nth argument for this call.
*
* The range of `n` is from `0` to `getNumberOfArguments() - 1`.
*/
Expr getArgument(int n) { result = this.(Call).getArgument(n) }
/** Gets the data flow node corresponding to this call. */
ExprNode getNode() { result.getExpr() = this }
/** Gets the enclosing callable of this call. */
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
Node getArgument(int n) { result = this.getPositionalArgument(n) }
}