diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll index 8beb2c5d319a..8d7b8e20e1af 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll @@ -2,11 +2,50 @@ private import cpp private import DataFlowPrivate Function viableImpl(MethodAccess ma) { - result = ma.getTarget() + result = viableCallable(ma) } +/** + * Gets a function that might be called by `call`. + */ Function viableCallable(Call call) { result = call.getTarget() + 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 function with + // the right signature is present in the database, we return that as a + // potential callee. + exists(result.getBlock()) and + exists(string qualifiedName, int nparams | + callSignatureWithoutBody(qualifiedName, nparams, call) and + functionSignature(result, qualifiedName, nparams) + ) +} + +/** + * 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, Call call) { + exists(Function target | + target = call.getTarget() 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() } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index 62dca33d323a..cae81e231679 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -237,6 +237,10 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) { moveCall.getTarget().getName() = "move" and fromExpr = moveCall.getArgument(0) ) + or + toExpr = any(StmtExpr stmtExpr | + fromExpr = stmtExpr.getResultExpr() + ) } VariableAccess getAnAccessToAssignedVariable(Expr assign) {