From b763b5f347a044aaa12f249eeb691d2091447e0b Mon Sep 17 00:00:00 2001 From: Fabian Schiebel <52407375+fabianbs96@users.noreply.github.com> Date: Mon, 28 Aug 2023 21:04:16 +0200 Subject: [PATCH] Cleaning up IDETabulationProblem (#653) * Add default implementation for allTopFunction() * Move the default flow function templates to their own class allowing container_type to be deduced (towards specifying sth else than std::set) * pre-commit TypeTraits.h * Merge branch 'development' into f-DefaultAllTopFn --------- Co-authored-by: Martin Mory --- .clang-tidy | 2 +- .../phasar/DataFlow/IfdsIde/FlowFunctions.h | 940 +++++++++--------- .../DataFlow/IfdsIde/IDETabulationProblem.h | 45 +- .../DataFlow/IfdsIde/IFDSTabulationProblem.h | 2 - .../DataFlow/IfdsIde/LLVMFlowFunctions.h | 21 - .../DataFlow/IfdsIde/LLVMZeroValue.h | 2 +- .../Problems/IDEExtendedTaintAnalysis.h | 12 +- .../IDEGeneralizedLCA/IDEGeneralizedLCA.h | 2 +- .../Problems/IDEInstInteractionAnalysis.h | 34 +- .../Problems/IDELinearConstantAnalysis.h | 4 +- .../IfdsIde/Problems/IDEProtoAnalysis.h | 2 +- .../Problems/IDESecureHeapPropagation.h | 10 +- .../DataFlow/IfdsIde/Problems/IDESolverTest.h | 2 +- .../IfdsIde/Problems/IDETypeStateAnalysis.h | 27 +- .../IfdsIde/Problems/IFDSConstAnalysis.h | 2 +- .../Problems/IFDSFieldSensTaintAnalysis.h | 2 +- .../IfdsIde/Problems/IFDSProtoAnalysis.h | 2 +- .../IfdsIde/Problems/IFDSSignAnalysis.h | 2 +- .../IfdsIde/Problems/IFDSSolverTest.h | 2 +- .../IfdsIde/Problems/IFDSTaintAnalysis.h | 2 +- .../IfdsIde/Problems/IFDSTypeAnalysis.h | 2 +- .../Problems/IFDSUninitializedVariables.h | 2 +- include/phasar/Utils/TypeTraits.h | 12 + .../Problems/IDEExtendedTaintAnalysis.cpp | 50 +- .../IDEGeneralizedLCA/IDEGeneralizedLCA.cpp | 35 +- .../Problems/IDELinearConstantAnalysis.cpp | 20 +- .../IfdsIde/Problems/IDEProtoAnalysis.cpp | 10 +- .../Problems/IDESecureHeapPropagation.cpp | 36 +- .../IfdsIde/Problems/IDESolverTest.cpp | 10 +- .../IfdsIde/Problems/IDETypeStateAnalysis.cpp | 30 +- .../IfdsIde/Problems/IFDSConstAnalysis.cpp | 13 +- .../IfdsIde/Problems/IFDSProtoAnalysis.cpp | 13 +- .../IfdsIde/Problems/IFDSSignAnalysis.cpp | 12 +- .../IfdsIde/Problems/IFDSSolverTest.cpp | 10 +- .../IfdsIde/Problems/IFDSTaintAnalysis.cpp | 22 +- .../IfdsIde/Problems/IFDSTypeAnalysis.cpp | 2 +- .../Problems/IFDSUninitializedVariables.cpp | 72 +- 37 files changed, 705 insertions(+), 763 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 847f4660f..063d1090a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -55,7 +55,7 @@ CheckOptions: - key: readability-identifier-naming.ParameterIgnoredRegexp value: (d|d1|d2|d3|d4|d5|eP|f|n) - key: readability-identifier-naming.FunctionIgnoredRegexp - value: (try_emplace|from_json|to_json|equal_to|to_string,DToString|NToString|FToString|LToString) + value: (try_emplace|from_json|to_json|equal_to|to_string|DToString|NToString|FToString|LToString) - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor value: 1 - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions diff --git a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h index dda69748e..87a3db452 100644 --- a/include/phasar/DataFlow/IfdsIde/FlowFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h @@ -97,533 +97,529 @@ using FlowFunctionPtrTypeOf = std::shared_ptr; template > using FlowFunctionPtrType = FlowFunctionPtrTypeOf>; -/// A flow function that propagates all incoming facts unchanged. -/// -/// Given a flow-function f = identityFlow(), then for all incoming -/// dataflow-facts x, f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x1 x1 x3 ... -/// | | | ... -/// id-instruction | | | ... -/// v v v ... -/// x1 x2 x3 ... -/// -template > auto identityFlow() { - struct IdFF final : public FlowFunction { - Container computeTargets(D Source) override { return {std::move(Source)}; } - }; - static auto TheIdentity = std::make_shared(); - - return TheIdentity; -} +/// Wrapper flow function that is automatically used by the IDESolver if the +/// autoAddZero configuration option is set to true (default). +/// Ensures that the tautological zero-flow fact (Λ) does not get killed. +template > +class ZeroedFlowFunction : public FlowFunction { + using typename FlowFunction::container_type; + using typename FlowFunction::FlowFunctionPtrType; -/// The most generic flow function. Invokes the passed function object F to -/// retrieve the desired data-flows. -/// -/// So, given a flow function f = lambdaFlow(F), then for all incoming -/// dataflow-facts x, f(x) = F(x). -/// -/// In the exploded supergraph it may look as follows: -/// -/// x -/// | -/// inst F -/// / / | \ \ ... -/// v v v v v -/// x1 x2 x x3 x4 -/// -template auto lambdaFlow(Fn &&F) { - using Container = std::invoke_result_t; - struct LambdaFlow final : public FlowFunction { - LambdaFlow(Fn &&F) : Flow(std::forward(F)) {} - Container computeTargets(D Source) override { - return std::invoke(Flow, std::move(Source)); +public: + ZeroedFlowFunction(FlowFunctionPtrType FF, D ZV) + : Delegate(std::move(FF)), ZeroValue(ZV) {} + container_type computeTargets(D Source) override { + if (Source == ZeroValue) { + container_type Result = Delegate->computeTargets(Source); + Result.insert(ZeroValue); + return Result; } + return Delegate->computeTargets(Source); + } - [[no_unique_address]] std::decay_t Flow; - }; +private: + FlowFunctionPtrType Delegate; + D ZeroValue; +}; - return std::make_shared(std::forward(F)); -} +namespace detail { +template +Container makeContainer(Range &&Rng) { + if constexpr (std::is_convertible_v, Container>) { + return std::forward(Rng); + } else { + Container C; + reserveIfPossible(C, Rng.size()); + for (auto &&Fact : Rng) { + C.insert(std::forward(Fact)); + } + return C; + } +}; +} // namespace detail //===----------------------------------------------------------------------===// -// Gen flow functions +// Flow Function Templates +//===----------------------------------------------------------------------===// -/// A flow function that generates a new dataflow fact (FactToGenerate) if -/// called with an already known dataflow fact (From). All other facts are -/// propagated like with the identityFlow. -/// -/// Given a flow function f = generateFlow(v, w), then for all incoming dataflow -/// facts x: -/// f(w) = {v, w}, -/// f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w u ... -/// | |\ | ... -/// inst | | \ | ... -/// v v v v ... -/// x w v u -/// -/// \note If the FactToGenerate already holds at the beginning of the statement, -/// this flow function does not kill it. For IFDS analysis it makes no -/// difference, but in the case of IDE, the corresponding edge functions are -/// being joined together potentially lowing precition. If that is an issue, use -/// transferFlow instead. -template > -auto generateFlow(psr::type_identity_t FactToGenerate, D From) { - struct GenFrom final : public FlowFunction { - GenFrom(D GenValue, D FromValue) - : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - return {std::move(Source), GenValue}; - } - return {std::move(Source)}; - } +template class FlowFunctionTemplates { +public: + using d_t = D; + using container_type = Container; - D GenValue; - D FromValue; - }; + /// A flow function that propagates all incoming facts unchanged. + /// + /// Given a flow-function f = identityFlow(), then for all incoming + /// dataflow-facts x, f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x1 x1 x3 ... + /// | | | ... + /// id-instruction | | | ... + /// v v v ... + /// x1 x2 x3 ... + /// + static auto identityFlow() { + struct IdFF final : public FlowFunction { + container_type computeTargets(d_t Source) override { + return {std::move(Source)}; + } + }; + static auto TheIdentity = std::make_shared(); - return std::make_shared(std::move(FactToGenerate), std::move(From)); -} + return TheIdentity; + } -/// A flow function similar to generateFlow, that generates a new dataflow fact -/// (FactToGenerate), if the given Predicate evaluates to true on an incoming -/// dataflow fact -/// -/// So, given a flow function f = generateFlowIf(v, p), for all incoming -/// dataflow facts x: -/// f(x) = {v, x} if p(x) == true -/// f(x) = {x} else. -/// -template , - typename Fn = psr::TrueFn, - typename = std::enable_if_t>> -auto generateFlowIf(D FactToGenerate, Fn Predicate) { - struct GenFlowIf final : public FlowFunction { - GenFlowIf(D GenValue, Fn &&Predicate) - : GenValue(std::move(GenValue)), - Predicate(std::forward(Predicate)) {} - - Container computeTargets(D Source) override { - if (std::invoke(Predicate, Source)) { - return {std::move(Source), GenValue}; + /// The most generic flow function. Invokes the passed function object F to + /// retrieve the desired data-flows. + /// + /// So, given a flow function f = lambdaFlow(F), then for all incoming + /// dataflow-facts x, f(x) = F(x). + /// + /// In the exploded supergraph it may look as follows: + /// + /// x + /// | + /// inst F + /// / / | \ \ ... + /// v v v v v + /// x1 x2 x x3 x4 + /// + template static auto lambdaFlow(Fn &&F) { + struct LambdaFlow final : public FlowFunction { + LambdaFlow(Fn &&F) : Flow(std::forward(F)) {} + container_type computeTargets(d_t Source) override { + return std::invoke(Flow, std::move(Source)); } - return {std::move(Source)}; - } - D GenValue; - [[no_unique_address]] std::decay_t Predicate; - }; + [[no_unique_address]] std::decay_t Flow; + }; - return std::make_shared(std::move(FactToGenerate), - std::forward(Predicate)); -} + return std::make_shared(std::forward(F)); + } -/// A flow function that generates multiple new dataflow facts (FactsToGenerate) -/// if called from an already known dataflow fact (From). -/// -/// Given a flow function f = generateManyFlows({v1, v2, ..., vN}, w), for all -/// incoming dataflow facts x: -/// f(w) = {v1, v2, ..., vN, w} -/// f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w u ... -/// | |\ \ ... \ | ... -/// inst | | \ \ ... \ | ... -/// v v v v ... \ v ... -/// x w v1 v2 ... vN u -/// -template , - typename Range = std::initializer_list, - typename = std::enable_if_t>> -auto generateManyFlows(Range &&FactsToGenerate, D From) { - struct GenMany final : public FlowFunction { - GenMany(Container &&GenValues, D FromValue) - : GenValues(std::move(GenValues)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - auto Ret = GenValues; - Ret.insert(std::move(Source)); - return Ret; + //===----------------------------------------------------------------------===// + // Gen flow functions + + /// A flow function that generates a new dataflow fact (FactToGenerate) if + /// called with an already known dataflow fact (From). All other facts are + /// propagated like with the identityFlow. + /// + /// Given a flow function f = generateFlow(v, w), then for all incoming + /// dataflow facts x: + /// f(w) = {v, w}, + /// f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w u ... + /// | |\ | ... + /// inst | | \ | ... + /// v v v v ... + /// x w v u + /// + /// \note If the FactToGenerate already holds at the beginning of the + /// statement, this flow function does not kill it. For IFDS analysis it makes + /// no difference, but in the case of IDE, the corresponding edge functions + /// are being joined together potentially lowing precition. If that is an + /// issue, use transferFlow instead. + static auto generateFlow(d_t FactToGenerate, d_t From) { + struct GenFrom final : public FlowFunction { + GenFrom(d_t GenValue, d_t FromValue) + : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + return {std::move(Source), GenValue}; + } + return {std::move(Source)}; } - return {std::move(Source)}; - } - Container GenValues; - D FromValue; - }; - - auto MakeContainer = [](Range &&Rng) -> Container { - if constexpr (std::is_convertible_v, Container>) { - return std::forward(Rng); - } else { - Container C; - for (auto &&Fact : Rng) { - C.insert(std::forward(Fact)); - } - return C; - } - }; - return std::make_shared( - MakeContainer(std::forward(FactsToGenerate)), std::move(From)); -} + d_t GenValue; + d_t FromValue; + }; -//===----------------------------------------------------------------------===// -// Kill flow functions + return std::make_shared(std::move(FactToGenerate), + std::move(From)); + } -/// A flow function that stops propagating a specific dataflow fact -/// (FactToKill). -/// -/// Given a flow function f = killFlow(v), for all incoming dataflow facts x: -/// f(v) = {} -/// f(x) = {x} -/// -/// In the exploded supergraph it may look as follows: -/// -/// u v w ... -/// | | | -/// inst | | -/// v v -/// u v w ... -/// -template > -auto killFlow(D FactToKill) { - struct KillFlow final : public FlowFunction { - KillFlow(D KillValue) : KillValue(std::move(KillValue)) {} - Container computeTargets(D Source) override { - if (Source == KillValue) { - return {}; + /// A flow function similar to generateFlow, that generates a new dataflow + /// fact (FactToGenerate), if the given Predicate evaluates to true on an + /// incoming dataflow fact + /// + /// So, given a flow function f = generateFlowIf(v, p), for all incoming + /// dataflow facts x: + /// f(x) = {v, x} if p(x) == true + /// f(x) = {x} else. + /// + template >> + static auto generateFlowIf(d_t FactToGenerate, Fn Predicate) { + struct GenFlowIf final : public FlowFunction { + GenFlowIf(d_t GenValue, Fn &&Predicate) + : GenValue(std::move(GenValue)), + Predicate(std::forward(Predicate)) {} + + container_type computeTargets(d_t Source) override { + if (std::invoke(Predicate, Source)) { + return {std::move(Source), GenValue}; + } + return {std::move(Source)}; } - return {std::move(Source)}; - } - D KillValue; - }; - return std::make_shared(std::move(FactToKill)); -} + d_t GenValue; + [[no_unique_address]] std::decay_t Predicate; + }; -/// A flow function similar to killFlow that stops propagating all dataflow -/// facts for that the given Predicate evaluates to true. -/// -/// Given a flow function f = killFlowIf(p), for all incoming dataflow facts x: -/// f(x) = {} if p(x) == true -/// f(x) = {x} else. -/// -template , - typename Fn = psr::TrueFn, - typename = std::enable_if_t>> -auto killFlowIf(Fn Predicate) { - struct KillFlowIf final : public FlowFunction { - KillFlowIf(Fn &&Predicate) : Predicate(std::forward(Predicate)) {} - - Container computeTargets(D Source) override { - if (std::invoke(Predicate, Source)) { - return {}; + return std::make_shared(std::move(FactToGenerate), + std::forward(Predicate)); + } + + /// A flow function that generates multiple new dataflow facts + /// (FactsToGenerate) if called from an already known dataflow fact (From). + /// + /// Given a flow function f = generateManyFlows({v1, v2, ..., vN}, w), for all + /// incoming dataflow facts x: + /// f(w) = {v1, v2, ..., vN, w} + /// f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w u ... + /// | |\ \ ... \ | ... + /// inst | | \ \ ... \ | ... + /// v v v v ... \ v ... + /// x w v1 v2 ... vN u + /// + template , + typename = std::enable_if_t>> + static auto generateManyFlows(Range &&FactsToGenerate, d_t From) { + struct GenMany final : public FlowFunction { + GenMany(container_type &&GenValues, d_t FromValue) + : GenValues(std::move(GenValues)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + auto Ret = GenValues; + Ret.insert(std::move(Source)); + return Ret; + } + return {std::move(Source)}; } - return {std::move(Source)}; - } - [[no_unique_address]] std::decay_t Predicate; - }; + container_type GenValues; + d_t FromValue; + }; - return std::make_shared(std::forward(Predicate)); -} + return std::make_shared(detail::makeContainer( + std::forward(FactsToGenerate)), + std::move(From)); + } -/// A flow function that stops propagating a specific set of dataflow facts -/// (FactsToKill). -/// -/// Given a flow function f = killManyFlows({v1, v2, ..., vN}), for all incoming -/// dataflow facts x: -/// f(v1) = {} -/// f(v2) = {} -/// ... -/// f(vN) = {} -/// f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// u v1 v2 ... vN w ... -/// | | | | | -/// inst | | -/// v v -/// u v1 v2 ... vN w ... -/// -template , - typename Range = std::initializer_list, - typename = std::enable_if_t>> -auto killManyFlows(Range &&FactsToKill) { - struct KillMany final : public FlowFunction { - KillMany(Container &&KillValues) : KillValues(std::move(KillValues)) {} - - Container computeTargets(D Source) override { - if (KillValues.count(Source)) { - return {}; + //===----------------------------------------------------------------------===// + // Kill flow functions + + /// A flow function that stops propagating a specific dataflow fact + /// (FactToKill). + /// + /// Given a flow function f = killFlow(v), for all incoming dataflow facts x: + /// f(v) = {} + /// f(x) = {x} + /// + /// In the exploded supergraph it may look as follows: + /// + /// u v w ... + /// | | | + /// inst | | + /// v v + /// u v w ... + /// + static auto killFlow(d_t FactToKill) { + struct KillFlow final : public FlowFunction { + KillFlow(d_t KillValue) : KillValue(std::move(KillValue)) {} + container_type computeTargets(d_t Source) override { + if (Source == KillValue) { + return {}; + } + return {std::move(Source)}; } - return {std::move(Source)}; - } + d_t KillValue; + }; - Container KillValues; - }; + return std::make_shared(std::move(FactToKill)); + } - auto MakeContainer = [](Range &&Rng) -> Container { - if constexpr (std::is_convertible_v, Container>) { - return std::forward(Rng); - } else { - Container C; - for (auto &&Fact : Rng) { - C.insert(std::forward(Fact)); + /// A flow function similar to killFlow that stops propagating all dataflow + /// facts for that the given Predicate evaluates to true. + /// + /// Given a flow function f = killFlowIf(p), for all incoming dataflow facts + /// x: + /// f(x) = {} if p(x) == true + /// f(x) = {x} else. + /// + template >> + static auto killFlowIf(Fn Predicate) { + struct KillFlowIf final : public FlowFunction { + KillFlowIf(Fn &&Predicate) : Predicate(std::forward(Predicate)) {} + + container_type computeTargets(d_t Source) override { + if (std::invoke(Predicate, Source)) { + return {}; + } + return {std::move(Source)}; } - return C; - } - }; - return std::make_shared( - MakeContainer(std::forward(FactsToKill))); -} -/// A flow function that stops propagating *all* incoming dataflow facts. -/// -/// Given a flow function f = killAllFlows(), for all incoming dataflow facts x, -/// f(x) = {}. -/// -template > auto killAllFlows() { - struct KillAllFF final : public FlowFunction { - Container computeTargets(D Source) override { return {std::move(Source)}; } - }; - static auto TheKillAllFlow = std::make_shared(); + [[no_unique_address]] std::decay_t Predicate; + }; - return TheKillAllFlow; -} - -//===----------------------------------------------------------------------===// -// Gen-and-kill flow functions + return std::make_shared(std::forward(Predicate)); + } -/// A flow function that composes kill and generate flow functions. -/// Like generateFlow it generates a new dataflow fact (FactToGenerate), if -/// called with a specific dataflow fact (From). -/// However, like killFlowIf it stops propagating all other dataflow facts. -/// -/// Given a flow function f = generateFlowAndKillAllOthers(v, w), for all -/// incoming dataflow facts x: -/// f(w) = {v, w} -/// f(x) = {}. -/// -/// Equivalent to: killFlowIf(λz.z!=w) o generateFlow(v, w) (where o denotes -/// function composition) -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w u ... -/// | |\ | -/// inst | \ ... -/// v v -/// x w v u -/// -template > -auto generateFlowAndKillAllOthers(psr::type_identity_t FactToGenerate, - D From) { - struct GenFlowAndKillAllOthers final : public FlowFunction { - GenFlowAndKillAllOthers(D GenValue, D FromValue) - : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - return {std::move(Source), GenValue}; + /// A flow function that stops propagating a specific set of dataflow facts + /// (FactsToKill). + /// + /// Given a flow function f = killManyFlows({v1, v2, ..., vN}), for all + /// incoming dataflow facts x: + /// f(v1) = {} + /// f(v2) = {} + /// ... + /// f(vN) = {} + /// f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// u v1 v2 ... vN w ... + /// | | | | | + /// inst | | + /// v v + /// u v1 v2 ... vN w ... + /// + template , + typename = std::enable_if_t>> + static auto killManyFlows(Range &&FactsToKill) { + struct KillMany final : public FlowFunction { + KillMany(Container &&KillValues) : KillValues(std::move(KillValues)) {} + + container_type computeTargets(d_t Source) override { + if (KillValues.count(Source)) { + return {}; + } + return {std::move(Source)}; } - return {}; - } - D GenValue; - D FromValue; - }; + container_type KillValues; + }; - return std::make_shared(std::move(FactToGenerate), - std::move(From)); -} + return std::make_shared(detail::makeContainer( + std::forward(FactsToKill))); + } -/// A flow function similar to generateFlowAndKillAllOthers that may generate -/// multiple dataflow facts (FactsToGenerate) is called with a specific fact -/// (From) and stops propagating all other dataflow facts. -/// -/// Given a flow function f = generateManyFlowsAndKillAllOthers({v1, v2, ..., -/// vN}, w), for all incoming dataflow facts x: -/// f(w) = {v1, v2, ..., vN, w} -/// f(x) = {}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w u ... -/// | |\ \ ... \ | ... -/// inst | \ \ ... \ ... -/// v v v ... \ ... -/// x w v1 v2 ... vN u -/// -template , - typename Range = std::initializer_list, - typename = std::enable_if_t>> -auto generateManyFlowsAndKillAllOthers(Range &&FactsToGenerate, D From) { - struct GenManyAndKillAllOthers final : public FlowFunction { - GenManyAndKillAllOthers(Container &&GenValues, D FromValue) - : GenValues(std::move(GenValues)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - auto Ret = GenValues; - Ret.insert(std::move(Source)); - return Ret; + /// A flow function that stops propagating *all* incoming dataflow facts. + /// + /// Given a flow function f = killAllFlows(), for all incoming dataflow facts + /// x, f(x) = {}. + /// + static auto killAllFlows() { + struct KillAllFF final : public FlowFunction { + Container computeTargets(d_t Source) override { + return {std::move(Source)}; } - return {}; - } + }; + static auto TheKillAllFlow = std::make_shared(); + + return TheKillAllFlow; + } - Container GenValues; - D FromValue; - }; - - auto MakeContainer = [](Range &&Rng) -> Container { - if constexpr (std::is_convertible_v, Container>) { - return std::forward(Rng); - } else { - Container C; - for (auto &&Fact : Rng) { - C.insert(std::forward(Fact)); + //===----------------------------------------------------------------------===// + // Gen-and-kill flow functions + + /// A flow function that composes kill and generate flow functions. + /// Like generateFlow it generates a new dataflow fact (FactToGenerate), if + /// called with a specific dataflow fact (From). + /// However, like killFlowIf it stops propagating all other dataflow facts. + /// + /// Given a flow function f = generateFlowAndKillAllOthers(v, w), for all + /// incoming dataflow facts x: + /// f(w) = {v, w} + /// f(x) = {}. + /// + /// Equivalent to: killFlowIf(λz.z!=w) o generateFlow(v, w) (where o denotes + /// function composition) + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w u ... + /// | |\ | + /// inst | \ ... + /// v v + /// x w v u + /// + static auto generateFlowAndKillAllOthers(d_t FactToGenerate, d_t From) { + struct GenFlowAndKillAllOthers final + : public FlowFunction { + GenFlowAndKillAllOthers(d_t GenValue, d_t FromValue) + : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + return {std::move(Source), GenValue}; + } + return {}; } - return C; - } - }; - return std::make_shared( - MakeContainer(std::forward(FactsToGenerate)), std::move(From)); -} -//===----------------------------------------------------------------------===// -// Miscellaneous flow functions + d_t GenValue; + d_t FromValue; + }; -/// A flow function that, similar to generateFlow, generates a new dataflow fact -/// (FactsToGenerate) when called with a specific dataflow fact (From). -/// Unlike generateFlow, it kills FactToGenerate if it is part of the incoming -/// facts. THis has no additional effect for IFDS analyses (which in fact should -/// use generateFlow instead), but for IDE analyses it may avoid joining the -/// edge functions reaching the FactToGenerate together which may improve the -/// analysis' precision. -/// -/// Given a flow function f = transferFlow(v, w), for all incoming dataflow -/// facts x: -/// f(v) = {} -/// f(w) = {v, w} -/// f(x) = {x}. -/// -/// In the exploded supergraph it may look as follows: -/// -/// x w v u ... -/// | |\ | | ... -/// | | \ | ... -/// inst | | \ | ... -/// v v v v ... -/// x w v u -/// -template > -auto transferFlow(psr::type_identity_t FactToGenerate, D From) { - struct TransferFlow final : public FlowFunction { - TransferFlow(D GenValue, D FromValue) - : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} - - Container computeTargets(D Source) override { - if (Source == FromValue) { - return {std::move(Source), GenValue}; - } - if (Source == GenValue) { + return std::make_shared(std::move(FactToGenerate), + std::move(From)); + } + + /// A flow function similar to generateFlowAndKillAllOthers that may generate + /// multiple dataflow facts (FactsToGenerate) is called with a specific fact + /// (From) and stops propagating all other dataflow facts. + /// + /// Given a flow function f = generateManyFlowsAndKillAllOthers({v1, v2, ..., + /// vN}, w), for all incoming dataflow facts x: + /// f(w) = {v1, v2, ..., vN, w} + /// f(x) = {}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w u ... + /// | |\ \ ... \ | ... + /// inst | \ \ ... \ ... + /// v v v ... \ ... + /// x w v1 v2 ... vN u + /// + template , + typename = std::enable_if_t>> + static auto generateManyFlowsAndKillAllOthers(Range &&FactsToGenerate, + d_t From) { + struct GenManyAndKillAllOthers final + : public FlowFunction { + GenManyAndKillAllOthers(Container &&GenValues, d_t FromValue) + : GenValues(std::move(GenValues)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + auto Ret = GenValues; + Ret.insert(std::move(Source)); + return Ret; + } return {}; } - return {std::move(Source)}; - } - D GenValue; - D FromValue; - }; + container_type GenValues; + d_t FromValue; + }; - return std::make_shared(std::move(FactToGenerate), - std::move(From)); -} + return std::make_shared( + detail::makeContainer( + std::forward(FactsToGenerate)), + std::move(From)); + } -/// A flow function that takes two other flow functions OneFF and OtherFF and -/// applies both flow functions on each input merging the results together with -/// set-union. -/// -/// Given a flow function f = unionFlows(g, h), for all incoming dataflow facts -/// x: -/// f(x) = g(x) u h(x). (where u denotes set-union) -/// -template && - std::is_same_v>> -auto unionFlows(FlowFunctionPtrTypeOf OneFF, - FlowFunctionPtrTypeOf OtherFF) { - struct UnionFlow final : public FlowFunction { - UnionFlow(FlowFunctionPtrTypeOf OneFF, - FlowFunctionPtrTypeOf OtherFF) noexcept - : OneFF(std::move(OneFF)), OtherFF(std::move(OtherFF)) {} - - Container computeTargets(D Source) override { - auto OneRet = OneFF->computeTargets(Source); - auto OtherRet = OtherFF->computeTargets(std::move(Source)); - if (OneRet.size() < OtherRet.size()) { - std::swap(OneRet, OtherRet); + //===----------------------------------------------------------------------===// + // Miscellaneous flow functions + + /// A flow function that, similar to generateFlow, generates a new dataflow + /// fact (FactsToGenerate) when called with a specific dataflow fact (From). + /// Unlike generateFlow, it kills FactToGenerate if it is part of the incoming + /// facts. THis has no additional effect for IFDS analyses (which in fact + /// should use generateFlow instead), but for IDE analyses it may avoid + /// joining the edge functions reaching the FactToGenerate together which may + /// improve the analysis' precision. + /// + /// Given a flow function f = transferFlow(v, w), for all incoming dataflow + /// facts x: + /// f(v) = {} + /// f(w) = {v, w} + /// f(x) = {x}. + /// + /// In the exploded supergraph it may look as follows: + /// + /// x w v u ... + /// | |\ | | ... + /// | | \ | ... + /// inst | | \ | ... + /// v v v v ... + /// x w v u + /// + static auto transferFlow(d_t FactToGenerate, d_t From) { + struct TransferFlow final : public FlowFunction { + TransferFlow(d_t GenValue, d_t FromValue) + : GenValue(std::move(GenValue)), FromValue(std::move(FromValue)) {} + + container_type computeTargets(d_t Source) override { + if (Source == FromValue) { + return {std::move(Source), GenValue}; + } + if (Source == GenValue) { + return {}; + } + return {std::move(Source)}; } - OneRet.insert(std::make_move_iterator(OtherRet.begin()), - std::make_move_iterator(OtherRet.end())); - return OneRet; - } + d_t GenValue; + d_t FromValue; + }; - FlowFunctionPtrTypeOf OneFF; - FlowFunctionPtrTypeOf OtherFF; - }; + return std::make_shared(std::move(FactToGenerate), + std::move(From)); + } - return std::make_shared(std::move(OneFF), std::move(OtherFF)); -} + /// A flow function that takes two other flow functions OneFF and OtherFF and + /// applies both flow functions on each input merging the results together + /// with set-union. + /// + /// Given a flow function f = unionFlows(g, h), for all incoming dataflow + /// facts x: + /// f(x) = g(x) u h(x). (where u denotes set-union) + /// + template && + std::is_same_v && + std::is_same_v>> + auto unionFlows(FlowFunctionPtrTypeOf OneFF, + FlowFunctionPtrTypeOf OtherFF) { + struct UnionFlow final : public FlowFunction { + UnionFlow(FlowFunctionPtrTypeOf OneFF, + FlowFunctionPtrTypeOf OtherFF) noexcept + : OneFF(std::move(OneFF)), OtherFF(std::move(OtherFF)) {} + + container_type computeTargets(d_t Source) override { + auto OneRet = OneFF->computeTargets(Source); + auto OtherRet = OtherFF->computeTargets(std::move(Source)); + if (OneRet.size() < OtherRet.size()) { + std::swap(OneRet, OtherRet); + } + + OneRet.insert(std::make_move_iterator(OtherRet.begin()), + std::make_move_iterator(OtherRet.end())); + return OneRet; + } -/// Wrapper flow function that is automatically used by the IDESolver if the -/// autoAddZero configuration option is set to true (default). -/// Ensures that the tautological zero-flow fact (Λ) does not get killed. -template > -class ZeroedFlowFunction : public FlowFunction { - using typename FlowFunction::container_type; - using typename FlowFunction::FlowFunctionPtrType; + FlowFunctionPtrTypeOf OneFF; + FlowFunctionPtrTypeOf OtherFF; + }; -public: - ZeroedFlowFunction(FlowFunctionPtrType FF, D ZV) - : Delegate(std::move(FF)), ZeroValue(ZV) {} - container_type computeTargets(D Source) override { - if (Source == ZeroValue) { - container_type Result = Delegate->computeTargets(Source); - Result.insert(ZeroValue); - return Result; - } - return Delegate->computeTargets(Source); + return std::make_shared(std::move(OneFF), std::move(OtherFF)); } - -private: - FlowFunctionPtrType Delegate; - D ZeroValue; }; //===----------------------------------------------------------------------===// // FlowFunctions Class //===----------------------------------------------------------------------===// -template > -class FlowFunctions { +template +class FlowFunctions + : protected FlowFunctionTemplates { static_assert( std::is_same::value, @@ -858,7 +854,8 @@ class FlowFunctions { // The default implementation returns a nullptr to indicate that the mechanism // should not be used. // - virtual FlowFunctionPtrType getSummaryFlowFunction(n_t Curr, f_t CalleeFun) { + virtual FlowFunctionPtrType getSummaryFlowFunction(n_t /*Curr*/, + f_t /*CalleeFun*/) { return nullptr; } }; @@ -868,7 +865,8 @@ class FlowFunctions { //////////////////////////////////////////////////////////////////////////////// template > -class Identity : public FlowFunction { +class [[deprecated("Use identityFlow() instead")]] Identity + : public FlowFunction { public: using typename FlowFunction::FlowFunctionType; using typename FlowFunction::FlowFunctionPtrType; @@ -913,7 +911,7 @@ typename FlowFunction::FlowFunctionPtrType makeLambdaFlow(Fn &&F) { } template > -class Compose : public FlowFunction { +class [[deprecated]] Compose : public FlowFunction { public: using typename FlowFunction::FlowFunctionType; using typename FlowFunction::FlowFunctionPtrType; diff --git a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h index cf4970f1d..ab20dc3f6 100644 --- a/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h @@ -12,6 +12,7 @@ #include "phasar/ControlFlow/ICFGBase.h" #include "phasar/DB/ProjectIRDBBase.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" #include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" #include "phasar/DataFlow/IfdsIde/EntryPointUtils.h" #include "phasar/DataFlow/IfdsIde/FlowFunctions.h" @@ -36,11 +37,29 @@ namespace psr { struct HasNoConfigurationType; +template class AllTopFnProvider { +public: + /// Returns an edge function that represents the top element of the analysis. + virtual EdgeFunction allTopFunction() = 0; +}; + +template +class AllTopFnProvider< + AnalysisDomainTy, + std::enable_if_t>> { +public: + /// Returns an edge function that represents the top element of the analysis. + virtual EdgeFunction allTopFunction() { + return AllTop{}; + } +}; + template > class IDETabulationProblem : public FlowFunctions, public EdgeFunctions, - public JoinLattice { + public JoinLattice, + public AllTopFnProvider { public: using ProblemAnalysisDomain = AnalysisDomainTy; using d_t = typename AnalysisDomainTy::d_t; @@ -54,9 +73,10 @@ class IDETabulationProblem : public FlowFunctions, using ConfigurationTy = HasNoConfigurationType; - explicit IDETabulationProblem(const ProjectIRDBBase *IRDB, - std::vector EntryPoints, - std::optional ZeroValue) + explicit IDETabulationProblem( + const ProjectIRDBBase *IRDB, std::vector EntryPoints, + std::optional + ZeroValue) noexcept(std::is_nothrow_move_constructible_v) : IRDB(IRDB), EntryPoints(std::move(EntryPoints)), ZeroValue(std::move(ZeroValue)) { assert(IRDB != nullptr); @@ -64,12 +84,9 @@ class IDETabulationProblem : public FlowFunctions, ~IDETabulationProblem() override = default; - /// Returns an edge function that represents the top element of the analysis. - virtual EdgeFunction allTopFunction() = 0; - /// Checks if the given data-flow fact is the special tautological lambda (or /// zero) fact. - [[nodiscard]] virtual bool isZeroValue(d_t FlowFact) const { + [[nodiscard]] virtual bool isZeroValue(d_t FlowFact) const noexcept { assert(ZeroValue.has_value()); return FlowFact == *ZeroValue; } @@ -79,23 +96,24 @@ class IDETabulationProblem : public FlowFunctions, [[nodiscard]] virtual InitialSeeds initialSeeds() = 0; /// Returns the special tautological lambda (or zero) fact. - [[nodiscard]] d_t getZeroValue() const { + [[nodiscard]] ByConstRef getZeroValue() const { assert(ZeroValue.has_value()); return *ZeroValue; } - void initializeZeroValue(d_t Zero) { + void initializeZeroValue(d_t Zero) noexcept( + std::is_nothrow_assignable_v &, d_t &&>) { assert(!ZeroValue.has_value()); ZeroValue = std::move(Zero); } /// Sets the configuration to be used by the IFDS/IDE solver. - void setIFDSIDESolverConfig(IFDSIDESolverConfig Config) { + void setIFDSIDESolverConfig(IFDSIDESolverConfig Config) noexcept { SolverConfig = Config; } /// Returns the configuration of the IFDS/IDE solver. - [[nodiscard]] IFDSIDESolverConfig &getIFDSIDESolverConfig() { + [[nodiscard]] IFDSIDESolverConfig &getIFDSIDESolverConfig() noexcept { return SolverConfig; } @@ -122,7 +140,8 @@ class IDETabulationProblem : public FlowFunctions, protected: typename FlowFunctions::FlowFunctionPtrType generateFromZero(d_t FactToGenerate) { - return generateFlow(std::move(FactToGenerate), getZeroValue()); + return FlowFunctions::generateFlow( + std::move(FactToGenerate), getZeroValue()); } /// Seeds that just start with ZeroValue and bottomElement() at the starting diff --git a/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h index 5deddf1f9..e669a26a9 100644 --- a/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h @@ -76,8 +76,6 @@ class IFDSTabulationProblem d_t /*SuccNode*/) final { return EdgeIdentity{}; } - - EdgeFunction allTopFunction() final { return AllTop{}; } }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h index 57bff2b65..dba21e5d5 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h @@ -355,27 +355,6 @@ mapFactsToCaller(const llvm::CallBase *CallSite, PropagateZeroToCaller); } -//===----------------------------------------------------------------------===// -// Propagation flow functions - -/// Utility function to simplify writing a flow function of the form: -/// generateFlow(Load, from: Load->getPointerOperand()). -template > -FlowFunctionPtrType -propagateLoad(const llvm::LoadInst *Load) { - return generateFlow( - Load, Load->getPointerOperand()); -} - -/// Utility function to simplify writing a flow function of the form: -/// generateFlow(Store->getValueOperand(), from: Store->getPointerOperand()). -template > -FlowFunctionPtrType -propagateStore(const llvm::StoreInst *Store) { - return generateFlow( - Store->getValueOperand(), Store->getPointerOperand()); -} - //===----------------------------------------------------------------------===// // Update flow functions diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h index e0f6d8b9e..ad55a9840 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h @@ -53,7 +53,7 @@ class LLVMZeroValue : public llvm::GlobalVariable { static const LLVMZeroValue *getInstance(); // NOLINTNEXTLINE(readability-identifier-naming) - static constexpr auto isLLVMZeroValue = [](const llvm::Value *V) { + static constexpr auto isLLVMZeroValue = [](const llvm::Value *V) noexcept { return V == getInstance(); }; }; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h index e2ba69e2d..e7dceb8eb 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @@ -246,17 +246,7 @@ class IDEExtendedTaintAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; - - EdgeFunctionType allTopFunction() override; - - // JoinLattice - - l_t topElement() override; - - l_t bottomElement() override; - - l_t join(l_t LHS, l_t RHS) override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // Printing functions diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h index 9461ff4f2..edde5b462 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h @@ -74,7 +74,7 @@ class IDEGeneralizedLCA : public IDETabulationProblem { [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h index 207c9bdbe..8f9a71af7 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -270,7 +270,7 @@ class IDEInstInteractionAnalysisT // if (const auto *Alloca = llvm::dyn_cast(Curr)) { PHASAR_LOG_LEVEL(DFADEBUG, "AllocaInst"); - return generateFromZero(Alloca); + return this->generateFromZero(Alloca); } // Handle indirect taints, i. e., propagate values that depend on branch @@ -293,7 +293,7 @@ class IDEInstInteractionAnalysisT // v v v v // 0 c x I // - return lambdaFlow([Br](d_t Src) { + return this->lambdaFlow([Br](d_t Src) { container_type Facts; Facts.insert(Src); if (Src == Br->getCondition()) { @@ -329,7 +329,7 @@ class IDEInstInteractionAnalysisT // v v v // 0 Y x // - return generateFlowIf( + return this->generateFlowIf( Load, [PointerOp = Load->getPointerOperand(), PTS = PT.getReachableAllocationSites( Load->getPointerOperand(), OnlyConsiderLocalAliases)]( @@ -355,7 +355,7 @@ class IDEInstInteractionAnalysisT // v v v // 0 x Y // - return lambdaFlow( + return this->lambdaFlow( [Store, PointerPTS = PT.getReachableAllocationSites( Store->getPointerOperand(), OnlyConsiderLocalAliases, Store)](d_t Src) -> container_type { @@ -396,7 +396,7 @@ class IDEInstInteractionAnalysisT // 0 y x // if (const auto *Load = llvm::dyn_cast(Curr)) { - return generateFlow(Load, Load->getPointerOperand()); + return this->generateFlow(Load, Load->getPointerOperand()); } // Handle store instructions // @@ -409,7 +409,7 @@ class IDEInstInteractionAnalysisT // 0 x y // if (const auto *Store = llvm::dyn_cast(Curr)) { - return lambdaFlow([Store](d_t Src) -> container_type { + return this->lambdaFlow([Store](d_t Src) -> container_type { // Override old value, i.e., kill value that is written to and // generate from value that is stored. if (Store->getPointerOperand() == Src) { @@ -448,7 +448,7 @@ class IDEInstInteractionAnalysisT // v v v v // 0 x o p // - return lambdaFlow([Inst = Curr](d_t Src) { + return this->lambdaFlow([Inst = Curr](d_t Src) { container_type Facts; if (IDEInstInteractionAnalysisT::isZeroValueImpl(Src)) { // keep the zero flow fact @@ -483,11 +483,11 @@ class IDEInstInteractionAnalysisT f_t DestFun) override { if (this->ICF->isHeapAllocatingFunction(DestFun)) { // Kill add facts and model the effects in getCallToRetFlowFunction(). - return killAllFlows(); + return this->killAllFlows(); } if (DestFun->isDeclaration()) { // We don't have anything that we could analyze, kill all facts. - return killAllFlows(); + return this->killAllFlows(); } const auto *CS = llvm::cast(CallSite); @@ -509,9 +509,9 @@ class IDEInstInteractionAnalysisT auto SRetFormal = CS->hasStructRetAttr() ? DestFun->getArg(0) : nullptr; if (SRetFormal) { - return unionFlows( + return this->unionFlows( std::move(MapFactsToCalleeFF), - generateFlowAndKillAllOthers(SRetFormal, this->getZeroValue())); + this->generateFlowAndKillAllOthers(SRetFormal, this->getZeroValue())); } return MapFactsToCalleeFF; @@ -582,9 +582,9 @@ class IDEInstInteractionAnalysisT } } - return lambdaFlow([CallSite = llvm::cast(CallSite), - OnlyDecls, - AllVoidRetTys](d_t Source) -> container_type { + return this->lambdaFlow([CallSite = llvm::cast(CallSite), + OnlyDecls, + AllVoidRetTys](d_t Source) -> container_type { // There are a few things to consider, in case only declarations of // callee targets are available. if (OnlyDecls) { @@ -659,7 +659,9 @@ class IDEInstInteractionAnalysisT return LLVMZeroValue::getInstance(); } - inline bool isZeroValue(d_t d) const override { return isZeroValueImpl(d); } + inline bool isZeroValue(d_t d) const noexcept override { + return isZeroValueImpl(d); + } // In addition provide specifications for the IDE parts. @@ -946,8 +948,6 @@ class IDEInstInteractionAnalysisT inline l_t join(l_t Lhs, l_t Rhs) override { return joinImpl(Lhs, Rhs); } - inline EdgeFunctionType allTopFunction() override { return AllTop(); } - // Provide some handy helper edge functions to improve reuse. // Edge function that kills all labels in a set (and may replaces them with diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h index d84f491cc..2e7c6d873 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h @@ -94,7 +94,7 @@ class IDELinearConstantAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts @@ -117,8 +117,6 @@ class IDELinearConstantAnalysis EdgeFunction getSummaryEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, d_t SuccNode) override; - EdgeFunction allTopFunction() override; - // Helper functions [[nodiscard]] lca_results_t getLCAResults(SolverResults SR); diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h index d4927219e..c4b9ab965 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h @@ -66,7 +66,7 @@ class IDEProtoAnalysis : public IDETabulationProblem { [[nodiscard]] d_t createZeroValue() const; - bool isZeroValue(d_t Fact) const override; + bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h index a41352335..81036cdbe 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h @@ -81,7 +81,7 @@ class IDESecureHeapPropagation [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts @@ -105,14 +105,6 @@ class IDESecureHeapPropagation n_t RetSite, d_t RetSiteNode) override; - l_t topElement() override; - - l_t bottomElement() override; - - l_t join(l_t Lhs, l_t Rhs) override; - - EdgeFunction allTopFunction() override; - void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS) override; }; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h index 2bc92e9db..3c1736fb5 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h @@ -67,7 +67,7 @@ class IDESolverTest : public IDETabulationProblem { [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; // in addition provide specifications for the IDE parts diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h index 475e18ead..9335838f9 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -44,18 +44,29 @@ class LLVMBasedICFG; class LLVMTypeHierarchy; namespace detail { -class IDETypeStateAnalysisBase { + +class IDETypeStateAnalysisBaseCommon : public LLVMAnalysisDomainDefault { +public: + using container_type = std::set; + using FlowFunctionPtrType = FlowFunctionPtrType; +}; + +class IDETypeStateAnalysisBase + : private IDETypeStateAnalysisBaseCommon, + private FlowFunctionTemplates< + IDETypeStateAnalysisBaseCommon::d_t, + IDETypeStateAnalysisBaseCommon::container_type> { public: virtual ~IDETypeStateAnalysisBase() = default; protected: IDETypeStateAnalysisBase(LLVMAliasInfoRef PT) noexcept : PT(PT) {} - using d_t = const llvm::Value *; - using n_t = const llvm::Instruction *; - using f_t = const llvm::Function *; - using container_type = std::set; - using FlowFunctionPtrType = FlowFunctionPtrType; + using typename IDETypeStateAnalysisBaseCommon::container_type; + using typename IDETypeStateAnalysisBaseCommon::d_t; + using typename IDETypeStateAnalysisBaseCommon::f_t; + using typename IDETypeStateAnalysisBaseCommon::FlowFunctionPtrType; + using typename IDETypeStateAnalysisBaseCommon::n_t; // --- Flow Functions @@ -115,7 +126,7 @@ class IDETypeStateAnalysisBase { private: FlowFunctionPtrType generateFromZero(d_t FactToGenerate) { - return generateFlow(FactToGenerate, LLVMZeroValue::getInstance()); + return generateFlow(FactToGenerate, LLVMZeroValue::getInstance()); } bool hasMatchingTypeName(const llvm::Type *Ty); @@ -383,7 +394,7 @@ class IDETypeStateAnalysis return LLVMZeroValue::getInstance(); } - [[nodiscard]] bool isZeroValue(d_t Fact) const override { + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h index 0d4585614..590513a44 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h @@ -142,7 +142,7 @@ class IFDSConstAnalysis */ [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h index fc0f52a9a..135a51811 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h @@ -81,7 +81,7 @@ class IFDSFieldSensTaintAnalysis return ExtendedValue(LLVMZeroValue::getInstance()); } - [[nodiscard]] bool isZeroValue(ExtendedValue EV) const override { + [[nodiscard]] bool isZeroValue(ExtendedValue EV) const noexcept override { return LLVMZeroValue::isLLVMZeroValue(EV.getValue()); } diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h index 9e3e43769..fb1db483c 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h @@ -52,7 +52,7 @@ class IFDSProtoAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h index 5575275c4..54338de63 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h @@ -53,7 +53,7 @@ class IFDSSignAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h index 8099e5184..edf176f77 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h @@ -51,7 +51,7 @@ class IFDSSolverTest [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h index 49479bc1e..5e6d85ccf 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h @@ -77,7 +77,7 @@ class IFDSTaintAnalysis [[nodiscard]] d_t createZeroValue() const; - bool isZeroValue(d_t FlowFact) const override; + bool isZeroValue(d_t FlowFact) const noexcept override; void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h index 3f9edcfe8..8f5c8c04f 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h @@ -44,7 +44,7 @@ class IFDSTypeAnalysis [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h index ee81523e0..c6a92f457 100644 --- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h @@ -60,7 +60,7 @@ class IFDSUninitializedVariables [[nodiscard]] d_t createZeroValue() const; - [[nodiscard]] bool isZeroValue(d_t Fact) const override; + [[nodiscard]] bool isZeroValue(d_t Fact) const noexcept override; void emitTextReport(const SolverResults &Results, llvm::raw_ostream &OS = llvm::outs()) override; diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 7aebbdb72..745cc4b42 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -68,6 +68,12 @@ template struct has_str().str())> : std::true_type { }; // NOLINT +template struct has_reserve : std::false_type {}; +template +struct has_reserve< + T, std::void_t().reserve(size_t(0)))>> + : std::true_type {}; + template struct has_adl_to_string { template ())))> @@ -251,6 +257,12 @@ template struct DefaultConstruct { } }; +template void reserveIfPossible(T &Container, size_t Capacity) { + if constexpr (detail::has_reserve::value) { + Container.reserve(Capacity); + } +} + template >> [[nodiscard]] decltype(auto) adl_to_string(const T &Val) { using std::to_string; diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp index 9c39547aa..02c08a309 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp @@ -66,15 +66,10 @@ auto IDEExtendedTaintAnalysis::createZeroValue() const -> d_t { return FactFactory.getOrCreateZero(); } -bool IDEExtendedTaintAnalysis::isZeroValue(d_t Fact) const { +bool IDEExtendedTaintAnalysis::isZeroValue(d_t Fact) const noexcept { return Fact->isZero(); } -IDEExtendedTaintAnalysis::EdgeFunctionType -IDEExtendedTaintAnalysis::allTopFunction() { - return AllTop{}; -} - // Flow functions: IDEExtendedTaintAnalysis::FlowFunctionPtrType @@ -101,7 +96,7 @@ IDEExtendedTaintAnalysis::getNormalFlowFunction(n_t Curr, } if (const auto *Phi = llvm::dyn_cast(Curr)) { - return lambdaFlow([this, Phi](d_t Source) -> std::set { + return lambdaFlow([this, Phi](d_t Source) -> std::set { auto NumOps = Phi->getNumIncomingValues(); for (unsigned I = 0; I < NumOps; ++I) { if (equivalent(Source, makeFlowFact(Phi->getIncomingValue(I)))) { @@ -113,7 +108,7 @@ IDEExtendedTaintAnalysis::getNormalFlowFunction(n_t Curr, }); } - return Identity::getInstance(); + return identityFlow(); } IDEExtendedTaintAnalysis::FlowFunctionPtrType @@ -128,8 +123,8 @@ IDEExtendedTaintAnalysis::getStoreFF(const llvm::Value *PointerOp, AliasInfoRef::AliasSetPtrTy PTS = nullptr; auto Mem = makeFlowFact(PointerOp); - return lambdaFlow([this, TV, Mem, PTS, PointerOp, ValueOp, Store, - PALevel](d_t Source) mutable -> std::set { + return lambdaFlow([this, TV, Mem, PTS, PointerOp, ValueOp, Store, + PALevel](d_t Source) mutable -> std::set { if (Source->isZero()) { std::set Ret = {Source}; generateFromZero(Ret, Store, PointerOp, ValueOp, @@ -273,8 +268,8 @@ auto IDEExtendedTaintAnalysis::handleConfig(const llvm::Instruction *Inst, populateWithMayAliases(SourceConfig); } - return lambdaFlow([Inst, this, SourceConfig{std::move(SourceConfig)}, - SinkConfig{std::move(SinkConfig)}](d_t Source) { + return lambdaFlow([Inst, this, SourceConfig{std::move(SourceConfig)}, + SinkConfig{std::move(SinkConfig)}](d_t Source) { std::set Ret = {Source}; if (Source->isZero()) { @@ -299,14 +294,13 @@ IDEExtendedTaintAnalysis::getCallFlowFunction(n_t CallStmt, f_t DestFun) { const auto *Call = llvm::cast(CallStmt); assert(Call); if (DestFun->isDeclaration()) { - return Identity::getInstance(); + return identityFlow(); } bool HasVarargs = Call->arg_size() > DestFun->arg_size(); const auto *const VA = HasVarargs ? getVAListTagOrNull(DestFun) : nullptr; - return lambdaFlow([this, Call, DestFun, - VA](d_t Source) -> std::set { + return lambdaFlow([this, Call, DestFun, VA](d_t Source) -> std::set { if (isZeroValue(Source)) { return {Source}; } @@ -394,7 +388,7 @@ IDEExtendedTaintAnalysis::getRetFlowFunction(n_t CallSite, f_t CalleeFun, if (!CallSite) { /// In case of unbalanced return, we may reach the artificial Global Ctor /// caller that has no caller - return killFlowIf([](d_t Source) { + return killFlowIf([](d_t Source) { return !llvm::isa_and_nonnull(Source->base()); }); } @@ -421,11 +415,11 @@ IDEExtendedTaintAnalysis::getRetFlowFunction(n_t CallSite, f_t CalleeFun, }; const auto *Call = llvm::cast(CallSite); - return lambdaFlow([this, Call, CalleeFun, - ExitStmt{llvm::cast(ExitStmt)}, - PTC{ArgAliasCache(PT, Call->arg_size(), - HasPreciseAliasInfo)}]( - d_t Source) mutable -> std::set { + return lambdaFlow([this, Call, CalleeFun, + ExitStmt{llvm::cast(ExitStmt)}, + PTC{ArgAliasCache(PT, Call->arg_size(), + HasPreciseAliasInfo)}]( + d_t Source) mutable -> std::set { if (isZeroValue(Source)) { return {Source}; } @@ -497,7 +491,7 @@ IDEExtendedTaintAnalysis::getCallToRetFlowFunction( // into // // that function - // return lambdaFlow([CallSite, this](d_t Source) -> std::set + // return lambdaFlow([CallSite, this](d_t Source) -> std::set // { // if (isZeroValue(Source)) { // return {}; @@ -538,7 +532,7 @@ IDEExtendedTaintAnalysis::getCallToRetFlowFunction( [](const llvm::Function *F) { return F->isDeclaration(); }); if (HasDeclaration) { - return Identity::getInstance(); + return identityFlow(); } return killFlow(getZeroValue()); @@ -765,16 +759,6 @@ void IDEExtendedTaintAnalysis::emitTextReport( OS << '\n'; } -// JoinLattice - -auto IDEExtendedTaintAnalysis::topElement() -> l_t { return Top{}; } - -auto IDEExtendedTaintAnalysis::bottomElement() -> l_t { return Bottom{}; } - -auto IDEExtendedTaintAnalysis::join(l_t LHS, l_t RHS) -> l_t { - return LHS.join(RHS, &BBO); -} - // Helpers: auto IDEExtendedTaintAnalysis::makeFlowFact(const llvm::Value *V) -> d_t { diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp index cfb72c540..b49ecb872 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.cpp @@ -39,12 +39,6 @@ namespace psr { using namespace glca; -template >> -inline auto flow(Fn Func) { - return lambdaFlow(std::forward(Func)); -} - IDEGeneralizedLCA::IDEGeneralizedLCA(const LLVMProjectIRDB *IRDB, const LLVMBasedICFG *ICF, std::vector EntryPoints, @@ -63,9 +57,9 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, const auto *ValueOp = Store->getValueOperand(); if (isConstant(ValueOp)) { // llvm::outs() << "==> constant store" << std::endl; - return lambdaFlow([=](IDEGeneralizedLCA::d_t Source) - -> std::set { - // llvm::outs() << "##> normal lambdaFlow for: " << + return lambdaFlow([=](IDEGeneralizedLCA::d_t Source) + -> std::set { + // llvm::outs() << "##> normal lambdaFlow for: " << // llvmIRToString(curr) // << " with " << llvmIRToString(source) << std::endl; if (Source == PointerOp) { @@ -77,7 +71,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, return {Source}; }); } - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { if (Source == PointerOp) { return {}; @@ -89,7 +83,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, }); } if (const auto *Load = llvm::dyn_cast(Curr)) { - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { // llvm::outs() << "LOAD " << llvmIRToString(curr) << std::endl; // llvm::outs() << "\twith " << llvmIRToString(source) << " ==> "; @@ -102,7 +96,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, }); } if (const auto *Gep = llvm::dyn_cast(Curr)) { - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { if (Source == Gep->getPointerOperand()) { return {Source, Gep}; @@ -116,7 +110,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, Cast->getSrcTy()->isFloatingPointTy()) && (Cast->getDestTy()->isIntegerTy() || Cast->getDestTy()->isFloatingPointTy())) { - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { if (Source == Cast->getOperand(0)) { return {Source, Cast}; @@ -132,7 +126,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, bool BothConst = LeftConst && RightConst; bool NoneConst = !LeftConst && !RightConst; - return lambdaFlow( + return lambdaFlow( [=](IDEGeneralizedLCA::d_t Source) -> std::set { if (Source == Lhs || Source == Rhs || ((BothConst || NoneConst) && isZeroValue(Source))) { @@ -142,7 +136,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, }); } /*else if (llvm::isa(curr)) { auto op = curr->getOperand(0); - return lambdaFlow([=](IDEGeneralizedLCA::d_t source) + return lambdaFlow([=](IDEGeneralizedLCA::d_t source) -> std::set { if (source == op) return {source, curr}; @@ -151,7 +145,7 @@ IDEGeneralizedLCA::getNormalFlowFunction(IDEGeneralizedLCA::n_t Curr, }); } */ - return Identity::getInstance(); + return identityFlow(); } std::shared_ptr> @@ -160,7 +154,7 @@ IDEGeneralizedLCA::getCallFlowFunction(IDEGeneralizedLCA::n_t CallStmt, assert(llvm::isa(CallStmt)); if (isStringConstructor(DestMthd)) { // kill all data-flow facts at calls to string constructors - return killAllFlows(); + return killAllFlows(); } return std::make_shared( llvm::cast(CallStmt), DestMthd); @@ -196,7 +190,7 @@ IDEGeneralizedLCA::getCallToRetFlowFunction(IDEGeneralizedLCA::n_t CallSite, // found std::string ctor return generateFromZero(CS->getArgOperand(0)); } - // return lambdaFlow([Call](IDEGeneralizedLCA::d_t Source) + // return lambdaFlow([Call](IDEGeneralizedLCA::d_t Source) // -> std::set { // // llvm::outs() << "In getCallToRetFlowFunction\n"; // // llvm::outs() << llvmIRToString(Source) << '\n'; @@ -210,7 +204,7 @@ IDEGeneralizedLCA::getCallToRetFlowFunction(IDEGeneralizedLCA::n_t CallSite, // return {Source}; // }); } - return Identity::getInstance(); + return identityFlow(); } std::shared_ptr> @@ -249,7 +243,8 @@ IDEGeneralizedLCA::d_t IDEGeneralizedLCA::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IDEGeneralizedLCA::isZeroValue(IDEGeneralizedLCA::d_t Fact) const { +bool IDEGeneralizedLCA::isZeroValue( + IDEGeneralizedLCA::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp index fef29aaf6..a8aa6e824 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.cpp @@ -304,7 +304,7 @@ IDELinearConstantAnalysis::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) { if (const auto *Load = llvm::dyn_cast(Curr)) { // only consider i32 load if (Load->getType()->isIntegerTy()) { - return generateFlowIf(Load, [Load](d_t Source) { + return generateFlowIf(Load, [Load](d_t Source) { return Source == Load->getPointerOperand(); }); } @@ -313,7 +313,7 @@ IDELinearConstantAnalysis::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) { if (llvm::isa(Curr)) { auto *Lop = Curr->getOperand(0); auto *Rop = Curr->getOperand(1); - return generateFlowIf(Curr, [this, Lop, Rop](d_t Source) { + return generateFlowIf(Curr, [this, Lop, Rop](d_t Source) { /// Intentionally include nonlinear operations here for being able to /// explicitly set them to BOTTOM in the edge function return (Lop == Source) || (Rop == Source) || @@ -331,12 +331,12 @@ IDELinearConstantAnalysis::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) { if (const auto *BinIntrinsic = llvm::dyn_cast(Agg)) { if (Extract->getType()->isIntegerTy()) { - return generateFlow(Curr, Agg); + return generateFlow(Curr, Agg); } } } - return identityFlow(); + return identityFlow(); } IDELinearConstantAnalysis::FlowFunctionPtrType @@ -351,7 +351,7 @@ IDELinearConstantAnalysis::getCallFlowFunction(n_t CallSite, f_t DestFun) { } } // Pass everything else as identity - return identityFlow(); + return identityFlow(); } IDELinearConstantAnalysis::FlowFunctionPtrType @@ -372,7 +372,7 @@ IDELinearConstantAnalysis::FlowFunctionPtrType IDELinearConstantAnalysis::getCallToRetFlowFunction( n_t CallSite, n_t /*RetSite*/, llvm::ArrayRef Callees) { if (llvm::all_of(Callees, [](f_t Fun) { return Fun->isDeclaration(); })) { - return identityFlow(); + return identityFlow(); } return mapFactsAlongsideCallSite( @@ -413,7 +413,7 @@ IDELinearConstantAnalysis::getSummaryFlowFunction(n_t Curr, f_t /*CalleeFun*/) { auto *Lop = BinIntrinsic->getLHS(); auto *Rop = BinIntrinsic->getRHS(); - return generateFlowIf(BinIntrinsic, [this, Lop, Rop](d_t Source) { + return generateFlowIf(BinIntrinsic, [this, Lop, Rop](d_t Source) { /// Intentionally include nonlinear operations here for being able to /// explicitly set them to BOTTOM in the edge function return (Lop == Source) || (Rop == Source) || @@ -430,7 +430,7 @@ IDELinearConstantAnalysis::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IDELinearConstantAnalysis::isZeroValue(d_t Fact) const { +bool IDELinearConstantAnalysis::isZeroValue(d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } @@ -564,10 +564,6 @@ IDELinearConstantAnalysis::getSummaryEdgeFunction(n_t Curr, d_t CurrNode, return EdgeIdentity{}; } -EdgeFunction IDELinearConstantAnalysis::allTopFunction() { - return AllTop{}; -} - void IDELinearConstantAnalysis::emitTextReport( const SolverResults &SR, llvm::raw_ostream &OS) { OS << "\n====================== IDE-Linear-Constant-Analysis Report " diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp index a0a8619e4..d3cff2862 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.cpp @@ -38,26 +38,26 @@ IDEProtoAnalysis::IDEProtoAnalysis(const LLVMProjectIRDB *IRDB, IDEProtoAnalysis::FlowFunctionPtrType IDEProtoAnalysis::getNormalFlowFunction(IDEProtoAnalysis::n_t /*Curr*/, IDEProtoAnalysis::n_t /*Succ*/) { - return Identity::getInstance(); + return identityFlow(); } IDEProtoAnalysis::FlowFunctionPtrType IDEProtoAnalysis::getCallFlowFunction(IDEProtoAnalysis::n_t /*CallSite*/, IDEProtoAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IDEProtoAnalysis::FlowFunctionPtrType IDEProtoAnalysis::getRetFlowFunction( IDEProtoAnalysis::n_t /*CallSite*/, IDEProtoAnalysis::f_t /*CalleeFun*/, IDEProtoAnalysis::n_t /*ExitSite*/, IDEProtoAnalysis::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IDEProtoAnalysis::FlowFunctionPtrType IDEProtoAnalysis::getCallToRetFlowFunction(IDEProtoAnalysis::n_t /*CallSite*/, IDEProtoAnalysis::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IDEProtoAnalysis::FlowFunctionPtrType @@ -79,7 +79,7 @@ IDEProtoAnalysis::d_t IDEProtoAnalysis::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IDEProtoAnalysis::isZeroValue(IDEProtoAnalysis::d_t Fact) const { +bool IDEProtoAnalysis::isZeroValue(IDEProtoAnalysis::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp index 116981c0a..a06853787 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.cpp @@ -63,13 +63,13 @@ IDESecureHeapPropagation::IDESecureHeapPropagation( IDESecureHeapPropagation::FlowFunctionPtrType IDESecureHeapPropagation::getNormalFlowFunction(n_t /*Curr*/, n_t /*Succ*/) { - return Identity::getInstance(); + return identityFlow(); } IDESecureHeapPropagation::FlowFunctionPtrType IDESecureHeapPropagation::getCallFlowFunction(n_t /*CallSite*/, f_t /*DestMthd*/) { - return Identity::getInstance(); + return identityFlow(); } IDESecureHeapPropagation::FlowFunctionPtrType @@ -77,7 +77,7 @@ IDESecureHeapPropagation::getRetFlowFunction(n_t /*CallSite*/, f_t /*CalleeMthd*/, n_t /*ExitInst*/, n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IDESecureHeapPropagation::FlowFunctionPtrType @@ -91,7 +91,7 @@ IDESecureHeapPropagation::getCallToRetFlowFunction( if (FName == InitializerFn) { return generateFromZero(SecureHeapFact::INITIALIZED); } - return Identity::getInstance(); + return identityFlow(); } IDESecureHeapPropagation::FlowFunctionPtrType IDESecureHeapPropagation::getSummaryFlowFunction(n_t /*CallSite*/, @@ -110,7 +110,7 @@ IDESecureHeapPropagation::createZeroValue() const { return SecureHeapFact::ZERO; } -bool IDESecureHeapPropagation::isZeroValue(d_t Fact) const { +bool IDESecureHeapPropagation::isZeroValue(d_t Fact) const noexcept { return Fact == SecureHeapFact::ZERO; } @@ -163,32 +163,6 @@ IDESecureHeapPropagation::getSummaryEdgeFunction(n_t /*CallSite*/, return nullptr; } -IDESecureHeapPropagation::l_t IDESecureHeapPropagation::topElement() { - return l_t::TOP; -} - -IDESecureHeapPropagation::l_t IDESecureHeapPropagation::bottomElement() { - return l_t::BOT; -} - -IDESecureHeapPropagation::l_t IDESecureHeapPropagation::join(l_t Lhs, l_t Rhs) { - if (Lhs == Rhs) { - return Lhs; - } - if (Lhs == l_t::TOP) { - return Rhs; - } - if (Rhs == l_t::TOP) { - return Lhs; - } - return l_t::BOT; -} - -EdgeFunction -IDESecureHeapPropagation::allTopFunction() { - return AllTop{}; -} - void IDESecureHeapPropagation::emitTextReport( const SolverResults &SR, llvm::raw_ostream &Os) { LLVMBasedCFG CFG; diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp index a5b37ec6f..1324d61a5 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.cpp @@ -42,26 +42,26 @@ IDESolverTest::IDESolverTest(const LLVMProjectIRDB *IRDB, IDESolverTest::FlowFunctionPtrType IDESolverTest::getNormalFlowFunction(IDESolverTest::n_t /*Curr*/, IDESolverTest::n_t /*Succ*/) { - return Identity::getInstance(); + return identityFlow(); } IDESolverTest::FlowFunctionPtrType IDESolverTest::getCallFlowFunction(IDESolverTest::n_t /*CallSite*/, IDESolverTest::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IDESolverTest::FlowFunctionPtrType IDESolverTest::getRetFlowFunction( IDESolverTest::n_t /*CallSite*/, IDESolverTest::f_t /*CalleeFun*/, IDESolverTest::n_t /*ExitStmt*/, IDESolverTest::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IDESolverTest::FlowFunctionPtrType IDESolverTest::getCallToRetFlowFunction(IDESolverTest::n_t /*CallSite*/, IDESolverTest::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IDESolverTest::FlowFunctionPtrType @@ -82,7 +82,7 @@ IDESolverTest::d_t IDESolverTest::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IDESolverTest::isZeroValue(IDESolverTest::d_t Fact) const { +bool IDESolverTest::isZeroValue(IDESolverTest::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp index b646ea57f..3f20b5d97 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.cpp @@ -55,13 +55,12 @@ auto IDETypeStateAnalysisBase::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) } if (const auto *Gep = llvm::dyn_cast(Curr)) { if (hasMatchingType(Gep->getPointerOperand())) { - return identityFlow(); - // return lambdaFlow([=](d_t Source) -> std::set { - // // if (Source == Gep->getPointerOperand()) { - // // return {Source, Gep}; - // //} - // return {Source}; - // }); + return lambdaFlow([=](d_t Source) -> std::set { + // if (Source == Gep->getPointerOperand()) { + // return {Source, Gep}; + //} + return {Source}; + }); } } // Check store instructions for target type. Perform a strong update, i.e. @@ -76,7 +75,7 @@ auto IDETypeStateAnalysisBase::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) Curr->getFunction()->getName().str()); RelevantAliasesAndAllocas.insert(Store->getValueOperand()); - return lambdaFlow( + return lambdaFlow( [Store, AliasesAndAllocas = std::move(RelevantAliasesAndAllocas)]( d_t Source) -> container_type { // We kill all relevant loacal aliases and alloca's @@ -93,7 +92,7 @@ auto IDETypeStateAnalysisBase::getNormalFlowFunction(n_t Curr, n_t /*Succ*/) }); } } - return identityFlow(); + return identityFlow(); } auto IDETypeStateAnalysisBase::getCallFlowFunction(n_t CallSite, f_t DestFun) @@ -101,7 +100,7 @@ auto IDETypeStateAnalysisBase::getCallFlowFunction(n_t CallSite, f_t DestFun) // Kill all data-flow facts if we hit a function of the target API. // Those functions are modled within Call-To-Return. if (isAPIFunction(llvm::demangle(DestFun->getName().str()))) { - return killAllFlows(); + return killAllFlows(); } // Otherwise, if we have an ordinary function call, we can just use the // standard mapping. @@ -116,10 +115,9 @@ auto IDETypeStateAnalysisBase::getRetFlowFunction(n_t CallSite, f_t CalleeFun, -> FlowFunctionPtrType { /// TODO: Implement return-POI in LLVMFlowFunctions.h - return lambdaFlow([this, CalleeFun, - CS = llvm::cast(CallSite), - Ret = llvm::dyn_cast(ExitStmt)]( - d_t Source) -> container_type { + return lambdaFlow([this, CalleeFun, CS = llvm::cast(CallSite), + Ret = llvm::dyn_cast(ExitStmt)]( + d_t Source) -> container_type { if (LLVMZeroValue::isLLVMZeroValue(Source)) { return {Source}; } @@ -206,12 +204,12 @@ auto IDETypeStateAnalysisBase::getCallToRetFlowFunction( if (!isAPIFunction(DemangledFname) && !Callee->isDeclaration()) { for (const auto &Arg : CS->args()) { if (hasMatchingType(Arg)) { - return killManyFlows(getWMAliasesAndAllocas(Arg.get())); + return killManyFlows(getWMAliasesAndAllocas(Arg.get())); } } } } - return identityFlow(); + return identityFlow(); } auto IDETypeStateAnalysisBase::getSummaryFlowFunction(n_t /*CallSite*/, diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp index c98996653..69cd1f1a2 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.cpp @@ -52,7 +52,7 @@ IFDSConstAnalysis::getNormalFlowFunction(IFDSConstAnalysis::n_t Curr, // If the store instruction sets up or updates the vtable, i.e. value // operand is vtable pointer, ignore it! if (isTouchVTableInst(Store)) { - return Identity::getInstance(); + return identityFlow(); } IFDSConstAnalysis::d_t PointerOp = Store->getPointerOperand(); @@ -86,7 +86,7 @@ IFDSConstAnalysis::getNormalFlowFunction(IFDSConstAnalysis::n_t Curr, } /* end store instruction */ // Pass everything else as identity - return Identity::getInstance(); + return identityFlow(); } IFDSConstAnalysis::FlowFunctionPtrType @@ -96,7 +96,7 @@ IFDSConstAnalysis::getCallFlowFunction(IFDSConstAnalysis::n_t CallSite, // memset) if (llvm::isa(CallSite)) { PHASAR_LOG_LEVEL(DEBUG, "Call statement is a LLVM MemIntrinsic!"); - return killAllFlows(); + return killAllFlows(); } // Check if its a Call Instruction or an Invoke Instruction. If so, we // need to map all actual parameters into formal parameters. @@ -110,7 +110,7 @@ IFDSConstAnalysis::getCallFlowFunction(IFDSConstAnalysis::n_t CallSite, } /* end call/invoke instruction */ // Pass everything else as identity - return Identity::getInstance(); + return identityFlow(); } IFDSConstAnalysis::FlowFunctionPtrType IFDSConstAnalysis::getRetFlowFunction( @@ -151,7 +151,7 @@ IFDSConstAnalysis::getCallToRetFlowFunction(IFDSConstAnalysis::n_t CallSite, } // Pass everything else as identity - return Identity::getInstance(); + return identityFlow(); } IFDSConstAnalysis::FlowFunctionPtrType @@ -173,7 +173,8 @@ IFDSConstAnalysis::d_t IFDSConstAnalysis::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IFDSConstAnalysis::isZeroValue(IFDSConstAnalysis::d_t Fact) const { +bool IFDSConstAnalysis::isZeroValue( + IFDSConstAnalysis::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp index c28cb8b0e..d35ef58f9 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.cpp @@ -34,32 +34,32 @@ IFDSProtoAnalysis::getNormalFlowFunction(IFDSProtoAnalysis::n_t Curr, if (const auto *Store = llvm::dyn_cast(Curr)) { return generateFromZero(Store->getPointerOperand()); } - return Identity::getInstance(); + return identityFlow(); } IFDSProtoAnalysis::FlowFunctionPtrType IFDSProtoAnalysis::getCallFlowFunction(IFDSProtoAnalysis::n_t /*CallSite*/, IFDSProtoAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSProtoAnalysis::FlowFunctionPtrType IFDSProtoAnalysis::getRetFlowFunction( IFDSProtoAnalysis::n_t /*CallSite*/, IFDSProtoAnalysis::f_t /*CalleeFun*/, IFDSProtoAnalysis::n_t /*ExitInst*/, IFDSProtoAnalysis::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSProtoAnalysis::FlowFunctionPtrType IFDSProtoAnalysis::getCallToRetFlowFunction(IFDSProtoAnalysis::n_t /*CallSite*/, IFDSProtoAnalysis::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSProtoAnalysis::FlowFunctionPtrType IFDSProtoAnalysis::getSummaryFlowFunction(IFDSProtoAnalysis::n_t /*CallSite*/, IFDSProtoAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } InitialSeeds::getInstance(); + return identityFlow(); } IFDSSignAnalysis::FlowFunctionPtrType IFDSSignAnalysis::getCallFlowFunction(IFDSSignAnalysis::n_t /*CallSite*/, IFDSSignAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSignAnalysis::FlowFunctionPtrType IFDSSignAnalysis::getRetFlowFunction( IFDSSignAnalysis::n_t /*CallSite*/, IFDSSignAnalysis::f_t /*CalleeFun*/, IFDSSignAnalysis::n_t /*ExitStmt*/, IFDSSignAnalysis::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSignAnalysis::FlowFunctionPtrType IFDSSignAnalysis::getCallToRetFlowFunction(IFDSSignAnalysis::n_t /*CallSite*/, IFDSSignAnalysis::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSignAnalysis::FlowFunctionPtrType IFDSSignAnalysis::getSummaryFlowFunction(IFDSSignAnalysis::n_t /*CallSite*/, IFDSSignAnalysis::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } InitialSeeds::getInstance(); + return identityFlow(); } IFDSSolverTest::FlowFunctionPtrType IFDSSolverTest::getCallFlowFunction(IFDSSolverTest::n_t /*CallSite*/, IFDSSolverTest::f_t /*DestFun*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSolverTest::FlowFunctionPtrType IFDSSolverTest::getRetFlowFunction( IFDSSolverTest::n_t /*CallSite*/, IFDSSolverTest::f_t /*CalleeFun*/, IFDSSolverTest::n_t /*ExitStmt*/, IFDSSolverTest::n_t /*RetSite*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSolverTest::FlowFunctionPtrType IFDSSolverTest::getCallToRetFlowFunction(IFDSSolverTest::n_t /*CallSite*/, IFDSSolverTest::n_t /*RetSite*/, llvm::ArrayRef /*Callees*/) { - return Identity::getInstance(); + return identityFlow(); } IFDSSolverTest::FlowFunctionPtrType @@ -69,7 +69,7 @@ IFDSSolverTest::d_t IFDSSolverTest::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IFDSSolverTest::isZeroValue(IFDSSolverTest::d_t Fact) const { +bool IFDSSolverTest::isZeroValue(IFDSSolverTest::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp index 4306af47c..890c357ad 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp @@ -158,7 +158,7 @@ auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr, populateWithMayAliases(Gen, Store); Gen.insert(Store->getValueOperand()); - return lambdaFlow( + return lambdaFlow( [Store, Gen{std::move(Gen)}](d_t Source) -> container_type { if (Store->getValueOperand() == Source) { return Gen; @@ -185,7 +185,7 @@ auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr, } if (const auto *Insert = llvm::dyn_cast(Curr)) { - return lambdaFlow([Insert](d_t Source) -> container_type { + return lambdaFlow([Insert](d_t Source) -> container_type { if (Source == Insert->getAggregateOperand() || Source == Insert->getInsertedValueOperand()) { return {Source, Insert}; @@ -200,11 +200,11 @@ auto IFDSTaintAnalysis::getNormalFlowFunction(n_t Curr, } if (const auto *Cast = llvm::dyn_cast(Curr)) { - return transferFlow(Cast, Cast->getOperand(0)); + return transferFlow(Cast, Cast->getOperand(0)); } // Otherwise we do not care and leave everything as it is - return Identity::getInstance(); + return identityFlow(); } auto IFDSTaintAnalysis::getCallFlowFunction(n_t CallSite, f_t DestFun) @@ -215,7 +215,7 @@ auto IFDSTaintAnalysis::getCallFlowFunction(n_t CallSite, f_t DestFun) // The respective taints or leaks are then generated in the corresponding // call to return flow function. if (isSourceCall(CS, DestFun) || isSinkCall(CS, DestFun)) { - return killAllFlows(); + return killAllFlows(); } // Map the actual into the formal parameters @@ -262,7 +262,7 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, if (DestFun->getName().equals("$sSS1poiyS2S_SStFZ")) { const auto *CS = llvm::cast(CallSite); - return generateFlowIf(CallSite, [CS](d_t Source) { + return generateFlowIf(CallSite, [CS](d_t Source) { return ((Source == CS->getArgOperand(1)) || (Source == CS->getArgOperand(3))); }); @@ -295,8 +295,8 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, if (Gen.empty()) { if (!Leak.empty() || !Kill.empty()) { - return lambdaFlow([Leak{std::move(Leak)}, Kill{std::move(Kill)}, - this, CallSite](d_t Source) -> container_type { + return lambdaFlow([Leak{std::move(Leak)}, Kill{std::move(Kill)}, this, + CallSite](d_t Source) -> container_type { if (Leak.count(Source)) { Leaks[CallSite].insert(Source); } @@ -316,8 +316,8 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite, // Gen nonempty Gen.insert(LLVMZeroValue::getInstance()); - return lambdaFlow([Gen{std::move(Gen)}, Leak{std::move(Leak)}, this, - CallSite](d_t Source) -> container_type { + return lambdaFlow([Gen{std::move(Gen)}, Leak{std::move(Leak)}, this, + CallSite](d_t Source) -> container_type { if (LLVMZeroValue::isLLVMZeroValue(Source)) { return Gen; } @@ -355,7 +355,7 @@ auto IFDSTaintAnalysis::createZeroValue() const -> d_t { return LLVMZeroValue::getInstance(); } -bool IFDSTaintAnalysis::isZeroValue(d_t FlowFact) const { +bool IFDSTaintAnalysis::isZeroValue(d_t FlowFact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(FlowFact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp index e798db4f2..f7521ff33 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.cpp @@ -94,7 +94,7 @@ IFDSTypeAnalysis::d_t IFDSTypeAnalysis::createZeroValue() const { return LLVMZeroValue::getInstance(); } -bool IFDSTypeAnalysis::isZeroValue(IFDSTypeAnalysis::d_t Fact) const { +bool IFDSTypeAnalysis::isZeroValue(IFDSTypeAnalysis::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); } diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp index b75979ed6..7dea9e963 100644 --- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp +++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.cpp @@ -168,26 +168,24 @@ IFDSUninitializedVariables::getNormalFlowFunction( } if (const auto *Alloc = llvm::dyn_cast(Curr)) { - return lambdaFlow( - [Alloc, this](IFDSUninitializedVariables::d_t Source) - -> std::set { - if (isZeroValue(Source)) { - if (Alloc->getAllocatedType()->isIntegerTy() || - Alloc->getAllocatedType()->isFloatingPointTy() || - Alloc->getAllocatedType()->isPointerTy() || - Alloc->getAllocatedType()->isArrayTy()) { - //------------------------------------------------------------ - // Why not generate for structs, but for arrays? (would be - // consistent to generate either both or none of them) - //------------------------------------------------------------ - - // generate the alloca - return {Source, Alloc}; - } - } - // otherwise propagate all facts - return {Source}; - }); + return lambdaFlow([Alloc, this](d_t Source) -> std::set { + if (isZeroValue(Source)) { + if (Alloc->getAllocatedType()->isIntegerTy() || + Alloc->getAllocatedType()->isFloatingPointTy() || + Alloc->getAllocatedType()->isPointerTy() || + Alloc->getAllocatedType()->isArrayTy()) { + //------------------------------------------------------------ + // Why not generate for structs, but for arrays? (would be + // consistent to generate either both or none of them) + //------------------------------------------------------------ + + // generate the alloca + return {Source, Alloc}; + } + } + // otherwise propagate all facts + return {Source}; + }); } // check if some instruction is using an undefined value (in)directly struct UVFF : FlowFunction { @@ -304,7 +302,7 @@ IFDSUninitializedVariables::getCallFlowFunction( }; return std::make_shared(DestFun, CS, getZeroValue()); } - return Identity::getInstance(); + return identityFlow(); } IFDSUninitializedVariables::FlowFunctionPtrType @@ -349,7 +347,7 @@ IFDSUninitializedVariables::getRetFlowFunction( return std::make_shared(CS, ExitStmt); } // kill everything else - return killAllFlows(); + return killAllFlows(); } IFDSUninitializedVariables::FlowFunctionPtrType @@ -361,23 +359,21 @@ IFDSUninitializedVariables::getCallToRetFlowFunction( // Handle pointer/reference parameters //---------------------------------------------------------------------- if (const auto *CS = llvm::dyn_cast(CallSite)) { - return lambdaFlow( - [CS](IFDSUninitializedVariables::d_t Source) - -> std::set { - if (Source->getType()->isPointerTy()) { - for (const auto &Arg : CS->args()) { - if (Arg.get() == Source) { - // do not propagate pointer arguments, since the function may - // initialize them (would be much more precise with - // field-sensitivity) - return {}; - } - } + return lambdaFlow([CS](d_t Source) -> std::set { + if (Source->getType()->isPointerTy()) { + for (const auto &Arg : CS->args()) { + if (Arg.get() == Source) { + // do not propagate pointer arguments, since the function may + // initialize them (would be much more precise with + // field-sensitivity) + return {}; } - return {Source}; - }); + } + } + return {Source}; + }); } - return Identity::getInstance(); + return identityFlow(); } IFDSUninitializedVariables::FlowFunctionPtrType @@ -402,7 +398,7 @@ IFDSUninitializedVariables::createZeroValue() const { } bool IFDSUninitializedVariables::isZeroValue( - IFDSUninitializedVariables::d_t Fact) const { + IFDSUninitializedVariables::d_t Fact) const noexcept { return LLVMZeroValue::isLLVMZeroValue(Fact); }