From ec29b2f1255bdb8c43c3f2287cbc575fc7ec45e0 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 10 Jan 2019 15:39:40 +0100 Subject: [PATCH 1/3] C++: Data flow dispatch across link targets --- .../dataflow/internal/DataFlowDispatch.qll | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) 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..bb7763f52c55 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,36 @@ 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(Function target | + target = call.getTarget() and + not exists(target.getBlock()) and + exists(result.getBlock()) and + exists(string qualifiedName, int nparams | + functionSignature(qualifiedName, nparams, target) and + functionSignature(qualifiedName, nparams, result) + ) + ) +} + +private predicate functionSignature(string qualifiedName, int nparams, Function f) { + qualifiedName = f.getQualifiedName() and + nparams = f.getNumberOfParameters() and + not f.isStatic() } /** From f3c8e71b1ed4a0d516b49120e1614442e18f82c7 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 10 Jan 2019 15:39:56 +0100 Subject: [PATCH 2/3] C++: Data flow through StmtExpr --- cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll | 4 ++++ 1 file changed, 4 insertions(+) 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) { From 7a5647ff7b2e896e8e374573a09a76dcffad531f Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Fri, 1 Mar 2019 20:06:25 +0000 Subject: [PATCH 3/3] C++: Tweak join order in flow across link targets The previous join seemed to perform fine, but it displayed a 20x tuple count bulge, which could be risky for the performance on large snapshots. --- .../dataflow/internal/DataFlowDispatch.qll | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) 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 bb7763f52c55..8d7b8e20e1af 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll @@ -17,18 +17,32 @@ Function viableCallable(Call call) { // 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 - exists(result.getBlock()) and - exists(string qualifiedName, int nparams | - functionSignature(qualifiedName, nparams, target) and - functionSignature(qualifiedName, nparams, result) - ) + functionSignature(target, qualifiedName, nparams) ) } -private predicate functionSignature(string qualifiedName, int nparams, Function f) { +/** + * 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()