Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling of unbalanced returns for IIA #664

Merged
merged 7 commits into from
Sep 6, 2023
13 changes: 13 additions & 0 deletions include/phasar/DataFlow/IfdsIde/FlowFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,19 @@ class FlowFunctions
virtual FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun,
n_t ExitInst, n_t RetSite) = 0;

// Performs any side-effects of a return-flow-function
//
// In case of unbalanced returns (if the option `followReturnsPastSeeds` is
// activated in the IfdsIdeSolverConfig), we will eventually reach a function
// that is not called from other functions. Still, we may want to apply a
// return-flow-function -- just for its side-effects, such as registering a
// taint
virtual void applyUnbalancedRetFlowFunctionSideEffects(f_t CalleeFun,
n_t ExitInst,
d_t Source) {
// By default, do nothing
}

//
// Describes the data-flows alongsite a CallSite.
//
Expand Down
33 changes: 33 additions & 0 deletions include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "phasar/Utils/EquivalenceClassMap.h"
#include "phasar/Utils/Logger.h"
#include "phasar/Utils/PAMMMacros.h"
#include "phasar/Utils/Utilities.h"

#include "llvm/ADT/DenseMap.h"

Expand Down Expand Up @@ -185,6 +186,8 @@ class FlowEdgeFunctionCache {
operator=(FlowEdgeFunctionCache &&FEFC) noexcept = default;

FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) {
assertNotNull(Curr);
assertNotNull(Succ);
PAMM_GET_INSTANCE;
IF_LOG_ENABLED(
PHASAR_LOG_LEVEL(DEBUG, "Normal flow function factory call");
Expand Down Expand Up @@ -217,6 +220,8 @@ class FlowEdgeFunctionCache {
}

FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) {
assertNotNull(CallSite);
assertNotNull(DestFun);
PAMM_GET_INSTANCE;
IF_LOG_ENABLED(
PHASAR_LOG_LEVEL(DEBUG, "Call flow function factory call");
Expand All @@ -241,6 +246,10 @@ class FlowEdgeFunctionCache {

FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun,
n_t ExitInst, n_t RetSite) {
assertNotNull(CallSite);
assertNotNull(CalleeFun);
assertNotNull(ExitInst);
assertNotNull(RetSite);
PAMM_GET_INSTANCE;
IF_LOG_ENABLED(
PHASAR_LOG_LEVEL(DEBUG, "Return flow function factory call");
Expand Down Expand Up @@ -270,6 +279,9 @@ class FlowEdgeFunctionCache {

FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite,
llvm::ArrayRef<f_t> Callees) {
assertNotNull(CallSite);
assertNotNull(RetSite);
assertAllNotNull(Callees);
PAMM_GET_INSTANCE;
IF_LOG_ENABLED(
PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return flow function factory call");
Expand Down Expand Up @@ -300,6 +312,8 @@ class FlowEdgeFunctionCache {
}

FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) {
assertNotNull(CallSite);
assertNotNull(DestFun);
// PAMM_GET_INSTANCE;
// INC_COUNTER("Summary-FF Construction", 1, Full);
IF_LOG_ENABLED(
Expand All @@ -313,6 +327,9 @@ class FlowEdgeFunctionCache {

EdgeFunction<l_t> getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ,
d_t SuccNode) {
assertNotNull(Curr);
assertNotNull(Succ);

PAMM_GET_INSTANCE;
IF_LOG_ENABLED(
PHASAR_LOG_LEVEL(DEBUG, "Normal edge function factory call");
Expand Down Expand Up @@ -357,6 +374,10 @@ class FlowEdgeFunctionCache {

EdgeFunction<l_t> getCallEdgeFunction(n_t CallSite, d_t SrcNode,
f_t DestinationFunction, d_t DestNode) {

assertNotNull(CallSite);
assertNotNull(DestinationFunction);

PAMM_GET_INSTANCE;
IF_LOG_ENABLED(
PHASAR_LOG_LEVEL(DEBUG, "Call edge function factory call");
Expand Down Expand Up @@ -387,6 +408,11 @@ class FlowEdgeFunctionCache {
EdgeFunction<l_t> getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction,
n_t ExitInst, d_t ExitNode,
n_t RetSite, d_t RetNode) {
assertNotNull(CallSite);
assertNotNull(CalleeFunction);
assertNotNull(ExitInst);
assertNotNull(RetSite);

PAMM_GET_INSTANCE;
IF_LOG_ENABLED(
PHASAR_LOG_LEVEL(DEBUG, "Return edge function factory call");
Expand Down Expand Up @@ -419,6 +445,10 @@ class FlowEdgeFunctionCache {
EdgeFunction<l_t> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode,
n_t RetSite, d_t RetSiteNode,
llvm::ArrayRef<f_t> Callees) {
assertNotNull(CallSite);
assertNotNull(RetSite);
assertAllNotNull(Callees);

PAMM_GET_INSTANCE;
IF_LOG_ENABLED(
PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return edge function factory call");
Expand Down Expand Up @@ -472,6 +502,9 @@ class FlowEdgeFunctionCache {

EdgeFunction<l_t> getSummaryEdgeFunction(n_t CallSite, d_t CallNode,
n_t RetSite, d_t RetSiteNode) {
assertNotNull(CallSite);
assertNotNull(RetSite);

PAMM_GET_INSTANCE;
IF_LOG_ENABLED(
PHASAR_LOG_LEVEL(DEBUG, "Summary edge function factory call");
Expand Down
12 changes: 5 additions & 7 deletions include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,9 @@ class IDESolver
// conditionally generated values should only
// be propagated into callers that have an incoming edge for this
// condition
if (SolverConfig.followReturnsPastSeeds() && Inc.empty() &&
IDEProblem.isZeroValue(d1)) {
/// TODO: Add a check for "d1 is seed in functionOf(n)"
if (SolverConfig.followReturnsPastSeeds() && Inc.empty() /*&&
IDEProblem.isZeroValue(d1)*/) {
const auto &Callers = ICF->getCallersOf(FunctionThatNeedsSummary);
for (n_t Caller : Callers) {
for (n_t RetSiteC : ICF->getReturnSitesOfCallAt(Caller)) {
Expand Down Expand Up @@ -922,11 +923,8 @@ class IDESolver
// the flow function has a side effect such as registering a taint;
// instead we thus call the return flow function will a null caller
if (Callers.empty()) {
FlowFunctionPtrType RetFunction =
CachedFlowEdgeFunctions.getRetFlowFunction(
nullptr, FunctionThatNeedsSummary, n, nullptr);
INC_COUNTER("FF Queries", 1, Full);
RetFunction->computeTargets(d2);
IDEProblem.applyUnbalancedRetFlowFunctionSideEffects(
FunctionThatNeedsSummary, n, d2);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,9 @@ class IDEInstInteractionAnalysisT
n_t /* RetSite */) override {
// Map return value back to the caller. If pointer parameters hold at the
// end of a callee function generate all of those in the caller context.

if (CallSite == nullptr) {
return this->killAllFlows();
}
auto MapFactsToCallerFF =
mapFactsToCaller<d_t>(llvm::cast<llvm::CallBase>(CallSite), ExitInst,
{}, [](const llvm::Value *RetVal, d_t Src) {
Expand Down
27 changes: 26 additions & 1 deletion include/phasar/Utils/Utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@
#include "phasar/Utils/TypeTraits.h"

#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"

#include <optional>
#include <set>
#include <string>
#include <type_traits>
Expand Down Expand Up @@ -176,7 +179,9 @@ template <typename Fn> class scope_exit { // NOLINT
template <typename Fn> scope_exit(Fn) -> scope_exit<Fn>;

// Copied from "https://en.cppreference.com/w/cpp/utility/variant/visit"
template <class... Ts> struct Overloaded : Ts... { using Ts::operator()...; };
template <class... Ts> struct Overloaded : Ts... {
using Ts::operator()...;
};
fabianbs96 marked this conversation as resolved.
Show resolved Hide resolved

// explicit deduction guide (not needed as of C++20)
template <class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>;
Expand Down Expand Up @@ -266,6 +271,26 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
return OS;
}

template <typename T>
LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const T &Value) {}

template <typename T>
LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const std::optional<T> &Value) {
assert(Value.has_value());
}

template <typename T>
LLVM_ATTRIBUTE_ALWAYS_INLINE void assertNotNull(const T *Value) {
assert(Value != nullptr);
}

template <typename T> void assertAllNotNull(const T &Range) {
assertNotNull(Range);
for (const auto &Elem : Range) {
assertNotNull(Elem);
}
}

} // namespace psr

#endif
Loading