diff --git a/include/phasar/PhasarLLVM/IfdsIde/EdgeFunction.h b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunction.h index 1967d8064..190a5ce15 100644 --- a/include/phasar/PhasarLLVM/IfdsIde/EdgeFunction.h +++ b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunction.h @@ -17,8 +17,9 @@ #ifndef PHASAR_PHASARLLVM_IFDSIDE_EDGEFUNCTION_H_ #define PHASAR_PHASARLLVM_IFDSIDE_EDGEFUNCTION_H_ -#include // std::cout in dump, better replace it with a ostream #include +#include +#include #include namespace psr { @@ -38,7 +39,7 @@ template class EdgeFunction { virtual bool equal_to(std::shared_ptr> other) const = 0; virtual void print(std::ostream &OS, bool isForDebug = false) const { - OS << "edge_function"; + OS << "EdgeFunction"; } std::string str() { diff --git a/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctionComposer.h b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctionComposer.h new file mode 100644 index 000000000..6848137b8 --- /dev/null +++ b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctionComposer.h @@ -0,0 +1,98 @@ +/****************************************************************************** + * Copyright (c) 2017 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Philipp Schubert and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_IFDSIDE_EDGEFUNCTIONCOMPOSER_H +#define PHASAR_PHASARLLVM_IFDSIDE_EDGEFUNCTIONCOMPOSER_H + +#include +#include +#include +#include +#include + +namespace psr { + +/** + * This abstract class models edge function composition. It holds two edge + * functions. The edge function computation order is implemented as + * F -> G -> otherFunction + * i.e. F is computed before G, G is computed before otherFunction. + * + * Note that an own implementation for the join function is required, since + * this varies between different analyses, and is not implemented by this + * class. + * It is also advised to provide a more precise compose function, which is able + * to reduce the result of the composition, rather than using the default + * implementation. By default, an explicit composition is used. Such a function + * definition can grow unduly large. + */ +template +class EdgeFunctionComposer + : public EdgeFunction, + public std::enable_shared_from_this> { +private: + // For debug purpose only + const unsigned EFComposer_Id; + static unsigned CurrEFComposer_Id; + +protected: + /// First edge function + std::shared_ptr> F; + /// Second edge function + std::shared_ptr> G; + +public: + EdgeFunctionComposer(std::shared_ptr> F, + std::shared_ptr> G) + : EFComposer_Id(++CurrEFComposer_Id), F(F), G(G) {} + + /** + * Target value computation is implemented as + * G(F(source)) + */ + virtual V computeTarget(V source) override { + return G->computeTarget(F->computeTarget(source)); + } + + /** + * Function composition is implemented as an explicit composition, i.e. + * (secondFunction * G) * F = EFC(F, EFC(G , otherFunction)) + * + * However, it is advised to immediately reduce the resulting edge function + * by providing an own implementation of this function. + */ + virtual std::shared_ptr> + composeWith(std::shared_ptr> secondFunction) override { + if (auto *EI = dynamic_cast *>(secondFunction.get())) { + return this->shared_from_this(); + } + return F->composeWith(G->composeWith(secondFunction)); + } + + // virtual std::shared_ptr> + // joinWith(std::shared_ptr> otherFunction) = 0; + + virtual bool equal_to(std::shared_ptr> other) const override { + if (auto EFC = dynamic_cast *>(other.get())) { + return F->equal_to(EFC->F) && G->equal_to(EFC->G); + } + return false; + } + + virtual void print(std::ostream &OS, bool isForDebug = false) const override { + OS << "EFComposer_" << EFComposer_Id << "[ " << F.get()->str() << " , " + << G.get()->str() << " ]"; + } +}; + +template unsigned EdgeFunctionComposer::CurrEFComposer_Id = 0; + +} // namespace psr + +#endif diff --git a/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/AllBottom.h b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/AllBottom.h index 03674fb2a..554f28e9f 100644 --- a/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/AllBottom.h +++ b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/AllBottom.h @@ -72,7 +72,7 @@ class AllBottom : public EdgeFunction, } virtual void print(std::ostream &OS, bool isForDebug = false) const override { - OS << "all_bottom"; + OS << "AllBottom"; } }; diff --git a/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/AllTop.h b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/AllTop.h index 0ba2cae1a..a91dc18bf 100644 --- a/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/AllTop.h +++ b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/AllTop.h @@ -54,7 +54,7 @@ class AllTop : public EdgeFunction, } virtual void print(std::ostream &OS, bool isForDebug = false) const override { - OS << "all_top"; + OS << "AllTop"; } }; diff --git a/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/EdgeIdentity.h b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/EdgeIdentity.h index ed8ce535f..28087006c 100644 --- a/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/EdgeIdentity.h +++ b/include/phasar/PhasarLLVM/IfdsIde/EdgeFunctions/EdgeIdentity.h @@ -73,7 +73,7 @@ class EdgeIdentity : public EdgeFunction, } virtual void print(std::ostream &OS, bool isForDebug = false) const override { - OS << "edge_identity"; + OS << "EdgeIdentity"; } }; diff --git a/include/phasar/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysis.h b/include/phasar/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysis.h index 9eefce047..070195013 100644 --- a/include/phasar/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysis.h +++ b/include/phasar/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysis.h @@ -16,6 +16,7 @@ #include #include +#include namespace llvm { class Instruction; @@ -34,6 +35,11 @@ class IDELinearConstantAnalysis private: std::vector EntryPoints; + // For debug purpose only + static unsigned CurrStoreConst_Id; + static unsigned CurrLoadStoreV_Id; + static unsigned CurrBinary_Id; + public: typedef const llvm::Value *d_t; typedef const llvm::Instruction *n_t; @@ -42,12 +48,6 @@ class IDELinearConstantAnalysis typedef int64_t v_t; typedef LLVMBasedICFG &i_t; - // For debug purpose only - static unsigned StoreConstCount; - static unsigned LoadStoreValueCount; - static unsigned BinaryCount; - static unsigned EdgeComposerCount; - static const v_t TOP; static const v_t BOTTOM; @@ -113,46 +113,26 @@ class IDELinearConstantAnalysis std::shared_ptr> allTopFunction() override; - /** - * secondFunction o G o F - * - * compose with: EFC(F, EFC(G,secondFunction)) - * compute target: G(F(source)) - * - * java solution: - * compose: G -> F -> secondFunction - * compute target: F(G(source)) - */ - class EdgeFunctionComposer - : public EdgeFunction, - public std::enable_shared_from_this { - private: - const unsigned EdgeFunctionID; - std::shared_ptr> F; - std::shared_ptr> G; + // Custom EdgeFunction declarations + class LCAEdgeFunctionComposer : public EdgeFunctionComposer { public: - EdgeFunctionComposer(std::shared_ptr> F, - std::shared_ptr> G); - - v_t computeTarget(v_t source) override; + LCAEdgeFunctionComposer(std::shared_ptr> F, + std::shared_ptr> G) + : EdgeFunctionComposer(F, G){}; std::shared_ptr> composeWith(std::shared_ptr> secondFunction) override; std::shared_ptr> joinWith(std::shared_ptr> otherFunction) override; - - bool equal_to(std::shared_ptr> other) const override; - - void print(std::ostream &OS, bool isForDebug = false) const override; }; class StoreConstant : public EdgeFunction, public std::enable_shared_from_this { private: - const unsigned EdgeFunctionID; - const IDELinearConstantAnalysis::v_t IntConst; + const unsigned StoreConst_Id; + const v_t IntConst; public: explicit StoreConstant(v_t IntConst); @@ -174,7 +154,7 @@ class IDELinearConstantAnalysis : public EdgeFunction, public std::enable_shared_from_this { private: - const unsigned EdgeFunctionID; + const unsigned LoadStoreV_Id; public: explicit LoadStoreValueIdentity(); @@ -192,6 +172,22 @@ class IDELinearConstantAnalysis void print(std::ostream &OS, bool isForDebug = false) const override; }; + // Helper functions + + /** + * The following binary operations are computed: + * - addition + * - subtraction + * - multiplication + * - division (signed/unsinged) + * - remainder (signed/unsinged) + * + * @brief Computes the result of a binary operation. + * @param op operator + * @param lop left operand + * @param rop right operand + * @return Result of binary operation + */ static v_t executeBinOperation(const unsigned op, v_t lop, v_t rop); std::string DtoString(d_t d) const override; diff --git a/lib/Controller/AnalysisController.cpp b/lib/Controller/AnalysisController.cpp index f2f1afc0e..5a81bacad 100644 --- a/lib/Controller/AnalysisController.cpp +++ b/lib/Controller/AnalysisController.cpp @@ -275,10 +275,7 @@ AnalysisController::AnalysisController( for (auto exit : ICFG.getExitPointsOf(f)) { cout << "Exit : " << lcaproblem.NtoString(exit) << endl; for (auto res : llvmlcasolver.resultsAt(exit, true)) { - cout << "Value: " - << (res.second == lcaproblem.bottomElement() - ? "BOT" - : lcaproblem.VtoString(res.second)) + cout << "Value: " << lcaproblem.VtoString(res.second) << "\tat " << lcaproblem.DtoString(res.first) << endl; } } diff --git a/lib/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysis.cpp b/lib/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysis.cpp index 22349049d..34271a285 100644 --- a/lib/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysis.cpp +++ b/lib/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysis.cpp @@ -39,10 +39,9 @@ using namespace psr; namespace psr { // Initialize debug counter for edge functions -unsigned IDELinearConstantAnalysis::StoreConstCount = 0; -unsigned IDELinearConstantAnalysis::LoadStoreValueCount = 0; -unsigned IDELinearConstantAnalysis::BinaryCount = 0; -unsigned IDELinearConstantAnalysis::EdgeComposerCount = 0; +unsigned IDELinearConstantAnalysis::CurrStoreConst_Id = 0; +unsigned IDELinearConstantAnalysis::CurrLoadStoreV_Id = 0; +unsigned IDELinearConstantAnalysis::CurrBinary_Id = 0; const IDELinearConstantAnalysis::v_t IDELinearConstantAnalysis::TOP = numeric_limits::min(); @@ -57,10 +56,9 @@ IDELinearConstantAnalysis::IDELinearConstantAnalysis( } IDELinearConstantAnalysis::~IDELinearConstantAnalysis() { - IDELinearConstantAnalysis::StoreConstCount = 0; - IDELinearConstantAnalysis::LoadStoreValueCount = 0; - IDELinearConstantAnalysis::BinaryCount = 0; - IDELinearConstantAnalysis::EdgeComposerCount = 0; + IDELinearConstantAnalysis::CurrStoreConst_Id = 0; + IDELinearConstantAnalysis::CurrLoadStoreV_Id = 0; + IDELinearConstantAnalysis::CurrBinary_Id = 0; } // Start formulating our analysis by specifying the parts required for IFDS @@ -391,7 +389,7 @@ IDELinearConstantAnalysis::getNormalEdgeFunction( LCAEF(const unsigned Op, IDELinearConstantAnalysis::d_t lop, IDELinearConstantAnalysis::d_t rop, IDELinearConstantAnalysis::d_t currNode) - : EdgeFunctionID(++IDELinearConstantAnalysis::BinaryCount), Op(Op), + : EdgeFunctionID(++IDELinearConstantAnalysis::CurrBinary_Id), Op(Op), lop(lop), rop(rop), currNode(currNode) {} IDELinearConstantAnalysis::v_t @@ -436,7 +434,7 @@ IDELinearConstantAnalysis::getNormalEdgeFunction( dynamic_cast(secondFunction.get())) { return this->shared_from_this(); } - return make_shared( + return make_shared( this->shared_from_this(), secondFunction); } @@ -537,20 +535,8 @@ IDELinearConstantAnalysis::allTopFunction() { return make_shared>(TOP); } -IDELinearConstantAnalysis::EdgeFunctionComposer::EdgeFunctionComposer( - shared_ptr> F, - shared_ptr> G) - : EdgeFunctionID(++IDELinearConstantAnalysis::EdgeComposerCount), F(F), - G(G) {} - -IDELinearConstantAnalysis::v_t -IDELinearConstantAnalysis::EdgeFunctionComposer::computeTarget( - IDELinearConstantAnalysis::v_t source) { - return G->computeTarget(F->computeTarget(source)); -} - shared_ptr> -IDELinearConstantAnalysis::EdgeFunctionComposer::composeWith( +IDELinearConstantAnalysis::LCAEdgeFunctionComposer::composeWith( shared_ptr> secondFunction) { if (auto *EI = dynamic_cast *>( secondFunction.get())) { @@ -564,7 +550,7 @@ IDELinearConstantAnalysis::EdgeFunctionComposer::composeWith( } shared_ptr> -IDELinearConstantAnalysis::EdgeFunctionComposer::joinWith( +IDELinearConstantAnalysis::LCAEdgeFunctionComposer::joinWith( shared_ptr> otherFunction) { if (otherFunction.get() == this || otherFunction->equal_to(this->shared_from_this())) { @@ -578,23 +564,9 @@ IDELinearConstantAnalysis::EdgeFunctionComposer::joinWith( IDELinearConstantAnalysis::BOTTOM); } -bool IDELinearConstantAnalysis::EdgeFunctionComposer::equal_to( - shared_ptr> other) const { - if (auto EC = dynamic_cast(other.get())) { - return F->equal_to(EC->F) && G->equal_to(EC->G); - } - return false; -} - -void IDELinearConstantAnalysis::EdgeFunctionComposer::print( - ostream &OS, bool isForDebug) const { - OS << "EC_" << IDELinearConstantAnalysis::EdgeFunctionComposer::EdgeFunctionID - << "[ " << F.get()->str() << " , " << G.get()->str() << " ]"; -} - IDELinearConstantAnalysis::StoreConstant::StoreConstant( IDELinearConstantAnalysis::v_t IntConst) - : EdgeFunctionID(++IDELinearConstantAnalysis::StoreConstCount), + : StoreConst_Id(++IDELinearConstantAnalysis::CurrStoreConst_Id), IntConst(IntConst) {} IDELinearConstantAnalysis::v_t @@ -614,7 +586,7 @@ IDELinearConstantAnalysis::StoreConstant::composeWith( dynamic_cast(secondFunction.get())) { return this->shared_from_this(); } - return make_shared( + return make_shared( this->shared_from_this(), secondFunction); } @@ -640,11 +612,11 @@ bool IDELinearConstantAnalysis::StoreConstant::equal_to( void IDELinearConstantAnalysis::StoreConstant::print(ostream &OS, bool isForDebug) const { - OS << "StoreConst_" << EdgeFunctionID; + OS << "StoreConst_" << StoreConst_Id; } IDELinearConstantAnalysis::LoadStoreValueIdentity::LoadStoreValueIdentity() - : EdgeFunctionID(++IDELinearConstantAnalysis::LoadStoreValueCount) {} + : LoadStoreV_Id(++IDELinearConstantAnalysis::CurrLoadStoreV_Id) {} IDELinearConstantAnalysis::v_t IDELinearConstantAnalysis::LoadStoreValueIdentity::computeTarget( @@ -680,10 +652,9 @@ bool IDELinearConstantAnalysis::LoadStoreValueIdentity::equal_to( void IDELinearConstantAnalysis::LoadStoreValueIdentity::print( ostream &OS, bool isForDebug) const { - OS << "Load/StoreValue_" << EdgeFunctionID; + OS << "LoadStoreV_" << LoadStoreV_Id; } -// add, sub, mul, udiv/sdiv, urem/srem IDELinearConstantAnalysis::v_t IDELinearConstantAnalysis::executeBinOperation( const unsigned op, IDELinearConstantAnalysis::v_t lop, IDELinearConstantAnalysis::v_t rop) { @@ -725,6 +696,9 @@ IDELinearConstantAnalysis::DtoString(IDELinearConstantAnalysis::d_t d) const { string IDELinearConstantAnalysis::VtoString(IDELinearConstantAnalysis::v_t v) const { + if (v == BOTTOM) { + return "Bottom"; + } return to_string(v); } diff --git a/unittests/PhasarLLVM/IfdsIde/CMakeLists.txt b/unittests/PhasarLLVM/IfdsIde/CMakeLists.txt index 37954f72e..268d54bc8 100644 --- a/unittests/PhasarLLVM/IfdsIde/CMakeLists.txt +++ b/unittests/PhasarLLVM/IfdsIde/CMakeLists.txt @@ -1 +1,9 @@ add_subdirectory(Problems) + +set(IfdsIdeSources + EdgeFunctionComposerTest.cpp +) + +foreach(TEST_SRC ${IfdsIdeSources}) + add_phasar_unittest(${TEST_SRC}) +endforeach(TEST_SRC) diff --git a/unittests/PhasarLLVM/IfdsIde/EdgeFunctionComposerTest.cpp b/unittests/PhasarLLVM/IfdsIde/EdgeFunctionComposerTest.cpp new file mode 100644 index 000000000..8087d1e4a --- /dev/null +++ b/unittests/PhasarLLVM/IfdsIde/EdgeFunctionComposerTest.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include + +using namespace psr; + +static unsigned CurrMulTwoEF_Id = 0; +static unsigned CurrAddTwoEF_Id = 0; + +struct MyEFC : EdgeFunctionComposer { + MyEFC(std::shared_ptr> F, + std::shared_ptr> G) + : EdgeFunctionComposer(F, G){}; + std::shared_ptr> + joinWith(std::shared_ptr> otherFunction) override { + return std::make_shared>(-1); + }; +}; + +struct MulTwoEF : EdgeFunction, std::enable_shared_from_this { +private: + const unsigned MulTwoEF_Id; + +public: + MulTwoEF(unsigned id) : MulTwoEF_Id(id){}; + int computeTarget(int source) override { return source * 2; }; + std::shared_ptr> + composeWith(std::shared_ptr> secondFunction) override { + return std::make_shared(this->shared_from_this(), secondFunction); + } + std::shared_ptr> + joinWith(std::shared_ptr> otherFunction) override { + return std::make_shared>(-1); + }; + bool equal_to(std::shared_ptr> other) const override { + return this == other.get(); + } + void print(std::ostream &os, bool isForDebug = false) const override { + os << "MulTwoEF_" << MulTwoEF_Id; + } +}; + +struct AddTwoEF : EdgeFunction, std::enable_shared_from_this { +private: + const unsigned AddTwoEF_Id; + +public: + AddTwoEF(unsigned id) : AddTwoEF_Id(id){}; + int computeTarget(int source) override { return source + 2; }; + std::shared_ptr> + composeWith(std::shared_ptr> secondFunction) override { + return std::make_shared(this->shared_from_this(), secondFunction); + } + std::shared_ptr> + joinWith(std::shared_ptr> otherFunction) override { + return std::make_shared>(-1); + }; + bool equal_to(std::shared_ptr> other) const override { + return this == other.get(); + } + void print(std::ostream &os, bool isForDebug = false) const override { + os << "AddTwoEF_" << AddTwoEF_Id; + } +}; + +TEST(EdgeFunctionComposerTest, HandleEFIDs) { + auto EF1 = std::make_shared(++CurrAddTwoEF_Id); + auto EF2 = std::make_shared(++CurrAddTwoEF_Id); + std::cout << "My EF : " << EF1->str() << " " << EF2->str() << '\n'; + EXPECT_EQ("AddTwoEF_1", EF1->str()); + EXPECT_EQ("AddTwoEF_2", EF2->str()); + auto EFC1 = std::make_shared(EF1, EF2); + auto EFC2 = std::make_shared(EF2, EdgeIdentity::getInstance()); + std::cout << "My EFC: " << EFC1->str() << " " << EFC2->str() << '\n'; + EXPECT_EQ("EFComposer_1[ AddTwoEF_1 , AddTwoEF_2 ]", EFC1->str()); + EXPECT_EQ("EFComposer_2[ AddTwoEF_2 , EdgeIdentity ]", EFC2->str()); + // Reset ID's for next test + CurrAddTwoEF_Id = 0; +} + +TEST(EdgeFunctionComposerTest, HandleEFComposition) { + // ((3 + 2) * 2) + 2 + int initialValue = 3; + auto AddEF1 = std::make_shared(++CurrAddTwoEF_Id); + auto AddEF2 = std::make_shared(++CurrAddTwoEF_Id); + auto MulEF = std::make_shared(++CurrMulTwoEF_Id); + auto ComposedEF = (AddEF1->composeWith(MulEF))->composeWith(AddEF2); + std::cout << "Compose: " << ComposedEF->str() << '\n'; + int result = ComposedEF->computeTarget(initialValue); + std::cout << "Result: " << result << '\n'; + EXPECT_EQ(12, result); + EXPECT_FALSE(AddEF1->equal_to(AddEF2)); +} + +// main function for the test case +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/unittests/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysisTest.cpp b/unittests/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysisTest.cpp index f511b683e..6145b6034 100644 --- a/unittests/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysisTest.cpp +++ b/unittests/PhasarLLVM/IfdsIde/Problems/IDELinearConstantAnalysisTest.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -63,7 +62,7 @@ class IDELinearConstantAnalysisTest : public ::testing::Test { } } } - EXPECT_THAT(results, ::testing::ContainerEq(groundTruth)); + EXPECT_EQ(results, groundTruth); } }; // Test Fixture diff --git a/unittests/PhasarLLVM/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp b/unittests/PhasarLLVM/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp index 1606bc1a3..21bb62985 100644 --- a/unittests/PhasarLLVM/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp +++ b/unittests/PhasarLLVM/IfdsIde/Problems/IFDSTaintAnalysisTest.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -63,7 +62,7 @@ class IFDSTaintAnalysisTest : public ::testing::Test { } FoundLeaks.insert(make_pair(SinkId, LeakedValueIds)); } - EXPECT_THAT(FoundLeaks, ::testing::ContainerEq(GroundTruth)); + EXPECT_EQ(FoundLeaks, GroundTruth); } }; // Test Fixture