diff --git a/.clang-tidy b/.clang-tidy index ad126f001..6b2721354 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -15,6 +15,7 @@ Checks: '-*, -readability-function-cognitive-complexity, -readability-convert-member-functions-to-static, -readability-isolate-declaration, + -readability-identifier-length, cppcoreguidelines-*, -cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, @@ -28,7 +29,6 @@ Checks: '-*, -bugprone-easily-swappable-parameters, modernize-*, -modernize-use-trailing-return-type, - -modernize-pass-by-value, performance-*, clang-analyzer-*, ' diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..5a7c35be2 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,26 @@ +# Patterns listed later take precedence over earlier patterns. +# All owners are automatically set as reviewers for PRs affecting their files. +# At least one owner must approve a PR affecting their files. + +* @MMory @fabianbs96 + +/include/phasar/PhasarLLVM/DataflowSolver/IfdsIde/Solver/IDESolver.h @pdschubert + +/include/phasar/PhasarLLVM/DataflowSolver/IfdsIde/FlowEdgeFunctionCache.h @vulder + +/include/phasar/PhasarLLVM/DataflowSolver/Mono @pdschubert + +/img @pdschubert + +/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h @pdschubert @vulder +/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/ @fabianbs96 +/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @fabianbs96 +/lib/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp @fabianbs96 +/lib/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/ @fabianbs96 + +/include/phasar/PhasarLLVM/AnalysisStrategy/ @pdschubert + +Dockerfile @janniclas +/.docker/ @janniclas + +/include/phasar/Utils/Logger.h @MMory diff --git a/CMakeLists.txt b/CMakeLists.txt index 39a7056e0..eaf494d15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,8 +125,8 @@ endif() find_package(Threads) # Boost -find_package(Boost 1.65.1 COMPONENTS graph program_options ${BOOST_THREAD} REQUIRED) -#find_package(Boost 1.72.0 COMPONENTS graph program_options ${BOOST_THREAD} REQUIRED) +find_package(Boost 1.65.1 COMPONENTS graph ${BOOST_THREAD} REQUIRED) +#find_package(Boost 1.72.0 COMPONENTS graph ${BOOST_THREAD} REQUIRED) include_directories(${Boost_INCLUDE_DIRS}) # Disable clang-tidy for the external projects diff --git a/CREDITS.txt b/CREDITS.txt index 1e296d87a..21300e565 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -2,22 +2,36 @@ This file is a partial list of people who have contributed to Phasar The fields are: name (N), email (E), web-address (W), description (D) + +Active Contributors: + N: Philipp Schubert E: philipp.schubert@upb.de W: http://it-schubert.com -D: Initial implementation and chief developer new features +D: Initial implementation, high-level architecture, IDESolver, InstInteractionAnalysis N: Martin Mory E: martin.mory@upb.de -D: CMake +D: CMake, Logger, Organization -N: Nicolas Bellec -E: nicolas.bellec@ens-rennes.fr -D: Call-graph algorithms +N: Fabian Schiebel +E: fabian.schiebel@iem.fraunhofer.de, fabianbs@mail.upb.de +D: ExtendedTaintAnalysis, general development, Organization + +N: Jan-Niclas Strüwer +E: struewer@mail.upb.de +D: ESG visualization adaptor, Docker, Mac Support N: Florian Sattler E: sattlerf@fim.uni-passau.de -D: CMake and CMake build as llvm drop-in +D: CMake and CMake build as llvm drop-in, CI/CD Pipeline, Performance, InstInteractionAnalysis + + +Former Contributors: + +N: Nicolas Bellec +E: nicolas.bellec@ens-rennes.fr +D: Call-graph algorithms N: Christian Stritzke E: christian.stritzke@iem.fraunhofer.de @@ -26,7 +40,3 @@ D: HexaStore implementation N: Richard Leer E: rleer@mail.upb.de D: Serialization, various fixes and data-flow analyses - -N: Jan-Niclas Strüwer -E: struewer@mail.upb.de -D: ESG visualization adaptor diff --git a/Config.cmake.in b/Config.cmake.in index 4be4b0a01..315a673ec 100644 --- a/Config.cmake.in +++ b/Config.cmake.in @@ -3,24 +3,47 @@ set(PHASAR_VERSION 1.0.0) @PACKAGE_INIT@ set_and_check(PHASAR_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") -foreach(component ${phasar_FIND_COMPONENTS}) - include("${CMAKE_CURRENT_LIST_DIR}/phasar_${component}-config.cmake") +include (CMakeFindDependencyMacro) +find_dependency(nlohmann_json) +find_dependency(nlohmann_json_schema_validator) +find_package(Boost 1.65.1 COMPONENTS program_options graph REQUIRED) + +# TODO: The order seems to be important. Fix this! + +set(PHASAR_COMPONENTS + utils + config + phasarllvm_utils + passes + db + pointer + typehierarchy + controlflow + taintconfig + ifdside +) + +foreach(component ${PHASAR_COMPONENTS}) include("${CMAKE_CURRENT_LIST_DIR}/phasar_${component}-targets.cmake") + list(APPEND PHASAR_NEEDED_LIBS phasar::phasar_${component}) endforeach() +list(REMOVE_DUPLICATES PHASAR_NEEDED_LIBS) + +find_package(LLVM 14 REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +link_directories(${LLVM_LIB_PATH} ${LLVM_LIBRARY_DIRS}) +find_library(LLVM_LIBRARY NAMES LLVM HINTS ${LLVM_LIBRARY_DIRS}) + function(phasar_config executable) - find_package(LLVM 14 REQUIRED CONFIG) - include_directories(${LLVM_INCLUDE_DIRS}) - link_directories(${LLVM_LIB_PATH} ${LLVM_LIBRARY_DIRS}) - find_library(LLVM_LIBRARY NAMES LLVM HINTS ${LLVM_LIBRARY_DIRS}) if(NOT ${LLVM_LIBRARY} STREQUAL "LLVM_LIBRARY-NOTFOUND") llvm_config(${executable} USE_SHARED ${PHASAR_LLVM_DEPS}) else() llvm_config(${executable} ${PHASAR_LLVM_DEPS}) endif() - list(REMOVE_DUPLICATES PHASAR_NEEDED_LIBS) + target_link_libraries(${executable} PUBLIC ${PHASAR_NEEDED_LIBS} - ) + ) endfunction() diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index d31b12811..67411042f 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -23,7 +23,6 @@ function(add_phasar_unittest test_name) phasar_utils phasar_mono phasar_db - phasar_experimental # phasar_clang phasar_passes phasar_pointer @@ -49,23 +48,28 @@ endfunction() function(generate_ll_file) set(options MEM2REG DEBUG O1 O2 O3) set(testfile FILE) - cmake_parse_arguments(GEN_LL "${options}" "${testfile}" "" ${ARGN} ) + cmake_parse_arguments(GEN_LL "${options}" "${testfile}" "" ${ARGN}) + # get file extension get_filename_component(test_code_file_ext ${GEN_LL_FILE} EXT) string(REPLACE "." "_" ll_file_suffix ${test_code_file_ext}) + # define .ll file name -# set(ll_file_suffix "_${test_code_file_ext}") + # set(ll_file_suffix "_${test_code_file_ext}") if(GEN_LL_MEM2REG) set(ll_file_suffix "${ll_file_suffix}_m2r") endif() + if(GEN_LL_DEBUG) set(ll_file_suffix "${ll_file_suffix}_dbg") endif() -# set(ll_file_suffix "${ll_file_suffix}.ll") + + # set(ll_file_suffix "${ll_file_suffix}.ll") string(REPLACE ${test_code_file_ext} "${ll_file_suffix}.ll" test_code_ll_file ${GEN_LL_FILE} ) + # get file path set(test_code_file_path "${CMAKE_CURRENT_SOURCE_DIR}/${GEN_LL_FILE}") @@ -79,31 +83,37 @@ function(generate_ll_file) set(GEN_CXX_FLAGS -std=c++17 -fno-discard-value-names -emit-llvm -S) set(GEN_C_FLAGS -fno-discard-value-names -emit-llvm -S) set(GEN_CMD_COMMENT "[LL]") + if(GEN_LL_MEM2REG) list(APPEND GEN_CXX_FLAGS -Xclang -disable-O0-optnone) list(APPEND GEN_C_FLAGS -Xclang -disable-O0-optnone) set(GEN_CMD_COMMENT "${GEN_CMD_COMMENT}[M2R]") endif() + if(GEN_LL_DEBUG) list(APPEND GEN_CXX_FLAGS -g) list(APPEND GEN_C_FLAGS -g) set(GEN_CMD_COMMENT "${GEN_CMD_COMMENT}[DBG]") endif() + if(GEN_LL_O1) list(APPEND GEN_CXX_FLAGS -O1) list(APPEND GEN_C_FLAGS -O1) set(GEN_CMD_COMMENT "${GEN_CMD_COMMENT}[O1]") endif() + if(GEN_LL_O2) list(APPEND GEN_CXX_FLAGS -O2) list(APPEND GEN_C_FLAGS -O2) set(GEN_CMD_COMMENT "${GEN_CMD_COMMENT}[O2]") endif() + if(GEN_LL_03) list(APPEND GEN_CXX_FLAGS -O3) list(APPEND GEN_C_FLAGS -O3) set(GEN_CMD_COMMENT "${GEN_CMD_COMMENT}[O3]") endif() + set(GEN_CMD_COMMENT "${GEN_CMD_COMMENT} ${GEN_LL_FILE}") # define .ll file generation command @@ -114,6 +124,7 @@ function(generate_ll_file) set(GEN_CMD ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}) list(APPEND GEN_CMD ${GEN_C_FLAGS}) endif() + if(GEN_LL_MEM2REG) add_custom_command( OUTPUT ${test_code_ll_file} @@ -125,13 +136,14 @@ function(generate_ll_file) ) else() add_custom_command( - OUTPUT ${test_code_ll_file} - COMMAND ${GEN_CMD} ${test_code_file_path} -o ${test_code_ll_file} - COMMENT ${GEN_CMD_COMMENT} - DEPENDS ${GEN_LL_FILE} - VERBATIM + OUTPUT ${test_code_ll_file} + COMMAND ${GEN_CMD} ${test_code_file_path} -o ${test_code_ll_file} + COMMENT ${GEN_CMD_COMMENT} + DEPENDS ${GEN_LL_FILE} + VERBATIM ) endif() + add_custom_target(${test_code_file_target} DEPENDS ${test_code_ll_file} ) @@ -141,41 +153,46 @@ endfunction() macro(add_phasar_executable name) set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib) - add_llvm_executable( ${name} ${ARGN} ) + add_llvm_executable(${name} ${ARGN}) set_target_properties(${name} PROPERTIES FOLDER "phasar_executables") - install (TARGETS ${name} + install(TARGETS ${name} RUNTIME DESTINATION bin ) endmacro(add_phasar_executable) macro(add_phasar_library name) set(srcs ${ARGN}) + if(MSVC_IDE OR XCODE) - file( GLOB_RECURSE headers *.h *.td *.def) + file(GLOB_RECURSE headers *.h *.td *.def) set(srcs ${srcs} ${headers}) - string( REGEX MATCHALL "/[^/]" split_path ${CMAKE_CURRENT_SOURCE_DIR}) - list( GET split_path -1 dir) - file( GLOB_RECURSE headers + string(REGEX MATCHALL "/[^/]" split_path ${CMAKE_CURRENT_SOURCE_DIR}) + list(GET split_path -1 dir) + file(GLOB_RECURSE headers ../../include/phasar${dir}/*.h) set(srcs ${srcs} ${headers}) endif(MSVC_IDE OR XCODE) - if (MODULE) + + if(MODULE) set(libkind MODULE) - elseif (SHARED_LIBRARY) + elseif(SHARED_LIBRARY) set(libkind SHARED) else() set(libkind) endif() - add_library( ${name} ${libkind} ${srcs} ) - add_library( phasar::${name} ALIAS ${name} ) - if( LLVM_COMMON_DEPENDS ) - add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} ) - endif( LLVM_COMMON_DEPENDS ) - if( LLVM_USED_LIBS ) + + add_library(${name} ${libkind} ${srcs}) + add_library(phasar::${name} ALIAS ${name}) + + if(LLVM_COMMON_DEPENDS) + add_dependencies(${name} ${LLVM_COMMON_DEPENDS}) + endif(LLVM_COMMON_DEPENDS) + + if(LLVM_USED_LIBS) foreach(lib ${LLVM_USED_LIBS}) - target_link_libraries( ${name} ${lib} ) + target_link_libraries(${name} ${lib}) endforeach(lib) - endif( LLVM_USED_LIBS ) + endif(LLVM_USED_LIBS) if(PHASAR_LINK_LIBS) foreach(lib ${PHASAR_LINK_LIBS}) @@ -187,65 +204,71 @@ macro(add_phasar_library name) endforeach(lib) endif(PHASAR_LINK_LIBS) - if( LLVM_LINK_COMPONENTS ) - if( USE_LLVM_FAT_LIB ) + if(LLVM_LINK_COMPONENTS) + if(USE_LLVM_FAT_LIB) llvm_config(${name} USE_SHARED ${LLVM_LINK_COMPONENTS}) else() llvm_config(${name} ${LLVM_LINK_COMPONENTS}) endif() - endif( LLVM_LINK_COMPONENTS ) + endif(LLVM_LINK_COMPONENTS) + if(MSVC) get_target_property(cflag ${name} COMPILE_FLAGS) + if(NOT cflag) set(cflag "") endif(NOT cflag) + set(cflag "${cflag} /Za") set_target_properties(${name} PROPERTIES COMPILE_FLAGS ${cflag}) endif(MSVC) - #cut off prefix phasar_ for convenient component names + + # cut off prefix phasar_ for convenient component names string(REGEX REPLACE phasar_ "" name component_name) + if(PHASAR_IN_TREE) install(TARGETS ${name} EXPORT LLVMExports LIBRARY DESTINATION lib ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}) else() - install(TARGETS ${name} - EXPORT phasarTargets - LIBRARY DESTINATION ${PHASAR_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${PHASAR_INSTALL_LIBDIR}) install(TARGETS ${name} EXPORT ${name}-targets COMPONENT ${component_name} - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/phasar - LIBRARY DESTINATION ${PHASAR_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${PHASAR_INSTALL_LIBDIR}) + + # NOTE: Library, archive and runtime destination are automatically set by + # GNUInstallDirs which is included in the top-level CMakeLists.txt + ) install(EXPORT ${name}-targets FILE ${name}-targets.cmake NAMESPACE phasar:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/phasar - COMPONENT ${component_name}) - install(FILES ${name}-config.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/phasar) + DESTINATION lib/cmake/phasar + COMPONENT ${component_name} + ) endif() + set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS ${name}) endmacro(add_phasar_library) macro(add_phasar_loadable_module name) set(srcs ${ARGN}) + # klduge: pass different values for MODULE with multiple targets in same dir # this allows building shared-lib and module in same dir # there must be a cleaner way to achieve this.... - if (MODULE) + if(MODULE) else() set(GLOBAL_NOT_MODULE TRUE) endif() + set(MODULE TRUE) add_phasar_library(${name} ${srcs}) - if (GLOBAL_NOT_MODULE) - unset (MODULE) + + if(GLOBAL_NOT_MODULE) + unset(MODULE) endif() - if (APPLE) + + if(APPLE) # Darwin-specific linker flags for loadable modules. set_target_properties(${name} PROPERTIES LINK_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress") @@ -255,10 +278,12 @@ endmacro(add_phasar_loadable_module) macro(subdirlist result curdir) file(GLOB children RELATIVE ${curdir} ${curdir}/*) set(dirlist "") + foreach(child ${children}) if(IS_DIRECTORY ${curdir}/${child}) list(APPEND dirlist ${child}) endif() endforeach() + set(${result} ${dirlist}) endmacro(subdirlist) diff --git a/config/DOTGraphConfig.json b/config/DOTGraphConfig.json index 1e0621b9f..4d2fd4c58 100644 --- a/config/DOTGraphConfig.json +++ b/config/DOTGraphConfig.json @@ -1,49 +1,48 @@ { - "CFNode": { - "style": "filled", - "shape": "record" - }, - "CFIntraEdge": { - }, - "CFInterEdge": { - "weight": "1" - }, - "FactNode": { - "style": "rounded" - }, - "FactIDEdge": { - "style": "dotted", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - }, - "FactCrossEdge": { + "CFNode": { + "style": "filled", + "shape": "record" + }, + "CFIntraEdge": {}, + "CFInterEdge": { + "weight": "1" + }, + "FactNode": { + "style": "rounded" + }, + "FactIDEdge": { "style": "dotted", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - }, - "FactInterEdge": { + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + }, + "FactCrossEdge": { + "style": "dotted", + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + }, + "FactInterEdge": { "weight": "0.1", - "style": "dashed", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - }, - "LambdaNode": { - "style": "rounded" - }, - "LambdaIDEdge": { - "style": "dotted", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - }, - "LambdaInterEdge": { + "style": "dashed", + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + }, + "LambdaNode": { + "style": "rounded" + }, + "LambdaIDEdge": { + "style": "dotted", + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + }, + "LambdaInterEdge": { "weight": "0.1", - "style": "dashed", - "arrowhead": "normal", - "fontsize": "11", - "arrowsize": "0.7" - } + "style": "dashed", + "arrowhead": "normal", + "fontsize": "11", + "arrowsize": "0.7" + } } diff --git a/config/phasar-source-sink-function.json b/config/phasar-source-sink-function.json index 573d667e3..711d8d571 100644 --- a/config/phasar-source-sink-function.json +++ b/config/phasar-source-sink-function.json @@ -1,20 +1,28 @@ { - "Source Functions": { - "source()": { - "Args": [], - "Return": true - }, - "read": { - "Args": [0, 1, 3], - "Return": false - } - }, - "Sink Functions": { - "sink(int)": { - "Args": [0] - }, - "write": { - "Args": [1] - } - } + "Source Functions": { + "source()": { + "Args": [], + "Return": true + }, + "read": { + "Args": [ + 0, + 1, + 3 + ], + "Return": false + } + }, + "Sink Functions": { + "sink(int)": { + "Args": [ + 0 + ] + }, + "write": { + "Args": [ + 1 + ] + } + } } diff --git a/examples/llvm-hello-world/main.cpp b/examples/llvm-hello-world/main.cpp index 9c7fb919f..fe8d6f776 100644 --- a/examples/llvm-hello-world/main.cpp +++ b/examples/llvm-hello-world/main.cpp @@ -1,8 +1,6 @@ #include #include -#include "llvm/IR/CallSite.h" -#include "llvm/IR/Constants.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" @@ -24,11 +22,11 @@ int main(int argc, char **argv) { } // parse an IR file into an LLVM module llvm::SMDiagnostic Diag; - std::unique_ptr C(new llvm::LLVMContext); - std::unique_ptr M = llvm::parseIRFile(argv[1], Diag, *C); + llvm::LLVMContext C; + std::unique_ptr M = llvm::parseIRFile(argv[1], Diag, C); // check if the module is alright bool broken_debug_info = false; - if (M.get() == nullptr || + if (M == nullptr || llvm::verifyModule(*M, &llvm::errs(), &broken_debug_info)) { llvm::errs() << "error: module not valid\n"; return 1; @@ -76,6 +74,5 @@ int main(int argc, char **argv) { // C++'s classical 'dynamic_cast'. } } - llvm::llvm_shutdown(); return 0; } diff --git a/examples/use-phasar-as-library/myphasartool.cpp b/examples/use-phasar-as-library/myphasartool.cpp deleted file mode 100644 index 9ecdc0d83..000000000 --- a/examples/use-phasar-as-library/myphasartool.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -#include -#include - -#include "phasar/DB/ProjectIRDB.h" -#include "phasar/PhasarLLVM/AnalysisStrategy/WholeProgramAnalysis.h" -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSLinearConstantAnalysis.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSSolver.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h" -#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" -#include "phasar/Utils/Logger.h" - -namespace llvm { -class Value; -} // namespace llvm - -using namespace psr; - -int main(int argc, const char **argv) { - if (argc < 2 || !std::filesystem::exists(argv[1]) || - std::filesystem::is_directory(argv[1])) { - llvm::errs() << "myphasartool\n" - "A small PhASAR-based example program\n\n" - "Usage: myphasartool \n"; - return 1; - } - ProjectIRDB DB({argv[1]}); - if (auto F = DB.getFunctionDefinition("main")) { - LLVMTypeHierarchy H(DB); - // print type hierarchy - H.print(); - LLVMPointsToSet P(DB); - // print points-to information - P.print(); - LLVMBasedICFG I(DB, CallGraphAnalysisType::OTF, {"main"}, &H, &P); - // print inter-procedural control-flow graph - I.print(); - // IFDS template parametrization test - llvm::outs() << "Testing IFDS:\n"; - IFDSLinearConstantAnalysis L(&DB, &H, &I, &P, {"main"}); - IFDSSolver_P S(L); - S.solve(); - S.dumpResults(); - // use PhASAR's strategy concept that allows for even easier analysis set-up - llvm::outs() << "Testing IDE:\n"; - WholeProgramAnalysis, - IDELinearConstantAnalysis> - WPA(DB, {"main"}, &P, &I, &H); - WPA.solve(); - WPA.dumpResults(); - WPA.releaseAllHelperAnalyses(); - } else { - llvm::errs() << "error: file does not contain a 'main' function!\n"; - } - return 0; -} diff --git a/examples/use-phasar-as-library/myphasartool.cpp b/examples/use-phasar-as-library/myphasartool.cpp new file mode 120000 index 000000000..f1171d5dc --- /dev/null +++ b/examples/use-phasar-as-library/myphasartool.cpp @@ -0,0 +1 @@ +../../tools/example-tool/myphasartool.cpp \ No newline at end of file diff --git a/include/phasar/Config/Configuration.h b/include/phasar/Config/Configuration.h index 34fd9435c..74d9f8401 100644 --- a/include/phasar/Config/Configuration.h +++ b/include/phasar/Config/Configuration.h @@ -17,14 +17,13 @@ #ifndef PHASAR_CONFIG_CONFIGURATION_H_ #define PHASAR_CONFIG_CONFIGURATION_H_ -#include -#include - -#include "boost/program_options.hpp" +#include "phasar/Config/Version.h" #include "llvm/ADT/iterator_range.h" -#include "phasar/Config/Version.h" +#include +#include +#include #define XSTR(S) STR(S) #define STR(S) #S @@ -105,13 +104,6 @@ class PhasarConfig { SpecialFuncNames.insert(std::move(SFName)); } - /// Variables map of the parsed command-line parameters - // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static boost::program_options::variables_map &VariablesMap() { - static boost::program_options::variables_map VMap; - return VMap; - } - ~PhasarConfig() = default; PhasarConfig(const PhasarConfig &) = delete; PhasarConfig operator=(const PhasarConfig &) = delete; diff --git a/include/phasar/Config/ContainerConfiguration.h b/include/phasar/Config/ContainerConfiguration.h deleted file mode 100644 index 1db6adb4c..000000000 --- a/include/phasar/Config/ContainerConfiguration.h +++ /dev/null @@ -1,70 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * ContainerConfiguration.h - * - * Created on: 02.05.2017 - * Author: philipp - */ - -#ifndef PHASAR_CONFIG_CONTAINER_CONFIGURATION_H_ -#define PHASAR_CONFIG_CONTAINER_CONFIGURATION_H_ - -#include -#include - -#include "boost/container/flat_map.hpp" -#include "boost/container/flat_set.hpp" -#include "boost/container/small_vector.hpp" - -namespace psr { -// check if we forgot some more useful container implementations - -// define the set implementation to use for the ICFG classes -// ------------- -template using ICFGSet = boost::container::flat_set; -// ---------------------------------------------------------------------------- - -// define the set implementation to use for the flow functions -// ------------- -#define FFSetPreAllocSize 10 - -template -using FFSet = boost::container::small_vector; -// ---------------------------------------------------------------------------- - -// define the map implementation to use for the special summaries -// ------------- -template -using SSMap = boost::container::flat_map; -// ---------------------------------------------------------------------------- - -// define the map implementation to use for the dynamic summaries -// ------------- -template -using DSMap = boost::container::flat_map; -// ---------------------------------------------------------------------------- - -// Monotone Framework related container implementations ----------------------- -// define the map implementation to use for classes of the monotone framework -// ------------- -template -using MonoMap = std::map; // boost::container::flat_map; -// ---------------------------------------------------------------------------- - -// define the set implementation to use for classes of the monotone framework -// ------------- -template -using MonoSet = std::set; // boost::container::flat_set; -// ---------------------------------------------------------------------------- - -} // namespace psr - -#endif diff --git a/include/phasar/Controller/AnalysisController.h b/include/phasar/Controller/AnalysisController.h index 7c8d248cd..ae057daba 100644 --- a/include/phasar/Controller/AnalysisController.h +++ b/include/phasar/Controller/AnalysisController.h @@ -10,17 +10,15 @@ #ifndef PHASAR_CONTROLLER_ANALYSISCONTROLLER_H #define PHASAR_CONTROLLER_ANALYSISCONTROLLER_H -#include -#include -#include - -#include "phasar/DB/ProjectIRDB.h" +#include "phasar/Controller/AnalysisControllerEmitterOptions.h" +#include "phasar/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/AnalysisStrategy/HelperAnalyses.h" #include "phasar/PhasarLLVM/AnalysisStrategy/Strategies.h" -#include "phasar/PhasarLLVM/AnalysisStrategy/WholeProgramAnalysis.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSSolver.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h" #include "phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h" #include "phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/IntraMonoSolver.h" #include "phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h" @@ -29,47 +27,27 @@ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" #include "phasar/Utils/EnumFlags.h" +#include "phasar/Utils/IO.h" #include "phasar/Utils/Soundness.h" -namespace psr { +#include +#include +#include -enum class AnalysisControllerEmitterOptions : uint32_t { - None = 0, - EmitIR = (1 << 0), - EmitRawResults = (1 << 1), - EmitTextReport = (1 << 2), - EmitGraphicalReport = (1 << 3), - EmitESGAsDot = (1 << 4), - EmitTHAsText = (1 << 5), - EmitTHAsDot = (1 << 6), - EmitTHAsJson = (1 << 7), - EmitCGAsText = (1 << 8), - EmitCGAsDot = (1 << 9), - EmitCGAsJson = (1 << 10), - EmitPTAAsText = (1 << 11), - EmitPTAAsDot = (1 << 12), - EmitPTAAsJson = (1 << 13), - EmitStatisticsAsJson = (1 << 14), -}; +namespace psr { class AnalysisController { private: - ProjectIRDB &IRDB; - LLVMTypeHierarchy TH; - LLVMPointsToSet PT; - LLVMBasedICFG ICF; + HelperAnalyses &HA; std::vector DataFlowAnalyses; std::vector AnalysisConfigs; - std::set EntryPoints; + std::vector EntryPoints; [[maybe_unused]] AnalysisStrategy Strategy; AnalysisControllerEmitterOptions EmitterOptions = AnalysisControllerEmitterOptions::None; std::string ProjectID; - std::string OutDirectory; std::filesystem::path ResultDirectory; IFDSIDESolverConfig SolverConfig; - [[maybe_unused]] Soundness SoundnessLevel; - [[maybe_unused]] bool AutoGlobalSupport; /// /// \brief The maximum length of the CallStrings used in the InterMonoSolver @@ -93,7 +71,6 @@ class AnalysisController { void executeIFDSTaint(); void executeIFDSType(); void executeIFDSSolverTest(); - void executeIFDSLinearConst(); void executeIFDSFieldSensTaint(); void executeIDEXTaint(); void executeIDEOpenSSLTS(); @@ -106,79 +83,64 @@ class AnalysisController { void executeInterMonoSolverTest(); void executeInterMonoTaint(); - template - void executeIntraMonoAnalysis() { - executeAnalysis, AnalysisTy, WithConfig>(); + template + void executeIntraMonoAnalysis(ProblemTy &Problem) { + IntraMonoSolver Solver(Problem); + Solver.solve(); + emitRequestedDataFlowResults(Solver); } - template - void executeInterMonoAnalysis() { - executeAnalysis, AnalysisTy, WithConfig>(); + template + void executeInterMonoAnalysis(ProblemTy &Problem) { + InterMonoSolver_P Solver(Problem); + Solver.solve(); + emitRequestedDataFlowResults(Solver); } - template - void executeIFDSAnalysis() { - executeAnalysis, AnalysisTy, WithConfig>(); + template void executeIFDSAnalysis(ProblemTy &Problem) { + IFDSSolver Solver(Problem, &HA.getICFG()); + Solver.solve(); + emitRequestedDataFlowResults(Solver); } - template - void executeIDEAnalysis() { - executeAnalysis, AnalysisTy, WithConfig>(); + template void executeIDEAnalysis(ProblemTy &Problem) { + IDESolver Solver(Problem, &HA.getICFG()); + Solver.solve(); + emitRequestedDataFlowResults(Solver); } - template - void executeAnalysis() { - if constexpr (WithConfig) { - std::string AnalysisConfigPath = - !AnalysisConfigs.empty() ? AnalysisConfigs[0] : ""; - auto Config = - !AnalysisConfigPath.empty() - ? TaintConfig(IRDB, parseTaintConfig(AnalysisConfigPath)) - : TaintConfig(IRDB); - WholeProgramAnalysis WPA( - SolverConfig, IRDB, &Config, EntryPoints, &PT, &ICF, &TH); - WPA.solve(); - emitRequestedDataFlowResults(WPA); - WPA.releaseAllHelperAnalyses(); - } else { - WholeProgramAnalysis WPA( - SolverConfig, IRDB, EntryPoints, &PT, &ICF, &TH); - WPA.solve(); - emitRequestedDataFlowResults(WPA); - WPA.releaseAllHelperAnalyses(); - } - } + TaintConfig makeTaintConfig(); - std::unique_ptr - openFileStream(llvm::StringRef Filename); - - template void emitRequestedDataFlowResults(T &WPA) { + template void emitRequestedDataFlowResults(T &Solver) { if (EmitterOptions & AnalysisControllerEmitterOptions::EmitTextReport) { if (!ResultDirectory.empty()) { - if (auto OFS = openFileStream("/psr-report.txt")) { - WPA.emitTextReport(*OFS); + if (auto OFS = + openFileStream(ResultDirectory.string() + "/psr-report.txt")) { + Solver.emitTextReport(*OFS); } } else { - WPA.emitTextReport(llvm::outs()); + Solver.emitTextReport(llvm::outs()); } } if (EmitterOptions & AnalysisControllerEmitterOptions::EmitGraphicalReport) { if (!ResultDirectory.empty()) { - if (auto OFS = openFileStream("/psr-report.html")) { - WPA.emitGraphicalReport(*OFS); + if (auto OFS = + openFileStream(ResultDirectory.string() + "/psr-report.html")) { + Solver.emitGraphicalReport(*OFS); } } else { - WPA.emitGraphicalReport(llvm::outs()); + Solver.emitGraphicalReport(llvm::outs()); } } if (EmitterOptions & AnalysisControllerEmitterOptions::EmitRawResults) { if (!ResultDirectory.empty()) { - if (auto OFS = openFileStream("/psr-raw-results.txt")) { - WPA.dumpResults(*OFS); + if (auto OFS = openFileStream(ResultDirectory.string() + + "/psr-raw-results.txt")) { + Solver.dumpResults(*OFS); } } else { - WPA.dumpResults(llvm::outs()); + Solver.dumpResults(llvm::outs()); } } if (EmitterOptions & AnalysisControllerEmitterOptions::EmitESGAsDot) { @@ -188,18 +150,14 @@ class AnalysisController { } public: - AnalysisController(ProjectIRDB &IRDB, - std::vector DataFlowAnalyses, - std::vector AnalysisConfigs, - PointerAnalysisType PTATy, CallGraphAnalysisType CGTy, - Soundness SoundnessLevel, bool AutoGlobalSupport, - const std::set &EntryPoints, - AnalysisStrategy Strategy, - AnalysisControllerEmitterOptions EmitterOptions, - IFDSIDESolverConfig SolverConfig, - const std::string &ProjectID = "default-phasar-project", - const std::string &OutDirectory = "", - const nlohmann::json &PrecomputedPointsToInfo = {}); + explicit AnalysisController( + HelperAnalyses &HA, std::vector DataFlowAnalyses, + std::vector AnalysisConfigs, + std::vector EntryPoints, AnalysisStrategy Strategy, + AnalysisControllerEmitterOptions EmitterOptions, + IFDSIDESolverConfig SolverConfig, + const std::string &ProjectID = "default-phasar-project", + const std::string &OutDirectory = ""); ~AnalysisController() = default; @@ -209,6 +167,13 @@ class AnalysisController { AnalysisController &operator=(const AnalysisController &&) = delete; void executeAs(AnalysisStrategy Strategy); + + static constexpr bool + needsToEmitPTA(AnalysisControllerEmitterOptions EmitterOptions) { + return (EmitterOptions & AnalysisControllerEmitterOptions::EmitPTAAsDot) || + (EmitterOptions & AnalysisControllerEmitterOptions::EmitPTAAsJson) || + (EmitterOptions & AnalysisControllerEmitterOptions::EmitPTAAsText); + } }; } // namespace psr diff --git a/include/phasar/Controller/AnalysisControllerEmitterOptions.h b/include/phasar/Controller/AnalysisControllerEmitterOptions.h new file mode 100644 index 000000000..668860f26 --- /dev/null +++ b/include/phasar/Controller/AnalysisControllerEmitterOptions.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * Copyright (c) 2022 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_CONTROLLER_ANALYSISCONTROLLEREMITTEROPTIONS_H +#define PHASAR_CONTROLLER_ANALYSISCONTROLLEREMITTEROPTIONS_H + +namespace psr { +enum class AnalysisControllerEmitterOptions { + None = 0, + EmitIR = (1 << 0), + EmitRawResults = (1 << 1), + EmitTextReport = (1 << 2), + EmitGraphicalReport = (1 << 3), + EmitESGAsDot = (1 << 4), + EmitTHAsText = (1 << 5), + EmitTHAsDot = (1 << 6), + EmitTHAsJson = (1 << 7), + EmitCGAsText = (1 << 8), + EmitCGAsDot = (1 << 9), + EmitCGAsJson = (1 << 10), + EmitPTAAsText = (1 << 11), + EmitPTAAsDot = (1 << 12), + EmitPTAAsJson = (1 << 13), + EmitStatisticsAsText = (1 << 14), + EmitStatisticsAsJson = (1 << 15), +}; +} // namespace psr + +#endif // PHASAR_CONTROLLER_ANALYSISCONTROLLEREMITTEROPTIONS_H diff --git a/include/phasar/DB/DBConn.h b/include/phasar/DB/DBConn.h deleted file mode 100644 index 5878a9ddc..000000000 --- a/include/phasar/DB/DBConn.h +++ /dev/null @@ -1,151 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * DBConn.h - * - * Created on: 23.08.2016 - * Author: pdschbrt - */ -/* -#ifndef PHASAR_DB_DBCONN_H_ -#define PHASAR_DB_DBCONN_H_ - -#include -#include -#include -#include - -#include "llvm/IR/Module.h" - -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDESummary.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToGraph.h" -#include "phasar/PhasarLLVM/Pointer/LLVMTypeHierarchy.h" -// If ProjectIRDB is no more returned, forward declare it and remove this -#include "phasar/DB/ProjectIRDB.h" - -#include "mysql_connection.h" -#include "sqlite3.h" - -namespace llvm { -class GlobalVariable; -class LLVMContext; -class StructType; -} // namespace llvm - -namespace psr { - -enum class QueryReturnCode { DBTrue, DBFalse, DBError }; - -#define SQL_STD_ERROR_HANDLING \ - std::cout << "# ERR: SQLException in " << __FILE__; \ - std::cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << std::endl; \ - std::cout << "# ERR: " << e.what(); \ - std::cout << " (MySQL error code: " << e.getErrorCode(); \ - std::cout << ", SQLState: " << e.getSQLState() << " )" << std::endl; - -// forward declarations -class VTable; - -class DBConn { -private: - DBConn(); - ~DBConn(); - sql::Driver *driver; - sql::Connection *conn; - const static std::string db_user; - const static std::string db_password; - const static std::string db_schema_name; - const static std::string db_server_address; - // Functions for internal use only - int getNextAvailableID(const std::string &TableName); - int getProjectID(const std::string &Identifier); - int getModuleID(const std::string &Identifier); - std::set getModuleIDsFromProject(const std::string &Identifier); - int getModuleIDFromFunctionID(const unsigned functionID); - int getModuleIDFromTypeID(const unsigned typeID); - std::set getFunctionID(const std::string &Identifier); - std::set getGlobalVariableID(const std::string &Identifier); - int getTypeID(const std::string &Identifier); - std::size_t getFunctionHash(const unsigned functionID); - std::size_t getModuleHash(const unsigned moduleID); - QueryReturnCode moduleHasTypeHierarchy(const unsigned moduleID); - QueryReturnCode globalVariableIsDeclaration(const unsigned globalVariableID); - std::set getAllTypeHierarchyIDs(); - std::set getAllModuleIDsFromTH(const unsigned typeHierarchyID); - - bool schemeExists(); - void buildDBScheme(); - void dropDBAndRebuildScheme(); - - bool insertModule(const std::string &ProjectIdentifier, - const llvm::Module *module); - std::unique_ptr getModule(const std::string &mod_name, - llvm::LLVMContext &Context); - bool insertGlobalVariable(const llvm::GlobalVariable &G, - const unsigned moduleID); - bool insertFunction(const llvm::Function &F, const unsigned moduleID); - bool insertType(const llvm::StructType &ST, const unsigned moduleID); - bool insertVTable(const VTable &VTBL, const std::string &TypeName, - const std::string &ProjectName); - void storeLTHGraphToHex(const LLVMTypeHierarchy::bidigraph_t &G, - const std::string hex_id); - -public: - DBConn(const DBConn &db) = delete; - DBConn(DBConn &&db) = delete; - DBConn &operator=(const DBConn &db) = delete; - DBConn &operator=(DBConn &&db) = delete; - static DBConn &getInstance(); - std::string getDBName(); - - void storeProjectIRDB(const std::string &ProjectName, - const ProjectIRDB &IRDB); - // We may want to pass an empty ProjectIRDB and do not return anything in - // order to suppress the copy constructor of ProjectIRDB and enforce a no copy - // rule. - ProjectIRDB loadProjectIRDB(const std::string &ProjectName); - - void storeLLVMBasedICFG(const LLVMBasedICFG &ICFG, - const std::string &ProjectName, bool use_hs = false); - LLVMBasedICFG loadLLVMBasedICFGfromModule(const std::string &ModuleName, - bool use_hs = false); - LLVMBasedICFG - loadLLVMBasedICFGfromModules(std::initializer_list ModuleNames, - bool use_hs = false); - LLVMBasedICFG loadLLVMBasedICFGfromProject(const std::string &ProjectName, - bool use_hs = false); - - void storePointsToGraph(const LLVMPointsToGraph &PTG, - const std::string &ProjectName, bool use_hs = false); - LLVMPointsToGraph loadPointsToGraphFromFunction(const std::string -&FunctionName, bool use_hs = false); - - void storeLLVMTypeHierarchy(LLVMTypeHierarchy &TH, - const std::string &ProjectName, - bool use_hs = false); - LLVMTypeHierarchy - loadLLVMTypeHierarchyFromModule(const std::string &ModuleName, - bool use_hs = false); - LLVMTypeHierarchy loadLLVMTypeHierarchyFromModules( - std::initializer_list ModuleNames, bool use_hs = false); - LLVMTypeHierarchy - loadLLVMTypeHierarchyFromProject(const std::string &ProjectName, - bool use_hs = false); - - void storeIDESummary(const IDESummary &S); - IDESummary loadIDESummary(const std::string &FunctionName, - const std::string &AnalysisName); -}; - -} // namespace psr - -#endif -*/ diff --git a/include/phasar/DB/LLVMProjectIRDB.h b/include/phasar/DB/LLVMProjectIRDB.h new file mode 100644 index 000000000..d1b1789d2 --- /dev/null +++ b/include/phasar/DB/LLVMProjectIRDB.h @@ -0,0 +1,168 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_DB_LLVMPROJECTIRDB_H +#define PHASAR_DB_LLVMPROJECTIRDB_H + +#include "phasar/DB/ProjectIRDBBase.h" +#include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" +#include "phasar/Utils/MaybeUniquePtr.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { +class LLVMProjectIRDB; + +template <> struct ProjectIRDBTraits { + using n_t = const llvm::Instruction *; + using f_t = const llvm::Function *; + using m_t = const llvm::Module *; + using g_t = const llvm::GlobalVariable *; +}; + +class LLVMProjectIRDB : public ProjectIRDBBase { + friend ProjectIRDBBase; + +public: + /// Reads and parses the given LLVM IR file and owns the resulting IR Module + explicit LLVMProjectIRDB(const llvm::Twine &IRFileName); + /// Initializes the new ProjectIRDB with the given IR Module _without_ taking + /// ownership. The module is not being preprocessed. + /// + /// CAUTION: Do not manage the same LLVM Module with multiple LLVMProjectIRDB + /// instances at the same time! This will confuse the ModulesToSlotTracker + explicit LLVMProjectIRDB(llvm::Module *Mod); + /// Initializes the new ProjectIRDB with the given IR Moduleand takes + /// ownership of it + explicit LLVMProjectIRDB(std::unique_ptr Mod, + bool DoPreprocessing = true); + + LLVMProjectIRDB(const LLVMProjectIRDB &) = delete; + LLVMProjectIRDB &operator=(LLVMProjectIRDB &) = delete; + + ~LLVMProjectIRDB(); + + [[nodiscard]] static std::unique_ptr + getParsedIRModuleOrNull(const llvm::Twine &IRFileName, + llvm::LLVMContext &Ctx) noexcept; + + /// Also use the const overload + using ProjectIRDBBase::getFunction; + /// Non-const overload + [[nodiscard]] llvm::Function *getFunction(llvm::StringRef FunctionName) { + return Mod->getFunction(FunctionName); + } + + /// Also use the const overload + using ProjectIRDBBase::getFunctionDefinition; + /// Non-const overload + [[nodiscard]] llvm::Function * + getFunctionDefinition(llvm::StringRef FunctionName); + + /// Also use the const overload + using ProjectIRDBBase::getModule; + /// Non-const overload + [[nodiscard]] llvm::Module *getModule() { return Mod.get(); } + + /// Similar to getInstruction(size_t), but is also able to return global + /// variables by id + [[nodiscard]] const llvm::Value *getValueFromId(size_t Id) const noexcept { + return Id < IdToInst.size() ? IdToInst[Id] : nullptr; + } + + void emitPreprocessedIR(llvm::raw_ostream &OS) const; + + /// Insert a new function F into the IRDB. F should be present in the same + /// llvm::Module that is managed by the IRDB. insertFunction should not be + /// called twice for the same function. Use with care! + void insertFunction(llvm::Function *F, bool DoPreprocessing = true); + +private: + [[nodiscard]] m_t getModuleImpl() const noexcept { return Mod.get(); } + [[nodiscard]] bool debugInfoAvailableImpl() const; + [[nodiscard]] FunctionRange getAllFunctionsImpl() const { + return llvm::map_range(Mod->functions(), + Ref2PointerConverter{}); + } + [[nodiscard]] f_t getFunctionImpl(llvm::StringRef FunctionName) const { + return Mod->getFunction(FunctionName); + } + [[nodiscard]] f_t + getFunctionDefinitionImpl(llvm::StringRef FunctionName) const; + [[nodiscard]] bool + hasFunctionImpl(llvm::StringRef FunctionName) const noexcept { + return Mod->getFunction(FunctionName) != nullptr; + } + [[nodiscard]] g_t + getGlobalVariableDefinitionImpl(llvm::StringRef GlobalVariableName) const; + [[nodiscard]] size_t getNumInstructionsImpl() const noexcept { + return IdToInst.size() - IdOffset; + } + [[nodiscard]] size_t getNumFunctionsImpl() const noexcept { + return Mod->size(); + } + [[nodiscard]] size_t getNumGlobalsImpl() const noexcept { + return Mod->global_size(); + } + + [[nodiscard]] n_t getInstructionImpl(size_t Id) const noexcept { + // Effectively make use of integer overflow here... + if (Id - IdOffset < IdToInst.size() - IdOffset) { + return llvm::cast(IdToInst[Id]); + } + return n_t{}; + } + + [[nodiscard]] auto getAllInstructionsImpl() const noexcept { + return llvm::map_range( + llvm::makeArrayRef(IdToInst).drop_front(IdOffset), + [](const llvm::Value *V) { return llvm::cast(V); }); + } + + [[nodiscard]] size_t getInstructionIdImpl(n_t Inst) const { + auto It = InstToId.find(Inst); + assert(It != InstToId.end()); + return It->second; + } + [[nodiscard]] bool isValidImpl() const noexcept; + + void dumpImpl() const; + + void initInstructionIds(); + /// XXX Later we might get rid of the metadata IDs entirely and therefore of + /// the preprocessing as well + void preprocessModule(llvm::Module *NonConstMod); + + llvm::LLVMContext Ctx; + MaybeUniquePtr Mod = nullptr; + size_t IdOffset = 0; + llvm::SmallVector IdToInst; + llvm::DenseMap InstToId; +}; + +/** + * Revserses the getMetaDataID function + */ +const llvm::Value *fromMetaDataId(const LLVMProjectIRDB &IRDB, + llvm::StringRef Id); + +extern template class ProjectIRDBBase; +} // namespace psr + +#endif // PHASAR_DB_LLVMPROJECTIRDB_H diff --git a/include/phasar/DB/ProjectIRDB.h b/include/phasar/DB/ProjectIRDB.h deleted file mode 100644 index 67958d216..000000000 --- a/include/phasar/DB/ProjectIRDB.h +++ /dev/null @@ -1,239 +0,0 @@ -/****************************************************************************** - * 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_DB_PROJECTIRDB_H_ -#define PHASAR_DB_PROJECTIRDB_H_ - -#include -#include -#include -#include -#include - -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/PassManager.h" -#include "llvm/Passes/PassBuilder.h" - -#include "nlohmann/json.hpp" -#include "phasar/Utils/EnumFlags.h" - -namespace llvm { -class Value; -class Instruction; -class Type; -class Function; -class GlobalVariable; -} // namespace llvm - -namespace psr { - -enum class IRDBOptions : uint32_t { NONE = 0, WPA = (1 << 0), OWNS = (1 << 1) }; - -/** - * This class owns the LLVM IR code of the project under analysis and some - * very important information associated with the IR. - * When an object of this class is destroyed it will clean up all IR related - * stuff that is stored in it. - */ -class ProjectIRDB { -private: - llvm::Module *WPAModule = nullptr; - IRDBOptions Options; - llvm::PassBuilder PB; - llvm::ModuleAnalysisManager MAM; - llvm::ModulePassManager MPM; - // Stores all allocation instructions - std::set AllocaInstructions; - // Stores all allocated types - std::set AllocatedTypes; - // Return or resum instructions - std::set RetOrResInstructions; - // Stores the contexts - std::vector> Contexts; - // Contains all modules that correspond to a project and owns them - std::map> Modules; - // Maps an id to its corresponding instruction - std::map IDInstructionMapping; - size_t NumberCallsites; - nlohmann::json StatsJson; - - void buildIDModuleMapping(llvm::Module *M); - - void preprocessModule(llvm::Module *M); - static bool wasCompiledWithDebugInfo(llvm::Module *M) { - return M->getNamedMetadata("llvm.dbg.cu") != nullptr; - }; - - void preprocessAllModules(); - - [[nodiscard]] llvm::Function * - internalGetFunction(llvm::StringRef FunctionName) const; - [[nodiscard]] llvm::Function * - internalGetFunctionDefinition(llvm::StringRef FunctionName) const; - -public: - /// Constructs an empty ProjectIRDB - ProjectIRDB(IRDBOptions Options); - /// Constructs a ProjectIRDB from a bunch of LLVM IR files - ProjectIRDB(const std::vector &IRFiles, - IRDBOptions Options = (IRDBOptions::WPA | IRDBOptions::OWNS)); - /// Constructs a ProjecIRDB from a bunch of LLVM Modules - ProjectIRDB(const std::vector &Modules, - IRDBOptions Options = IRDBOptions::WPA); - - ProjectIRDB(ProjectIRDB &&) = default; - ProjectIRDB &operator=(ProjectIRDB &&) = default; - - ProjectIRDB(ProjectIRDB &) = delete; - ProjectIRDB &operator=(const ProjectIRDB &) = delete; - - ~ProjectIRDB(); - - void insertModule(llvm::Module *M); - - // add WPA support by providing a fat completely linked module - void linkForWPA(); - // get a completely linked module for the WPA_MODE - llvm::Module *getWPAModule(); - - [[nodiscard]] inline bool containsSourceFile(const std::string &File) const { - return Modules.find(File) != Modules.end(); - }; - - [[nodiscard]] inline bool empty() const { return Modules.empty(); }; - - [[nodiscard]] bool debugInfoAvailable() const; - - llvm::Module *getModule(const std::string &ModuleName); - - [[nodiscard]] inline std::set getAllModules() const { - std::set ModuleSet; - for (const auto &[File, Module] : Modules) { - ModuleSet.insert(Module.get()); - } - return ModuleSet; - } - - [[nodiscard]] std::set getAllFunctions() const; - - [[nodiscard]] const llvm::Function * - getFunctionDefinition(llvm::StringRef FunctionName) const; - [[nodiscard]] llvm::Function * - getFunctionDefinition(llvm::StringRef FunctionName); - - [[nodiscard]] const llvm::Function * - getFunction(llvm::StringRef FunctionName) const; - [[nodiscard]] llvm::Function *getFunction(llvm::StringRef FunctionName); - - [[nodiscard]] const llvm::GlobalVariable * - getGlobalVariableDefinition(const std::string &GlobalVariableName) const; - - llvm::Module *getModuleDefiningFunction(const std::string &FunctionName); - - [[nodiscard]] const llvm::Module * - getModuleDefiningFunction(const std::string &FunctionName) const; - - [[nodiscard]] inline const std::set & - getAllocaInstructions() const { - return AllocaInstructions; - }; - - /** - * LLVM's intrinsic global variables are excluded. - * - * @brief Returns all stack and heap allocations, including global variables. - */ - [[nodiscard]] std::set getAllMemoryLocations() const; - - [[nodiscard]] std::set getAllSourceFiles() const; - - [[nodiscard]] std::set getAllocatedTypes() const { - return AllocatedTypes; - }; - - [[nodiscard]] std::set - getAllocatedStructTypes() const; - - [[nodiscard]] inline std::set - getRetOrResInstructions() const { - return RetOrResInstructions; - }; - - [[nodiscard]] inline std::size_t getNumberOfModules() const { - return Modules.size(); - }; - - [[nodiscard]] inline std::size_t getNumInstructions() const { - return IDInstructionMapping.size(); - } - - [[nodiscard]] inline std::size_t getNumCallsites() const { - return NumberCallsites; - } - - [[nodiscard]] std::size_t getNumGlobals() const; - - [[nodiscard]] llvm::Instruction *getInstruction(std::size_t Id) const; - - [[nodiscard]] static std::size_t getInstructionID(const llvm::Instruction *I); - - void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; - - void print() const; - - void emitPreprocessedIR(llvm::raw_ostream &OS = llvm::outs(), - bool ShortenIR = false) const; - - /** - * Allows the (de-)serialization of Instructions, Arguments, GlobalValues and - * Operands into unique Hexastore string representation. - * - * What values can be serialized and what scheme is used? - * - * 1. Instructions - * - * . - * - * 2. Formal parameters - * - * .f - * - * 3. Global variables - * - * - * - * 4. ZeroValue - * - * - * - * 5. Operand of an instruction - * - * ..o. - * - * @brief Creates a unique string representation for any given - * llvm::Value. - */ - [[nodiscard]] static std::string valueToPersistedString(const llvm::Value *V); - /** - * @brief Convertes the given string back into the llvm::Value it represents. - * @return Pointer to the converted llvm::Value. - */ - [[nodiscard]] const llvm::Value * - persistedStringToValue(const std::string &StringRep) const; -}; - -/** - * Revserses the getMetaDataID function - */ -const llvm::Value *fromMetaDataId(const ProjectIRDB &IRDB, llvm::StringRef Id); - -} // namespace psr - -#endif diff --git a/include/phasar/DB/ProjectIRDBBase.h b/include/phasar/DB/ProjectIRDBBase.h new file mode 100644 index 000000000..1821491a1 --- /dev/null +++ b/include/phasar/DB/ProjectIRDBBase.h @@ -0,0 +1,163 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_DB_PROJECTIRDBBASE_H +#define PHASAR_DB_PROJECTIRDBBASE_H + +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" + +namespace psr { +template struct ProjectIRDBTraits { + // using n_t + // using f_t + // using m_t + // using g_t +}; + +/// This class owns the IR code of the project under analysis and some +/// very important information associated with the IR. +/// When an object of this class is destroyed it will clean up all IR related +/// stuff that is stored in it. +/// +/// m_t - module type +/// f_t - function type +/// n_t - instruction type +/// g_t - global variable type +/// +/// \remark XXX Once we have upgraded to C++20, we might want to use a concept +/// instead... +template class ProjectIRDBBase { +public: + using n_t = typename ProjectIRDBTraits::n_t; + using f_t = typename ProjectIRDBTraits::f_t; + using m_t = typename ProjectIRDBTraits::m_t; + using g_t = typename ProjectIRDBTraits::g_t; + + /// Returns the managed module + [[nodiscard]] m_t getModule() const noexcept { + assert(isValid()); + return self().getModuleImpl(); + } + + /// Check if debug information are available. + [[nodiscard]] bool debugInfoAvailable() const { + assert(isValid()); + return self().debugInfoAvailableImpl(); + } + + /// Returns a range of all function definitions and declarations available + [[nodiscard]] decltype(auto) getAllFunctions() const { + static_assert( + is_iterable_over_v); + assert(isValid()); + return self().getAllFunctionsImpl(); + } + + // Returns the function's definition if available, its declaration otherwise. + [[nodiscard]] f_t getFunction(llvm::StringRef FunctionName) const { + assert(isValid()); + return self().getFunctionImpl(FunctionName); + } + /// Returns the function's definition if available, null otherwise. + [[nodiscard]] f_t getFunctionDefinition(llvm::StringRef FunctionName) const { + assert(isValid()); + return self().getFunctionDefinitionImpl(FunctionName); + } + /// Returns whether the IRDB contains a function with the given name. + [[nodiscard]] bool hasFunction(llvm::StringRef FunctionName) const noexcept { + assert(isValid()); + return self().hasFunctionImpl(FunctionName); + } + + /// Returns the global variable's definition if available, null otherwise. + [[nodiscard]] g_t + getGlobalVariableDefinition(llvm::StringRef GlobalVariableName) const { + assert(isValid()); + return self().getGlobalVariableDefinitionImpl(GlobalVariableName); + } + + /// Returns the number of instruction in the managed module. + [[nodiscard]] size_t getNumInstructions() const noexcept { + assert(isValid()); + return self().getNumInstructionsImpl(); + } + /// Returns the number of global variables in the managed module. + [[nodiscard]] size_t getNumGlobals() const noexcept { + assert(isValid()); + return self().getNumGlobalsImpl(); + } + /// Returns the number of functions in the managed module. + [[nodiscard]] size_t getNumFunctions() const noexcept { + assert(isValid()); + return self().getNumFunctionsImpl(); + } + + /// Returns the instruction to the corresponding Id. Returns nullptr, if there + /// is no instruction for this Id + [[nodiscard]] n_t getInstruction(size_t Id) const { + assert(isValid()); + return self().getInstructionImpl(Id); + } + /// Returns an instruction's ID. The instruction must belong to the managed + /// module for this function to work + [[nodiscard]] size_t getInstructionId(n_t Inst) const { + assert(isValid()); + return self().getInstructionId(Inst); + } + + [[nodiscard]] decltype(auto) getAllInstructions() const { + static_assert( + is_iterable_over_v); + assert(isValid()); + return self().getAllInstructionsImpl(); + } + + /// Sanity check to verify that th IRDB really manages a Module and all + /// functions work properly. + /// All functions of this IRDB require isValid() to return true, if not stated + /// differently -- otherwise, they must not be called. + /// This function (obviously) does not require isValid() to return true. + [[nodiscard]] bool isValid() const noexcept { return self().isValidImpl(); } + + /// Dumps the managed module to llvm::dbgs() if isValid(); otherwise prints + /// "". + /// This function can be invoked from a debugger. + LLVM_DUMP_METHOD void dump() const { + if (!isValid()) { + llvm::dbgs() << "\n"; + llvm::dbgs().flush(); + return; + } + self().dumpImpl(); + } + + ProjectIRDBBase(const ProjectIRDBBase &) = delete; + ProjectIRDBBase &operator=(const ProjectIRDBBase &) = delete; + + ProjectIRDBBase(ProjectIRDBBase &&) noexcept = default; + ProjectIRDBBase &operator=(ProjectIRDBBase &&) noexcept = default; + + ~ProjectIRDBBase() = default; + +private: + friend Derived; + ProjectIRDBBase() noexcept = default; + + Derived &self() noexcept { return static_cast(*this); } + const Derived &self() const noexcept { + return static_cast(*this); + } +}; +} // namespace psr + +#endif // PHASAR_DB_PROJECTIRDBBASE_H diff --git a/include/phasar/Experimental/Experimental.h b/include/phasar/Experimental/Experimental.h deleted file mode 100644 index 250665bc1..000000000 --- a/include/phasar/Experimental/Experimental.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef PHASAR_EXPERIMENTAL_EXPERIMENTAL_H_ -#define PHASAR_EXPERIMENTAL_EXPERIMENTAL_H_ - -#endif diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalyses.h b/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalyses.h new file mode 100644 index 000000000..98abb315c --- /dev/null +++ b/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalyses.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel, Philipp Schubert and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSES_H_ +#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSES_H_ + +#include "phasar/PhasarLLVM/AnalysisStrategy/HelperAnalysisConfig.h" + +#include "nlohmann/json.hpp" + +#include +#include +#include +#include + +namespace psr { +class LLVMProjectIRDB; +class LLVMTypeHierarchy; +class LLVMBasedICFG; +class LLVMPointsToInfo; + +class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions) +public: + explicit HelperAnalyses(std::string IRFile, + std::optional PrecomputedPTS, + PointerAnalysisType PTATy, bool AllowLazyPTS, + std::vector EntryPoints, + CallGraphAnalysisType CGTy, Soundness SoundnessLevel, + bool AutoGlobalSupport); + + explicit HelperAnalyses(std::string IRFile, + std::vector EntryPoints, + HelperAnalysisConfig Config = {}); + ~HelperAnalyses(); + + LLVMProjectIRDB &getProjectIRDB(); + LLVMPointsToInfo &getPointsToInfo(); + LLVMTypeHierarchy &getTypeHierarchy(); + LLVMBasedICFG &getICFG(); + +private: + std::unique_ptr IRDB; + std::unique_ptr PT; + std::unique_ptr TH; + std::unique_ptr ICF; + + // IRDB + std::string IRFile; + + // PTS + std::optional PrecomputedPTS; + PointerAnalysisType PTATy{}; + bool AllowLazyPTS{}; + + // ICF + std::vector EntryPoints; + CallGraphAnalysisType CGTy{}; + Soundness SoundnessLevel{}; + bool AutoGlobalSupport{}; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSES_H_ diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalysisConfig.h b/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalysisConfig.h new file mode 100644 index 000000000..c2492c1bb --- /dev/null +++ b/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalysisConfig.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSISCONFIG_H +#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSISCONFIG_H + +#include "phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h" +#include "phasar/PhasarLLVM/Pointer/PointerAnalysisType.h" + +#include "nlohmann/json.hpp" +#include "phasar/Utils/Soundness.h" + +#include + +namespace psr { +struct HelperAnalysisConfig { + std::optional PrecomputedPTS = std::nullopt; + PointerAnalysisType PTATy = PointerAnalysisType::CFLAnders; + CallGraphAnalysisType CGTy = CallGraphAnalysisType::OTF; + Soundness SoundnessLevel = Soundness::Soundy; + bool AutoGlobalSupport = true; + bool AllowLazyPTS = true; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSISCONFIG_H diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.def b/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.def index b02ab772e..ac1716aed 100644 --- a/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.def +++ b/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.def @@ -8,14 +8,13 @@ *****************************************************************************/ #ifndef ANALYSIS_STRATEGY_TYPES -#define ANALYSIS_STRATEGY_TYPES(NAME, CMDFLAG, TYPE) +#define ANALYSIS_STRATEGY_TYPES(NAME, CMDFLAG, DESC) #endif -ANALYSIS_STRATEGY_TYPES("DemandDrivenAnalysis", "DD", DemandDriven) -ANALYSIS_STRATEGY_TYPES("IncrementalUpdateAnalysis", "INC", Incremental) -ANALYSIS_STRATEGY_TYPES("ModuleWiseAnalysis", "MWA", ModuleWise) -ANALYSIS_STRATEGY_TYPES("VariationalAnalysis", "VAR", Variational) -ANALYSIS_STRATEGY_TYPES("WholeProgramAnalysis", "WPA", WholeProgram) -ANALYSIS_STRATEGY_TYPES("None", "none", None) +ANALYSIS_STRATEGY_TYPES(WholeProgram, "WPA", "Whole-program analysis (default)") +ANALYSIS_STRATEGY_TYPES(DemandDriven, "DD", "Demand-driven analysis") +ANALYSIS_STRATEGY_TYPES(Incremental, "INC", "Incremental-update analysis") +ANALYSIS_STRATEGY_TYPES(ModuleWise, "MWA", "Module-wise analysis") +ANALYSIS_STRATEGY_TYPES(Variational, "VAR", "Variational analysis") #undef ANALYSIS_STRATEGY_TYPES diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.h b/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.h index 66e5df95a..91c38d0f1 100644 --- a/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.h +++ b/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.h @@ -10,20 +10,29 @@ #ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_STRATEGIES_H #define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_STRATEGIES_H +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + #include +namespace llvm { +class raw_ostream; +} // namespace llvm + namespace psr { enum class AnalysisStrategy { -#define ANALYSIS_STRATEGY_TYPES(NAME, CMDFLAG, TYPE) TYPE, + None, +#define ANALYSIS_STRATEGY_TYPES(NAME, CMDFLAG, DESC) NAME, #include "phasar/PhasarLLVM/AnalysisStrategy/Strategies.def" + }; std::string toString(const AnalysisStrategy &S); -AnalysisStrategy toAnalysisStrategy(const std::string &S); +AnalysisStrategy toAnalysisStrategy(llvm::StringRef S); -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const AnalysisStrategy &S); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, AnalysisStrategy S); } // namespace psr diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/WholeProgramAnalysis.h b/include/phasar/PhasarLLVM/AnalysisStrategy/WholeProgramAnalysis.h deleted file mode 100644 index 4abfc97c2..000000000 --- a/include/phasar/PhasarLLVM/AnalysisStrategy/WholeProgramAnalysis.h +++ /dev/null @@ -1,193 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2019 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_ANALYSISSTRATEGY_WHOLEPROGRAMANALYSIS_H_ -#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_WHOLEPROGRAMANALYSIS_H_ - -#include -#include -#include -#include -#include -#include - -#include "phasar/DB/ProjectIRDB.h" -#include "phasar/PhasarLLVM/AnalysisStrategy/AnalysisSetup.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" - -namespace psr { - -template -class WholeProgramAnalysis { - // Check if the solver is able to solve the given problem description - static_assert( - std::is_base_of_v, - "Problem description does not match solver type!"); - // Check if the setup is a valid analysis setup - static_assert(std::is_base_of_v, - "Setup is not a valid analysis setup!"); - -private: - using TypeHierarchyTy = typename Setup::TypeHierarchyTy; - using PointerAnalysisTy = typename Setup::PointerAnalysisTy; - using CallGraphAnalysisTy = typename Setup::CallGraphAnalysisTy; - using ConfigurationTy = typename ProblemDescription::ConfigurationTy; - - ProjectIRDB &IRDB; - std::unique_ptr TypeHierarchy; - std::unique_ptr PointerInfo; - std::unique_ptr CallGraph; - std::set EntryPoints; - ConfigurationTy *Config = nullptr; - bool OwnsConfig = false; - std::string ConfigPath; - ProblemDescription ProblemDesc; - Solver DataFlowSolver; - -public: - WholeProgramAnalysis(IFDSIDESolverConfig SolverConfig, ProjectIRDB &IRDB, - std::set EntryPoints = {}, - PointerAnalysisTy *PointerInfo = nullptr, - CallGraphAnalysisTy *CallGraph = nullptr, - TypeHierarchyTy *TypeHierarchy = nullptr) - : IRDB(IRDB), - TypeHierarchy(TypeHierarchy == nullptr - ? std::make_unique(IRDB) - : std::unique_ptr(TypeHierarchy)), - PointerInfo(PointerInfo == nullptr - ? std::make_unique(IRDB) - : std::unique_ptr(PointerInfo)), - CallGraph(CallGraph == nullptr - ? std::make_unique( - IRDB, CallGraphAnalysisType::OTF, EntryPoints, - this->TypeHierarchy.get(), this->PointerInfo.get()) - : std::unique_ptr(CallGraph)), - EntryPoints(EntryPoints), - ProblemDesc(&IRDB, TypeHierarchy, CallGraph, PointerInfo, EntryPoints), - DataFlowSolver(ProblemDesc) { - if constexpr (has_setIFDSIDESolverConfig_v) { - ProblemDesc.setIFDSIDESolverConfig(SolverConfig); - } - } - - template >> - WholeProgramAnalysis(IFDSIDESolverConfig SolverConfig, ProjectIRDB &IRDB, - ConfigurationTy *Config, - std::set EntryPoints = {}, - PointerAnalysisTy *PointerInfo = nullptr, - CallGraphAnalysisTy *CallGraph = nullptr, - TypeHierarchyTy *TypeHierarchy = nullptr) - : IRDB(IRDB), - TypeHierarchy(TypeHierarchy == nullptr - ? std::make_unique(IRDB) - : std::unique_ptr(TypeHierarchy)), - PointerInfo(PointerInfo == nullptr - ? std::make_unique(IRDB) - : std::unique_ptr(PointerInfo)), - CallGraph(CallGraph == nullptr - ? std::make_unique( - IRDB, CallGraphAnalysisType::OTF, EntryPoints, - this->TypeHierarchy.get(), this->PointerInfo.get()) - : std::unique_ptr(CallGraph)), - EntryPoints(EntryPoints), Config(Config), - ProblemDesc(&IRDB, TypeHierarchy, CallGraph, PointerInfo, *Config, - EntryPoints), - DataFlowSolver(ProblemDesc) { - if constexpr (has_setIFDSIDESolverConfig_v) { - ProblemDesc.setIFDSIDESolverConfig(SolverConfig); - } - } - - template >> - WholeProgramAnalysis(IFDSIDESolverConfig SolverConfig, ProjectIRDB &IRDB, - std::string ConfigPath, - std::set EntryPoints = {}, - PointerAnalysisTy *PointerInfo = nullptr, - CallGraphAnalysisTy *CallGraph = nullptr, - TypeHierarchyTy *TypeHierarchy = nullptr) - : IRDB(IRDB), - TypeHierarchy(TypeHierarchy == nullptr - ? std::make_unique(IRDB) - : std::unique_ptr(TypeHierarchy)), - PointerInfo(PointerInfo == nullptr - ? std::make_unique(IRDB) - : std::unique_ptr(PointerInfo)), - CallGraph(CallGraph == nullptr - ? std::make_unique( - IRDB, CallGraphAnalysisType::OTF, EntryPoints, - this->TypeHierarchy.get(), this->PointerInfo.get()) - : std::unique_ptr(CallGraph)), - EntryPoints(EntryPoints), Config(new ConfigurationTy(ConfigPath)), - OwnsConfig(true), ConfigPath(ConfigPath), - ProblemDesc(&IRDB, TypeHierarchy, CallGraph, PointerInfo, *Config, - EntryPoints), - DataFlowSolver(ProblemDesc) { - if constexpr (has_setIFDSIDESolverConfig_v) { - ProblemDesc.setIFDSIDESolverConfig(SolverConfig); - } - } - - WholeProgramAnalysis(const WholeProgramAnalysis &) = delete; - WholeProgramAnalysis(WholeProgramAnalysis &&) = delete; - WholeProgramAnalysis &operator=(WholeProgramAnalysis &) = delete; - WholeProgramAnalysis &operator=(WholeProgramAnalysis &&) = delete; - - ~WholeProgramAnalysis() { - if (OwnsConfig) { - delete Config; - Config = nullptr; - } - } - - void solve() { DataFlowSolver.solve(); } - - void operator()() { solve(); } - - void dumpResults(llvm::raw_ostream &OS = llvm::outs()) { - DataFlowSolver.dumpResults(OS); - } - - void emitTextReport(llvm::raw_ostream &OS = llvm::outs()) { - DataFlowSolver.emitTextReport(OS); - } - - void emitGraphicalReport(llvm::raw_ostream &OS = llvm::outs()) { - DataFlowSolver.emitGraphicalReport(OS); - } - - void emitESG(llvm::raw_ostream &OS = llvm::outs()) { - // if (std::is_base_of_v) { - // DataFlowSolver.emitESGAsDot(OS); - // } - } - - void releaseAllHelperAnalyses() { - releasePointerInformation(); - releaseCallGraph(); - releaseTypeHierarchy(); - } - - PointerAnalysisTy *releasePointerInformation() { - return PointerInfo.release(); - } - - CallGraphAnalysisTy *releaseCallGraph() { return CallGraph.release(); } - - TypeHierarchyTy *releaseTypeHierarchy() { return TypeHierarchy.release(); } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/BiDiICFG.h b/include/phasar/PhasarLLVM/ControlFlow/BiDiICFG.h deleted file mode 100644 index e3af7a661..000000000 --- a/include/phasar/PhasarLLVM/ControlFlow/BiDiICFG.h +++ /dev/null @@ -1,61 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * BiDiICFG.h - * - * Created on: 15.09.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_BIDIICFG_H_ -#define PHASAR_PHASARLLVM_CONTROLFLOW_BIDIICFG_H_ - -#include - -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" - -namespace psr { - -template class BiDiICFG : public ICFG { -public: - virtual ~BiDiICFG() = default; - - virtual std::vector getPredsOf(N U) = 0; - - virtual std::set getEndPointsOf(F Func) = 0; - - virtual std::vector getPredsOfCallAt(N U) = 0; - - virtual std::set allNonCallEndNodes() = 0; - - // also exposed to some clients who need it - // virtual DirectedGraph getOrCreateUnitGraph(F body) = 0; - - virtual std::vector getParameterRefs(F Func) = 0; - - /** - * Gets whether the given statement is a return site of at least one call - * @param n The statement to check - * @return True if the given statement is a return site, otherwise false - */ - virtual bool isReturnSite(N U) = 0; - - /** - * Checks whether the given statement is reachable from the entry point - * @param u The statement to check - * @return True if there is a control flow path from the entry point of the - * program to the given statement, otherwise false - */ - virtual bool isReachable(N U) = 0; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/CFG.h b/include/phasar/PhasarLLVM/ControlFlow/CFG.h deleted file mode 100644 index dfe42fb2a..000000000 --- a/include/phasar/PhasarLLVM/ControlFlow/CFG.h +++ /dev/null @@ -1,97 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * CFG.h - * - * Created on: 07.06.2017 - * Author: philipp - */ - -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_CFG_H_ -#define PHASAR_PHASARLLVM_CONTROLFLOW_CFG_H_ - -#include -#include -#include -#include - -#include "nlohmann/json.hpp" - -namespace llvm { -class raw_ostream; -} - -namespace psr { - -enum class SpecialMemberFunctionType { -#define SPECIAL_MEMBER_FUNCTION_TYPES(NAME, TYPE) TYPE, -#include "phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def" -}; - -std::string toString(const SpecialMemberFunctionType &SMFT); - -SpecialMemberFunctionType toSpecialMemberFunctionType(const std::string &SMFT); - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const SpecialMemberFunctionType &SMFT); - -template class CFG { -public: - virtual ~CFG() = default; - - virtual F getFunctionOf(N Inst) const = 0; - - virtual std::vector getPredsOf(N Inst) const = 0; - - virtual std::vector getSuccsOf(N Inst) const = 0; - - virtual std::vector> getAllControlFlowEdges(F Fun) const = 0; - - virtual std::vector getAllInstructionsOf(F Fun) const = 0; - - virtual std::set getStartPointsOf(F Fun) const = 0; - - virtual std::set getExitPointsOf(F Fun) const = 0; - - virtual bool isCallSite(N Inst) const = 0; - - virtual bool isExitInst(N Inst) const = 0; - - virtual bool isStartPoint(N Inst) const = 0; - - virtual bool isFieldLoad(N Inst) const = 0; - - virtual bool isFieldStore(N Inst) const = 0; - - virtual bool isFallThroughSuccessor(N Inst, N Succ) const = 0; - - virtual bool isBranchTarget(N Inst, N Succ) const = 0; - - virtual bool isHeapAllocatingFunction(F Fun) const = 0; - - virtual bool isSpecialMemberFunction(F Fun) const = 0; - - virtual SpecialMemberFunctionType - getSpecialMemberFunctionType(F Fun) const = 0; - - virtual std::string getStatementId(N Inst) const = 0; - - virtual std::string getFunctionName(F Fun) const = 0; - - virtual std::string getDemangledFunctionName(F Fun) const = 0; - - virtual void print(F Fun, llvm::raw_ostream &OS) const = 0; - - virtual nlohmann::json getAsJson(F Fun) const = 0; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/CFGBase.h b/include/phasar/PhasarLLVM/ControlFlow/CFGBase.h new file mode 100644 index 000000000..a3e707e3b --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/CFGBase.h @@ -0,0 +1,153 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H +#define PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H + +#include "phasar/PhasarLLVM/Utils/ByRef.h" +#include "phasar/Utils/TypeTraits.h" + +#include "nlohmann/json.hpp" + +namespace psr { + +enum class SpecialMemberFunctionType; + +template struct CFGTraits { + // using n_t + // using f_t +}; + +template class CFGBase { +public: + using n_t = typename CFGTraits::n_t; + using f_t = typename CFGTraits::f_t; + + /// Returns the function where the given instruction is defined + [[nodiscard]] f_t getFunctionOf(ByConstRef Inst) const noexcept { + return self().getFunctionOfImpl(Inst); + } + /// Returns an iterable range of all predecessor instructions of Inst in the + /// CFG + [[nodiscard]] decltype(auto) getPredsOf(ByConstRef Inst) const { + static_assert( + is_iterable_over_v); + return self().getPredsOfImpl(Inst); + } + /// Returns an iterable range of all successor instructions of Inst in the + /// CFG. NOTE: This function is typically being called in a hot part of the + /// analysis and should therefore be highly optimized for performance + [[nodiscard]] decltype(auto) getSuccsOf(ByConstRef Inst) const { + static_assert( + is_iterable_over_v); + return self().getSuccsOfImpl(Inst); + } + /// Returns an iterable range of all edges in the CFG of the given function + [[nodiscard]] decltype(auto) + getAllControlFlowEdges(ByConstRef Fun) const { + static_assert( + is_iterable_over_v>); + return self().getAllControlFlowEdgesImpl(Fun); + } + /// Returns an iterable range of all instructions of the given function. NOTE: + /// even if the CFG is initialized to ignore debugging instructions, they may + /// be contained here. + [[nodiscard]] decltype(auto) getAllInstructionsOf(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getAllInstructionsOfImpl(Fun); + } + /// Returns an iterable range of all starting instructions of the given + /// function. For a forward-CFG, this is typically a singleton range + [[nodiscard]] decltype(auto) getStartPointsOf(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getStartPointsOfImpl(Fun); + } + /// Returns an iterable range of all exit instructions (often return + /// instructions) of the given function. For a backward-CFG, this is typically + /// a singleton range + [[nodiscard]] decltype(auto) getExitPointsOf(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getExitPointsOfImpl(Fun); + } + [[nodiscard]] bool isCallSite(ByConstRef Inst) const noexcept { + return self().isCallSiteImpl(Inst); + } + [[nodiscard]] bool isExitInst(ByConstRef Inst) const noexcept { + return self().isExitInstImpl(Inst); + } + [[nodiscard]] bool isStartPoint(ByConstRef Inst) const noexcept { + return self().isStartPointImpl(Inst); + } + [[nodiscard]] bool isFieldLoad(ByConstRef Inst) const noexcept { + return self().isFieldLoadImpl(Inst); + } + [[nodiscard]] bool isFieldStore(ByConstRef Inst) const noexcept { + return self().isFieldStoreImpl(Inst); + } + [[nodiscard]] bool + isFallThroughSuccessor(ByConstRef Inst, + ByConstRef Succ) const noexcept { + return self().isFallThroughSuccessorImpl(Inst, Succ); + } + [[nodiscard]] bool isBranchTarget(ByConstRef Inst, + ByConstRef Succ) const noexcept { + return self().isBranchTargetImpl(Inst, Succ); + } + [[nodiscard]] bool isHeapAllocatingFunction(ByConstRef Fun) const { + return self().isHeapAllocatingFunctionImpl(Fun); + } + [[nodiscard]] bool isSpecialMemberFunction(ByConstRef Fun) const { + return self().isSpecialMemberFunctionImpl(Fun); + } + [[nodiscard]] SpecialMemberFunctionType + getSpecialMemberFunctionType(ByConstRef Fun) const { + return self().getSpecialMemberFunctionTypeImpl(Fun); + } + [[nodiscard]] decltype(auto) getStatementId(ByConstRef Inst) const { + static_assert(is_string_like_v); + return self().getStatementIdImpl(Inst); + } + [[nodiscard]] decltype(auto) getFunctionName(ByConstRef Fun) const { + static_assert(is_string_like_v); + return self().getFunctionNameImpl(Fun); + } + [[nodiscard]] decltype(auto) + getDemangledFunctionName(ByConstRef Fun) const { + static_assert( + is_string_like_v); + return self().getDemangledFunctionNameImpl(Fun); + } + void print(ByConstRef Fun, llvm::raw_ostream &OS) const { + self().printImpl(Fun, OS); + } + [[nodiscard]] nlohmann::json getAsJson(ByConstRef Fun) const { + return self().getAsJsonImpl(Fun); + } + +private: + Derived &self() noexcept { return static_cast(*this); } + const Derived &self() const noexcept { + return static_cast(*this); + } +}; + +template +// NOLINTNEXTLINE(readability-identifier-naming) +constexpr bool is_cfg_v = is_crtp_base_of_v + &&std::is_same_v + &&std::is_same_v; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H diff --git a/include/phasar/PhasarLLVM/ControlFlow/ICFG.h b/include/phasar/PhasarLLVM/ControlFlow/ICFG.h deleted file mode 100644 index c5dc3b01b..000000000 --- a/include/phasar/PhasarLLVM/ControlFlow/ICFG.h +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * ICFG.h - * - * Created on: 17.08.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_ICFG_H_ -#define PHASAR_PHASARLLVM_CONTROLFLOW_ICFG_H_ - -#include -#include -#include -#include - -#include "llvm/ADT/DenseMap.h" -#include "llvm/Support/raw_ostream.h" - -#include "nlohmann/json.hpp" - -#include "phasar/PhasarLLVM/ControlFlow/CFG.h" - -namespace psr { - -enum class CallGraphAnalysisType { -#define ANALYSIS_SETUP_CALLGRAPH_TYPE(NAME, CMDFLAG, TYPE) TYPE, -#include "phasar/PhasarLLVM/Utils/AnalysisSetups.def" - Invalid -}; - -std::string toString(const CallGraphAnalysisType &CGA); - -CallGraphAnalysisType toCallGraphAnalysisType(const std::string &S); - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const CallGraphAnalysisType &CGA); - -template class ICFG : public virtual CFG { - -protected: - std::vector GlobalInitializers; - - virtual void collectGlobalCtors() = 0; - - virtual void collectGlobalDtors() = 0; - - virtual void collectGlobalInitializers() = 0; - - virtual void collectRegisteredDtors() = 0; - -public: - ~ICFG() override = default; - - [[nodiscard]] virtual std::set getAllFunctions() const = 0; - - [[nodiscard]] virtual F getFunction(const std::string &Fun) const = 0; - - [[nodiscard]] virtual bool isIndirectFunctionCall(N Stmt) const = 0; - - [[nodiscard]] virtual bool isVirtualFunctionCall(N Stmt) const = 0; - - [[nodiscard]] virtual std::set allNonCallStartNodes() const = 0; - - [[nodiscard]] virtual std::set getCalleesOfCallAt(N Stmt) const = 0; - - [[nodiscard]] virtual std::set getCallersOf(F Fun) const = 0; - - [[nodiscard]] virtual std::set getCallsFromWithin(F Fun) const = 0; - - [[nodiscard]] virtual std::set getReturnSitesOfCallAt(N Stmt) const = 0; - - [[nodiscard]] const std::vector &getGlobalInitializers() const { - return GlobalInitializers; - } - - using CFG::print; // tell the compiler we wish to have both prints - virtual void print(llvm::raw_ostream &OS = llvm::outs()) const = 0; - - using CFG::getAsJson; // tell the compiler we wish to have both prints - [[nodiscard]] virtual nlohmann::json getAsJson() const = 0; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/ICFGBase.h b/include/phasar/PhasarLLVM/ControlFlow/ICFGBase.h new file mode 100644 index 000000000..680a4e393 --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/ICFGBase.h @@ -0,0 +1,133 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H +#define PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H + +#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" +#include "phasar/Utils/TypeTraits.h" + +#include "nlohmann/json.hpp" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { +template class ICFGBase { +public: + using n_t = typename CFGTraits::n_t; + using f_t = typename CFGTraits::f_t; + + ICFGBase() noexcept { + static_assert(is_crtp_base_of_v, + "An ICFG must also be a CFG"); + } + + /// Returns an iterable range of all function definitions or declarations in + /// the ICFG + [[nodiscard]] decltype(auto) getAllFunctions() const { + return self().getAllFunctionsImpl(); + } + + /// returns the function definition or declaration with the given name. If + /// ther eis no such function, returns a default constructed f_t (nullptr for + /// pointers). + [[nodiscard]] f_t getFunction(llvm::StringRef Fun) const { + return self().getFunctionImpl(Fun); + } + + /// Returns true, iff the given instruction is a call-site where the callee is + /// called via a function-pointer or another kind of virtual call. + /// NOTE: Trivial cases where a bitcast of a function is called may still + /// count as indirect call. + [[nodiscard]] bool isIndirectFunctionCall(ByConstRef Inst) const { + return self().isIndirectFunctionCallImpl(Inst); + } + /// Returns true, iff the given instruction is a call-site where the callee is + /// called via virtual dispatch. NOTE: Here, a class-hierarchy is required and + /// a simple function-pointer is not sufficient. + [[nodiscard]] bool isVirtualFunctionCall(ByConstRef Inst) const { + return self().isVirtualFunctionCallImpl(Inst); + } + /// Returns an iterable range of all instructions in all functions of the ICFG + /// that are neither call-sites nor start-points of a function + [[nodiscard]] decltype(auto) allNonCallStartNodes() const { + static_assert( + is_iterable_over_v); + return self().allNonCallStartNodesImpl(); + } + /// Returns an iterable range of all possible callee candidates at the given + /// call-site induced by the used call-graph. NOTE: This function is typically + /// called in a hot part of the analysis and should therefore be very fast + [[nodiscard]] decltype(auto) getCalleesOfCallAt(ByConstRef Inst) const { + static_assert( + is_iterable_over_v); + return self().getCalleesOfCallAtImpl(Inst); + } + /// Returns an iterable range of all possible call-site candidates that may + /// call the given function induced by the used call-graph. + [[nodiscard]] decltype(auto) getCallersOf(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getCallersOfImpl(Fun); + } + /// Returns an iterable range of all call-instruction in the given function + [[nodiscard]] decltype(auto) getCallsFromWithin(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getCallsFromWithinImpl(Fun); + } + /// Returns an iterable range of all return-sites of the given + /// call-instruction. Often the same as getSuccsOf. NOTE: This function is + /// typically called in a hot part of the analysis and should therefore be + /// very fast + [[nodiscard]] decltype(auto) + getReturnSitesOfCallAt(ByConstRef Inst) const { + static_assert( + is_iterable_over_v); + return self().getReturnSitesOfCallAtImpl(Inst); + } + /// Returns an iterable range of all global initializer functions + [[nodiscard]] decltype(auto) + getGlobalInitializers(ByConstRef Fun) const { + static_assert( + is_iterable_over_v); + return self().getGlobalInitializersImpl(Fun); + } + /// Prints the underlying call-graph as DOT to the given output-stream + void print(llvm::raw_ostream &OS = llvm::outs()) const { + self().printImpl(OS); + } + /// Returns the underlying call-graph as JSON + [[nodiscard]] nlohmann::json getAsJson() const { + return self().getAsJsonImpl(); + } + +private: + Derived &self() noexcept { return static_cast(*this); } + const Derived &self() const noexcept { + return static_cast(*this); + } +}; + +/// True, iff ICF is a proper instantiation of ICFGBase with n_t and f_t taken +/// from the given analysis-Domain +template +// NOLINTNEXTLINE(readability-identifier-naming) +constexpr bool is_icfg_v = is_crtp_base_of_v + &&std::is_same_v + &&std::is_same_v; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h index b10641351..9792fca22 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h @@ -1,26 +1,16 @@ /****************************************************************************** - * Copyright (c) 2017 Philipp Schubert. + * Copyright (c) 2022 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 + * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -/* - * LLVMBasedBackwardCFG.h - * - * Created on: 07.06.2017 - * Author: philipp - */ - #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDCFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDCFG_H_ -#include -#include -#include - +#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" namespace llvm { @@ -30,36 +20,43 @@ class Instruction; namespace psr { -class LLVMBasedBackwardCFG : public LLVMBasedCFG { -public: - LLVMBasedBackwardCFG() = default; - - ~LLVMBasedBackwardCFG() override = default; - - [[nodiscard]] std::vector - getPredsOf(const llvm::Instruction *Inst) const override; +class LLVMProjectIRDB; +class LLVMBasedBackwardCFG; - [[nodiscard]] std::vector - getSuccsOf(const llvm::Instruction *Inst) const override; +class LLVMBasedBackwardCFG + : public detail::LLVMBasedCFGImpl { + friend CFGBase; - [[nodiscard]] std::set - getStartPointsOf(const llvm::Function *Fun) const override; + using base_t = detail::LLVMBasedCFGImpl; - [[nodiscard]] std::set - getExitPointsOf(const llvm::Function *Fun) const override; - - [[nodiscard]] bool isExitInst(const llvm::Instruction *Inst) const override; - - [[nodiscard]] bool isStartPoint(const llvm::Instruction *Inst) const override; - - [[nodiscard]] bool - isFallThroughSuccessor(const llvm::Instruction *Inst, - const llvm::Instruction *Succ) const override; - - [[nodiscard]] bool - isBranchTarget(const llvm::Instruction *Inst, - const llvm::Instruction *Succ) const override; +public: + LLVMBasedBackwardCFG(bool IgnoreDbgInstructions = true) noexcept; + LLVMBasedBackwardCFG(const LLVMProjectIRDB &IRDB, + bool IgnoreDbgInstructions = true); + +private: + [[nodiscard]] f_t getFunctionOfImpl(n_t Inst) const noexcept; + [[nodiscard]] llvm::SmallVector getPredsOfImpl(n_t Inst) const; + [[nodiscard]] llvm::SmallVector getSuccsOfImpl(n_t Inst) const; + [[nodiscard]] std::vector> + getAllControlFlowEdgesImpl(f_t Fun) const; + + [[nodiscard]] llvm::SmallVector getStartPointsOfImpl(f_t Fun) const; + [[nodiscard]] llvm::SmallVector getExitPointsOfImpl(f_t Fun) const; + + [[nodiscard]] bool isExitInstImpl(n_t Inst) const noexcept; + [[nodiscard]] bool isStartPointImpl(n_t Inst) const noexcept; + + [[nodiscard]] bool isFallThroughSuccessorImpl(n_t Inst, + n_t Succ) const noexcept; + [[nodiscard]] bool isBranchTargetImpl(n_t Inst, n_t Succ) const noexcept; + + llvm::DenseMap + BackwardRets; + llvm::DenseMap + BackwardRetToFunction; }; + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h index 2fc0f8158..61571a8d1 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h @@ -1,140 +1,73 @@ /****************************************************************************** - * Copyright (c) 2017 Philipp Schubert. + * Copyright (c) 2022 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 + * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDICFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDICFG_H_ -#include -#include -#include -#include -#include -#include -#include - -#include "llvm/IR/LLVMContext.h" - -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" +#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h" -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/Utils/Soundness.h" +#include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" -namespace llvm { -class Instruction; -class Function; -class Module; -class Instruction; -class BitCastInst; -} // namespace llvm +#include "llvm/IR/LLVMContext.h" namespace psr { -class Resolver; -class ProjectIRDB; -class LLVMTypeHierarchy; -class LLVMPointsToGraph; +class LLVMBasedICFG; -class LLVMBasedBackwardsICFG - : public ICFG, - public virtual LLVMBasedBackwardCFG { -private: - LLVMBasedICFG &ForwardICFG; - static inline const std::unique_ptr LLVMBackwardRetCTX = - std::make_unique(); +class LLVMBasedBackwardICFG : public LLVMBasedBackwardCFG, + public ICFGBase { + friend ICFGBase; class LLVMBackwardRet { private: - const llvm::ReturnInst *Instance; + const llvm::ReturnInst *Instance = nullptr; public: - LLVMBackwardRet() - : Instance(llvm::ReturnInst::Create(*LLVMBackwardRetCTX)){}; - [[nodiscard]] const llvm::ReturnInst *getInstance() const { + LLVMBackwardRet(llvm::LLVMContext &Ctx) + : Instance(llvm::ReturnInst::Create(Ctx)){}; + [[nodiscard]] const llvm::ReturnInst *getInstance() const noexcept { return Instance; } }; - std::unordered_map BackwardRets; - llvm::DenseMap - BackwardRetToFunction; - -public: - LLVMBasedBackwardsICFG(LLVMBasedICFG &ICFG); - - ~LLVMBasedBackwardsICFG() override = default; - - std::set getAllFunctions() const override; - - bool isIndirectFunctionCall(const llvm::Instruction *Stmt) const override; - - bool isVirtualFunctionCall(const llvm::Instruction *Stmt) const override; - - const llvm::Function *getFunction(const std::string &Fun) const override; - - std::set - getCalleesOfCallAt(const llvm::Instruction *N) const override; - - std::set - getCallersOf(const llvm::Function *M) const override; - - std::set - getCallsFromWithin(const llvm::Function *M) const override; - - std::set - getReturnSitesOfCallAt(const llvm::Instruction *N) const override; - std::set allNonCallStartNodes() const override; + using CFGBase::print; + using ICFGBase::print; - [[nodiscard]] const llvm::Function * - getFunctionOf(const llvm::Instruction *Stmt) const override; + using CFGBase::getAsJson; + using ICFGBase::getAsJson; - [[nodiscard]] std::vector - getPredsOf(const llvm::Instruction *Stmt) const override; - - [[nodiscard]] std::vector - getSuccsOf(const llvm::Instruction *Stmt) const override; - - [[nodiscard]] std::set - getExitPointsOf(const llvm::Function *Fun) const override; - - [[nodiscard]] bool isExitInst(const llvm::Instruction *Stmt) const override; - - void mergeWith(const LLVMBasedBackwardsICFG &Other); - - using LLVMBasedBackwardCFG::print; // tell the compiler we wish to have both - // prints - void print(llvm::raw_ostream &OS) const override; - - void printAsDot(llvm::raw_ostream &OS) const; - - using LLVMBasedBackwardCFG::getAsJson; // tell the compiler we wish to have - // both prints - nlohmann::json getAsJson() const override; - - unsigned getNumOfVertices(); - - unsigned getNumOfEdges(); - - std::vector getDependencyOrderedFunctions(); +public: + LLVMBasedBackwardICFG(LLVMBasedICFG *ForwardICFG); private: - void createBackwardRets(); - -protected: - void collectGlobalCtors() override; - - void collectGlobalDtors() override; - - void collectGlobalInitializers() override; + [[nodiscard]] FunctionRange getAllFunctionsImpl() const; + [[nodiscard]] f_t getFunctionImpl(llvm::StringRef Fun) const; + + [[nodiscard]] bool isIndirectFunctionCallImpl(n_t Inst) const; + [[nodiscard]] bool isVirtualFunctionCallImpl(n_t Inst) const; + [[nodiscard]] std::vector allNonCallStartNodesImpl() const; + [[nodiscard]] llvm::ArrayRef + getCalleesOfCallAtImpl(n_t Inst) const noexcept; + [[nodiscard]] llvm::ArrayRef getCallersOfImpl(f_t Fun) const noexcept; + [[nodiscard]] llvm::SmallVector getCallsFromWithinImpl(f_t Fun) const; + [[nodiscard]] llvm::SmallVector + getReturnSitesOfCallAtImpl(n_t Inst) const; + void printImpl(llvm::raw_ostream &OS) const; + [[nodiscard]] nlohmann::json getAsJsonImpl() const; + + llvm::LLVMContext BackwardRetsCtx; + llvm::DenseMap BackwardRets; + llvm::DenseMap + BackwardRetToFunction; - void collectRegisteredDtors() override; + LLVMBasedICFG *ForwardICFG{}; }; - } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBiDiICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBiDiICFG.h deleted file mode 100644 index f9ff3b729..000000000 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBiDiICFG.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBIDIICFG_H_ -#define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBIDIICFG_H_ - -#endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h index a26c694aa..d1d195433 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h @@ -1,133 +1,115 @@ /****************************************************************************** - * Copyright (c) 2017 Philipp Schubert. + * Copyright (c) 2022 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 + * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -/* - * LLVMBasedCFG.h - * - * Created on: 07.06.2017 - * Author: philipp - */ - #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDCFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDCFG_H_ -#include -#include -#include - -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Function.h" - -#include "phasar/PhasarLLVM/ControlFlow/CFG.h" -#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" #include "nlohmann/json.hpp" -namespace psr { - -class LLVMBasedCFG - : public virtual CFG { -public: - LLVMBasedCFG(bool IgnoreDbgInstructions = true) - : IgnoreDbgInstructions(IgnoreDbgInstructions) {} - - ~LLVMBasedCFG() override = default; - - [[nodiscard]] const llvm::Function * - getFunctionOf(const llvm::Instruction *Inst) const override; - - [[nodiscard]] std::vector - getPredsOf(const llvm::Instruction *Inst) const override; - - [[nodiscard]] std::vector - getSuccsOf(const llvm::Instruction *Inst) const override; - - [[nodiscard]] std::vector< - std::pair> - getAllControlFlowEdges(const llvm::Function *Fun) const override; - - [[nodiscard]] std::vector - getAllInstructionsOf(const llvm::Function *Fun) const override; - - [[nodiscard]] std::set - getStartPointsOf(const llvm::Function *Fun) const override; - - [[nodiscard]] std::set - getExitPointsOf(const llvm::Function *Fun) const override; +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instructions.h" - [[nodiscard]] bool isCallSite(const llvm::Instruction *Inst) const override; +namespace llvm { +class Function; +} // namespace llvm - [[nodiscard]] bool isExitInst(const llvm::Instruction *Inst) const override; - - [[nodiscard]] bool isStartPoint(const llvm::Instruction *Inst) const override; +namespace psr { +class LLVMBasedCFG; +class LLVMBasedBackwardCFG; - [[nodiscard]] bool isFieldLoad(const llvm::Instruction *Inst) const override; +template <> struct CFGTraits { + using n_t = const llvm::Instruction *; + using f_t = const llvm::Function *; +}; - [[nodiscard]] bool isFieldStore(const llvm::Instruction *Inst) const override; +template <> struct CFGTraits : CFGTraits {}; - [[nodiscard]] bool - isFallThroughSuccessor(const llvm::Instruction *Inst, - const llvm::Instruction *Succ) const override; +namespace detail { +template class LLVMBasedCFGImpl : public CFGBase { + friend CFGBase; + friend class LLVMBasedBackwardCFG; - [[nodiscard]] bool - isBranchTarget(const llvm::Instruction *Inst, - const llvm::Instruction *Succ) const override; +public: + using typename CFGBase::n_t; + using typename CFGBase::f_t; - [[nodiscard]] bool - isHeapAllocatingFunction(const llvm::Function *Fun) const override; + [[nodiscard]] bool getIgnoreDbgInstructions() const noexcept { + return IgnoreDbgInstructions; + } - [[nodiscard]] bool - isSpecialMemberFunction(const llvm::Function *Fun) const override; +protected: + LLVMBasedCFGImpl(bool IgnoreDbgInstructions = true) noexcept + : IgnoreDbgInstructions(IgnoreDbgInstructions) {} + bool IgnoreDbgInstructions = false; + + [[nodiscard]] f_t getFunctionOfImpl(n_t Inst) const noexcept; + [[nodiscard]] llvm::SmallVector getPredsOfImpl(n_t Inst) const; + [[nodiscard]] llvm::SmallVector getSuccsOfImpl(n_t Inst) const; + [[nodiscard]] std::vector> + getAllControlFlowEdgesImpl(f_t Fun) const; + [[nodiscard]] auto getAllInstructionsOfImpl(f_t Fun) const { + return llvm::map_range(llvm::instructions(Fun), + [](const llvm::Instruction &Inst) { return &Inst; }); + } + [[nodiscard]] llvm::SmallVector getStartPointsOfImpl(f_t Fun) const; + [[nodiscard]] llvm::SmallVector getExitPointsOfImpl(f_t Fun) const; + [[nodiscard]] bool isCallSiteImpl(n_t Inst) const noexcept { + return llvm::isa(Inst); + } + [[nodiscard]] bool isExitInstImpl(n_t Inst) const noexcept { + return llvm::isa(Inst); + } + [[nodiscard]] bool isStartPointImpl(n_t Inst) const noexcept; + [[nodiscard]] bool isFieldLoadImpl(n_t Inst) const noexcept; + [[nodiscard]] bool isFieldStoreImpl(n_t Inst) const noexcept; + [[nodiscard]] bool isFallThroughSuccessorImpl(n_t Inst, + n_t Succ) const noexcept; + [[nodiscard]] bool isBranchTargetImpl(n_t Inst, n_t Succ) const noexcept; + [[nodiscard]] bool isHeapAllocatingFunctionImpl(f_t Fun) const; + [[nodiscard]] bool isSpecialMemberFunctionImpl(f_t Fun) const { + return this->getSpecialMemberFunctionType(Fun) != + SpecialMemberFunctionType{}; + } [[nodiscard]] SpecialMemberFunctionType - getSpecialMemberFunctionType(const llvm::Function *Fun) const override; - - [[nodiscard]] std::string - getStatementId(const llvm::Instruction *Inst) const override; - - [[nodiscard]] std::string - getFunctionName(const llvm::Function *Fun) const override; - - [[nodiscard]] std::string - getDemangledFunctionName(const llvm::Function *Fun) const override; + getSpecialMemberFunctionTypeImpl(f_t Fun) const; + [[nodiscard]] std::string getStatementIdImpl(n_t Inst) const; + [[nodiscard]] auto getFunctionNameImpl(f_t Fun) const { + return Fun->getName(); + } + [[nodiscard]] std::string getDemangledFunctionNameImpl(f_t Fun) const; + void printImpl(f_t Fun, llvm::raw_ostream &OS) const { OS << *Fun; } + [[nodiscard]] nlohmann::json getAsJsonImpl(f_t /*Fun*/) const { return ""; } +}; +} // namespace detail - void print(const llvm::Function *Fun, - llvm::raw_ostream &OS = llvm::outs()) const override; +class LLVMBasedCFG : public detail::LLVMBasedCFGImpl { + friend CFGBase; + friend class LLVMBasedBackwardCFG; - [[nodiscard]] nlohmann::json - getAsJson(const llvm::Function *Fun) const override; +public: + LLVMBasedCFG(bool IgnoreDbgInstructions = true) noexcept + : detail::LLVMBasedCFGImpl(IgnoreDbgInstructions) {} [[nodiscard]] nlohmann::json exportCFGAsJson(const llvm::Function *F) const; - [[nodiscard]] nlohmann::json exportCFGAsSourceCodeJson(const llvm::Function *F) const; - -protected: - // Ignores debug instructions in control flow if set to true. - const bool IgnoreDbgInstructions; - - struct SourceCodeInfoWithIR : public SourceCodeInfo { - std::string IR; - }; - - friend void from_json(const nlohmann::json &J, // NOLINT - SourceCodeInfoWithIR &Info); - friend void to_json(nlohmann::json &J, // NOLINT - const SourceCodeInfoWithIR &Info); - - /// Used by export(I)CFGAsJson - static SourceCodeInfoWithIR - getFirstNonEmpty(llvm::BasicBlock::const_iterator &It, - llvm::BasicBlock::const_iterator End); - static SourceCodeInfoWithIR getFirstNonEmpty(const llvm::BasicBlock *BB); }; +extern template class detail::LLVMBasedCFGImpl; +extern template class detail::LLVMBasedCFGImpl; + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index 784fd3d26..3c7182f86 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -17,329 +17,164 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDICFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDICFG_H_ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "boost/container/flat_set.hpp" -#include "boost/graph/adjacency_list.hpp" - -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Module.h" - -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" +#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" +#include "phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h" +#include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" +#include "phasar/Utils/MaybeUniquePtr.h" #include "phasar/Utils/Soundness.h" -namespace llvm { -class Instruction; -class Function; -class Module; -class Instruction; -class BitCastInst; -} // namespace llvm +#include "nlohmann/json.hpp" -namespace psr { +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/raw_ostream.h" + +#include -class Resolver; -class ProjectIRDB; +#include "phasar/Utils/MemoryResource.h" + +/// On some MAC systems, is still not fully implemented, so do +/// a workaround here + +#if HAS_MEMORY_RESOURCE +#include +#else +#include "llvm/Support/Allocator.h" +#endif + +namespace psr { +class LLVMPointsToInfo; class LLVMTypeHierarchy; +class LLVMPointsToInfo; +class LLVMProjectIRDB; -class LLVMBasedICFG - : public ICFG, - public virtual LLVMBasedCFG { - friend class LLVMBasedBackwardsICFG; +class LLVMBasedICFG; +template <> struct CFGTraits : CFGTraits {}; - using GlobalCtorTy = std::multimap; - using GlobalDtorTy = std::multimap>; +class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { + friend ICFGBase; -private: - ProjectIRDB &IRDB; - CallGraphAnalysisType CGType; - Soundness S; - bool UserTHInfos = true; - bool UserPTInfos = true; - LLVMTypeHierarchy *TH; - LLVMPointsToInfo *PT; - std::unique_ptr Res; - llvm::DenseSet VisitedFunctions; - std::unordered_set UserEntryPoints; - - GlobalCtorTy GlobalCtors; - GlobalDtorTy GlobalDtors; - - llvm::Function *GlobalCleanupFn = nullptr; - - llvm::SmallDenseMap - GlobalRegisteredDtorsCaller; - - // The worklist for direct callee resolution. - std::vector FunctionWL; - - // Map indirect calls to the number of possible targets found for it. Fixpoint - // is not reached when more targets are found. - llvm::DenseMap IndirectCalls; - // The VertexProperties for our call-graph. - struct VertexProperties { - const llvm::Function *F = nullptr; - VertexProperties() = default; - VertexProperties(const llvm::Function *F); - [[nodiscard]] std::string getFunctionName() const; - }; + struct Builder; - // The EdgeProperties for our call-graph. - struct EdgeProperties { - const llvm::Instruction *CS = nullptr; - size_t ID = 0; - EdgeProperties() = default; - EdgeProperties(const llvm::Instruction *I); - [[nodiscard]] std::string getCallSiteAsString() const; + struct OnlyDestroyDeleter { + template void operator()(T *Data) { std::destroy_at(Data); } }; - /// Specify the type of graph to be used. - using bidigraph_t = - boost::adjacency_list; - - // Let us have some handy typedefs. - using vertex_t = boost::graph_traits::vertex_descriptor; - using vertex_iterator = boost::graph_traits::vertex_iterator; - using edge_t = boost::graph_traits::edge_descriptor; - using out_edge_iterator = boost::graph_traits::out_edge_iterator; - using in_edge_iterator = boost::graph_traits::in_edge_iterator; - - /// The call graph. - bidigraph_t CallGraph; - - /// Maps functions to the corresponding vertex id. - std::unordered_map FunctionVertexMap; - - void processFunction(const llvm::Function *F, Resolver &Resolver, - bool &FixpointReached); - - bool constructDynamicCall(const llvm::Instruction *I, Resolver &Resolver); - - std::unique_ptr - makeResolver(ProjectIRDB &IRDB, LLVMTypeHierarchy &TH, LLVMPointsToInfo &PT); - - template - static void insertGlobalCtorsDtorsImpl(MapTy &Into, const llvm::Module *M, - llvm::StringRef Fun) { - const auto *Gtors = M->getGlobalVariable(Fun); - if (Gtors == nullptr) { - return; - } - - if (const auto *FunArray = llvm::dyn_cast( - Gtors->getType()->getPointerElementType())) { - if (const auto *ConstFunArray = - llvm::dyn_cast(Gtors->getInitializer())) { - for (const auto &Op : ConstFunArray->operands()) { - if (const auto *FunDesc = llvm::dyn_cast(Op)) { - auto *Fun = llvm::dyn_cast(FunDesc->getOperand(1)); - const auto *Prio = - llvm::dyn_cast(FunDesc->getOperand(0)); - if (Fun && Prio) { - auto PrioInt = size_t(Prio->getLimitedValue(SIZE_MAX)); - Into.emplace(PrioInt, Fun); - } - } - } - } - } - } - - llvm::Function *buildCRuntimeGlobalDtorsModel(llvm::Module &M); - const llvm::Function *buildCRuntimeGlobalCtorsDtorsModel(llvm::Module &M); - - struct dependency_visitor; - public: static constexpr llvm::StringLiteral GlobalCRuntimeModelName = "__psrCRuntimeGlobalCtorsModel"; - /** - * Why a multimap? A given instruction might have multiple target functions. - * For example, if the points-to analysis indicates that a pointer could - * be for multiple different types. - */ - using OutEdgesAndTargets = std::unordered_multimap; - - LLVMBasedICFG(ProjectIRDB &IRDB, CallGraphAnalysisType CGType, - const std::set &EntryPoints = {}, - LLVMTypeHierarchy *TH = nullptr, LLVMPointsToInfo *PT = nullptr, - Soundness S = Soundness::Soundy, bool IncludeGlobals = true); - - LLVMBasedICFG(const LLVMBasedICFG &ICF); - - LLVMBasedICFG &operator=(const LLVMBasedICFG &) = delete; - - ~LLVMBasedICFG() override; - - [[nodiscard]] const llvm::Function *getFirstGlobalCtorOrNull() const; - - [[nodiscard]] const llvm::Function *getLastGlobalDtorOrNull() const; - - /** - * \return all of the functions in the IRDB, this may include some not in the - * callgraph - */ - [[nodiscard]] std::set - getAllFunctions() const override; - - /** - * A boost flat_set is used here because we already have the functions in - * order, so building it is fast since we can always add to the end. We get - * the performance and space benefits of array-backed storage and all the - * functionality of a set. - * - * \return all of the functions which are represented by a vertex in the - * callgraph. - */ - [[nodiscard]] boost::container::flat_set - getAllVertexFunctions() const; - - bool isIndirectFunctionCall(const llvm::Instruction *N) const override; - - bool isVirtualFunctionCall(const llvm::Instruction *N) const override; - - [[nodiscard]] const llvm::Function * - getFunction(const std::string &Fun) const override; - - /** - * Essentially the same as `getCallsFromWithin`, but uses the callgraph - * data directly. - * \return all call sites within a given method. - */ - std::vector - getOutEdges(const llvm::Function *Fun) const; - - /** - * For the supplied function, get all the output edge Instructions and - * the corresponding Function. This pulls data directly from the callgraph. - * - * \return the edges and the target function for each edge. - */ - OutEdgesAndTargets getOutEdgeAndTarget(const llvm::Function *Fun) const; - - /** - * Removes all edges found for the given instruction within the - * sourceFunction. \return number of edges removed - */ - size_t removeEdges(const llvm::Function *F, const llvm::Instruction *Inst); - - /** - * Removes the vertex for the given function. - * CAUTION: does not remove edges, invoking this on a function with - * IN or OUT edges is a bad idea. - * \return true iff the vertex was found and removed. - */ - bool removeVertex(const llvm::Function *Fun); - - /** - * \return the total number of in edges to the vertex representing this - * Function. - */ - size_t getCallerCount(const llvm::Function *Fun) const; - - /** - * \return all callee methods for a given call that might be called. - */ - [[nodiscard]] std::set - getCalleesOfCallAt(const llvm::Instruction *N) const override; - - void forEachCalleeOfCallAt( - const llvm::Instruction *I, - llvm::function_ref Callback) const; - - /** - * \return all caller statements/nodes of a given method. - */ - [[nodiscard]] std::set - getCallersOf(const llvm::Function *Fun) const override; - - /** - * \return all call sites within a given method. - */ - [[nodiscard]] std::set - getCallsFromWithin(const llvm::Function *Fun) const override; - - [[nodiscard]] std::set - getReturnSitesOfCallAt(const llvm::Instruction *N) const override; - - [[nodiscard]] std::set - allNonCallStartNodes() const override; - - void mergeWith(const LLVMBasedICFG &Other); - - [[nodiscard]] CallGraphAnalysisType getCallGraphAnalysisType() const; - - using LLVMBasedCFG::print; // tell the compiler we wish to have both prints - void print(llvm::raw_ostream &OS = llvm::outs()) const override; - - void printAsDot(llvm::raw_ostream &OS = llvm::outs(), - bool PrintEdgeLabels = true) const; - - void printInternalPTGAsDot(llvm::raw_ostream &OS = llvm::outs()) const; - - using LLVMBasedCFG::getAsJson; // tell the compiler we wish to have both - // prints - [[nodiscard]] nlohmann::json getAsJson() const override; - - void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; - - /// Create an IR based JSON export of the whole ICFG. + /// Constructs the ICFG based on the given IRDB and the entry-points using a + /// fixpoint iteration. This may take a long time. /// - /// Note: The exported JSON contains a list of all edges in this ICFG - [[nodiscard]] nlohmann::json exportICFGAsJson() const; - - /// Create a JSON export of the whole ICFG similar to exportICFGAsJson() - /// enriched with source-code information on every edge and ignoring debug - /// instructions - [[nodiscard]] nlohmann::json exportICFGAsSourceCodeJson() const; + /// \param IRDB The IR code where the ICFG should be based on. Must not be + /// nullptr. + /// \param CGType The analysis kind to use for call-graph resolution + /// \param EntryPoints The names of the functions to start with when + /// incrementally building up the ICFG. For whole-program analysis of an + /// executable use {"main"}. + /// \param TH The type-hierarchy implementation to use. Will be constructed + /// on-the-fly if nullptr, but required + /// \param PT The points-to implementation to use. Will be constructed + /// on-the-fly if nullptr, but required + /// \param S The soundness level to expect from the analysis. Currently unused + /// \param IncludeGlobals Properly include global constructors/destructors + /// into the ICFG, if true. Requires to generate artificial functions into the + /// IRDB. True by default + explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB, CallGraphAnalysisType CGType, + llvm::ArrayRef EntryPoints = {}, + LLVMTypeHierarchy *TH = nullptr, + LLVMPointsToInfo *PT = nullptr, + Soundness S = Soundness::Soundy, + bool IncludeGlobals = true); + + ~LLVMBasedICFG(); + + LLVMBasedICFG(const LLVMBasedICFG &) = delete; + LLVMBasedICFG &operator=(const LLVMBasedICFG &) = delete; - [[nodiscard]] unsigned getNumOfVertices() const; + LLVMBasedICFG(LLVMBasedICFG &&) noexcept = delete; + LLVMBasedICFG &operator=(LLVMBasedICFG &&) noexcept = delete; - [[nodiscard]] unsigned getNumOfEdges() const; + /// Exports the whole ICFG (not only the call-graph) as DOT. + /// + /// \param WithSourceCodeInfo If true, not only contains the LLVM instructions + /// as labels, but source-code information as well (e.g. function name, line + /// no, col no, src-line). + [[nodiscard]] std::string + exportICFGAsDot(bool WithSourceCodeInfo = true) const; + /// Similar to exportICFGAsDot, but exports the ICFG as JSON instead + [[nodiscard]] nlohmann::json + exportICFGAsJson(bool WithSourceCodeInfo = true) const; - std::vector getDependencyOrderedFunctions(); + /// Returns all functions from the underlying IRDB that are part of the ICFG, + /// i.e. that are reachable from the entry-points + [[nodiscard]] llvm::ArrayRef getAllVertexFunctions() const noexcept; - [[nodiscard]] const llvm::Function * - getRegisteredDtorsCallerOrNull(const llvm::Module *Mod); + /// Gets the underlying IRDB + [[nodiscard]] LLVMProjectIRDB *getIRDB() const noexcept { return IRDB; } - template void forEachGlobalCtor(Fn &&F) const { - for (auto [Prio, Fun] : GlobalCtors) { - std::invoke(F, static_cast(Fun)); - } - } + using CFGBase::print; + using ICFGBase::print; - template void forEachGlobalDtor(Fn &&F) const { - for (auto [Prio, Fun] : GlobalDtors) { - std::invoke(F, static_cast(Fun)); - } - } + using CFGBase::getAsJson; + using ICFGBase::getAsJson; -protected: - void collectGlobalCtors() final; +private: + [[nodiscard]] FunctionRange getAllFunctionsImpl() const; + [[nodiscard]] f_t getFunctionImpl(llvm::StringRef Fun) const; + + [[nodiscard]] bool isIndirectFunctionCallImpl(n_t Inst) const; + [[nodiscard]] bool isVirtualFunctionCallImpl(n_t Inst) const; + [[nodiscard]] std::vector allNonCallStartNodesImpl() const; + [[nodiscard]] llvm::ArrayRef + getCalleesOfCallAtImpl(n_t Inst) const noexcept; + [[nodiscard]] llvm::ArrayRef getCallersOfImpl(f_t Fun) const noexcept; + [[nodiscard]] llvm::SmallVector getCallsFromWithinImpl(f_t Fun) const; + [[nodiscard]] llvm::SmallVector + getReturnSitesOfCallAtImpl(n_t Inst) const; + void printImpl(llvm::raw_ostream &OS) const; + [[nodiscard]] nlohmann::json getAsJsonImpl() const; + + [[nodiscard]] llvm::Function *buildCRuntimeGlobalCtorsDtorsModel( + llvm::Module &M, llvm::ArrayRef UserEntryPoints); + + // -------------------- Utilities -------------------- + + llvm::SmallVector * + addFunctionVertex(const llvm::Function *F); + llvm::SmallVector * + addInstructionVertex(const llvm::Instruction *Inst); + + void addCallEdge(const llvm::Instruction *CS, const llvm::Function *Callee); + void addCallEdge(const llvm::Instruction *CS, + llvm::SmallVector *Callees, + const llvm::Function *Callee); + +#if HAS_MEMORY_RESOURCE + std::pmr::monotonic_buffer_resource MRes; +#else + llvm::BumpPtrAllocator MRes; +#endif - void collectGlobalDtors() final; + llvm::DenseMap, + OnlyDestroyDeleter>> + CalleesAt; + llvm::DenseMap, + OnlyDestroyDeleter>> + CallersOf; - void collectGlobalInitializers() final; + llvm::SmallVector VertexFunctions; - void collectRegisteredDtors() final; + LLVMProjectIRDB *IRDB = nullptr; + MaybeUniquePtr TH; }; - } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h index 9f5b69ee2..46c752d3e 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h @@ -17,8 +17,6 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_CHARESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_CHARESOLVER_H_ -#include - #include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" namespace llvm { @@ -29,11 +27,13 @@ class Function; namespace psr { class CHAResolver : public Resolver { public: - CHAResolver(ProjectIRDB &IRDB, LLVMTypeHierarchy &TH); + CHAResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH); ~CHAResolver() override = default; FunctionSetTy resolveVirtualCall(const llvm::CallBase *CallSite) override; + + [[nodiscard]] std::string str() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.def b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.def new file mode 100644 index 000000000..c136232c0 --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.def @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2019 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 CALL_GRAPH_ANALYSIS_TYPE +#define CALL_GRAPH_ANALYSIS_TYPE(NAME, CMDFLAG, DESC) +#endif + +CALL_GRAPH_ANALYSIS_TYPE(NORESOLVE, "nores", "Don't resolve indirect- and virtual calls") +CALL_GRAPH_ANALYSIS_TYPE(CHA, "cha", "Class hierarchy analysis") +CALL_GRAPH_ANALYSIS_TYPE(RTA, "rta", "Rapid type analysis") +CALL_GRAPH_ANALYSIS_TYPE(DTA, "dta", "Declared type analysis") +CALL_GRAPH_ANALYSIS_TYPE(VTA, "vta", "Variable type analysis") +CALL_GRAPH_ANALYSIS_TYPE(OTF, "otf", "On-the-fly analysis based on points-to info") + +#undef CALL_GRAPH_ANALYSIS_TYPE diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h new file mode 100644 index 000000000..99bbda20c --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Philipp Schubert, Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_CALLGRAPHANALYSISTYPE_H +#define PHASAR_PHASARLLVM_CALLGRAPHANALYSISTYPE_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { +enum class CallGraphAnalysisType { +#define CALL_GRAPH_ANALYSIS_TYPE(NAME, CMDFLAG, DESC) NAME, +#include "phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.def" + Invalid +}; + +std::string toString(CallGraphAnalysisType CGA); + +CallGraphAnalysisType toCallGraphAnalysisType(llvm::StringRef S); + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, CallGraphAnalysisType CGA); + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_CALLGRAPHANALYSISTYPE_H diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h index af354e37d..3cfd888ca 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h @@ -17,20 +17,18 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_DTARESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_DTARESOLVER_H_ -#include -#include - -#include "llvm/IR/Instructions.h" - #include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" #include "phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h" // To switch the TypeGraph //#include "phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h" +#include + namespace llvm { class Instruction; class CallBase; class Function; +class BitCastInst; } // namespace llvm namespace psr { @@ -57,13 +55,15 @@ class DTAResolver : public CHAResolver { bool heuristicAntiConstructorVtablePos(const llvm::BitCastInst *BitCast); public: - DTAResolver(ProjectIRDB &IRDB, LLVMTypeHierarchy &TH); + DTAResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH); ~DTAResolver() override = default; FunctionSetTy resolveVirtualCall(const llvm::CallBase *CallSite) override; void otherInst(const llvm::Instruction *Inst) override; + + [[nodiscard]] std::string str() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h index c6756c412..1b23477ee 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h @@ -10,8 +10,6 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_NORESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_NORESOLVER_H_ -#include - #include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" namespace llvm { @@ -30,7 +28,7 @@ class NOResolver final : public Resolver { const llvm::CallBase *CallSite); public: - NOResolver(ProjectIRDB &IRDB); + NOResolver(LLVMProjectIRDB &IRDB); ~NOResolver() override = default; @@ -46,6 +44,8 @@ class NOResolver final : public Resolver { FunctionSetTy resolveFunctionPointer(const llvm::CallBase *CallSite) override; void otherInst(const llvm::Instruction *Inst) override; + + [[nodiscard]] std::string str() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h index 31e9300b5..6bc00e735 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h @@ -17,18 +17,14 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_OTFRESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_OTFRESOLVER_H_ +#include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" +#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" + #include #include -#include -#include #include #include -#include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/TinyPtrVector.h" - namespace llvm { class Instruction; class CallBase; @@ -39,17 +35,16 @@ class Value; namespace psr { -class ProjectIRDB; class LLVMBasedICFG; class LLVMTypeHierarchy; -class OTFResolver : public CHAResolver { +class OTFResolver : public Resolver { protected: LLVMBasedICFG &ICF; LLVMPointsToInfo &PT; public: - OTFResolver(ProjectIRDB &IRDB, LLVMTypeHierarchy &TH, LLVMBasedICFG &ICF, + OTFResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH, LLVMBasedICFG &ICF, LLVMPointsToInfo &PT); ~OTFResolver() override = default; @@ -71,6 +66,8 @@ class OTFResolver : public CHAResolver { static std::vector> getActualFormalPointerPairs(const llvm::CallBase *CallSite, const llvm::Function *CalleeTarget); + + [[nodiscard]] std::string str() const override; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h index 27bc8a1bf..36cc24162 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h @@ -17,24 +17,30 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RTARESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RTARESOLVER_H_ -#include - #include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" namespace llvm { class CallBase; class StructType; class Function; +class StructType; } // namespace llvm namespace psr { class RTAResolver : public CHAResolver { public: - RTAResolver(ProjectIRDB &IRDB, LLVMTypeHierarchy &TH); + RTAResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH); ~RTAResolver() override = default; FunctionSetTy resolveVirtualCall(const llvm::CallBase *CallSite) override; + + [[nodiscard]] std::string str() const override; + +private: + void resolveAllocatedStructTypes(); + + std::vector AllocatedStructTypes; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h index 6f51d3dc5..d14382efc 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h @@ -17,12 +17,12 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RESOLVER_H_ +#include "llvm/ADT/DenseSet.h" + +#include #include -#include #include -#include "llvm/ADT/DenseSet.h" - namespace llvm { class Instruction; class CallBase; @@ -31,8 +31,11 @@ class StructType; } // namespace llvm namespace psr { -class ProjectIRDB; +class LLVMProjectIRDB; class LLVMTypeHierarchy; +class LLVMPointsToInfo; +enum class CallGraphAnalysisType; +class LLVMBasedICFG; std::optional getVFTIndex(const llvm::CallBase *CallSite); @@ -42,10 +45,10 @@ std::string getReceiverTypeName(const llvm::CallBase &CallSite); class Resolver { protected: - ProjectIRDB &IRDB; + LLVMProjectIRDB &IRDB; LLVMTypeHierarchy *TH; - Resolver(ProjectIRDB &IRDB); + Resolver(LLVMProjectIRDB &IRDB); const llvm::Function * getNonPureVirtualVFTEntry(const llvm::StructType *T, unsigned Idx, @@ -54,7 +57,7 @@ class Resolver { public: using FunctionSetTy = llvm::SmallDenseSet; - Resolver(ProjectIRDB &IRDB, LLVMTypeHierarchy &TH); + Resolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH); virtual ~Resolver() = default; @@ -70,6 +73,12 @@ class Resolver { virtual FunctionSetTy resolveFunctionPointer(const llvm::CallBase *CallSite); virtual void otherInst(const llvm::Instruction *Inst); + + [[nodiscard]] virtual std::string str() const = 0; + + static std::unique_ptr + create(CallGraphAnalysisType Ty, LLVMProjectIRDB *IRDB, LLVMTypeHierarchy *TH, + LLVMBasedICFG *ICF = nullptr, LLVMPointsToInfo *PT = nullptr); }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def b/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def index 917e777f2..51aa044b4 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def +++ b/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def @@ -11,12 +11,13 @@ #define SPECIAL_MEMBER_FUNCTION_TYPES(NAME, TYPE) #endif +SPECIAL_MEMBER_FUNCTION_TYPES("None", None) SPECIAL_MEMBER_FUNCTION_TYPES("Constructor", Constructor) SPECIAL_MEMBER_FUNCTION_TYPES("Destructor", Destructor) SPECIAL_MEMBER_FUNCTION_TYPES("CopyConstructor", CopyConstructor) SPECIAL_MEMBER_FUNCTION_TYPES("MoveConstructor", MoveConstructor) SPECIAL_MEMBER_FUNCTION_TYPES("CopyAssignment", CopyAssignment) SPECIAL_MEMBER_FUNCTION_TYPES("MoveAssignment", MoveAssignment) -SPECIAL_MEMBER_FUNCTION_TYPES("None", None) + #undef SPECIAL_MEMBER_FUNCTION_TYPES diff --git a/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h b/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h new file mode 100644 index 000000000..9f6e488b0 --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * 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 + *****************************************************************************/ + +/* + * CFG.h + * + * Created on: 07.06.2017 + * Author: philipp + */ + +#ifndef PHASAR_PHASARLLVM_SPECIALMEMBERFUNCTIONTYPE_H +#define PHASAR_PHASARLLVM_SPECIALMEMBERFUNCTIONTYPE_H + +#include "llvm/ADT/StringRef.h" + +#include + +namespace llvm { +class raw_ostream; +} // namespace llvm + +namespace psr { + +enum class SpecialMemberFunctionType { +#define SPECIAL_MEMBER_FUNCTION_TYPES(NAME, TYPE) TYPE, +#include "phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def" +}; + +std::string toString(SpecialMemberFunctionType SMFT); + +SpecialMemberFunctionType toSpecialMemberFunctionType(llvm::StringRef SMFT); + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + SpecialMemberFunctionType SMFT); +} // namespace psr + +#endif // PHASAR_PHASARLLVM_SPECIALMEMBERFUNCTIONTYPE_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/DefaultSeeds.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/DefaultSeeds.h deleted file mode 100644 index f0f0f0051..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/DefaultSeeds.h +++ /dev/null @@ -1,39 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * DefaultSeeds.h - * - * Created on: 14.10.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_DEFAULTSEEDS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_DEFAULTSEEDS_H - -#include -#include -#include - -namespace psr { - -template class DefaultSeeds { -public: - static std::map> make(std::vector Nodes, D ZeroNode) { - std::map> Result; - for (N Node : Nodes) { - Result.insert(std::move(Node), {ZeroNode}); - } - return Result; - } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFact.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFact.h deleted file mode 100644 index 78561be81..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFact.h +++ /dev/null @@ -1,34 +0,0 @@ -/****************************************************************************** - * 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_DATAFLOWSOLVER_IFDSIDE_EDGEFACT_H_ -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFACT_H_ - -namespace llvm { -class raw_ostream; -} // namespace llvm - -namespace psr { - -/// A common superclass of edge-facts used by non-template IDETabulationProblems -class EdgeFact { -public: - virtual ~EdgeFact() = default; - virtual void print(llvm::raw_ostream &OS) const = 0; -}; - -static inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const EdgeFact &E) { - E.print(OS); - return OS; -} - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFactWrapper.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFactWrapper.h deleted file mode 100644 index cd5873ac4..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFactWrapper.h +++ /dev/null @@ -1,75 +0,0 @@ -/****************************************************************************** - * 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_DATAFLOWSOLVER_IFDSIDE_EDGEFACTWRAPPER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFACTWRAPPER_H - -#include -#include -#include - -#include "llvm/Support/raw_ostream.h" - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFact.h" - -namespace psr { - -/// A Wrapper over your edge-fact. Please create a subclass of this template and -/// overwrite the print function if necessary -template class EdgeFactWrapper : public EdgeFact { - static_assert(std::is_copy_constructible_v && - std::is_move_constructible_v, - "The edge fact type must be copy- and move constructible"); - -private: - T Fact; - -public: - using l_t = T; - EdgeFactWrapper(const T &F) : Fact(F) {} - EdgeFactWrapper(T &&F) : Fact(std::move(F)) {} - ~EdgeFactWrapper() override = default; - [[nodiscard]] const T &get() const { return Fact; } - void print(llvm::raw_ostream &OS) const override { OS << Fact << '\n'; } -}; - -/// A simple memory manager for EdgeFactWrappers. You may use them in your -/// IDETabulationProblem to manage your edge-facts. Please note that this -/// manager only works, if the template argument EFW is a non-abstract (subclass -/// of) EdgeFactWrapper and has a constructor taking a single edge-fact. -template class EdgeFactManager { - static_assert(std::is_base_of_v, EFW>, - "Your custom EdgeFactWrapper type must inherit from " - "psr::EdgeFactWrapper"); - static_assert(!std::is_abstract_v, - "Your custom EdgeFactWrapper is an abstract class. Please make " - "sure to overwrite all pure virtual functions"); - static_assert( - std::is_same_v()))>, - "Your custom EdgeFactWrapper must have a constructor where the only " - "parameter is of the wrapped type l_t"); - -private: - std::map> Cache; - -public: - template - EdgeFact *getOrCreateEdgeFact(EFTy &&Fact) { - auto &CValue = Cache[Fact]; - if (!CValue) { - CValue = std::make_unique(std::forward(Fact)); - } - return CValue.get(); - } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h index 13cdc405b..4fcc0a884 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h @@ -17,6 +17,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONS_H_ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONS_H_ +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" @@ -461,7 +462,7 @@ template class EdgeFunctions { // virtual EdgeFunctionPtrType getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) = 0; + d_t RetSiteNode, llvm::ArrayRef Callees) = 0; // // Also refer to FlowFunction::getSummaryFlowFunction() diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h index f6d4f69b9..d79581fc9 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h @@ -20,7 +20,6 @@ #include "llvm/ADT/DenseMap.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFact.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" #include "phasar/Utils/EquivalenceClassMap.h" @@ -120,7 +119,7 @@ class FlowEdgeFunctionCache { std::map, FlowFunctionPtrType> CallFlowFunctionCache; std::map, FlowFunctionPtrType> ReturnFlowFunctionCache; - std::map>, FlowFunctionPtrType> + std::map, FlowFunctionPtrType> CallToRetFlowFunctionCache; // Caches for the edge functions std::map, EdgeFunctionPtrType> @@ -271,7 +270,7 @@ class FlowEdgeFunctionCache { } FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - const std::set Callees) { + llvm::ArrayRef Callees) { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return flow function factory call"); @@ -283,8 +282,8 @@ class FlowEdgeFunctionCache { PHASAR_LOG_LEVEL(DEBUG, "(F) Callee's : "); for (auto callee : Callees) { PHASAR_LOG_LEVEL(DEBUG, " " << Problem.FtoString(callee)); - }); - auto Key = std::tie(CallSite, RetSite, Callees); + };); + auto Key = std::tie(CallSite, RetSite); auto SearchCallToRetFlowFunction = CallToRetFlowFunctionCache.find(Key); if (SearchCallToRetFlowFunction != CallToRetFlowFunctionCache.end()) { PHASAR_LOG_LEVEL(DEBUG, "Flow function fetched from cache"); @@ -435,7 +434,7 @@ class FlowEdgeFunctionCache { EdgeFunctionPtrType getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode, - const std::set &Callees) { + llvm::ArrayRef Callees) { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return edge function factory call"); diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFact.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFact.h deleted file mode 100644 index 285b94d5f..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFact.h +++ /dev/null @@ -1,47 +0,0 @@ -/****************************************************************************** - * 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_DATAFLOWSOLVER_IFDSIDE_FLOWFACT_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWFACT_H - -#include -#include - -namespace psr { - -/// A common superclass of dataflow-facts used by non-template tabulation -/// problems -class FlowFact { -public: - virtual ~FlowFact() = default; - virtual void print(llvm::raw_ostream &OS) const = 0; - - /// An abbreviation of an unsafe cast to T. Please use this only, if you know - /// by 100% that this FlowFact is of type T - template T *as() { - static_assert(std::is_base_of_v); - return reinterpret_cast(this); - } - /// An abbreviation of an unsafe cast to T. Please use this only, if you know - /// by 100% that this FlowFact is of type T - template [[nodiscard]] const T *as() const { - static_assert(std::is_base_of_v); - return reinterpret_cast(this); - } -}; - -static inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const FlowFact &F) { - F.print(OS); - return OS; -} - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFactWrapper.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFactWrapper.h deleted file mode 100644 index 02bdb9ba1..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFactWrapper.h +++ /dev/null @@ -1,116 +0,0 @@ -/****************************************************************************** - * 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_DATAFLOWSOLVER_IFDSIDE_FLOWFACTWRAPPER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWFACTWRAPPER_H - -#include -#include -#include -#include -#include - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFact.h" - -namespace psr { - -/// A Wrapper over your dataflow-fact. It already contains a special treatment -/// for the ZERO (Λ) value. Please create a subclass of this template and -/// overwrite the print function if necessary. Note, that your data-flow fact -/// must be copy- and move constructible. -template class FlowFactWrapper : public FlowFact { - static_assert(std::is_copy_constructible_v && - std::is_move_constructible_v, - "The dataflow fact type must be copy- and move constructible"); - -private: - std::optional Fact; - -public: - using d_t = T; - - FlowFactWrapper(std::nullptr_t) : Fact() {} - FlowFactWrapper(const T &F) : Fact(F) {} - FlowFactWrapper(T &&F) : Fact(std::move(F)) {} - ~FlowFactWrapper() override = default; - [[nodiscard]] const std::optional &get() const { return Fact; } - [[nodiscard]] bool isZero() const { return !Fact; } - - void print(llvm::raw_ostream &OS) const final { - if (isZero()) { - OS << "Λ"; - } else { - print(OS, *Fact); - } - OS << '\n'; - } - - virtual void print(llvm::raw_ostream &OS, const T &NonZeroFact) const { - OS << NonZeroFact; - } -}; - -/// A simple memory manager for FlowFactWrappers. You may use them in your -/// TabulationProblem to manage your dataflow-facts. Please note that this -/// manager only works, if the template argument FFW is a non-abstract (subclass -/// of) FlowFactWrapper and has a constructor taking a single dataflow-fact (or -/// nullptr for ZERO). -template class FlowFactManager { - static_assert(std::is_base_of_v, FFW>, - "Your custom FlowFactWrapper type must inherit from " - "psr::FlowFactWrapper"); - static_assert(!std::is_abstract_v, - "Your custom FlowFactWrapper is an abstract class. Please make " - "sure to overwrite all pure virtual functions"); - static_assert( - std::is_same_v()))>, - "Your custom FlowFactWrapper must have a constructor where the only " - "parameter is of the wrapped type d_t"); - static_assert(std::is_same_v, - "Your custom FlowFactWrapper must have a constructor that " - "takes a nullptr for creating the zero value"); - -private: - std::map> Cache; - std::unique_ptr ZeroCache; - - // Allow the 'getOrCreateFlowFacts' template to get FlowFacts passed by using - // this overload - const FlowFact *getOrCreateFlowFact(const FlowFact *Fact) const { - return Fact; - } - -public: - FlowFact *getOrCreateZero() { - if (!ZeroCache) { - ZeroCache = std::make_unique(nullptr); - } - return ZeroCache.get(); - } - - template - FlowFact *getOrCreateFlowFact(FFTy &&Fact) { - auto &CValue = Cache[Fact]; - if (!CValue) { - CValue = std::make_unique(std::forward(Fact)); - } - return CValue.get(); - } - - template - std::set getOrCreateFlowFacts(Args &&...Arguments) { - std::set Ret; - (Ret.insert(getOrCreateFlowFact(std::forward(Arguments))), ...); - return Ret; - } -}; -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h index 45cfdd8d1..d33ddc646 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h @@ -17,10 +17,16 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWFUNCTIONS_H_ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWFUNCTIONS_H_ +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/ArrayRef.h" + #include +#include #include #include #include +#include #include namespace psr { @@ -59,377 +65,558 @@ template > class FlowFunction { virtual container_type computeTargets(D Source) = 0; }; -template > -class Identity : public FlowFunction { -public: - using typename FlowFunction::FlowFunctionType; - using typename FlowFunction::FlowFunctionPtrType; - - using typename FlowFunction::container_type; +/// Helper template to check at compile-time whether a type implements the +/// FlowFunction interface, no matter which data-flow fact type it uses. +/// +/// Use is_flowfunction_v instead. +template struct IsFlowFunction { + template + static std::true_type test(const FlowFunction &); + static std::false_type test(...) {} + + static constexpr bool value = // NOLINT + std::is_same_v()))>; +}; - ~Identity() override = default; - Identity(const Identity &I) = delete; - Identity &operator=(const Identity &I) = delete; - // simply return what the user provides - container_type computeTargets(D Source) override { return {Source}; } - static std::shared_ptr getInstance() { - static std::shared_ptr Instance = - std::shared_ptr(new Identity); - return Instance; - } +/// Helper template to check at compile-time whether a type implements the +/// FlowFunction interface, no matter which data-flow fact type it uses. +template +static constexpr bool is_flowfunction_v = IsFlowFunction::value; // NOLINT -private: - Identity() = default; -}; +/// Given a flow-function type FF, returns a (smart) pointer type pointing to FF +template >> +using FlowFunctionPtrTypeOf = std::shared_ptr; -template > -class LambdaFlow : public FlowFunction { -public: - using typename FlowFunction::container_type; +/// Given a dataflow-fact type and optionally a container-type, returns a +/// (smart) pointer type pointing to a FlowFunction with the specified +/// flow-fact- and container type. +/// +/// Equivalent to FlowFunctionPtrTypeOf> +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; +} - LambdaFlow(Fn &&F) : Flow(std::move(F)) {} - LambdaFlow(const Fn &F) : Flow(F) {} - ~LambdaFlow() override = default; - container_type computeTargets(D Source) override { return Flow(Source); } +/// 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 , + typename = std::enable_if_t< + std::is_invocable_v && + std::is_convertible_v, Container>>> +auto lambdaFlow(Fn &&F) { + struct LambdaFlow final : public FlowFunction { + LambdaFlow(Fn &&F) : Flow(std::forward(F)) {} + Container computeTargets(D Source) override { + return std::invoke(Flow, std::move(Source)); + } -private: - // std::function flow; - Fn Flow; -}; + [[no_unique_address]] std::decay_t Flow; + }; -template > -typename FlowFunction::FlowFunctionPtrType makeLambdaFlow(Fn &&F) { - return std::make_shared, Container>>( - std::forward(F)); + return std::make_shared(std::forward(F)); } -template > -class Compose : public FlowFunction { -public: - using typename FlowFunction::FlowFunctionType; - using typename FlowFunction::FlowFunctionPtrType; +//===----------------------------------------------------------------------===// +// Gen flow functions - using typename FlowFunction::container_type; +/// 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)}; + } - Compose(const std::vector> &Funcs) : Funcs(Funcs) {} + D GenValue; + D FromValue; + }; - ~Compose() override = default; + return std::make_shared(std::move(FactToGenerate), std::move(From)); +} - container_type computeTargets(const D &Source) override { - container_type Current(Source); - for (const FlowFunctionType &Func : Funcs) { - container_type Next; - for (const D &Fact : Current) { - container_type Target = Func.computeTargets(Fact); - Next.insert(Target.begin(), Target.end()); +/// 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 = 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}; } - Current = Next; + return {std::move(Source)}; } - return Current; - } - static FlowFunctionPtrType - compose(const std::vector &Funcs) { - std::vector Vec; - for (const FlowFunctionType &Func : Funcs) { - if (Func != Identity::getInstance()) { - Vec.insert(Func); + D GenValue; + [[no_unique_address]] std::decay_t Predicate; + }; + + 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>> +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; } + return {std::move(Source)}; } - if (Vec.size() == 1) { // NOLINT(readability-container-size-empty) - return Vec[0]; - } - if (Vec.empty()) { - return Identity::getInstance(); - } - return std::make_shared(Vec); - } -protected: - const std::vector Funcs; -}; + 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)); +} //===----------------------------------------------------------------------===// -// Gen flow functions +// 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 ... +/// template > -class Gen : public FlowFunction { - using typename FlowFunction::container_type; - -protected: - D GenValue; - D ZeroValue; - -public: - Gen(D GenValue, D ZeroValue) : GenValue(GenValue), ZeroValue(ZeroValue) {} - ~Gen() override = default; - - container_type computeTargets(D Source) override { - if (Source == ZeroValue) { - return {Source, GenValue}; +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 {}; + } + return {std::move(Source)}; } - return {Source}; - } -}; + D KillValue; + }; -/** - * @brief Generates the given value if the given predicate evaluates to true. - * @tparam D The type of data-flow facts to be generated. - */ -template > -class GenIf : public FlowFunction { -public: - using typename FlowFunction::container_type; + return std::make_shared(std::move(FactToKill)); +} - GenIf(D GenValue, std::function Predicate) - : GenValues({GenValue}), Predicate(std::move(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 = 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::move(Source)}; + } - GenIf(container_type GenValues, std::function Predicate) - : GenValues(std::move(GenValues)), Predicate(std::move(Predicate)) {} + [[no_unique_address]] std::decay_t Predicate; + }; - ~GenIf() override = default; + return std::make_shared(std::forward(Predicate)); +} - container_type computeTargets(D Source) override { - if (Predicate(Source)) { - container_type ToGenerate; - ToGenerate.insert(Source); - ToGenerate.insert(GenValues.begin(), GenValues.end()); - return ToGenerate; +/// 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>> +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 {}; + } + return {std::move(Source)}; } - return {Source}; - } - -protected: - container_type GenValues; - std::function Predicate; -}; -template > -class GenAll : public FlowFunction { -public: - using typename FlowFunction::container_type; + Container KillValues; + }; - GenAll(container_type GenValues, D ZeroValue) - : GenValues(std::move(GenValues)), ZeroValue(ZeroValue) {} - ~GenAll() override = default; - container_type computeTargets(D Source) override { - if (Source == ZeroValue) { - GenValues.insert(Source); - return GenValues; + 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 {Source}; - } + }; + return std::make_shared( + MakeContainer(std::forward(FactsToKill))); +} -protected: - container_type GenValues; - D ZeroValue; -}; +/// 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(); + + return TheKillAllFlow; +} //===----------------------------------------------------------------------===// -// Kill flow functions +// 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 +/// template > -class Kill : public FlowFunction { -public: - using typename FlowFunction::container_type; - - Kill(D KillValue) : KillValue(KillValue) {} - ~Kill() override = default; - container_type computeTargets(D Source) override { - if (Source == KillValue) { +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}; + } return {}; } - return {Source}; - } -protected: - D KillValue; -}; + D GenValue; + D FromValue; + }; -/// \brief Kills all facts for which the given predicate evaluates to true. -/// \tparam D The type of data-flow facts to be killed. -template > -class KillIf : public FlowFunction { -public: - using typename FlowFunction::container_type; + return std::make_shared(std::move(FactToGenerate), + std::move(From)); +} - KillIf(std::function Predicate) : Predicate(std::move(Predicate)) {} - ~KillIf() override = default; - container_type computeTargets(D Source) override { - if (Predicate(Source)) { +/// 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>> +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; + } return {}; } - return {Source}; - } -protected: - std::function Predicate; -}; + 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)); +} -template > -class KillMultiple : public FlowFunction { -public: - using typename FlowFunction::container_type; +//===----------------------------------------------------------------------===// +// Miscellaneous flow functions - KillMultiple(std::set KillValues) : KillValues(std::move(KillValues)) {} - ~KillMultiple() override = default; - container_type computeTargets(D Source) override { - if (KillValues.find(Source) != KillValues.end()) { - return {}; +/// 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 {}; + } + return {std::move(Source)}; } - return {Source}; - } -protected: - container_type KillValues; -}; + D GenValue; + D FromValue; + }; -template > -class KillAll : public FlowFunction { -public: - using typename FlowFunction::container_type; + return std::make_shared(std::move(FactToGenerate), + std::move(From)); +} - ~KillAll() override = default; - KillAll(const KillAll &K) = delete; - KillAll &operator=(const KillAll &K) = delete; - container_type computeTargets(D /*Source*/) override { - return container_type(); - } +/// 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); + } - static std::shared_ptr> getInstance() { - static std::shared_ptr Instance = - std::shared_ptr(new KillAll); - return Instance; - } + OneRet.insert(std::make_move_iterator(OtherRet.begin()), + std::make_move_iterator(OtherRet.end())); + return OneRet; + } -private: - KillAll() = default; -}; + FlowFunctionPtrTypeOf OneFF; + FlowFunctionPtrTypeOf OtherFF; + }; -//===----------------------------------------------------------------------===// -// Gen-and-kill flow functions + return std::make_shared(std::move(OneFF), std::move(OtherFF)); +} +/// 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 GenAndKillAllOthers : public FlowFunction { -public: +class ZeroedFlowFunction : public FlowFunction { using typename FlowFunction::container_type; + using typename FlowFunction::FlowFunctionPtrType; - GenAndKillAllOthers(D GenValue, D ZeroValue) - : GenValue(GenValue), ZeroValue(ZeroValue) {} - ~GenAndKillAllOthers() override = default; +public: + ZeroedFlowFunction(FlowFunctionPtrType FF, D ZV) + : Delegate(std::move(FF)), ZeroValue(ZV) {} container_type computeTargets(D Source) override { if (Source == ZeroValue) { - return {ZeroValue, GenValue}; + container_type Result = Delegate->computeTargets(Source); + Result.insert(ZeroValue); + return Result; } - return {}; + return Delegate->computeTargets(Source); } private: - D GenValue; + FlowFunctionPtrType Delegate; D ZeroValue; }; -template > -class GenAllAndKillAllOthers : public FlowFunction { -public: - using typename FlowFunction::container_type; - - GenAllAndKillAllOthers(const container_type &GenValues, D ZeroValue) - : GenValues(GenValues), ZeroValue(ZeroValue) {} - ~GenAllAndKillAllOthers() override = default; - container_type computeTargets(D Source) override { - if (Source == ZeroValue) { - GenValues.insert(Source); - return GenValues; - } - return {}; - } - -protected: - container_type GenValues; - D ZeroValue; -}; - -//===----------------------------------------------------------------------===// -// Miscellaneous flow functions - -template > -class Transfer : public FlowFunction { -public: - using typename FlowFunction::container_type; - - Transfer(D ToValue, D FromValue) : ToValue(ToValue), FromValue(FromValue) {} - ~Transfer() override = default; - container_type computeTargets(D Source) override { - if (Source == FromValue) { - return {Source, ToValue}; - } - if (Source == ToValue) { - return {}; - } - return {Source}; - } - -protected: - D ToValue; - D FromValue; -}; - -template > -class Union : public FlowFunction { -public: - using typename FlowFunction::container_type; - using typename FlowFunction::FlowFunctionType; - using typename FlowFunction::FlowFunctionPtrType; - - Union(const std::vector &FlowFuncs) - : FlowFuncs([&FlowFuncs]() { - if (FlowFuncs.empty()) { - return std::vector( - {Identity::getInstance()}); - } - return FlowFuncs; - }()) {} - - ~Union() override = default; - container_type computeTargets(D Source) override { - container_type Result; - for (const auto &FlowFunc : FlowFuncs) { - container_type Target = FlowFunc->computeTargets(Source); - Result.insert(Target.begin(), Target.end()); - } - return Result; - } - -protected: - const std::vector FlowFuncs; -}; - -template > -class ZeroedFlowFunction : public FlowFunction { - using typename FlowFunction::container_type; - using typename FlowFunction::FlowFunctionPtrType; - -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); - } - -private: - FlowFunctionPtrType Delegate; - D ZeroValue; -}; - -//===----------------------------------------------------------------------===// -// FlowFunctions Class -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +// FlowFunctions Class +//===----------------------------------------------------------------------===// template > @@ -657,7 +844,7 @@ class FlowFunctions { // virtual FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) = 0; + llvm::ArrayRef Callees) = 0; // // May be used to encode special sementics of a given callee target (whose @@ -671,6 +858,370 @@ class FlowFunctions { virtual FlowFunctionPtrType getSummaryFlowFunction(n_t Curr, f_t CalleeFun) = 0; }; + +//////////////////////////////////////////////////////////////////////////////// +// Legacy Flow Functions +//////////////////////////////////////////////////////////////////////////////// + +template > +class Identity : public FlowFunction { +public: + using typename FlowFunction::FlowFunctionType; + using typename FlowFunction::FlowFunctionPtrType; + + using typename FlowFunction::container_type; + + ~Identity() override = default; + Identity(const Identity &I) = delete; + Identity &operator=(const Identity &I) = delete; + // simply return what the user provides + container_type computeTargets(D Source) override { return {Source}; } + static std::shared_ptr getInstance() { + static std::shared_ptr Instance = + std::shared_ptr(new Identity); + return Instance; + } + +private: + Identity() = default; +}; + +template > +class [[deprecated("Use lambdaFlow() instead")]] LambdaFlow + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + LambdaFlow(Fn && F) : Flow(std::move(F)) {} + LambdaFlow(const Fn &F) : Flow(F) {} + ~LambdaFlow() override = default; + container_type computeTargets(D Source) override { return Flow(Source); } + +private: + // std::function flow; + Fn Flow; +}; + +template > +typename FlowFunction::FlowFunctionPtrType makeLambdaFlow(Fn &&F) { + return std::make_shared, Container>>( + std::forward(F)); +} + +template > +class Compose : public FlowFunction { +public: + using typename FlowFunction::FlowFunctionType; + using typename FlowFunction::FlowFunctionPtrType; + + using typename FlowFunction::container_type; + + Compose(const std::vector> &Funcs) : Funcs(Funcs) {} + + ~Compose() override = default; + + container_type computeTargets(const D &Source) override { + container_type Current(Source); + for (const FlowFunctionType &Func : Funcs) { + container_type Next; + for (const D &Fact : Current) { + container_type Target = Func.computeTargets(Fact); + Next.insert(Target.begin(), Target.end()); + } + Current = Next; + } + return Current; + } + + static FlowFunctionPtrType + compose(const std::vector &Funcs) { + std::vector Vec; + for (const FlowFunctionType &Func : Funcs) { + if (Func != Identity::getInstance()) { + Vec.insert(Func); + } + } + if (Vec.size() == 1) { // NOLINT(readability-container-size-empty) + return Vec[0]; + } + if (Vec.empty()) { + return Identity::getInstance(); + } + return std::make_shared(Vec); + } + +protected: + const std::vector Funcs; +}; + +//===----------------------------------------------------------------------===// +// Gen flow functions + +template > +class [[deprecated("Use generateFlow() instead")]] Gen + : public FlowFunction { + using typename FlowFunction::container_type; + +protected: + D GenValue; + D ZeroValue; + +public: + Gen(D GenValue, D ZeroValue) : GenValue(GenValue), ZeroValue(ZeroValue) {} + ~Gen() override = default; + + container_type computeTargets(D Source) override { + if (Source == ZeroValue) { + return {Source, GenValue}; + } + return {Source}; + } +}; + +/** + * @brief Generates the given value if the given predicate evaluates to true. + * @tparam D The type of data-flow facts to be generated. + */ +template > +class [[deprecated("Use generateFlowIf() instead")]] GenIf + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + GenIf(D GenValue, std::function Predicate) + : GenValues({GenValue}), Predicate(std::move(Predicate)) {} + + GenIf(container_type GenValues, std::function Predicate) + : GenValues(std::move(GenValues)), Predicate(std::move(Predicate)) {} + + ~GenIf() override = default; + + container_type computeTargets(D Source) override { + if (Predicate(Source)) { + container_type ToGenerate; + ToGenerate.insert(Source); + ToGenerate.insert(GenValues.begin(), GenValues.end()); + return ToGenerate; + } + return {Source}; + } + +protected: + container_type GenValues; + std::function Predicate; +}; + +template > +class [[deprecated("Use generateManyFlows() instead")]] GenAll + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + GenAll(container_type GenValues, D ZeroValue) + : GenValues(std::move(GenValues)), ZeroValue(ZeroValue) {} + ~GenAll() override = default; + container_type computeTargets(D Source) override { + if (Source == ZeroValue) { + GenValues.insert(Source); + return GenValues; + } + return {Source}; + } + +protected: + container_type GenValues; + D ZeroValue; +}; + +//===----------------------------------------------------------------------===// +// Kill flow functions + +template > +class [[deprecated("Use killFlow() instead")]] Kill + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + Kill(D KillValue) : KillValue(KillValue) {} + ~Kill() override = default; + container_type computeTargets(D Source) override { + if (Source == KillValue) { + return {}; + } + return {Source}; + } + +protected: + D KillValue; +}; + +/// \brief Kills all facts for which the given predicate evaluates to true. +/// \tparam D The type of data-flow facts to be killed. +template > +class [[deprecated("Use killFlowIf instead")]] KillIf + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + KillIf(std::function Predicate) : Predicate(std::move(Predicate)) {} + ~KillIf() override = default; + container_type computeTargets(D Source) override { + if (Predicate(Source)) { + return {}; + } + return {Source}; + } + +protected: + std::function Predicate; +}; + +template > +class [[deprecated("Use killManyFlows() instead")]] KillMultiple + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + KillMultiple(std::set KillValues) : KillValues(std::move(KillValues)) {} + ~KillMultiple() override = default; + container_type computeTargets(D Source) override { + if (KillValues.find(Source) != KillValues.end()) { + return {}; + } + return {Source}; + } + +protected: + container_type KillValues; +}; + +template > +class [[deprecated("Use killAllFlows() instead")]] KillAll + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + ~KillAll() override = default; + KillAll(const KillAll &K) = delete; + KillAll &operator=(const KillAll &K) = delete; + container_type computeTargets(D /*Source*/) override { + return container_type(); + } + + static std::shared_ptr> getInstance() { + static std::shared_ptr Instance = + std::shared_ptr(new KillAll); + return Instance; + } + +private: + KillAll() = default; +}; + +//===----------------------------------------------------------------------===// +// Gen-and-kill flow functions +template > +class [[deprecated( + "Use generateFlowAndKillAllOthers() instead")]] GenAndKillAllOthers + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + GenAndKillAllOthers(D GenValue, D ZeroValue) + : GenValue(GenValue), ZeroValue(ZeroValue) {} + ~GenAndKillAllOthers() override = default; + container_type computeTargets(D Source) override { + if (Source == ZeroValue) { + return {ZeroValue, GenValue}; + } + return {}; + } + +private: + D GenValue; + D ZeroValue; +}; + +template > +class [[deprecated( + "Use generateManyFlowsAndKillAllOthers() instead")]] GenAllAndKillAllOthers + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + GenAllAndKillAllOthers(const container_type &GenValues, D ZeroValue) + : GenValues(GenValues), ZeroValue(ZeroValue) {} + ~GenAllAndKillAllOthers() override = default; + container_type computeTargets(D Source) override { + if (Source == ZeroValue) { + GenValues.insert(Source); + return GenValues; + } + return {}; + } + +protected: + container_type GenValues; + D ZeroValue; +}; + +//===----------------------------------------------------------------------===// +// Miscellaneous flow functions + +template > +class [[deprecated("Use transferFlow() instead")]] Transfer + : public FlowFunction { +public: + using typename FlowFunction::container_type; + + Transfer(D ToValue, D FromValue) : ToValue(ToValue), FromValue(FromValue) {} + ~Transfer() override = default; + container_type computeTargets(D Source) override { + if (Source == FromValue) { + return {Source, ToValue}; + } + if (Source == ToValue) { + return {}; + } + return {Source}; + } + +protected: + D ToValue; + D FromValue; +}; + +template > +class [[deprecated("Use unionFlows() instead")]] Union + : public FlowFunction { +public: + using typename FlowFunction::container_type; + using typename FlowFunction::FlowFunctionType; + using typename FlowFunction::FlowFunctionPtrType; + + Union(const std::vector &FlowFuncs) + : FlowFuncs([&FlowFuncs]() { + if (FlowFuncs.empty()) { + return std::vector( + {Identity::getInstance()}); + } + return FlowFuncs; + }()) {} + + ~Union() override = default; + container_type computeTargets(D Source) override { + container_type Result; + for (const auto &FlowFunc : FlowFuncs) { + container_type Target = FlowFunc->computeTargets(Source); + Result.insert(Target.begin(), Target.end()); + } + return Result; + } + +protected: + const std::vector FlowFuncs; +}; + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDESummaries.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDESummaries.h deleted file mode 100644 index fb02ec574..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDESummaries.h +++ /dev/null @@ -1,36 +0,0 @@ -/****************************************************************************** - * 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_IDESUMMARIES_H_ -#define PHASAR_PHASARLLVM_IFDSIDE_IDESUMMARIES_H_ - -#include - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/Utils/Table.h" - -namespace psr { - -template class IDESummaries { -private: - Table>>> summaries; - -public: - void - addSummaries(Table>>> Sum) { - summaries.insert(Sum); - } - Table>>> getSummaries() { - return summaries; - } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDESummary.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDESummary.h deleted file mode 100644 index 8bd6ba3c1..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDESummary.h +++ /dev/null @@ -1,22 +0,0 @@ -/****************************************************************************** - * 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_IDESUMMARY_H_ -#define PHASAR_PHASARLLVM_IFDSIDE_IDESUMMARY_H_ - -namespace psr { - -// template -class IDESummary { -public: - IDESummary() {} -}; -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h index 2bc2da172..c907b42ed 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h @@ -1,45 +1,47 @@ /****************************************************************************** - * Copyright (c) 2017 Philipp Schubert. + * Copyright (c) 2022 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 + * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -/* - * IDETabulationProblem.h - * - * Created on: 04.08.2016 - * Author: pdschbrt - */ - #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IDETABULATIONPROBLEM_H_ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IDETABULATIONPROBLEM_H_ +#include "phasar/DB/ProjectIRDBBase.h" +#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/JoinLattice.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h" +#include "phasar/PhasarLLVM/Utils/Printer.h" +#include "phasar/Utils/Soundness.h" + +#include #include #include #include - -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/JoinLattice.h" +#include namespace psr { -class ProjectIRDB; -template class TypeHierarchy; -template class PointsToInfo; +struct HasNoConfigurationType; template > -class IDETabulationProblem - : public IFDSTabulationProblem, - public virtual EdgeFunctions, - public virtual JoinLattice, - public virtual EdgeFactPrinter { +class IDETabulationProblem : public FlowFunctions, + public NodePrinter, + public DataFlowFactPrinter, + public FunctionPrinter, + public EdgeFunctions, + public JoinLattice, + public EdgeFactPrinter { public: + using ProblemAnalysisDomain = AnalysisDomainTy; using d_t = typename AnalysisDomainTy::d_t; using n_t = typename AnalysisDomainTy::n_t; using f_t = typename AnalysisDomainTy::f_t; @@ -47,23 +49,92 @@ class IDETabulationProblem using v_t = typename AnalysisDomainTy::v_t; using l_t = typename AnalysisDomainTy::l_t; using i_t = typename AnalysisDomainTy::i_t; - - static_assert(std::is_base_of_v, i_t>, - "Type parameter i_t must implement the ICFG interface!"); + using db_t = typename AnalysisDomainTy::db_t; using typename EdgeFunctions::EdgeFunctionPtrType; - IDETabulationProblem(const ProjectIRDB *IRDB, - const TypeHierarchy *TH, const i_t *ICF, - PointsToInfo *PT, - std::set EntryPoints = {}) - : IFDSTabulationProblem( - IRDB, TH, ICF, PT, std::move(EntryPoints)) {} + using ConfigurationTy = HasNoConfigurationType; - ~IDETabulationProblem() override = default; + explicit IDETabulationProblem(const db_t *IRDB, + std::vector EntryPoints, + std::optional ZeroValue) + : IRDB(IRDB), EntryPoints(std::move(EntryPoints)), + ZeroValue(std::move(ZeroValue)) { + static_assert(std::is_base_of_v, db_t>, + "db_t must implement the ProjectIRDBBase interface!"); + assert(IRDB != nullptr); + } + + virtual ~IDETabulationProblem() = default; /// Returns an edge function that represents the top element of the analysis. virtual EdgeFunctionPtrType 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 { + assert(ZeroValue.has_value()); + return FlowFact == *ZeroValue; + } + + /// Returns initial seeds to be used for the analysis. This is a mapping of + /// statements to initial analysis facts. + [[nodiscard]] virtual InitialSeeds initialSeeds() = 0; + + /// Returns the special tautological lambda (or zero) fact. + [[nodiscard]] d_t getZeroValue() const { + assert(ZeroValue.has_value()); + return *ZeroValue; + } + + void initializeZeroValue(d_t Zero) { + assert(!ZeroValue.has_value()); + ZeroValue = std::move(Zero); + } + + /// Sets the configuration to be used by the IFDS/IDE solver. + void setIFDSIDESolverConfig(IFDSIDESolverConfig Config) { + SolverConfig = Config; + } + + /// Returns the configuration of the IFDS/IDE solver. + [[nodiscard]] IFDSIDESolverConfig &getIFDSIDESolverConfig() { + return SolverConfig; + } + + /// Generates a text report of the results that is written to the specified + /// output stream. + virtual void + emitTextReport([[maybe_unused]] const SolverResults &Results, + llvm::raw_ostream &OS = llvm::outs()) { + OS << "No text report available!\n"; + } + + /// Generates a graphical report, e.g. in html or other markup languages, of + /// the results that is written to the specified output stream. + virtual void emitGraphicalReport( + [[maybe_unused]] const SolverResults &Results, + llvm::raw_ostream &OS = llvm::outs()) { + OS << "No graphical report available!\n"; + } + + /// Sets the level of soundness to be used by the analysis. Returns false if + /// the level of soundness is ignored. Otherwise, true. + virtual bool setSoundness(Soundness /*S*/) { return false; } + +protected: + typename FlowFunctions::FlowFunctionPtrType + generateFromZero(d_t FactToGenerate) { + return generateFlow(std::move(FactToGenerate), getZeroValue()); + } + + const db_t *IRDB{}; + std::vector EntryPoints; + std::optional ZeroValue; + + IFDSIDESolverConfig SolverConfig{}; + + [[maybe_unused]] Soundness SF = Soundness::Soundy; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h index 8563c0f7e..7524e2911 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h @@ -17,13 +17,13 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSIDESOLVERCONFIG_H_ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSIDESOLVERCONFIG_H_ -#include "phasar/Config/Configuration.h" #include "phasar/Utils/EnumFlags.h" -#include "phasar/Utils/Logger.h" + +#include namespace llvm { class raw_ostream; -} +} // namespace llvm namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSSummary.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSSummary.h deleted file mode 100644 index f2a527b17..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSSummary.h +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * Summary.h - * - * Created on: 26.05.2017 - * Author: philipp - */ - -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSSUMMARY_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSSUMMARY_H - -#include -#include - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" - -namespace psr { - -template class IFDSSummary : FlowFunction { -private: - N StartNode; - N EndNode; - std::vector Context; - std::set Outputs; - D ZeroValue; - -public: - IFDSSummary(N Start, N End, std::vector C, std::set Gen, D ZV) - : StartNode(Start), EndNode(End), Context(std::move(C)), Outputs(Gen), - ZeroValue(ZV) {} - virtual ~IFDSSummary() = default; - std::set computeTargets(D Source) override { - if (Source == ZeroValue) { - Outputs.insert(Source); - return Outputs; - } - return {Source}; - } - - N getStartNode() const { return StartNode; } - - N getEndNode() const { return EndNode; } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h index cc4920d79..d0a5aa284 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h @@ -1,148 +1,102 @@ /****************************************************************************** - * Copyright (c) 2017 Philipp Schubert. + * Copyright (c) 2022 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 + * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -/* - * IFDSTabulationProblem.h - * - * Created on: 04.08.2016 - * Author: pdschbrt - */ - #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H -#include +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" +#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" + #include #include -#include "phasar/PhasarLLVM/ControlFlow/ICFG.h" -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h" -#include "phasar/PhasarLLVM/Utils/Printer.h" -#include "phasar/Utils/Soundness.h" - namespace psr { -struct HasNoConfigurationType; - -class ProjectIRDB; -template class TypeHierarchy; -template class PointsToInfo; - template > class IFDSTabulationProblem - : public virtual FlowFunctions, - public virtual NodePrinter, - public virtual DataFlowFactPrinter, - public virtual FunctionPrinter { -public: - using ProblemAnalysisDomain = AnalysisDomainTy; - - using d_t = typename AnalysisDomainTy::d_t; - using n_t = typename AnalysisDomainTy::n_t; - using f_t = typename AnalysisDomainTy::f_t; - using t_t = typename AnalysisDomainTy::t_t; - using v_t = typename AnalysisDomainTy::v_t; - using l_t = typename AnalysisDomainTy::l_t; - using i_t = typename AnalysisDomainTy::i_t; - - static_assert(std::is_base_of_v, i_t>, - "I must implement the ICFG interface!"); - -protected: - IFDSIDESolverConfig SolverConfig; - const ProjectIRDB *IRDB; - const TypeHierarchy *TH; - const i_t *ICF; - PointsToInfo *PT; - d_t ZeroValue; - std::set EntryPoints; - [[maybe_unused]] Soundness SF = Soundness::Unused; + : public IDETabulationProblem, + Container> { + using Base = + IDETabulationProblem, Container>; public: - using ConfigurationTy = HasNoConfigurationType; - - IFDSTabulationProblem(const ProjectIRDB *IRDB, - const TypeHierarchy *TH, const i_t *ICF, - PointsToInfo *PT, - std::set EntryPoints = {}) - : IRDB(IRDB), TH(TH), ICF(ICF), PT(PT), - EntryPoints(std::move(EntryPoints)) {} - + using typename Base::d_t; + using typename Base::db_t; + using typename Base::EdgeFunctionPtrType; + using typename Base::f_t; + using typename Base::i_t; + using typename Base::l_t; + using typename Base::n_t; + using typename Base::ProblemAnalysisDomain; + using typename Base::t_t; + using typename Base::v_t; + + explicit IFDSTabulationProblem(const db_t *IRDB, + std::vector EntryPoints, + d_t ZeroValue) + : Base(IRDB, std::move(EntryPoints), std::move(ZeroValue)) {} ~IFDSTabulationProblem() override = default; - /// Returns the tautological lambda (or zero) data-flow fact. - [[nodiscard]] virtual d_t createZeroValue() const = 0; - - /// Checks if the given data-flow fact is the special tautological lambda (or - /// zero) fact. - [[nodiscard]] virtual bool isZeroValue(d_t FlowFact) const = 0; - - /// Returns initial seeds to be used for the analysis. This is a mapping of - /// statements to initial analysis facts. - [[nodiscard]] virtual InitialSeeds initialSeeds() = 0; - - /// Returns the special tautological lambda (or zero) fact. - [[nodiscard]] d_t getZeroValue() const { return ZeroValue; } + EdgeFunctionPtrType getNormalEdgeFunction(n_t /*Curr*/, d_t /*CurrNode*/, + n_t /*Succ*/, + d_t /*SuccNode*/) final { + return EdgeIdentity::getInstance(); + } - /// Returns the analysis' entry points. - [[nodiscard]] std::set getEntryPoints() const { - return EntryPoints; + EdgeFunctionPtrType getCallEdgeFunction(n_t /*CallInst*/, d_t /*SrcNode*/, + f_t /*CalleeFun*/, + d_t /*DestNode*/) final { + return EdgeIdentity::getInstance(); } - /// Returns the underlying IR. - [[nodiscard]] const ProjectIRDB *getProjectIRDB() const { return IRDB; } + EdgeFunctionPtrType getReturnEdgeFunction(n_t /*CallSite*/, f_t /*CalleeFun*/, + n_t /*ExitInst*/, d_t /*ExitNode*/, + n_t /*RetSite*/, + d_t /*RetNode*/) final { + return EdgeIdentity::getInstance(); + } - /// Returns the underlying type hierarchy. - [[nodiscard]] const TypeHierarchy *getTypeHierarchy() const { - return TH; + EdgeFunctionPtrType + getCallToRetEdgeFunction(n_t /*CallSite*/, d_t /*CallNode*/, n_t /*RetSite*/, + d_t /*RetSiteNode*/, + llvm::ArrayRef /*Callees*/) final { + return EdgeIdentity::getInstance(); } - /// Returns the underlying inter-procedural control-flow graph. - [[nodiscard]] const i_t *getICFG() const { return ICF; } + EdgeFunctionPtrType getSummaryEdgeFunction(n_t /*Curr*/, d_t /*CurrNode*/, + n_t /*Succ*/, + d_t /*SuccNode*/) final { + return EdgeIdentity::getInstance(); + } - /// Returns the underlying points-to information. - [[nodiscard]] PointsToInfo *getPointstoInfo() const { return PT; } + BinaryDomain topElement() final { return BinaryDomain::TOP; } - /// Sets the configuration to be used by the IFDS/IDE solver. - void setIFDSIDESolverConfig(IFDSIDESolverConfig Config) { - SolverConfig = Config; - } + BinaryDomain bottomElement() final { return BinaryDomain::BOTTOM; } - /// Returns the configuration of the IFDS/IDE solver. - [[nodiscard]] IFDSIDESolverConfig &getIFDSIDESolverConfig() { - return SolverConfig; + BinaryDomain join(BinaryDomain Lhs, BinaryDomain Rhs) final { + if (Lhs == BinaryDomain::TOP && Rhs == BinaryDomain::TOP) { + return BinaryDomain::TOP; + } + return BinaryDomain::BOTTOM; } - /// Generates a text report of the results that is written to the specified - /// output stream. - virtual void - emitTextReport([[maybe_unused]] const SolverResults &Results, - llvm::raw_ostream &OS = llvm::outs()) { - OS << "No text report available!\n"; + EdgeFunctionPtrType allTopFunction() final { + static EdgeFunctionPtrType AllTopFn = + std::make_shared>(BinaryDomain::TOP); + return AllTopFn; } - /// Generates a graphical report, e.g. in html or other markup languages, of - /// the results that is written to the specified output stream. - virtual void emitGraphicalReport( - [[maybe_unused]] const SolverResults &Results, - llvm::raw_ostream &OS = llvm::outs()) { - OS << "No graphical report available!\n"; + void printEdgeFact(llvm::raw_ostream &OS, BinaryDomain Val) const final { + OS << Val; } - - /// Sets the level of soundness to be used by the analysis. Returns false if - /// the level of soundness is ignored. Otherwise, true. - virtual bool setSoundness(Soundness /*S*/) { return false; } }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h index 6f66e631d..7f89d566d 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h @@ -10,13 +10,13 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_INITIALSEEDS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_INITIALSEEDS_H +#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" + #include #include #include -#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" - namespace psr { template class InitialSeeds { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h index 444fb42fb..f20549334 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h @@ -10,413 +10,429 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMFLOWFUNCTIONS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMFLOWFUNCTIONS_H +#include #include #include #include +#include +#include #include +#include "llvm/ADT/PointerIntPair.h" #include "llvm/IR/Constant.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/Casting.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" -namespace llvm { -class Value; -class Use; -class Function; -class Instruction; -} // namespace llvm - namespace psr { -/// A flow function that can be wrapped around another flow function -/// in order to kill unnecessary temporary values that are no longer -/// in use, but otherwise would be still propagated through the exploded -/// super-graph. -/// \brief Automatically kills temporary loads that are no longer in use. -class AutoKillTMPs : public FlowFunction { -protected: - FlowFunctionPtrType Delegate; - const llvm::Instruction *Inst; - -public: - AutoKillTMPs(FlowFunctionPtrType FF, const llvm::Instruction *In) - : Delegate(std::move(FF)), Inst(In) {} - - ~AutoKillTMPs() override = default; - - container_type computeTargets(const llvm::Value *Source) override { - container_type Result = Delegate->computeTargets(Source); - for (const llvm::Use &U : Inst->operands()) { - if (llvm::isa(U)) { - Result.erase(U); - } - } - return Result; - } -}; - //===----------------------------------------------------------------------===// // Mapping functions -/// A predicate can be used to specify additional requirements for the -/// propagation. -/// \brief Propagates all non pointer parameters alongside the call site. -template > -class MapFactsAlongsideCallSite - : public FlowFunction { - using typename FlowFunction::container_type; - -protected: - const llvm::CallBase *CallSite; - bool PropagateGlobals; - std::function Predicate; - -public: - MapFactsAlongsideCallSite( - const llvm::CallBase *CallSite, bool PropagateGlobals, - std::function - Predicate = - [](const llvm::CallBase *CallSite, const llvm::Value *V) { - // Globals are considered to be involved in this default - // implementation. - // Need llvm::Constant here to cover also ConstantExpr - // and ConstantAggregate - if (llvm::isa(V)) { - return true; - } - // Checks if a values is involved in a call, i.e., may be - // modified by a callee, in which case its flow is controlled by - // getCallFlowFunction() and getRetFlowFunction(). - bool Involved = false; - for (const auto &Arg : CallSite->args()) { - if (Arg == V && V->getType()->isPointerTy()) { - Involved = true; - } - } - return Involved; - }) - : CallSite(CallSite), PropagateGlobals(PropagateGlobals), - Predicate(std::move(Predicate)){}; - ~MapFactsAlongsideCallSite() override = default; - - container_type computeTargets(const llvm::Value *Source) override { - // Pass ZeroValue as is - if (LLVMZeroValue::getInstance()->isLLVMZeroValue(Source)) { - return {Source}; - } - // Pass global variables as is, if desired - // Need llvm::Constant here to cover also ConstantExpr and ConstantAggregate - if (PropagateGlobals && llvm::isa(Source)) { - return {Source}; - } - // Propagate if predicate does not hold, i.e., fact is not involved in the - // call - if (!Predicate(CallSite, Source)) { - return {Source}; - } - // Otherwise kill fact - return {}; - } -}; - -/// A predicate can be used to specifiy additonal requirements for mapping -/// actual parameter into formal parameter. -/// \brief Generates all valid formal parameter in the callee context. -template > -class MapFactsToCallee : public FlowFunction { - using typename FlowFunction::container_type; - -protected: - const llvm::Function *DestFun; - bool PropagateGlobals; - std::vector Actuals{}; - std::vector Formals{}; - std::function ActualPredicate; - std::function FormalPredicate; - const llvm::Value *CallInstr; - const bool PropagateZeroToCallee; - const bool PropagateRetToCallee; - -public: - MapFactsToCallee( - const llvm::CallBase *CallSite, const llvm::Function *DestFun, - bool PropagateGlobals = true, - std::function ActualPredicate = - [](const llvm::Value *) { return true; }, - std::function FormalPredicate = - [](const llvm::Argument *) { return true; }, - const bool PropagateZeroToCallee = true, - const bool PropagateRetToCallee = false) - : DestFun(DestFun), PropagateGlobals(PropagateGlobals), - ActualPredicate(std::move(ActualPredicate)), - FormalPredicate(std::move(FormalPredicate)), CallInstr(CallSite), - PropagateZeroToCallee(PropagateZeroToCallee), - PropagateRetToCallee(PropagateRetToCallee) { - // Set up the actual parameters - for (const auto &Actual : CallSite->args()) { - Actuals.push_back(Actual); - } - // Set up the formal parameters - for (const auto &Formal : DestFun->args()) { - Formals.push_back(&Formal); - } - } +/// A flow function that serves as default-implementation for the call-to-return +/// flow function. +/// For more details on the use-case of call-to-return flow functions, see the +/// documentation of FlowFunction::getCallToRetFlowFunction(). +/// +/// Propagates all dataflow facts unchanged, except for global variables and +/// arguments of the specified call-site. +/// Global variables are propagated only if PropagateGlobals is set to true; for +/// the argument values the PropagateArgs function defines on a per-arg basis +/// whether the respective argument should be propagated or killed. +/// By default (when not specifying PropagateArgs), all parameters are +/// propagated unchanged. +/// +/// For analyses that propagate values via reference parameters in the +/// return flow function, it is useful to kill the respective arguments here to +/// enable strong updates. +/// +template < + typename Fn = TrueFn, typename Container = std::set, + typename = + std::enable_if_t>> +auto mapFactsAlongsideCallSite(const llvm::CallBase *CallSite, + Fn &&PropagateArgs = {}, + bool PropagateGlobals = true) { + struct Mapper : public FlowFunction { + + Mapper(const llvm::CallBase *CS, bool PropagateGlobals, Fn &&PropArgs) + : CSAndPropGlob(CS, PropagateGlobals), + PropArgs(std::forward(PropArgs)) {} + + Container computeTargets(const llvm::Value *Source) override { + // Pass ZeroValue as is + if (LLVMZeroValue::isLLVMZeroValue(Source)) { + return {Source}; + } + // Pass global variables as is, if desired + // Need llvm::Constant here to cover also ConstantExpr and + // ConstantAggregate + if (llvm::isa(Source)) { + if (CSAndPropGlob.getInt()) { + return {Source}; + } + return {}; + } - ~MapFactsToCallee() override = default; + for (const auto &Arg : CSAndPropGlob.getPointer()->args()) { + if (Arg.get() == Source) { + if (std::invoke(PropArgs, Arg.get())) { + return {Arg.get()}; + } + return {}; + } + } - container_type computeTargets(const llvm::Value *Source) override { - // If DestFun is a declaration we cannot follow this call, we thus need to - // kill everything - if (DestFun->isDeclaration()) { - return {}; + return {Source}; } - // Pass ZeroValue as is, if desired - if (LLVMZeroValue::getInstance()->isLLVMZeroValue(Source)) { - if (PropagateZeroToCallee) { - return {Source}; + + llvm::PointerIntPair CSAndPropGlob; + [[no_unique_address]] std::decay_t PropArgs; + }; + + return std::make_shared(CallSite, PropagateGlobals, + std::forward(PropagateArgs)); +} + +/// A flow function that serves as default implementation of the +/// call flow function. For more information about call flow functions, see +/// FlowFunctions::getCallFlowFunction(). +/// +/// Propagates the arguments of the specified call-site into the callee function +/// if the function PropagateArgumentWithSource evaluates to true when invoked +/// with the argument and a currently holding dataflow fact. +/// Global variables are propagated into the callee function only, if the flag +/// PropagateGlobals is set to true. +/// The special zero (Λ) value gets propagated into the callee function if +/// PropagateZeroToCallee is true. For most analyses it makes sense to propagate +/// Λ everywhere. +/// +/// Given a call-site cs: r = fun(..., ax, ...) and a function prototype +/// fun(..., px, ...). Further let f = mapFactsToCallee(cs, fun, ...). Then for +/// any dataflow fact x: +/// f(Λ) = {Λ} if PropagateZeroToCallee else {}, +/// f(ax) = {px} if PropagateArgumentWithSource(ax, ax) else {}, +/// f(g) = {g} if g is GlobalVariable && PropagateGlobals else {}, +/// f(x) = {px} if PropagateArgumentWithSource(ax, x) else {}. +/// +/// \note Unlike the old version, this one is only meant for forward-analyses +template , + typename Container = std::set, + typename = std::enable_if_t>> +FlowFunctionPtrType +mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, + Fn &&PropagateArgumentWithSource = {}, + bool PropagateGlobals = true, + bool PropagateZeroToCallee = true) { + struct Mapper : public FlowFunction { + + Mapper(const llvm::CallBase *CS, const llvm::Function *DestFun, + bool PropagateGlobals, bool PropagateZeroToCallee, Fn &&PropArg) + : CSAndPropGlob(CS, PropagateGlobals), + DestFunAndPropZero(DestFun, PropagateZeroToCallee), + PropArg(std::forward(PropArg)) {} + + Container computeTargets(const llvm::Value *Source) override { + // If DestFun is a declaration we cannot follow this call, we thus need to + // kill everything + if (DestFunAndPropZero.getPointer()->isDeclaration()) { + return {}; } - return {}; - } - container_type Res; - // Pass global variables as is, if desired - // Globals could also be actual arguments, then the formal argument needs to - // be generated below. - // Need llvm::Constant here to cover also ConstantExpr and ConstantAggregate - if (PropagateGlobals && llvm::isa(Source)) { - Res.insert(Source); - } - // Handle back propagation of return value in backwards analysis. - // We add it to the result here. Later, normal flow in callee can identify - // it - if (PropagateRetToCallee) { - if (Source == CallInstr) { + + Container Res; + if (DestFunAndPropZero.getInt() && + LLVMZeroValue::isLLVMZeroValue(Source)) { + Res.insert(Source); + } else if (CSAndPropGlob.getInt() && + !LLVMZeroValue::isLLVMZeroValue(Source) && + llvm::isa(Source)) { + // Pass global variables as is, if desired + // Globals could also be actual arguments, then the formal argument + // needs to be generated below. Need llvm::Constant here to cover also + // ConstantExpr and ConstantAggregate Res.insert(Source); } - } - // Handle C-style varargs functions - if (DestFun->isVarArg()) { - // Map actual parameters to corresponding formal parameters. - for (unsigned Idx = 0; Idx < Actuals.size(); ++Idx) { - if (Source == Actuals[Idx] && ActualPredicate(Actuals[Idx])) { - if (Idx >= DestFun->arg_size()) { - // Over-approximate by trying to add the - // alloca [1 x %struct.__va_list_tag], align 16 - // to the results - // find the allocated %struct.__va_list_tag and generate it - for (const auto &BB : *DestFun) { - for (const auto &I : BB) { - if (const auto *Alloc = llvm::dyn_cast(&I)) { - if (Alloc->getAllocatedType()->isArrayTy() && - Alloc->getAllocatedType()->getArrayNumElements() > 0 && - Alloc->getAllocatedType() + + const auto *CS = CSAndPropGlob.getPointer(); + const auto *DestFun = DestFunAndPropZero.getPointer(); + assert(CS->arg_size() >= DestFun->arg_size()); + assert(CS->arg_size() == DestFun->arg_size() || DestFun->isVarArg()); + + llvm::CallBase::const_op_iterator ArgIt = CS->arg_begin(); + llvm::CallBase::const_op_iterator ArgEnd = CS->arg_end(); + llvm::Function::const_arg_iterator ParamIt = DestFun->arg_begin(); + llvm::Function::const_arg_iterator ParamEnd = DestFun->arg_end(); + + for (; ParamIt != ParamEnd; ++ParamIt, ++ArgIt) { + if (std::invoke(PropArg, ArgIt->get(), Source)) { + Res.insert(&*ParamIt); + } + } + + if (ArgIt != ArgEnd && + std::any_of( + ArgIt, ArgEnd, + std::bind(std::ref(PropArg), std::placeholders::_1, Source))) { + // Over-approximate by trying to add the + // alloca [1 x %struct.__va_list_tag], align 16 + // to the results + // find the allocated %struct.__va_list_tag and generate it + + for (const auto &BB : *DestFun) { + for (const auto &I : BB) { + if (const auto *Alloc = llvm::dyn_cast(&I)) { + if (Alloc->getAllocatedType()->isArrayTy() && + Alloc->getAllocatedType()->getArrayNumElements() > 0 && + Alloc->getAllocatedType() + ->getArrayElementType() + ->isStructTy() && + Alloc->getAllocatedType() ->getArrayElementType() - ->isStructTy() && - Alloc->getAllocatedType() - ->getArrayElementType() - ->getStructName() == "struct.__va_list_tag") { - Res.insert(Alloc); - } - } + ->getStructName() == "struct.__va_list_tag") { + Res.insert(Alloc); } } - } else { - assert(Idx < Formals.size() && - "Out of bound access to formal parameters!"); - if (FormalPredicate(Formals[Idx])) { - Res.insert(Formals[Idx]); // corresponding formal - } } } } + + return Res; } - // Handle ordinary case - // Map actual parameters to corresponding formal parameters. - for (unsigned Idx = 0; Idx < Actuals.size() && Idx < DestFun->arg_size(); - ++Idx) { - if (Source == Actuals[Idx] && ActualPredicate(Actuals[Idx])) { - assert(Idx < Formals.size() && - "Out of bound access to formal parameters!"); - Res.insert(Formals[Idx]); // corresponding formal + + llvm::PointerIntPair CSAndPropGlob; + llvm::PointerIntPair DestFunAndPropZero; + [[no_unique_address]] std::decay_t PropArg; + }; + + return std::make_shared( + CallSite, DestFun, PropagateGlobals, PropagateZeroToCallee, + std::forward(PropagateArgumentWithSource)); +} + +/// A flow function that serves as default-implementation of the return flow +/// function. For more information about return flow functions, see +/// FlowFunctions::getRetFlowFunction(). +/// +/// Propagates the return value back to the call-site and based on the +/// PropagateParameter predicate propagates back parameters holding as dataflow +/// facts. +/// +/// Let a call-site cs: r = fun(..., ax, ...) a function prototype fun(..., +/// px, ...) and an exit statement exit: return rv. +/// Further given a flow function f = mapFactsToCaller(cs, exit, ...). Then for +/// all dataflow facts x holding at exit: +/// f(rv) = {r} if PropagateRet(rv, rv) else {}, +/// f(px) = {ax} if PropagateParameter(px, px) else {}, +/// f(g) = {g} if PropagateGlobals else {}, +/// f(Λ) = {Λ} if PropagateZeroToCaller else {}, +/// f(x) = ({ax} if PropagateParameter(ax, x) else {}) union ({r} if +/// PropagateRet(rv, x) else {}). +/// +template , + typename FnRet = std::equal_to, + typename Container = std::set, + typename = std::enable_if_t< + std::is_invocable_r_v && + std::is_invocable_r_v>> +FlowFunctionPtrType mapFactsToCaller( + const llvm::CallBase *CallSite, const llvm::Instruction *ExitInst, + FnParam &&PropagateParameter = {}, FnRet &&PropagateRet = {}, + bool PropagateGlobals = true, bool PropagateZeroToCaller = true) { + struct Mapper : public FlowFunction { + Mapper(const llvm::CallBase *CallSite, const llvm::Instruction *ExitInst, + bool PropagateGlobals, FnParam &&PropagateParameter, + FnRet &&PropagateRet, bool PropagateZeroToCaller) + : CSAndPropGlob(CallSite, PropagateGlobals), + ExitInstAndPropZero(ExitInst, PropagateZeroToCaller), + PropArg(std::forward(PropagateParameter)), + PropRet(std::forward(PropagateRet)) {} + + Container computeTargets(const llvm::Value *Source) override { + Container Res; + if (ExitInstAndPropZero.getInt() && + LLVMZeroValue::isLLVMZeroValue(Source)) { + Res.insert(Source); + } else if (CSAndPropGlob.getInt() && llvm::isa(Source)) { + // Pass global variables as is, if desired + // Globals could also be actual arguments, then the formal argument + // needs to be generated below. Need llvm::Constant here to cover also + // ConstantExpr and ConstantAggregate + Res.insert(Source); } - } - return Res; - } -}; // namespace psr - -/// Predicates can be used to specify additional requirements for mapping -/// actual parameters into formal parameters and the return value. -/// \note Currently, the return value predicate only allows checks regarding -/// the callee method. -/// \brief Generates all valid actual parameters and the return value in the -/// caller context. -template > -class MapFactsToCaller : public FlowFunction { - using typename FlowFunction::container_type; - -private: - const llvm::CallBase *CallSite; - const llvm::Function *CalleeFun; - const llvm::ReturnInst *ExitInst; - bool PropagateGlobals; - const bool PropagateZeroToCaller; - std::vector Actuals; - std::vector Formals; - std::function ParamPredicate; - std::function ReturnPredicate; - -public: - MapFactsToCaller( - const llvm::CallBase *CallSite, const llvm::Function *CalleeFun, - const llvm::Instruction *ExitInst, bool PropagateGlobals = true, - std::function ParamPredicate = - [](const llvm::Value *) { return true; }, - std::function ReturnPredicate = - [](const llvm::Function *) { return true; }, - bool PropagateZeroToCaller = true) - : CallSite(CallSite), CalleeFun(CalleeFun), - ExitInst(llvm::dyn_cast(ExitInst)), - PropagateGlobals(PropagateGlobals), - PropagateZeroToCaller(PropagateZeroToCaller), - ParamPredicate(std::move(ParamPredicate)), - ReturnPredicate(std::move(ReturnPredicate)) { - assert(ExitInst && "Should not be null"); - // Set up the actual parameters - for (const auto &Actual : CallSite->args()) { - Actuals.push_back(Actual); - } - // Set up the formal parameters - for (const auto &Formal : CalleeFun->args()) { - Formals.push_back(&Formal); - } - } - ~MapFactsToCaller() override = default; + const auto *CS = CSAndPropGlob.getPointer(); + const auto *DestFun = ExitInstAndPropZero.getPointer()->getFunction(); + assert(CS->arg_size() >= DestFun->arg_size()); + assert(CS->arg_size() == DestFun->arg_size() || DestFun->isVarArg()); - // std::set - container_type computeTargets(const llvm::Value *Source) override { - assert(!CalleeFun->isDeclaration() && - "Cannot perform mapping to caller for function declaration"); - // Pass ZeroValue as is, if desired - if (LLVMZeroValue::getInstance()->isLLVMZeroValue(Source)) { - if (PropagateZeroToCaller) { - return {Source}; + llvm::CallBase::const_op_iterator ArgIt = CS->arg_begin(); + llvm::CallBase::const_op_iterator ArgEnd = CS->arg_end(); + llvm::Function::const_arg_iterator ParamIt = DestFun->arg_begin(); + llvm::Function::const_arg_iterator ParamEnd = DestFun->arg_end(); + + for (; ParamIt != ParamEnd; ++ParamIt, ++ArgIt) { + if (std::invoke(PropArg, &*ParamIt, Source)) { + Res.insert(ArgIt->get()); + } } - return {}; - } - // Pass global variables as is, if desired - // Need llvm::Constant here to cover also ConstantExpr and ConstantAggregate - if (PropagateGlobals && llvm::isa(Source)) { - return {Source}; - } - // Do the parameter mapping - container_type Res; - // Handle C-style varargs functions - if (CalleeFun->isVarArg()) { - const llvm::Instruction *AllocVarArg; - // Find the allocation of %struct.__va_list_tag - for (const auto &BB : *CalleeFun) { - for (const auto &I : BB) { + + if (ArgIt != ArgEnd) { + // Over-approximate by trying to add the + // alloca [1 x %struct.__va_list_tag], align 16 + // to the results + // find the allocated %struct.__va_list_tag and generate it + + for (const auto &I : llvm::instructions(DestFun)) { if (const auto *Alloc = llvm::dyn_cast(&I)) { - if (Alloc->getAllocatedType()->isArrayTy() && - Alloc->getAllocatedType()->getArrayNumElements() > 0 && - Alloc->getAllocatedType() - ->getArrayElementType() - ->isStructTy() && - Alloc->getAllocatedType() - ->getArrayElementType() - ->getStructName() == "struct.__va_list_tag") { - AllocVarArg = Alloc; - // TODO break out this nested loop earlier (without goto ;-) + const auto *AllocTy = Alloc->getAllocatedType(); + if (AllocTy->isArrayTy() && AllocTy->getArrayNumElements() > 0 && + AllocTy->getArrayElementType()->isStructTy() && + AllocTy->getArrayElementType()->getStructName() == + "struct.__va_list_tag") { + if (std::invoke(PropArg, Alloc, Source)) { + Res.insert(ArgIt, ArgEnd); + break; + } } } } } - // Generate the varargs things by using an over-approximation - if (Source == AllocVarArg) { - for (unsigned Idx = Formals.size(); Idx < Actuals.size(); ++Idx) { - Res.insert(Actuals[Idx]); + + if (const auto *RetInst = llvm::dyn_cast( + ExitInstAndPropZero.getPointer()); + RetInst && RetInst->getReturnValue()) { + if (std::invoke(PropRet, RetInst->getReturnValue(), Source)) { + Res.insert(CS); } } + + return Res; } - // Handle ordinary case - // Map formal parameter into corresponding actual parameter. - for (unsigned Idx = 0; Idx < Formals.size(); ++Idx) { - if (Source == Formals[Idx] && ParamPredicate(Formals[Idx])) { - Res.insert(Actuals[Idx]); // corresponding actual - } - } - // Collect return value facts - if (ExitInst != nullptr && Source == ExitInst->getReturnValue() && - ReturnPredicate(CalleeFun)) { - Res.insert(CallSite); - } - return Res; - } -}; + + llvm::PointerIntPair CSAndPropGlob; + llvm::PointerIntPair + ExitInstAndPropZero; + [[no_unique_address]] std::decay_t PropArg; + [[no_unique_address]] std::decay_t PropRet; + }; + + return std::make_shared(CallSite, ExitInst, PropagateGlobals, + std::forward(PropagateParameter), + std::forward(PropagateRet), + PropagateZeroToCaller); +} //===----------------------------------------------------------------------===// // Propagation flow functions -template class PropagateLoad : public FlowFunction { -protected: - const llvm::LoadInst *Load; +/// 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()); +} -public: - PropagateLoad(const llvm::LoadInst *L) : Load(L) {} - virtual ~PropagateLoad() = default; +//===----------------------------------------------------------------------===// +// Update flow functions - std::set computeTargets(D Source) override { - if (Source == Load->getPointerOperand()) { - return {Source, Load}; +/// A flow function that models a strong update on a memory location modified by +/// a store instruction +/// +/// Given a flow function f = strongUpdateStore(store a to b, pred), for all +/// holding dataflow facts x: +/// f(b) = {}, +/// f(x) = {x, b} if pred(x) else {x}. +/// +template , + typename = std::enable_if_t< + std::is_invocable_r_v>> +FlowFunctionPtrType +strongUpdateStore(const llvm::StoreInst *Store, Fn &&GeneratePointerOpIf) { + struct StrongUpdateFlow + : public FlowFunction { + + StrongUpdateFlow(const llvm::StoreInst *Store, Fn &&GeneratePointerOpIf) + : Store(Store), Pred(std::forward(GeneratePointerOpIf)) {} + + Container computeTargets(const llvm::Value *Source) override { + if (Source == Store->getPointerOperand()) { + return {}; + } + if (std::invoke(Pred, Source)) { + return {Source, Store->getPointerOperand()}; + } + return {Source}; } - return {Source}; - } -}; -template class PropagateStore : public FlowFunction { -protected: - const llvm::StoreInst *Store; + const llvm::StoreInst *Store; + [[no_unique_address]] std::decay_t Pred; + }; + + return std::make_shared( + Store, std::forward(GeneratePointerOpIf)); +} + +/// A flow function that models a strong update on a memory location modified by +/// a store instruction. Similar to transferFlow. +/// +/// Given a flow function f = strongUpdateStore(store a to b), for all +/// holding dataflow facts x: +/// f(b) = {}, +/// f(a) = {a, b}, +/// f(x) = {x}. +/// +/// In the exploded supergraph it may look as follows: +/// +/// x a b ... +/// | |\ | +/// | | \ ... +/// store a to b | | \ ... +/// v v v +/// x a b ... +/// +template > +FlowFunctionPtrType +strongUpdateStore(const llvm::StoreInst *Store) { + struct StrongUpdateFlow + : public FlowFunction { -public: - PropagateStore(const llvm::StoreInst *S) : Store(S) {} - virtual ~PropagateStore() = default; + StrongUpdateFlow(const llvm::StoreInst *Store) : Store(Store) {} - std::set computeTargets(D Source) override { - if (Store->getValueOperand() == Source) { - return {Source, Store->getPointerOperand()}; + Container computeTargets(const llvm::Value *Source) override { + if (Source == Store->getPointerOperand()) { + return {}; + } + if (Source == Store->getValueOperand()) { + return {Source, Store->getPointerOperand()}; + } + return {Source}; } - return {Source}; - } -}; - -//===----------------------------------------------------------------------===// -// Update flow functions -template class StrongUpdateStore : public FlowFunction { -protected: - const llvm::StoreInst *Store; - std::function Predicate; + const llvm::StoreInst *Store; + }; -public: - StrongUpdateStore(const llvm::StoreInst *S, std::function P) - : Store(S), Predicate(std::move(P)) {} - - ~StrongUpdateStore() override = default; - - std::set computeTargets(D Source) override { - if (Source == Store->getPointerOperand()) { - return {}; - } - if (Predicate(Source)) { - return {Source, Store->getPointerOperand()}; - } - return {Source}; - } -}; + return std::make_shared(Store); +} } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h index 5be941068..9e6511597 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h @@ -20,11 +20,7 @@ #include #include "llvm/ADT/StringRef.h" -#include "llvm/IR/Constants.h" #include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/Alignment.h" namespace llvm { class Value; @@ -32,30 +28,14 @@ class Value; namespace psr { -// do not touch, its only purpose is to make ZeroValue working -inline const std::unique_ptr - LLVMZeroValueCTX(new llvm::LLVMContext); -inline const std::unique_ptr - LLVMZeroValueMod(new llvm::Module("zero_module", *LLVMZeroValueCTX)); - /** * This class may be used to represent the special zero value for IFDS * and IDE problems. The LLVMZeroValue is implemented as a singleton. */ class LLVMZeroValue : public llvm::GlobalVariable { private: - LLVMZeroValue() - : llvm::GlobalVariable( - *LLVMZeroValueMod, llvm::Type::getIntNTy(*LLVMZeroValueCTX, 2), - true, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - llvm::ConstantInt::get(*LLVMZeroValueCTX, - llvm::APInt(/*nbits*/ 2, - /*value*/ 0, - /*signed*/ true)), - LLVMZeroValueInternalName) { - setAlignment(llvm::MaybeAlign(4)); - } - ~LLVMZeroValue() = default; + LLVMZeroValue(llvm::Module &Mod); // NOLINT(modernize-use-equals-delete) + static constexpr auto LLVMZeroValueInternalName = "zero_value"; public: @@ -63,6 +43,7 @@ class LLVMZeroValue : public llvm::GlobalVariable { LLVMZeroValue &operator=(const LLVMZeroValue &Z) = delete; LLVMZeroValue(LLVMZeroValue &&Z) = delete; LLVMZeroValue &operator=(LLVMZeroValue &&Z) = delete; + ~LLVMZeroValue() = default; [[nodiscard]] llvm::StringRef getName() const { return LLVMZeroValueInternalName; @@ -73,10 +54,7 @@ class LLVMZeroValue : public llvm::GlobalVariable { } // Do not specify a destructor (at all)! - static const LLVMZeroValue *getInstance() { - static const auto *ZV = new LLVMZeroValue; - return ZV; - } + static const LLVMZeroValue *getInstance(); }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h index caa8979e3..55594e770 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h @@ -10,12 +10,12 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_EDGEDOMAIN_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_EDGEDOMAIN_H +#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" + #include "llvm/ADT/PointerIntPair.h" #include "llvm/IR/Instruction.h" // Need a complete type llvm::Instruction for llvm::PointerIntPair #include "llvm/Support/raw_ostream.h" -#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" - namespace psr { class BasicBlockOrdering; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h index 157d2cca6..b2dda23ea 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @@ -10,24 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEEXTENDEDTAINTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEEXTENDEDTAINTANALYSIS_H -#include -#include -#include -#include -#include -#include -#include -#include - -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallBitVector.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Value.h" -#include "llvm/Support/Casting.h" - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" +#include "phasar/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h" @@ -35,21 +18,30 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" -#include "phasar/PhasarLLVM/Pointer/PointsToInfo.h" -#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/BasicBlockOrdering.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/PhasarLLVM/Utils/LatticeDomain.h" -#include "phasar/Utils/Logger.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/Casting.h" + +#include +#include +#include +#include +#include namespace psr { -class ProjectIRDB; class LLVMBasedICFG; class LLVMPointsToInfo; +template class SolverResults; struct IDEExtendedTaintAnalysisDomain : public LLVMAnalysisDomainDefault { using d_t = AbstractMemoryLocation; @@ -186,19 +178,21 @@ class IDEExtendedTaintAnalysis /// The GetDomTree parameter can be used to inject a custom DominatorTree /// analysis or the results from a LLVM pass computing dominator trees template - IDEExtendedTaintAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, + IDEExtendedTaintAnalysis(const LLVMProjectIRDB *IRDB, const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, const TaintConfig *TSF, - std::set EntryPoints, unsigned Bound, + std::vector EntryPoints, unsigned Bound, bool DisableStrongUpdates, GetDomTree &&GDT = DefaultDominatorTreeAnalysis{}) - : base_t(IRDB, TH, ICF, PT, std::move(EntryPoints)), AnalysisBase(TSF), - BBO(std::forward(GDT)), + : base_t(IRDB, std::move(EntryPoints), std::nullopt), AnalysisBase(TSF), + PT(PT), ICF(ICF), BBO(std::forward(GDT)), FactFactory(IRDB->getNumInstructions()), - DL((*IRDB->getAllModules().begin())->getDataLayout()), Bound(Bound), + DL(IRDB->getModule()->getDataLayout()), Bound(Bound), PostProcessed(DisableStrongUpdates), DisableStrongUpdates(DisableStrongUpdates) { - base_t::ZeroValue = IDEExtendedTaintAnalysis::createZeroValue(); + assert(PT != nullptr); + assert(ICF != nullptr); + initializeZeroValue(createZeroValue()); FactFactory.setDataLayout(DL); @@ -219,8 +213,9 @@ class IDEExtendedTaintAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallStmt, f_t DestFun) override; @@ -237,9 +232,10 @@ class IDEExtendedTaintAnalysis n_t ExitInst, d_t ExitNode, n_t RetSite, d_t RetNode) override; - EdgeFunctionPtrType getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, - n_t RetSite, d_t RetSiteNode, - std::set Callees) override; + EdgeFunctionPtrType + getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, + d_t RetSiteNode, + llvm::ArrayRef Callees) override; EdgeFunctionPtrType getSummaryEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, d_t SuccNode) override; @@ -248,7 +244,7 @@ class IDEExtendedTaintAnalysis InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; @@ -276,6 +272,9 @@ class IDEExtendedTaintAnalysis llvm::raw_ostream &OS = llvm::outs()) override; private: + LLVMPointsToInfo *PT{}; + const LLVMBasedICFG *ICF{}; + /// Save all leaks here that were found using the IFDS part if the analysis. /// Hence, this map may contain sanitized facts. XTaint::LeakMap_t Leaks; @@ -308,14 +307,13 @@ class IDEExtendedTaintAnalysis /// may not be sanitized. /// /// This function involves a post-processing step the first time it is called. - const LeakMap_t & - getAllLeaks(IDESolver &Solver) &; + const LeakMap_t &getAllLeaks(const SolverResults &SR) &; /// Return a map from llvm::Instruction to sets of leaks (llvm::Values) that /// may not be sanitized. /// /// This function involves a post-processing step the first time it is called. - LeakMap_t getAllLeaks(IDESolver &Solver) &&; + LeakMap_t getAllLeaks(const SolverResults &SR) &&; /// Return a map from llvm::Instruction to sets of leaks (llvm::Values) that /// may or may not be sanitized. /// @@ -342,14 +340,14 @@ template class IDEExtendedTaintAnalysis : public XTaint::IDEExtendedTaintAnalysis { public: template - IDEExtendedTaintAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, + IDEExtendedTaintAnalysis(const LLVMProjectIRDB *IRDB, const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, const TaintConfig &TSF, - std::set EntryPoints = {}, + std::vector EntryPoints = {}, GetDomTree &&GDT = DefaultDominatorTreeAnalysis{}) - : XTaint::IDEExtendedTaintAnalysis(IRDB, TH, ICF, PT, &TSF, EntryPoints, - BOUND, !USE_STRONG_UPDATES, - std::forward(GDT)) {} + : XTaint::IDEExtendedTaintAnalysis( + IRDB, ICF, PT, &TSF, std::move(EntryPoints), BOUND, + !USE_STRONG_UPDATES, std::forward(GDT)) {} using ConfigurationTy = TaintConfig; }; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h index 76bd3ebcc..c6a07f32c 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h @@ -13,7 +13,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" -namespace psr { +namespace psr::glca { struct AllBot { using type = AllBottom; @@ -25,6 +25,6 @@ struct AllBot { bool NonRec = false); }; -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h index c546903ca..2b3227fd3 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h @@ -14,7 +14,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" -namespace psr { +namespace psr::glca { class BinaryEdgeFunction : public EdgeFunction, @@ -46,6 +46,6 @@ class BinaryEdgeFunction void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; }; -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h index 59ccbce1c..34c7ffa45 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h @@ -14,8 +14,8 @@ namespace llvm { class Value; } // namespace llvm -namespace psr { +namespace psr::glca { bool isConstant(const llvm::Value *Val); -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h index af731888e..ff69dc5ae 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h @@ -19,7 +19,7 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/Instructions.h" -namespace psr { +namespace psr::glca { enum class Ordering { Less, Greater, Equal, Incomparable }; @@ -96,13 +96,13 @@ bool operator<(const ev_t &Lhs, const ev_t &Rhs); bool isTopValue(const ev_t &Val); llvm::raw_ostream &operator<<(llvm::raw_ostream &Os, const ev_t &Val); -} // namespace psr +} // namespace psr::glca namespace std { -template <> struct hash { +template <> struct hash { hash() = default; - size_t operator()(const psr::EdgeValue &Val) const { + size_t operator()(const psr::glca::EdgeValue &Val) const { auto Hash = hash()(Val.getKind()); uint64_t AsInt; double AsFloat; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h index 41608916b..495432972 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h @@ -15,7 +15,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h" -namespace psr { +namespace psr::glca { class EdgeValueSet { std::unordered_set Underlying; @@ -41,6 +41,6 @@ class EdgeValueSet { bool operator!=(const EdgeValueSet &Other) const; }; -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h index 1bed62b8f..f5efbc5fb 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h @@ -13,7 +13,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" -namespace psr { +namespace psr::glca { class GenConstant : public EdgeFunction, public std::enable_shared_from_this { @@ -37,6 +37,6 @@ class GenConstant : public EdgeFunction, void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; }; -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h index e9ccca09c..49285fcea 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h @@ -10,17 +10,17 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCA_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCA_H -#include -#include -#include -#include - #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Utils/Printer.h" +#include +#include +#include +#include + namespace psr { /// \brief An implementation of a linear constant analysis, similar to /// IDELinearConstantAnalysis, but with an extended edge-Value @@ -28,16 +28,10 @@ namespace psr { /// increase precision. struct IDEGeneralizedLCADomain : LLVMAnalysisDomainDefault { - using l_t = EdgeValueSet; + using l_t = glca::EdgeValueSet; }; -// Forward declare the IDETabulationProblem as we require its toString -// functionality. -template -class IDETabulationProblem; - class IDEGeneralizedLCA : public IDETabulationProblem { - size_t MaxSetSize; public: using d_t = typename IDEGeneralizedLCADomain::d_t; @@ -59,12 +53,8 @@ class IDEGeneralizedLCA : public IDETabulationProblem { using lca_results_t = std::map>; - IDEGeneralizedLCA( - const ProjectIRDB *IRDB, - const TypeHierarchy *TH, - const LLVMBasedICFG *ICF, - PointsToInfo *PT, - std::set EntryPoints, size_t MaxSetSize); + IDEGeneralizedLCA(const LLVMProjectIRDB *IRDB, const LLVMBasedICFG *ICF, + std::vector EntryPoints, size_t MaxSetSize); std::shared_ptr> getNormalFlowFunction(n_t Curr, n_t Succ) override; @@ -79,14 +69,14 @@ class IDEGeneralizedLCA : public IDETabulationProblem { std::shared_ptr> getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryFlowFunction(n_t CallStmt, f_t DestMthd) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; @@ -107,7 +97,8 @@ class IDEGeneralizedLCA : public IDETabulationProblem { std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallStmt, d_t CallNode, n_t RetSite, @@ -137,6 +128,9 @@ class IDEGeneralizedLCA : public IDETabulationProblem { lca_results_t getLCAResults(SolverResults SR); private: + const LLVMBasedICFG *ICF{}; + size_t MaxSetSize; + void stripBottomResults(std::unordered_map &Res); [[nodiscard]] bool isEntryPoint(const std::string &Name) const; template std::string VtoString(V Val); // NOLINT diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/JoinEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/JoinEdgeFunction.h index 248a799d5..92f89a5d4 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/JoinEdgeFunction.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/JoinEdgeFunction.h @@ -13,7 +13,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" -namespace psr { +namespace psr::glca { class JoinEdgeFunction : public EdgeFunction, public std::enable_shared_from_this { @@ -44,6 +44,6 @@ class JoinEdgeFunction : public EdgeFunction, getSecond() const; }; -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h index 348933638..ffc64e127 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h @@ -14,7 +14,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" -namespace psr { +namespace psr::glca { class LCAEdgeFunctionComposer : public EdgeFunctionComposer { @@ -38,6 +38,6 @@ class LCAEdgeFunctionComposer getSecond() const; }; -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h index 7429992f4..b69c86621 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h @@ -18,7 +18,7 @@ class Function; class Value; } // namespace llvm -namespace psr { +namespace psr::glca { class MapFactsToCalleeFlowFunction : public FlowFunction { protected: @@ -34,6 +34,6 @@ class MapFactsToCalleeFlowFunction : public FlowFunction { computeTargets(const llvm::Value *Source) override; }; -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h index f466c93f9..936b4833f 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h @@ -30,7 +30,7 @@ class Instruction; class ReturnInst; class Value; } // namespace llvm -namespace psr { +namespace psr::glca { class MapFactsToCallerFlowFunction : public FlowFunction { std::vector Actuals; @@ -47,6 +47,6 @@ class MapFactsToCallerFlowFunction : public FlowFunction { computeTargets(const llvm::Value *Source) override; }; -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h index 9c21d60ea..fc7bb20c0 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h @@ -14,7 +14,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" -namespace psr { +namespace psr::glca { class TypecastEdgeFunction : public EdgeFunction, @@ -43,6 +43,6 @@ class TypecastEdgeFunction void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; }; -} // namespace psr +} // namespace psr::glca #endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h index b7efa8724..9a69a9eb5 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -17,10 +17,10 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" +#include "phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h" #include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" -#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/PhasarLLVM/Utils/LatticeDomain.h" @@ -184,6 +184,9 @@ template > { + using IDETabulationProblem< + IDEInstInteractionAnalysisDomain>::generateFromZero; + public: using AnalysisDomainTy = IDEInstInteractionAnalysisDomain; @@ -205,16 +208,14 @@ class IDEInstInteractionAnalysisT std::variant InstOrGlobal); IDEInstInteractionAnalysisT( - const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}, + const LLVMProjectIRDB *IRDB, const LLVMBasedICFG *ICF, + LLVMPointsToInfo *PT, std::vector EntryPoints = {"main"}, std::function EdgeFactGenerator = nullptr) : IDETabulationProblem( - IRDB, TH, ICF, PT, std::move(EntryPoints)), - EdgeFactGen(std::move(EdgeFactGenerator)) { - this->ZeroValue = - IDEInstInteractionAnalysisT::createZeroValue(); + IRDB, std::move(EntryPoints), createZeroValue()), + ICF(ICF), PT(PT), EdgeFactGen(std::move(EdgeFactGenerator)) { + assert(ICF != nullptr); + assert(PT != nullptr); IIAAAddLabelsEF::initEdgeFunctionCleaner(); IIAAKillOrReplaceEF::initEdgeFunctionCleaner(); } @@ -244,7 +245,7 @@ class IDEInstInteractionAnalysisT // if (const auto *Alloca = llvm::dyn_cast(Curr)) { PHASAR_LOG_LEVEL(DFADEBUG, "AllocaInst"); - return std::make_shared>(Alloca, this->getZeroValue()); + return generateFromZero(Alloca); } // Handle indirect taints, i. e., propagate values that depend on branch @@ -416,7 +417,7 @@ class IDEInstInteractionAnalysisT // 0 y x // if (const auto *Load = llvm::dyn_cast(Curr)) { - return std::make_shared>(Load, Load->getPointerOperand()); + return generateFlow(Load, Load->getPointerOperand()); } // Handle store instructions // @@ -566,11 +567,11 @@ class IDEInstInteractionAnalysisT f_t DestFun) override { if (this->ICF->isHeapAllocatingFunction(DestFun)) { // Kill add facts and model the effects in getCallToRetFlowFunction(). - return KillAll::getInstance(); + return killAllFlows(); } if (DestFun->isDeclaration()) { // We don't have anything that we could analyze, kill all facts. - return KillAll::getInstance(); + return killAllFlows(); } const auto *CS = llvm::cast(CallSite); // Map actual to formal parameters. @@ -611,7 +612,7 @@ class IDEInstInteractionAnalysisT return {}; } // Pass ZeroValue as is, if desired - if (LLVMZeroValue::getInstance()->isLLVMZeroValue(Source)) { + if (LLVMZeroValue::isLLVMZeroValue(Source)) { return {Source}; } container_type Res; @@ -680,10 +681,10 @@ class IDEInstInteractionAnalysisT SRetFormals.insert(DestFun->getArg(Idx)); } } - auto GenSRetFormals = std::make_shared>( - SRetFormals, this->getZeroValue()); - return std::make_shared>( - std::vector({MapFactsToCalleeFF, GenSRetFormals})); + + return unionFlows(std::move(MapFactsToCalleeFF), + generateManyFlowsAndKillAllOthers(std::move(SRetFormals), + this->getZeroValue())); } inline FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, @@ -714,7 +715,7 @@ class IDEInstInteractionAnalysisT std::set computeTargets(IDEIIAFlowFact Source) override { // Pass ZeroValue as is, if desired - if (LLVMZeroValue::getInstance()->isLLVMZeroValue(Source.getBase())) { + if (LLVMZeroValue::isLLVMZeroValue(Source.getBase())) { return {Source}; } // Pass global variables as is, if desired @@ -780,11 +781,9 @@ class IDEInstInteractionAnalysisT // Generate the respective callsite. The callsite will receive its // value from this very return instruction cf. // getReturnEdgeFunction(). - auto ConstantRetGen = std::make_shared>( - CallSite, this->getZeroValue()); - return std::make_shared>( - std::vector( - {MapFactsToCallerFF, ConstantRetGen})); + return unionFlows(std::move(MapFactsToCallerFF), + generateFlowAndKillAllOthers( + CallSite, this->getZeroValue())); } } } @@ -794,7 +793,7 @@ class IDEInstInteractionAnalysisT inline FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t /* RetSite */, - std::set Callees) override { + llvm::ArrayRef Callees) override { // Model call to heap allocating functions (new, new[], malloc, etc.) -- // only model direct calls, though. if (Callees.size() == 1) { @@ -813,7 +812,7 @@ class IDEInstInteractionAnalysisT // v v // 0 x // - return std::make_shared>(CallSite, this->getZeroValue()); + return generateFromZero(CallSite); } } } @@ -825,31 +824,47 @@ class IDEInstInteractionAnalysisT // behavior that is intended. In that case, we must propagate all data-flow // facts alongside the call site. bool OnlyDecls = true; + bool AllVoidRetTys = true; for (auto Callee : Callees) { if (!Callee->isDeclaration()) { OnlyDecls = false; } + if (!Callee->getReturnType()->isVoidTy()) { + AllVoidRetTys = false; + } } + struct MapFactsAlongsideCallSite : public FlowFunction { bool OnlyDecls; + bool AllVoidRetTys; const llvm::CallBase *CallSite; + d_t ZeroValue; - MapFactsAlongsideCallSite(bool OnlyDecls, const llvm::CallBase *CallSite) - : OnlyDecls(OnlyDecls), CallSite(CallSite) {} + MapFactsAlongsideCallSite(bool OnlyDecls, bool AllVoidRetTys, + const llvm::CallBase *CallSite, d_t ZeroValue) + : OnlyDecls(OnlyDecls), AllVoidRetTys(AllVoidRetTys), + CallSite(CallSite), ZeroValue(ZeroValue) {} std::set computeTargets(IDEIIAFlowFact Source) override { - // Pass ZeroValue as is - if (LLVMZeroValue::getInstance()->isLLVMZeroValue(Source.getBase())) { - return {Source}; - } - // Pass variables as identity, if no function definition is available - // as they would be otherwise killed. + // There are a few things to consider, in case only declarations of + // callee targets are available. if (OnlyDecls) { - return {Source}; + + if (!AllVoidRetTys) { + // If one or more of the declaration-only targets return a value, it + // must be generated from zero! + if (Source == ZeroValue) { + return {Source, CallSite}; + } + } else { + // If all declaration-only callee targets return void, just pass + // everything as identity. + return {Source}; + } } - // Do not global variables (if definitions of the callee function(s) are - // available), since the effect of the callee on these values will be - // modelled using combined getCallFlowFunction and + // Do not pass global variables if definitions of the callee + // function(s) are available, since the effect of the callee on these + // values will be modelled using combined getCallFlowFunction and // getReturnFlowFunction. if (llvm::isa(Source.getBase())) { return {}; @@ -861,7 +876,8 @@ class IDEInstInteractionAnalysisT } }; return std::make_shared( - OnlyDecls, llvm::dyn_cast(CallSite)); + OnlyDecls, AllVoidRetTys, llvm::dyn_cast(CallSite), + this->getZeroValue()); } inline FlowFunctionPtrType @@ -889,26 +905,25 @@ class IDEInstInteractionAnalysisT Seeds.addSeed(&EntryPointFun->front().front(), &Arg, BottomElement); } // Generate all global variables using generalized initial seeds - for (const auto *M : this->IRDB->getAllModules()) { - for (const auto &G : M->globals()) { - if (const auto *GV = llvm::dyn_cast(&G)) { - l_t InitialValues = BitVectorSet(); - std::set EdgeFacts; - if (EdgeFactGen) { - EdgeFacts = EdgeFactGen(GV); - // fill BitVectorSet - InitialValues = - BitVectorSet(EdgeFacts.begin(), EdgeFacts.end()); - } - Seeds.addSeed(&EntryPointFun->front().front(), GV, InitialValues); + + for (const auto &G : this->IRDB->getModule()->globals()) { + if (const auto *GV = llvm::dyn_cast(&G)) { + l_t InitialValues = BitVectorSet(); + std::set EdgeFacts; + if (EdgeFactGen) { + EdgeFacts = EdgeFactGen(GV); + // fill BitVectorSet + InitialValues = + BitVectorSet(EdgeFacts.begin(), EdgeFacts.end()); } + Seeds.addSeed(&EntryPointFun->front().front(), GV, InitialValues); } } } return Seeds; } - [[nodiscard]] inline d_t createZeroValue() const override { + [[nodiscard]] inline d_t createZeroValue() const { // Create a special value to represent the zero value! return LLVMZeroValue::getInstance(); } @@ -1297,7 +1312,8 @@ class IDEInstInteractionAnalysisT inline std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t /* RetSite */, - d_t RetSiteNode, std::set Callees) override { + d_t RetSiteNode, + llvm::ArrayRef Callees) override { // Check if the user has registered a fact generator function l_t UserEdgeFacts = BitVectorSet(); std::set EdgeFacts; @@ -1674,8 +1690,7 @@ class IDEInstInteractionAnalysisT protected: static inline bool isZeroValueImpl(d_t d) { - // NOLINTNEXTLINE(readability-static-accessed-through-instance) - return LLVMZeroValue::getInstance()->isLLVMZeroValue(d); + return LLVMZeroValue::isLLVMZeroValue(d); } static void printEdgeFactImpl(llvm::raw_ostream &OS, l_t EdgeFact) { @@ -1715,7 +1730,7 @@ class IDEInstInteractionAnalysisT } private: - /// Filters out all variables that had a non empty set during edge functions + /// Filters out all variables that had a non-empty set during edge functions /// computations. inline std::unordered_set removeVariablesWithoutEmptySetValue( const SolverResults &Solution, @@ -1729,7 +1744,7 @@ class IDEInstInteractionAnalysisT // at some point. Therefore, we only care for the variables and their // associated values and ignore at which point a variable may holds as a // data-flow fact. - const auto *Variable = Result.getColumnKey(); + const auto Variable = Result.getColumnKey(); const auto &Value = Result.getValue(); // skip result entry if variable is not in the set of all variables if (Variables.find(Variable) == Variables.end()) { @@ -1748,6 +1763,8 @@ class IDEInstInteractionAnalysisT return Variables; } + const LLVMBasedICFG *ICF{}; + LLVMPointsToInfo *PT{}; std::function EdgeFactGen; static inline const l_t BottomElement = Bottom{}; static inline const l_t TopElement = Top{}; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h index a46a6e6b2..e71dc1deb 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h @@ -12,7 +12,7 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/Utils/LatticeDomain.h" #include "llvm/Support/raw_ostream.h" @@ -42,11 +42,6 @@ class LLVMPointsToInfo; class IDELinearConstantAnalysis : public IDETabulationProblem { -private: - // For debug purpose only - static unsigned CurrGenConstantId; // NOLINT - static unsigned CurrLCAIDId; // NOLINT - static unsigned CurrBinaryId; // NOLINT public: using IDETabProblemType = @@ -59,13 +54,9 @@ class IDELinearConstantAnalysis using typename IDETabProblemType::t_t; using typename IDETabProblemType::v_t; - static const l_t TOP; - static const l_t BOTTOM; - - IDELinearConstantAnalysis(const ProjectIRDB *IRDB, - const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IDELinearConstantAnalysis(const LLVMProjectIRDB *IRDB, + const LLVMBasedICFG *ICF, + std::vector EntryPoints = {"main"}); ~IDELinearConstantAnalysis() override; @@ -85,24 +76,7 @@ class IDELinearConstantAnalysis IRTrace == Rhs.IRTrace; } - operator std::string() const { - std::string Buffer; - llvm::raw_string_ostream OS(Buffer); - OS << "Line " << LineNr << ": " << SrcNode << '\n'; - OS << "Var(s): "; - for (auto It = VariableToValue.begin(); It != VariableToValue.end(); - ++It) { - if (It != VariableToValue.begin()) { - OS << ", "; - } - OS << It->first << " = " << It->second; - } - OS << "\nCorresponding IR Instructions:\n"; - for (const auto *Ir : IRTrace) { - OS << " " << llvmIRToString(Ir) << '\n'; - } - return OS.str(); - } + operator std::string() const; }; using lca_results_t = std::map>; @@ -118,15 +92,16 @@ class IDELinearConstantAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitInst, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; [[nodiscard]] InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; @@ -146,7 +121,8 @@ class IDELinearConstantAnalysis std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, @@ -160,108 +136,8 @@ class IDELinearConstantAnalysis std::shared_ptr> allTopFunction() override; - // Custom EdgeFunction declarations - - class LCAEdgeFunctionComposer : public EdgeFunctionComposer { - public: - 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; - }; - - class GenConstant : public EdgeFunction, - public std::enable_shared_from_this { - private: - const unsigned GenConstantId; - const int64_t IntConst; - - public: - explicit GenConstant(int64_t IntConst); - - l_t computeTarget(l_t Source) override; - - 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(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - }; - - class LCAIdentity : public EdgeFunction, - public std::enable_shared_from_this { - private: - const unsigned LCAIDId; - - public: - explicit LCAIdentity(); - - l_t computeTarget(l_t Source) override; - - 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(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - }; - - class BinOp : public EdgeFunction, - public std::enable_shared_from_this { - private: - const unsigned EdgeFunctionID, Op; - d_t Lop, Rop, CurrNode; - - public: - BinOp(unsigned Op, d_t Lop, d_t Rop, d_t CurrNode); - - l_t computeTarget(l_t Source) override; - - 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(llvm::raw_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 l_t executeBinOperation(unsigned Op, l_t LVal, l_t RVal); - - static char opToChar(unsigned Op); - - [[nodiscard]] bool isEntryPoint(const std::string &FunctionName) const; - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; @@ -274,6 +150,9 @@ class IDELinearConstantAnalysis void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; + +private: + const LLVMBasedICFG *ICF{}; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h index 1cdd8080b..dd0996fdc 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h @@ -10,14 +10,12 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEPROTOANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEPROTOANALYSIS_H -#include +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + #include #include #include -#include - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" namespace llvm { class Instruction; @@ -28,10 +26,6 @@ class Value; namespace psr { -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - struct IDEProtoAnalysisDomain : public LLVMAnalysisDomainDefault { using l_t = const llvm::Value *; }; @@ -47,9 +41,8 @@ class IDEProtoAnalysis : public IDETabulationProblem { using typename IDETabProblemType::t_t; using typename IDETabProblemType::v_t; - IDEProtoAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IDEProtoAnalysis(const LLVMProjectIRDB *IRDB, + std::vector EntryPoints = {"main"}); ~IDEProtoAnalysis() override = default; @@ -62,15 +55,16 @@ class IDEProtoAnalysis : public IDETabulationProblem { FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitInst, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; bool isZeroValue(d_t Fact) const override; @@ -90,7 +84,8 @@ class IDEProtoAnalysis : public IDETabulationProblem { std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h index a25a215ae..9bca773a6 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h @@ -10,22 +10,10 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESECUREHEAPPROPAGATION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESECUREHEAPPROPAGATION_H -#include "llvm/ADT/StringRef.h" - -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" -#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" -namespace llvm { -class Instruction; -class Value; -class StructType; -class Function; -} // namespace llvm +#include "llvm/ADT/StringRef.h" namespace psr { enum class SecureHeapFact { ZERO, INITIALIZED }; @@ -53,9 +41,9 @@ class IDESecureHeapPropagation using typename IDETabProblemType::t_t; using typename IDETabProblemType::v_t; - IDESecureHeapPropagation(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IDESecureHeapPropagation(const LLVMProjectIRDB *IRDB, + std::vector EntryPoints = {"main"}); + ~IDESecureHeapPropagation() override = default; FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override; @@ -65,15 +53,16 @@ class IDESecureHeapPropagation FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeMthd, n_t ExitInst, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestMthd) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; @@ -100,7 +89,8 @@ class IDESecureHeapPropagation std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, @@ -118,50 +108,6 @@ class IDESecureHeapPropagation void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS) override; - - struct SHPEdgeFn : public EdgeFunction, - public std::enable_shared_from_this { - ~SHPEdgeFn() override = default; - - std::shared_ptr> - joinWith(std::shared_ptr> OtherFunction) override; - }; - - struct SHPEdgeFunctionComposer - : public EdgeFunctionComposer, - public std::enable_shared_from_this { - ~SHPEdgeFunctionComposer() override = default; - std::shared_ptr> - joinWith(std::shared_ptr> OtherFunction) override; - }; - struct SHPGenEdgeFn : public SHPEdgeFn { - SHPGenEdgeFn(l_t Val); - ~SHPGenEdgeFn() override = default; - - l_t computeTarget(l_t Source) override; - - bool equal_to(std::shared_ptr> Other) const override; - std::shared_ptr> - composeWith(std::shared_ptr> SecondFunction) override; - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - static std::shared_ptr getInstance(l_t Val); - - private: - l_t Value; - }; - - struct IdentityEdgeFunction : public SHPEdgeFn { - ~IdentityEdgeFunction() override = default; - - l_t computeTarget(l_t Source) override; - std::shared_ptr> - composeWith(std::shared_ptr> SecondFunction) override; - bool equal_to(std::shared_ptr> Other) const override; - - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - - static std::shared_ptr getInstance(); - }; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h index 1c1058135..a40697cde 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h @@ -10,15 +10,13 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESOLVERTEST_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESOLVERTEST_H -#include -#include +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - namespace llvm { class Instruction; class Function; @@ -28,17 +26,11 @@ class Value; namespace psr { -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - struct IDESolverTestAnalysisDomain : public LLVMAnalysisDomainDefault { using l_t = const llvm::Value *; }; class IDESolverTest : public IDETabulationProblem { -private: - std::vector EntryPoints; public: using IDETabProblemType = IDETabulationProblem; @@ -50,9 +42,8 @@ class IDESolverTest : public IDETabulationProblem { using typename IDETabProblemType::t_t; using typename IDETabProblemType::v_t; - IDESolverTest(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IDESolverTest(const LLVMProjectIRDB *IRDB, + std::vector EntryPoints = {"main"}); ~IDESolverTest() override = default; @@ -65,15 +56,16 @@ class IDESolverTest : public IDETabulationProblem { FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; @@ -93,7 +85,8 @@ class IDESolverTest : public IDETabulationProblem { std::shared_ptr> getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; std::shared_ptr> getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETaintAnalysis.h deleted file mode 100644 index fd4c8a6e4..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETaintAnalysis.h +++ /dev/null @@ -1,138 +0,0 @@ -/****************************************************************************** - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETAINTANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETAINTANALYSIS_H - -#include -#include -#include -#include - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - -namespace llvm { -class Instruction; -class Function; -class StructType; -class Value; -} // namespace llvm - -namespace psr { - -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - -struct IDETaintAnalysisDomain : LLVMAnalysisDomainDefault { - using l_t = const llvm::Value *; -}; - -class IDETaintAnalysis : public IDETabulationProblem { -public: - using IDETabProblemType = IDETabulationProblem; - using typename IDETabProblemType::d_t; - using typename IDETabProblemType::f_t; - using typename IDETabProblemType::i_t; - using typename IDETabProblemType::l_t; - using typename IDETabProblemType::n_t; - using typename IDETabProblemType::t_t; - using typename IDETabProblemType::v_t; - - std::set SourceFunctions = {"fread", "read"}; - // keep in mind that 'char** argv' of main is a source for tainted values as - // well - std::set SinkFunctions = {"fwrite", "write", "printf"}; - static bool setContainsStr(std::set Strs, - const std::string &Str); - - IDETaintAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); - - ~IDETaintAnalysis() override = default; - - // start formulating our analysis by specifying the parts required for IFDS - - FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override; - - FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override; - - FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, - n_t ExitInst, n_t RetSite) override; - - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; - - FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, - f_t DestFun) override; - - InitialSeeds initialSeeds() override; - - [[nodiscard]] d_t createZeroValue() const override; - - [[nodiscard]] bool isZeroValue(d_t Fact) const override; - - // in addition provide specifications for the IDE parts - - std::shared_ptr> - getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, - d_t SuccNode) override; - - std::shared_ptr> - getCallEdgeFunction(n_t CallSite, d_t SrcNode, f_t DestinationFunction, - d_t DestNode) override; - - std::shared_ptr> - getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, n_t ExitInst, - d_t ExitNode, n_t RetSite, d_t RetNode) override; - - std::shared_ptr> - getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; - - std::shared_ptr> - getSummaryEdgeFunction(n_t CallSite, d_t CallNode, 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; - - std::shared_ptr> allTopFunction() override; - - class IDETainAnalysisAllTop - : public EdgeFunction, - public std::enable_shared_from_this { - l_t computeTarget(l_t Source) override; - - 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 printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; - - void printEdgeFact(llvm::raw_ostream &OS, l_t L) const override; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h index dd8a8a426..efd535d73 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -10,18 +10,16 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H -#include -#include -#include -#include -#include +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" #include "llvm/IR/InstrTypes.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" +#include +#include +#include +#include namespace llvm { class CallBase; @@ -32,9 +30,8 @@ class Value; namespace psr { -class LLVMBasedICFG; -class LLVMTypeHierarchy; class LLVMPointsToInfo; +struct TypeStateDescription; struct IDETypeStateAnalysisDomain : public LLVMAnalysisDomainDefault { using l_t = int; @@ -54,57 +51,12 @@ class IDETypeStateAnalysis using ConfigurationTy = TypeStateDescription; -private: - const TypeStateDescription &TSD; - std::map PointsToCache; - std::map> - RelevantAllocaCache; - - /** - * @brief Returns all alloca's that are (indirect) aliases of V. - * - * Currently PhASAR's points-to information does not include alloca - * instructions, since alloca instructions, i.e. memory locations, are of - * type T* for a target type T. Thus they do not alias directly. Therefore, - * for each alias of V we collect related alloca instructions by checking - * load and store instructions for used alloca's. - */ - std::set getRelevantAllocas(d_t V); - - /** - * @brief Returns whole-module aliases of V. - * - * This function retrieves whole-module points-to information. We store - * already computed points-to information in a cache to prevent expensive - * recomputation since the whole module points-to graph can be huge. This - * might become unnecessary once PhASAR's PointsToGraph starts using a cache - * itself. - */ - std::set getWMPointsToSet(d_t V); - - /** - * @brief Provides whole module aliases and relevant alloca's of V. - */ - std::set getWMAliasesAndAllocas(d_t V); - - /** - * @brief Provides local aliases and relevant alloca's of V. - */ - std::set getLocalAliasesAndAllocas(d_t V, const std::string &Fname); - - /** - * @brief Checks if the type machtes the type of interest. - */ - bool hasMatchingType(d_t V); - -public: const l_t TOP; const l_t BOTTOM; - IDETypeStateAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - const TypeStateDescription &TSD, - std::set EntryPoints = {"main"}); + IDETypeStateAnalysis(const LLVMProjectIRDB *IRDB, LLVMPointsToInfo *PT, + const TypeStateDescription *TSD, + std::vector EntryPoints = {"main"}); ~IDETypeStateAnalysis() override = default; @@ -117,39 +69,40 @@ class IDETypeStateAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; // in addition provide specifications for the IDE parts - std::shared_ptr> - getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, - d_t SuccNode) override; + EdgeFunctionPtrType getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, + d_t SuccNode) override; - std::shared_ptr> - getCallEdgeFunction(n_t CallSite, d_t SrcNode, f_t DestinationFunction, - d_t DestNode) override; + EdgeFunctionPtrType getCallEdgeFunction(n_t CallSite, d_t SrcNode, + f_t DestinationFunction, + d_t DestNode) override; - std::shared_ptr> - getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, n_t ExitInst, - d_t ExitNode, n_t RetSite, d_t RetNode) override; + EdgeFunctionPtrType getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, + n_t ExitInst, d_t ExitNode, + n_t RetSite, d_t RetNode) override; - std::shared_ptr> + EdgeFunctionPtrType getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, std::set Callees) override; + d_t RetSiteNode, + llvm::ArrayRef Callees) override; - std::shared_ptr> - getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode) override; + EdgeFunctionPtrType getSummaryEdgeFunction(n_t CallSite, d_t CallNode, + n_t RetSite, + d_t RetSiteNode) override; l_t topElement() override; @@ -165,7 +118,7 @@ class IDETypeStateAnalysis */ l_t join(l_t Lhs, l_t Rhs) override; - std::shared_ptr> allTopFunction() override; + EdgeFunctionPtrType allTopFunction() override; void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; @@ -178,66 +131,49 @@ class IDETypeStateAnalysis void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; - // customize the edge function composer - class TSEdgeFunctionComposer : public EdgeFunctionComposer { - private: - l_t BotElement; - - public: - TSEdgeFunctionComposer(std::shared_ptr> F, - std::shared_ptr> G, l_t Bot) - : EdgeFunctionComposer(F, G), BotElement(Bot) {} - - std::shared_ptr> - joinWith(std::shared_ptr> OtherFunction) override; - }; - - class TSEdgeFunction : public EdgeFunction, - public std::enable_shared_from_this { - protected: - const TypeStateDescription &TSD; - // Do not use a reference here, since LLVM's StringRef's (obtained by str()) - // might turn to nullptr for whatever reason... - const std::string Token; - const llvm::CallBase *CallSite; - - public: - TSEdgeFunction(const TypeStateDescription &TSD, const std::string &Tok, - const llvm::CallBase *CB) - : TSD(TSD), Token(Tok), CallSite(CB){}; - - l_t computeTarget(l_t Source) override; - - 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(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - }; - class TSConstant : public EdgeFunction, - public std::enable_shared_from_this { - const TypeStateDescription &TSD; - l_t State; - - public: - TSConstant(const TypeStateDescription &TSD, l_t State); +private: + const TypeStateDescription *TSD{}; + LLVMPointsToInfo *PT{}; + std::map PointsToCache; + std::map> + RelevantAllocaCache; - l_t computeTarget(l_t Source) override; + /** + * @brief Returns all alloca's that are (indirect) aliases of V. + * + * Currently PhASAR's points-to information does not include alloca + * instructions, since alloca instructions, i.e. memory locations, are of + * type T* for a target type T. Thus they do not alias directly. Therefore, + * for each alias of V we collect related alloca instructions by checking + * load and store instructions for used alloca's. + */ + std::set getRelevantAllocas(d_t V); - std::shared_ptr> - composeWith(std::shared_ptr> SecondFunction) override; + /** + * @brief Returns whole-module aliases of V. + * + * This function retrieves whole-module points-to information. We store + * already computed points-to information in a cache to prevent expensive + * recomputation since the whole module points-to graph can be huge. This + * might become unnecessary once PhASAR's PointsToGraph starts using a cache + * itself. + */ + std::set getWMPointsToSet(d_t V); - std::shared_ptr> - joinWith(std::shared_ptr> OtherFunction) override; + /** + * @brief Provides whole module aliases and relevant alloca's of V. + */ + std::set getWMAliasesAndAllocas(d_t V); - bool equal_to(std::shared_ptr> Other) const override; + /** + * @brief Provides local aliases and relevant alloca's of V. + */ + std::set getLocalAliasesAndAllocas(d_t V, const std::string &Fname); - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - }; + /** + * @brief Checks if the type machtes the type of interest. + */ + bool hasMatchingType(d_t V); }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h index 552734267..7c3e4bae7 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h @@ -10,15 +10,14 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSCONSTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSCONSTANALYSIS_H -#include +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + #include #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - // Forward declaration of types for which we only use its pointer or ref type namespace llvm { class Instruction; @@ -28,10 +27,7 @@ class Value; } // namespace llvm namespace psr { - -class LLVMBasedICFG; class LLVMPointsToInfo; -class LLVMTypeHierarchy; /** * This IFDS analysis will compute possibly mutable memory @@ -44,16 +40,10 @@ class LLVMTypeHierarchy; */ class IFDSConstAnalysis : public IFDSTabulationProblem { -private: - // Holds all allocated memory locations, including global variables - std::set AllMemLocs; // FIXME: initialize within the constructor body! - // Holds all initialized variables and objects. - std::set Initialized; public: - IFDSConstAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IFDSConstAnalysis(const LLVMProjectIRDB *IRDB, LLVMPointsToInfo *PT, + std::vector EntryPoints = {"main"}); ~IFDSConstAnalysis() override = default; @@ -126,8 +116,9 @@ class IFDSConstAnalysis * @param CallSite Call site. * @param retSite Return site. */ - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; /** * @brief Not used for this analysis, i.e. always returning nullptr. @@ -145,7 +136,7 @@ class IFDSConstAnalysis /** * @brief Returns appropriate zero value. */ - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; @@ -213,6 +204,13 @@ class IFDSConstAnalysis */ // clang-format on static std::set getContextRelevantPointsToSet(std::set &PointsToSet, f_t Context); + +private: + LLVMPointsToInfo *PT{}; + // Holds all allocated memory locations, including global variables + std::set AllMemLocs; // FIXME: initialize within the constructor body! + // Holds all initialized variables and objects. + std::set Initialized; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h index 44271e1e2..1c892bc39 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h @@ -5,24 +5,22 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSFIELDSENSTAINTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSFIELDSENSTAINTANALYSIS_H -#include -#include -#include -#include - -#include "llvm/IR/Function.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Value.h" - -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" #include "phasar/PhasarLLVM/Domain/ExtendedValue.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Value.h" + +#include +#include +#include + namespace llvm { class Value; class Function; @@ -31,10 +29,6 @@ class StructType; namespace psr { -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - struct IFDSFieldSensTaintAnalysisDomain : public LLVMIFDSAnalysisDomainDefault { using d_t = ExtendedValue; }; @@ -44,11 +38,10 @@ class IFDSFieldSensTaintAnalysis public: using ConfigurationTy = TaintConfig; - IFDSFieldSensTaintAnalysis(const ProjectIRDB *IRDB, - const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - const TaintConfig &TaintConfig, - std::set EntryPoints = {"main"}); + IFDSFieldSensTaintAnalysis(const LLVMProjectIRDB *IRDB, + const TaintConfig *TaintConfig, + std::vector EntryPoints = {"main"}); + ~IFDSFieldSensTaintAnalysis() override = default; FlowFunctionPtrType @@ -68,7 +61,7 @@ class IFDSFieldSensTaintAnalysis FlowFunctionPtrType getCallToRetFlowFunction(const llvm::Instruction *CallSite, const llvm::Instruction *RetSite, - std::set Callees) override; + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(const llvm::Instruction *CallSite, @@ -82,13 +75,13 @@ class IFDSFieldSensTaintAnalysis BinaryDomain> &SolverResults, llvm::raw_ostream &OS = llvm::outs()) override; - [[nodiscard]] ExtendedValue createZeroValue() const override { + [[nodiscard]] ExtendedValue createZeroValue() const { // create a special value to represent the zero value! return ExtendedValue(LLVMZeroValue::getInstance()); } [[nodiscard]] bool isZeroValue(ExtendedValue EV) const override { - return LLVMZeroValue::getInstance()->isLLVMZeroValue(EV.getValue()); + return LLVMZeroValue::isLLVMZeroValue(EV.getValue()); } void printNode(llvm::raw_ostream &OS, @@ -121,9 +114,9 @@ class IFDSFieldSensTaintAnalysis } private: - const TaintConfig &Config; + const TaintConfig *Config{}; - TraceStats Stats; + TraceStats Stats{}; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSLinearConstantAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSLinearConstantAnalysis.h deleted file mode 100644 index 1bb64b752..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSLinearConstantAnalysis.h +++ /dev/null @@ -1,101 +0,0 @@ -/****************************************************************************** - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSLINEARCONSTANTANALYSIS_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSLINEARCONSTANTANALYSIS_H - -#include -#include -#include -#include -#include - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - -// Forward declaration of types for which we only use its pointer or ref type -namespace llvm { -class Instruction; -class Function; -class StructType; -class Value; -} // namespace llvm - -namespace psr { - -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - -// A small pair data type to encode data flow facts for this LCA -struct LCAPair { - const llvm::Value *First{nullptr}; - int Second{0}; - LCAPair() = default; - LCAPair(const llvm::Value *V, int I); - friend bool operator==(const LCAPair &Lhs, const LCAPair &Rhs); - friend bool operator!=(const LCAPair &Lhs, const LCAPair &Rhs); - friend bool operator<(const LCAPair &Lhs, const LCAPair &Rhs); -}; - -} // namespace psr - -// Specialize hash to be used in containers like std::unordered_map -namespace std { -template <> struct hash { - std::size_t operator()(const psr::LCAPair &K) const; -}; -} // namespace std - -namespace psr { - -struct IFDSLinearConstantAnalysisDomain : public LLVMIFDSAnalysisDomainDefault { - using d_t = LCAPair; -}; - -class IFDSLinearConstantAnalysis - : public IFDSTabulationProblem { -public: - IFDSLinearConstantAnalysis(const ProjectIRDB *IRDB, - const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); - - ~IFDSLinearConstantAnalysis() override = default; - - FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override; - - FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override; - - FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, - n_t ExitStmt, n_t RetSite) override; - - FlowFunctionPtrType getCallToRetFlowFunction( - n_t CallSite, n_t RetSite, - std::set Callees) override; - - FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, - f_t DestFun) override; - - InitialSeeds initialSeeds() override; - - [[nodiscard]] d_t createZeroValue() const override; - - [[nodiscard]] bool isZeroValue(d_t Fact) const override; - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override; - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h index 63d1e6ea7..a12032852 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h @@ -10,15 +10,15 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSPROTOANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSPROTOANALYSIS_H +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + #include #include #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - namespace llvm { class Instruction; class Function; @@ -28,16 +28,11 @@ class Value; namespace psr { -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - class IFDSProtoAnalysis : public IFDSTabulationProblem { public: - IFDSProtoAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IFDSProtoAnalysis(const LLVMProjectIRDB *IRDB, + std::vector EntryPoints = {"main"}); ~IFDSProtoAnalysis() override = default; @@ -48,15 +43,16 @@ class IFDSProtoAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitInst, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h index c474ba9d0..7f059e250 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h @@ -10,15 +10,14 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSIGNANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSIGNANALYSIS_H -#include +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + #include #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - namespace llvm { class Instruction; class Function; @@ -28,16 +27,11 @@ class Value; namespace psr { -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - class IFDSSignAnalysis : public IFDSTabulationProblem { public: - IFDSSignAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IFDSSignAnalysis(const LLVMProjectIRDB *IRDB, + std::vector EntryPoints = {"main"}); ~IFDSSignAnalysis() override = default; @@ -48,15 +42,16 @@ class IFDSSignAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h index 3a78ec309..286cbbf47 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h @@ -10,15 +10,12 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSOLVERTEST_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSOLVERTEST_H -#include -#include -#include +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - namespace llvm { class Instruction; class Function; @@ -28,16 +25,11 @@ class Value; namespace psr { -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - class IFDSSolverTest : public IFDSTabulationProblem { public: - IFDSSolverTest(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IFDSSolverTest(const LLVMProjectIRDB *IRDB, + std::vector EntryPoints = {"main"}); ~IFDSSolverTest() override = default; @@ -48,15 +40,16 @@ class IFDSSolverTest FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h index 37d14ac0b..63864b19b 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h @@ -11,8 +11,7 @@ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTAINTANALYSIS_H #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" -#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include #include @@ -21,18 +20,13 @@ // Forward declaration of types for which we only use its pointer or ref type namespace llvm { -class Instruction; class Function; -class StructType; -class Value; +class CallBase; } // namespace llvm namespace psr { - -class LLVMBasedICFG; -class LLVMTypeHierarchy; class LLVMPointsToInfo; -struct HasNoConfigurationType; +class TaintConfig; /** * This analysis tracks data-flows through a program. Data flows from @@ -45,17 +39,6 @@ struct HasNoConfigurationType; */ class IFDSTaintAnalysis : public IFDSTabulationProblem { -private: - const TaintConfig &Config; - - bool isSourceCall(const llvm::CallBase *CB, - const llvm::Function *Callee) const; - bool isSinkCall(const llvm::CallBase *CB, const llvm::Function *Callee) const; - bool isSanitizerCall(const llvm::CallBase *CB, - const llvm::Function *Callee) const; - - void populateWithMayAliases(std::set &Facts) const; - void populateWithMustAliases(std::set &Facts) const; public: // Setup the configuration type @@ -70,10 +53,9 @@ class IFDSTaintAnalysis * @param TSF * @param EntryPoints */ - IFDSTaintAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - const TaintConfig &Config, - std::set EntryPoints = {"main"}); + IFDSTaintAnalysis(const LLVMProjectIRDB *IRDB, LLVMPointsToInfo *PT, + const TaintConfig *Config, + std::vector EntryPoints = {"main"}); ~IFDSTaintAnalysis() override = default; @@ -84,15 +66,16 @@ class IFDSTaintAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; bool isZeroValue(d_t FlowFact) const override; @@ -104,6 +87,19 @@ class IFDSTaintAnalysis void emitTextReport(const SolverResults &SR, llvm::raw_ostream &OS = llvm::outs()) override; + +private: + const TaintConfig *Config{}; + LLVMPointsToInfo *PT{}; + + bool isSourceCall(const llvm::CallBase *CB, + const llvm::Function *Callee) const; + bool isSinkCall(const llvm::CallBase *CB, const llvm::Function *Callee) const; + bool isSanitizerCall(const llvm::CallBase *CB, + const llvm::Function *Callee) const; + + void populateWithMayAliases(std::set &Facts) const; + void populateWithMustAliases(std::set &Facts) const; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h index 1e4f707d9..6009ba3ce 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h @@ -10,33 +10,20 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTYPEANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTYPEANALYSIS_H -#include +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - -namespace llvm { -class Instruction; -class Function; -class StructType; -class Value; -} // namespace llvm - namespace psr { -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - class IFDSTypeAnalysis : public IFDSTabulationProblem { public: - IFDSTypeAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IFDSTypeAnalysis(const LLVMProjectIRDB *IRDB, + std::vector EntryPoints = {"main"}); ~IFDSTypeAnalysis() override = default; @@ -47,14 +34,15 @@ class IFDSTypeAnalysis FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t Curr, f_t DestFun) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h index 38c835b46..691549168 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h @@ -10,30 +10,18 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSUNINITIALIZEDVARIABLES_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSUNINITIALIZEDVARIABLES_H +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + #include #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - -namespace llvm { -class Instruction; -class Function; -class StructType; -class Value; -} // namespace llvm - namespace psr { -class LLVMBasedICFG; -class LLVMTypeHierarchy; -class LLVMPointsToInfo; - class IFDSUninitializedVariables : public IFDSTabulationProblem { -private: struct UninitResult { UninitResult() = default; unsigned int Line = 0; @@ -47,13 +35,10 @@ class IFDSUninitializedVariables [[nodiscard]] bool empty() const; void print(llvm::raw_ostream &OS); }; - std::map> UndefValueUses; public: - IFDSUninitializedVariables(const ProjectIRDB *IRDB, - const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - std::set EntryPoints = {"main"}); + IFDSUninitializedVariables(const LLVMProjectIRDB *IRDB, + std::vector EntryPoints = {"main"}); ~IFDSUninitializedVariables() override = default; @@ -64,15 +49,16 @@ class IFDSUninitializedVariables FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, n_t ExitStmt, n_t RetSite) override; - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override; + FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t RetSite, + llvm::ArrayRef Callees) override; FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, f_t DestFun) override; InitialSeeds initialSeeds() override; - [[nodiscard]] d_t createZeroValue() const override; + [[nodiscard]] d_t createZeroValue() const; [[nodiscard]] bool isZeroValue(d_t Fact) const override; @@ -88,6 +74,9 @@ class IFDSUninitializedVariables [[nodiscard]] const std::map> &getAllUndefUses() const; std::vector aggregateResults(); + +private: + std::map> UndefValueUses; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/BiDiIDESolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/BiDiIDESolver.h deleted file mode 100644 index ea820efa0..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/BiDiIDESolver.h +++ /dev/null @@ -1,20 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * BiDiIDESolver.h - * - * Created on: 15.09.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_IFDSIDE_SOLVER_BIDIIDESOLVER_H_ -#define PHASAR_PHASARLLVM_IFDSIDE_SOLVER_BIDIIDESOLVER_H_ - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/BiDiIFDSSolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/BiDiIFDSSolver.h deleted file mode 100644 index bde696030..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/BiDiIFDSSolver.h +++ /dev/null @@ -1,19 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * BiDiIFDSSolver.h - * - * Created on: 15.09.2016 - * Author: pdschbrt - */ -#ifndef PHASAR_PHASARLLVM_IFDSIDE_SOLVER_BIDIIFDSSOLVER_H_ -#define PHASAR_PHASARLLVM_IFDSIDE_SOLVER_BIDIIFDSSOLVER_H_ - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/DefaultSeeds.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/DefaultSeeds.h deleted file mode 100644 index a63a9e7f5..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/DefaultSeeds.h +++ /dev/null @@ -1,39 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * DefaultSeeds.h - * - * Created on: 03.11.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_IFDSIDE_SOLVER_DEFAULTSEEDS_H_ -#define PHASAR_PHASARLLVM_IFDSIDE_SOLVER_DEFAULTSEEDS_H_ - -#include -#include -#include - -namespace psr { - -class DefaultSeeds { -public: - template - static std::map> make(std::vector instructions, - D zeroNode) { - std::map> res; - for (const N &n : instructions) - res.insert({n, std::set{zeroNode}}); - return res; - } -}; -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h index ed670cfc7..c2ad9949a 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h @@ -17,22 +17,6 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IDESOLVER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IDESOLVER_H -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nlohmann/json.hpp" - -#include "boost/algorithm/string/trim.hpp" - -#include "llvm/Support/raw_ostream.h" - #include "phasar/Config/Configuration.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h" @@ -41,12 +25,9 @@ #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/JoinLattice.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JoinHandlingNode.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JumpFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/LinkedNode.h" #include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathEdge.h" +#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h" #include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" #include "phasar/PhasarLLVM/Utils/DOTGraph.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" @@ -54,37 +35,28 @@ #include "phasar/Utils/PAMMMacros.h" #include "phasar/Utils/Table.h" -namespace psr { - -// Forward declare the Transformation -template -class IFDSToIDETabulationProblem; - -struct NoIFDSExtension {}; +#include "nlohmann/json.hpp" -template struct IFDSExtension { - using BaseAnalysisDomain = typename AnalysisDomainTy::BaseAnalysisDomain; +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" - IFDSExtension(IFDSTabulationProblem &Problem) - : TransformedProblem( - std::make_unique< - IFDSToIDETabulationProblem>( - Problem)) {} +#include +#include +#include +#include +#include +#include +#include +#include - std::unique_ptr> - TransformedProblem; -}; +namespace psr { /// Solves the given IDETabulationProblem as described in the 1996 paper by /// Sagiv, Horwitz and Reps. To solve the problem, call solve(). Results /// can then be queried by using resultAt() and resultsAt(). template , - bool = is_analysis_domain_extensions::value> -class IDESolver - : protected std::conditional_t< - is_analysis_domain_extensions::value, - IFDSExtension, NoIFDSExtension> { + typename Container = std::set> +class IDESolver { public: using ProblemTy = IDETabulationProblem; using container_type = typename ProblemTy::container_type; @@ -99,13 +71,16 @@ class IDESolver using t_t = typename AnalysisDomainTy::t_t; using v_t = typename AnalysisDomainTy::v_t; - IDESolver(IDETabulationProblem &Problem) - : IDEProblem(Problem), ZeroValue(Problem.getZeroValue()), - ICF(Problem.getICFG()), SolverConfig(Problem.getIFDSIDESolverConfig()), + IDESolver(IDETabulationProblem &Problem, + const i_t *ICF) + : IDEProblem(Problem), ZeroValue(Problem.getZeroValue()), ICF(ICF), + SolverConfig(Problem.getIFDSIDESolverConfig()), CachedFlowEdgeFunctions(Problem), AllTop(Problem.allTopFunction()), JumpFn(std::make_shared>( AllTop, IDEProblem)), - Seeds(Problem.initialSeeds()) {} + Seeds(Problem.initialSeeds()) { + assert(ICF != nullptr); + } IDESolver(const IDESolver &) = delete; IDESolver &operator=(const IDESolver &) = delete; @@ -129,15 +104,21 @@ class IDESolver n_t Curr; for (unsigned I = 0; I < Cells.size(); ++I) { Curr = Cells[I].getRowKey(); - std::string NStr = IDEProblem.NtoString(Cells[I].getRowKey()); - boost::algorithm::trim(NStr); + auto NStr = llvm::StringRef(IDEProblem.NtoString(Cells[I].getRowKey())) + .trim() + .str(); + std::string NodeStr = ICF->getFunctionName(ICF->getFunctionOf(Curr)) + "::" + NStr; J[DataFlowID][NodeStr]; - std::string FactStr = IDEProblem.DtoString(Cells[I].getColumnKey()); - boost::algorithm::trim(FactStr); - std::string ValueStr = IDEProblem.LtoString(Cells[I].getValue()); - boost::algorithm::trim(ValueStr); + std::string FactStr = + llvm::StringRef(IDEProblem.DtoString(Cells[I].getColumnKey())) + .trim() + .str(); + std::string ValueStr = + llvm::StringRef(IDEProblem.LtoString(Cells[I].getValue())) + .trim() + .str(); J[DataFlowID][NodeStr]["Facts"] += {FactStr, ValueStr}; } } @@ -418,27 +399,6 @@ class IDESolver std::map, size_t> FSummaryReuse; - // When transforming an IFDSTabulationProblem into an IDETabulationProblem, - // we need to allocate dynamically, otherwise the objects lifetime runs out - // - as a modifiable r-value reference created here that should be stored in - // a modifiable l-value reference within the IDESolver implementation leads - // to (massive) undefined behavior (and nightmares): - // https://stackoverflow.com/questions/34240794/understanding-the-warning-binding-r-value-to-l-value-reference - template ::value, - IFDSAnalysisDomainTy>> - IDESolver(IFDSTabulationProblem &Problem) - : IFDSExtension(Problem), - IDEProblem(*this->TransformedProblem), - ZeroValue(IDEProblem.getZeroValue()), ICF(IDEProblem.getICFG()), - SolverConfig(IDEProblem.getIFDSIDESolverConfig()), - CachedFlowEdgeFunctions(IDEProblem), - AllTop(IDEProblem.allTopFunction()), - JumpFn(std::make_shared>( - AllTop, IDEProblem)), - Seeds(IDEProblem.initialSeeds()) {} - /// Lines 13-20 of the algorithm; processing a call site in the caller's /// context. /// @@ -466,8 +426,8 @@ class IDESolver // a call node; line 14... d_t d2 = Edge.factAtTarget(); EdgeFunctionPtrType f = jumpFunction(Edge); - const std::set ReturnSiteNs = ICF->getReturnSitesOfCallAt(n); - const std::set Callees = ICF->getCalleesOfCallAt(n); + const auto &ReturnSiteNs = ICF->getReturnSitesOfCallAt(n); + const auto &Callees = ICF->getCalleesOfCallAt(n); IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Possible callees:"); for (auto Callee @@ -518,7 +478,7 @@ class IDESolver ADD_TO_HISTOGRAM("Data-flow facts", res.size(), 1, PAMM_SEVERITY_LEVEL::Full); // for each callee's start point(s) - std::set StartPointsOf = ICF->getStartPointsOf(SCalledProcN); + auto StartPointsOf = ICF->getStartPointsOf(SCalledProcN); if (StartPointsOf.empty()) { PHASAR_LOG_LEVEL(DEBUG, "Start points of '" + ICF->getFunctionName(SCalledProcN) + @@ -921,9 +881,8 @@ class IDESolver // Phase II(ii) // we create an array of all nodes and then dispatch fractions of this // array to multiple threads - const std::set AllNonCallStartNodes = ICF->allNonCallStartNodes(); - valueComputationTask( - {AllNonCallStartNodes.begin(), AllNonCallStartNodes.end()}); + const auto AllNonCallStartNodes = ICF->allNonCallStartNodes(); + valueComputationTask(AllNonCallStartNodes); } /// Schedules the processing of initial seeds, initiating the analysis. @@ -993,8 +952,7 @@ class IDESolver d_t d1 = Edge.factAtSource(); d_t d2 = Edge.factAtTarget(); // for each of the method's start points, determine incoming calls - const std::set StartPointsOf = - ICF->getStartPointsOf(FunctionThatNeedsSummary); + const auto StartPointsOf = ICF->getStartPointsOf(FunctionThatNeedsSummary); std::map Inc; for (n_t SP : StartPointsOf) { // line 21.1 of Naeem/Lhotak/Rodriguez @@ -1086,7 +1044,7 @@ class IDESolver // condition if (SolverConfig.followReturnsPastSeeds() && Inc.empty() && IDEProblem.isZeroValue(d1)) { - const std::set Callers = ICF->getCallersOf(FunctionThatNeedsSummary); + const auto &Callers = ICF->getCallersOf(FunctionThatNeedsSummary); for (n_t Caller : Callers) { for (n_t RetSiteC : ICF->getReturnSitesOfCallAt(Caller)) { FlowFunctionPtrType RetFunction = @@ -1862,9 +1820,10 @@ operator<<(llvm::raw_ostream &OS, return OS; } -template -IDESolver(Problem &) -> IDESolver; +template +IDESolver(Problem &, ICF *) + -> IDESolver; template using IDESolver_P = IDESolver #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h" -#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" - namespace psr { -template struct AnalysisDomainExtender; - template -class IFDSSolver : public IDESolver> { +class IFDSSolver : public IDESolver> { + static_assert(std::is_same_v, + "Expect an IFDS analysis domain"); + public: using ProblemTy = IFDSTabulationProblem; - using D = typename AnalysisDomainTy::d_t; - using N = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using n_t = typename AnalysisDomainTy::n_t; + using i_t = typename AnalysisDomainTy::i_t; - IFDSSolver(IFDSTabulationProblem &IFDSProblem) - : IDESolver>(IFDSProblem) {} + template >> + IFDSSolver(IFDSTabulationProblem &IFDSProblem, const i_t *ICF) + : IDESolver>(IFDSProblem, ICF) {} - ~IFDSSolver() override = default; + virtual ~IFDSSolver() = default; /// Returns the data-flow results at the given statement. - [[nodiscard]] virtual std::set ifdsResultsAt(N Inst) { - std::set KeySet; - std::unordered_map ResultMap = this->resultsAt(Inst); + [[nodiscard]] virtual std::set ifdsResultsAt(n_t Inst) { + std::set KeySet; + std::unordered_map ResultMap = this->resultsAt(Inst); for (const auto &FlowFact : ResultMap) { KeySet.insert(FlowFact.first); } @@ -69,10 +72,10 @@ class IFDSSolver : public IDESolver> { /// This result accessor function returns the results at the successor /// instruction(s) reflecting that the expression on the left-hand side holds /// if the expression on the right-hand side holds. - template + template [[nodiscard]] typename std::enable_if_t< std::is_same_v, llvm::Instruction *>, - std::set> + std::set> ifdsResultsAtInLLVMSSA(NTy Inst) { auto getResultMap // NOLINT = [this, Inst]() { @@ -86,7 +89,7 @@ class IFDSSolver : public IDESolver> { "Expected to find a valid successor node!"); return this->resultsAt(Inst->getNextNode()); }; - std::set KeySet; + std::set KeySet; for (auto &[FlowFact, LatticeValue] : getResultMap()) { KeySet.insert(FlowFact); } @@ -94,8 +97,9 @@ class IFDSSolver : public IDESolver> { } }; -template -IFDSSolver(Problem &) -> IFDSSolver; +template +IFDSSolver(Problem &, ICF *) + -> IFDSSolver; template using IFDSSolver_P = IFDSSolver; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h deleted file mode 100644 index 1e7c58cde..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSToIDETabulationProblem.h +++ /dev/null @@ -1,201 +0,0 @@ -/****************************************************************************** - * 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_DATAFLOWSOLVER_IFDSIDE_SOLVER_IFDSTOIDETABULATIONPROBLEM_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IFDSTOIDETABULATIONPROBLEM_H - -#include -#include -#include -#include - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" - -namespace psr { - -extern const std::shared_ptr> ALLBOTTOM; - -template -struct AnalysisDomainExtender : public OriginalAnalysisDomain { - static_assert( - std::is_same::value || - std::is_same::value, - "Lattice domain is overwritten here, expected it to be void or " - "BinaryDomain but found a different type."); - using BaseAnalysisDomain = OriginalAnalysisDomain; - using l_t = BinaryDomain; -}; - -template -struct is_analysis_domain_extensions : std::false_type {}; // NOLINT - -template -struct is_analysis_domain_extensions< - AnalysisDomainTy, - std::void_t> - : std::true_type {}; - -/** - * This class promotes a given IFDSTabulationProblem to an IDETabulationProblem - * using a binary domain for the edge functions. - */ -template > -class IFDSToIDETabulationProblem - : public IDETabulationProblem, - Container> { - using typename IDETabulationProblem, - Container>::FlowFunctionPtrType; - - using n_t = typename AnalysisDomainExtender::n_t; - using f_t = typename AnalysisDomainExtender::f_t; - using d_t = typename AnalysisDomainExtender::d_t; - using l_t = typename AnalysisDomainExtender::l_t; - -public: - IFDSTabulationProblem &Problem; - - IFDSToIDETabulationProblem( - IFDSTabulationProblem &IFDSProblem) - : IDETabulationProblem>( - IFDSProblem.getProjectIRDB(), IFDSProblem.getTypeHierarchy(), - IFDSProblem.getICFG(), IFDSProblem.getPointstoInfo(), - IFDSProblem.getEntryPoints()), - Problem(IFDSProblem) { - this->ZeroValue = Problem.createZeroValue(); - } - - FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override { - return Problem.getNormalFlowFunction(Curr, Succ); - } - - FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override { - return Problem.getCallFlowFunction(CallSite, DestFun); - } - - FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, - n_t ExitInst, n_t RetSite) override { - return Problem.getRetFlowFunction(CallSite, CalleeFun, ExitInst, RetSite); - } - - FlowFunctionPtrType getCallToRetFlowFunction(n_t CallSite, n_t RetSite, - std::set Callees) override { - return Problem.getCallToRetFlowFunction(CallSite, RetSite, Callees); - } - - FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, - f_t DestFun) override { - return Problem.getSummaryFlowFunction(CallSite, DestFun); - } - - InitialSeeds initialSeeds() override { - return Problem.initialSeeds(); - } - - [[nodiscard]] d_t createZeroValue() const override { - return Problem.createZeroValue(); - } - - [[nodiscard]] bool isZeroValue(d_t Fact) const override { - return Problem.isZeroValue(Fact); - } - - BinaryDomain topElement() override { return BinaryDomain::TOP; } - - BinaryDomain bottomElement() override { return BinaryDomain::BOTTOM; } - - BinaryDomain join(BinaryDomain Lhs, BinaryDomain Rhs) override { - if (Lhs == BinaryDomain::TOP && Rhs == BinaryDomain::TOP) { - return BinaryDomain::TOP; - } - return BinaryDomain::BOTTOM; - } - - std::shared_ptr> allTopFunction() override { - return std::make_shared>(BinaryDomain::TOP); - } - - std::shared_ptr> - getNormalEdgeFunction(n_t /*Src*/, d_t SrcNode, n_t /*Tgt*/, - d_t /*TgtNode*/) override { - if (Problem.isZeroValue(SrcNode)) { - return ALLBOTTOM; - } - return EdgeIdentity::getInstance(); - } - - std::shared_ptr> - getCallEdgeFunction(n_t /*CallSite*/, d_t SrcNode, - f_t /*DestinationFunction*/, d_t /*DestNode*/) override { - if (Problem.isZeroValue(SrcNode)) { - return ALLBOTTOM; - } - return EdgeIdentity::getInstance(); - } - - std::shared_ptr> - getReturnEdgeFunction(n_t /*CallSite*/, f_t /*CalleeFunction*/, - n_t /*ExitInst*/, d_t ExitNode, n_t /*ReturnSite*/, - d_t /*RetNode*/) override { - if (Problem.isZeroValue(ExitNode)) { - return ALLBOTTOM; - } - return EdgeIdentity::getInstance(); - } - - std::shared_ptr> - getCallToRetEdgeFunction(n_t /*CallSite*/, d_t CallNode, n_t /*ReturnSite*/, - d_t /*ReturnSideNode*/, - std::set /*Callees*/) override { - if (Problem.isZeroValue(CallNode)) { - return ALLBOTTOM; - } - return EdgeIdentity::getInstance(); - } - - std::shared_ptr> - getSummaryEdgeFunction(n_t /*CallSite*/, d_t /*CallNode*/, n_t /*RetSite*/, - d_t /*RetSiteNode*/) override { - return EdgeIdentity::getInstance(); - } - - void printNode(llvm::raw_ostream &OS, n_t Stmt) const override { - Problem.printNode(OS, Stmt); - } - - void printDataFlowFact(llvm::raw_ostream &OS, d_t Fact) const override { - Problem.printDataFlowFact(OS, Fact); - } - - void printFunction(llvm::raw_ostream &OS, f_t Func) const override { - Problem.printFunction(OS, Func); - } - - void printEdgeFact(llvm::raw_ostream &OS, BinaryDomain Val) const override { - OS << Val; - } - - void emitTextReport(const SolverResults &Results, - llvm::raw_ostream &OS = llvm::outs()) override { - Problem.emitTextReport(Results, OS); - } - - void emitGraphicalReport(const SolverResults &Results, - llvm::raw_ostream &OS = llvm::outs()) override { - Problem.emitGraphicalReport(Results, OS); - } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JoinHandlingNode.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JoinHandlingNode.h deleted file mode 100644 index 4aff86257..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JoinHandlingNode.h +++ /dev/null @@ -1,66 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * JoinHandlingNode.h - * - * Created on: 23.11.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_JOINHANDLINGNODE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_JOINHANDLINGNODE_H - -#include - -namespace psr { - -template class JoinHandlingNode { -public: - virtual ~JoinHandlingNode(); - JoinHandlingNode(JoinHandlingNode &Other) = delete; - JoinHandlingNode &operator=(JoinHandlingNode &Other) = delete; - /** - * - * @param joiningNode the node abstraction that was propagated to the same - * target after {@code this} node. - * @return true if the join could be handled and no further propagation of the - * {@code joiningNode} is necessary, otherwise false meaning - * the node should be propagated by the solver. - */ - virtual bool handleJoin(T JoiningNode) = 0; - - class JoinKey { - private: - std::vector Elements; - - public: - /** - * - * @param elements Passed elements must be immutable with respect to their - * hashCode and equals implementations. - */ - JoinKey(std::vector Elems) : Elements(Elems) {} - int hash() { return 0; } - bool equals() { return false; } - }; - - /** - * - * @return a JoinKey object used to identify which node abstractions require - * manual join handling. - * For nodes with {@code equal} JoinKey instances {@link - * #handleJoin(JoinHandlingNode)} will be called. - */ - virtual JoinKey createJoinKey() = 0; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JoinHandlingNodeIFDSSolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JoinHandlingNodeIFDSSolver.h deleted file mode 100644 index c22502f17..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JoinHandlingNodeIFDSSolver.h +++ /dev/null @@ -1,44 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * JoinHandlingNodeIFDSSolver.h - * - * Created on: 23.11.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_IFDSIDE_SOLVER_JOINHANDLINGNODEIFDSSOLVER_H_ -#define PHASAR_PHASARLLVM_IFDSIDE_SOLVER_JOINHANDLINGNODEIFDSSOLVER_H_ - -namespace psr { - -/** - * An {@link IFDSSolver} that tracks paths for reporting. To do so, it requires - * that data-flow abstractions implement the LinkedNode interface. - * The solver implements a cache of data-flow facts for each statement and - * source value. If for the same statement and source value the same - * target value is seen again (as determined through a cache hit), then the - * solver propagates the cached value but at the same time links - * both target values with one another. - */ -template -class JoinHandlingNodesIFDSSolver { - // class JoinHandlingNodesIFDSSolver, F, I - // extends InterproceduralCFG> extends IFDSSolver { - // - // public JoinHandlingNodesIFDSSolver(IFDSTabulationProblem - // ifdsProblem) { - // super(ifdsProblem); - // } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/LinkedNode.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/LinkedNode.h deleted file mode 100644 index 41cf0d22e..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/LinkedNode.h +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * LinkedNode.h - * - * Created on: 23.11.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_LINKEDNODE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_LINKEDNODE_H - -namespace psr { - -/** - * A data-flow fact that can be linked with other equal facts. - * Equality and hash-code operations must not take the linking data - * structures into account! - * - * @deprecated Use {@link JoinHandlingNode} instead. - */ -template class LinkedNode { -public: - virtual ~LinkedNode() = default; - /** - * Links this node to a neighbor node, i.e., to an abstraction that would have - * been merged - * with this one of paths were not being tracked. - */ - virtual void addNeighbor(D OriginalAbstraction) = 0; - virtual void setCallingContext(D CallingContext) = 0; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h index 1cf3ed6a1..9efebee1c 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h @@ -17,16 +17,16 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_INTERMONOPROBLEM_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_INTERMONOPROBLEM_H +#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" +#include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" +#include "phasar/Utils/BitVectorSet.h" + #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" -#include "phasar/Utils/BitVectorSet.h" - namespace psr { -class ProjectIRDB; template class TypeHierarchy; template class PointsToInfo; template class ICFG; @@ -40,20 +40,23 @@ class InterMonoProblem : public IntraMonoProblem { using t_t = typename AnalysisDomainTy::t_t; using v_t = typename AnalysisDomainTy::v_t; using i_t = typename AnalysisDomainTy::i_t; + using db_t = typename AnalysisDomainTy::db_t; using mono_container_t = typename AnalysisDomainTy::mono_container_t; - static_assert(std::is_base_of_v, i_t>, - "I must implement the ICFG interface!"); - protected: const i_t *ICF; public: - InterMonoProblem(const ProjectIRDB *IRDB, const TypeHierarchy *TH, + InterMonoProblem(const db_t *IRDB, const TypeHierarchy *TH, const i_t *ICF, const PointsToInfo *PT, - std::set EntryPoints = {}) + std::vector EntryPoints = {}) : IntraMonoProblem(IRDB, TH, ICF, PT, EntryPoints), - ICF(ICF) {} + ICF(ICF) { + static_assert(is_icfg_v, + "Type parameter i_t must implement the ICFG interface!"); + static_assert(std::is_base_of_v, db_t>, + "db_t must implement the ProjectIRDBBase interface!"); + } ~InterMonoProblem() override = default; InterMonoProblem(const InterMonoProblem &Other) = delete; @@ -69,7 +72,7 @@ class InterMonoProblem : public IntraMonoProblem { const mono_container_t &In) = 0; virtual mono_container_t callToRetFlow(n_t CallSite, n_t RetSite, - std::set Callees, + llvm::ArrayRef Callees, const mono_container_t &In) = 0; [[nodiscard]] const i_t *getICFG() const { return ICF; } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h index 40177c2d4..77f8beb26 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h @@ -17,20 +17,21 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_INTRAMONOPROBLEM_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_INTRAMONOPROBLEM_H +#include "phasar/DB/ProjectIRDBBase.h" +#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" +#include "phasar/PhasarLLVM/Utils/Printer.h" +#include "phasar/Utils/BitVectorSet.h" +#include "phasar/Utils/Soundness.h" + #include #include #include #include -#include "phasar/PhasarLLVM/Utils/Printer.h" -#include "phasar/Utils/BitVectorSet.h" -#include "phasar/Utils/Soundness.h" - namespace psr { struct HasNoConfigurationType; -class ProjectIRDB; template class TypeHierarchy; template class PointsToInfo; template class CFG; @@ -47,31 +48,34 @@ class IntraMonoProblem : public NodePrinter, using v_t = typename AnalysisDomainTy::v_t; using i_t = typename AnalysisDomainTy::i_t; using c_t = typename AnalysisDomainTy::c_t; + using db_t = typename AnalysisDomainTy::db_t; using mono_container_t = typename AnalysisDomainTy::mono_container_t; - static_assert(std::is_base_of_v, c_t>, - "c_t must implement the CFG interface!"); - using ProblemAnalysisDomain = AnalysisDomainTy; protected: - const ProjectIRDB *IRDB; + const db_t *IRDB; const TypeHierarchy *TH; const c_t *CF; const PointsToInfo *PT; - std::set EntryPoints; - [[maybe_unused]] Soundness S = Soundness::Unused; + std::vector EntryPoints; + [[maybe_unused]] Soundness S = Soundness::Soundy; public: // denote that a problem does not require a configuration (type/file) // a user problem can override the type of configuration to be used, if any using ConfigurationTy = HasNoConfigurationType; - IntraMonoProblem(const ProjectIRDB *IRDB, const TypeHierarchy *TH, + IntraMonoProblem(const db_t *IRDB, const TypeHierarchy *TH, const c_t *CF, const PointsToInfo *PT, - std::set EntryPoints = {}) + std::vector EntryPoints = {}) : IRDB(IRDB), TH(TH), CF(CF), PT(PT), - EntryPoints(std::move(EntryPoints)) {} + EntryPoints(std::move(EntryPoints)) { + static_assert(is_cfg_v, + "c_t must implement the CFG interface!"); + static_assert(std::is_base_of_v, db_t>, + "db_t must implement the ProjectIRDBBase interface!"); + } ~IntraMonoProblem() override = default; @@ -87,11 +91,11 @@ class IntraMonoProblem : public NodePrinter, virtual std::unordered_map initialSeeds() = 0; - [[nodiscard]] std::set getEntryPoints() const { + [[nodiscard]] const std::vector &getEntryPoints() const { return EntryPoints; } - [[nodiscard]] const ProjectIRDB *getProjectIRDB() const { return IRDB; } + [[nodiscard]] const db_t *getProjectIRDB() const { return IRDB; } [[nodiscard]] const TypeHierarchy *getTypeHierarchy() const { return TH; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h index 8ae4bcc97..046f5f0f4 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h @@ -10,17 +10,17 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOFULLCONSTANTPROPAGATION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOFULLCONSTANTPROPAGATION_H +#include "phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h" +#include "phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoFullConstantPropagation.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" + #include #include #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h" -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoFullConstantPropagation.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" -#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" - namespace llvm { class Value; class Instruction; @@ -30,7 +30,6 @@ class StructType; namespace psr { -class ProjectIRDB; class LLVMBasedICFG; class LLVMTypeHierarchy; class LLVMPointsToInfo; @@ -48,11 +47,11 @@ class InterMonoFullConstantPropagation using i_t = IntraMonoFullConstantPropagation::i_t; using mono_container_t = IntraMonoFullConstantPropagation::mono_container_t; - InterMonoFullConstantPropagation(const ProjectIRDB *IRDB, + InterMonoFullConstantPropagation(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, const LLVMBasedICFG *ICF, const LLVMPointsToInfo *PT, - std::set EntryPoints = {}); + std::vector EntryPoints = {}); ~InterMonoFullConstantPropagation() override = default; @@ -65,7 +64,7 @@ class InterMonoFullConstantPropagation n_t RetSite, const mono_container_t &In) override; mono_container_t callToRetFlow(n_t CallSite, n_t RetSite, - std::set Callees, + llvm::ArrayRef Callees, const mono_container_t &In) override; mono_container_t merge(const mono_container_t &Lhs, diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h index 035754b30..7b8cadb5e 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h @@ -17,16 +17,15 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOSOLVERTEST_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOSOLVERTEST_H +#include "phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/Utils/BitVectorSet.h" + #include #include #include #include -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" -#include "phasar/Utils/BitVectorSet.h" - namespace llvm { class Instruction; class Value; @@ -53,9 +52,9 @@ class InterMonoSolverTest : public InterMonoProblem { using i_t = InterMonoSolverTestDomain::i_t; using mono_container_t = InterMonoSolverTestDomain::mono_container_t; - InterMonoSolverTest(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, + InterMonoSolverTest(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, const LLVMBasedICFG *ICF, const LLVMPointsToInfo *PT, - std::set EntryPoints = {}); + std::vector EntryPoints = {}); ~InterMonoSolverTest() override = default; @@ -74,7 +73,7 @@ class InterMonoSolverTest : public InterMonoProblem { n_t RetSite, const mono_container_t &In) override; mono_container_t callToRetFlow(n_t CallSite, n_t RetSite, - std::set Callees, + llvm::ArrayRef Callees, const mono_container_t &In) override; std::unordered_map initialSeeds() override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h index 80462b2f7..ed97f674b 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h @@ -17,16 +17,16 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOTAINTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOTAINTANALYSIS_H -#include -#include -#include - #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" #include "phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" #include "phasar/Utils/BitVectorSet.h" +#include +#include +#include + namespace llvm { class Instruction; class Value; @@ -55,10 +55,10 @@ class InterMonoTaintAnalysis using mono_container_t = InterMonoTaintAnalysisDomain::mono_container_t; using ConfigurationTy = TaintConfig; - InterMonoTaintAnalysis(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, const LLVMPointsToInfo *PT, - const TaintConfig &Config, - std::set EntryPoints = {}); + InterMonoTaintAnalysis(const LLVMProjectIRDB *IRDB, + const LLVMTypeHierarchy *TH, const LLVMBasedICFG *ICF, + const LLVMPointsToInfo *PT, const TaintConfig &Config, + std::vector EntryPoints = {}); ~InterMonoTaintAnalysis() override = default; @@ -77,7 +77,7 @@ class InterMonoTaintAnalysis n_t RetSite, const mono_container_t &In) override; mono_container_t callToRetFlow(n_t CallSite, n_t RetSite, - std::set Callees, + llvm::ArrayRef Callees, const mono_container_t &In) override; std::unordered_map initialSeeds() override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoFullConstantPropagation.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoFullConstantPropagation.h index 5f97797e8..08aff4aa4 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoFullConstantPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoFullConstantPropagation.h @@ -17,6 +17,11 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOFULLCONSTANTPROPAGATION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOFULLCONSTANTPROPAGATION_H +#include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" +#include "phasar/Utils/BitVectorSet.h" + #include #include #include @@ -24,11 +29,6 @@ #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" -#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" -#include "phasar/Utils/BitVectorSet.h" - namespace llvm { class Value; class Instruction; @@ -40,7 +40,6 @@ namespace psr { class LLVMBasedCFG; class LLVMBasedICFG; -class ProjectIRDB; class LLVMTypeHierarchy; class LLVMPointsToInfo; class InterMonoFullConstantPropagation; @@ -75,11 +74,11 @@ class IntraMonoFullConstantPropagation executeBinOperation(unsigned Op, plain_d_t Lop, plain_d_t Rop); public: - IntraMonoFullConstantPropagation(const ProjectIRDB *IRDB, + IntraMonoFullConstantPropagation(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, const LLVMBasedCFG *CF, const LLVMPointsToInfo *PT, - std::set EntryPoints = {}); + std::vector EntryPoints = {}); ~IntraMonoFullConstantPropagation() override = default; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoSolverTest.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoSolverTest.h index eea0b05fb..d0e81b6b6 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoSolverTest.h @@ -17,14 +17,14 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOSOLVERTEST_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOSOLVERTEST_H +#include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/Utils/BitVectorSet.h" + #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" -#include "phasar/Utils/BitVectorSet.h" - namespace llvm { class Value; class Instruction; @@ -54,9 +54,9 @@ class IntraMonoSolverTest using i_t = IntraMonoSolverTestAnalysisDomain::i_t; using mono_container_t = IntraMonoSolverTestAnalysisDomain::mono_container_t; - IntraMonoSolverTest(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, + IntraMonoSolverTest(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, const LLVMBasedCFG *CF, const LLVMPointsToInfo *PT, - std::set EntryPoints = {}); + std::vector EntryPoints = {}); ~IntraMonoSolverTest() override = default; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoUninitVariables.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoUninitVariables.h index 32b28cb85..902a23df9 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoUninitVariables.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoUninitVariables.h @@ -10,14 +10,14 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOUNINITVARIABLES_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTRAMONOUNINITVARIABLES_H +#include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + #include #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - namespace llvm { class Value; class Instruction; @@ -47,9 +47,10 @@ class IntraMonoUninitVariables using i_t = IntraMonoUninitVariablesDomain::i_t; using mono_container_t = IntraMonoUninitVariablesDomain::mono_container_t; - IntraMonoUninitVariables(const ProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedCFG *CF, const LLVMPointsToInfo *PT, - std::set EntryPoints = {}); + IntraMonoUninitVariables(const LLVMProjectIRDB *IRDB, + const LLVMTypeHierarchy *TH, const LLVMBasedCFG *CF, + const LLVMPointsToInfo *PT, + std::vector EntryPoints = {}); ~IntraMonoUninitVariables() override = default; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h index 441373c42..254ee7eec 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h @@ -295,15 +295,18 @@ template class InterMonoSolver { auto CTXRm(Ctx); llvm::outs() << "CTXRm: " << CTXRm << '\n'; // we need to use several call- and retsites if the context is empty - std::set CallSites; - std::set RetSites; + llvm::SmallVector CallSites; + // handle empty context if (Ctx.empty()) { - CallSites = ICF->getCallersOf(ICF->getFunctionOf(Src)); + const auto &Callers = ICF->getCallersOf(ICF->getFunctionOf(Src)); + CallSites.append(Callers.begin(), Callers.end()); } else { // handle context containing at least one element - CallSites.insert(CTXRm.pop_back()); + CallSites.push_back(CTXRm.pop_back()); } + + std::set RetSites; // retrieve the possible return sites for each call for (auto CallSite : CallSites) { auto RetSitesPerCall = ICF->getReturnSitesOfCallAt(CallSite); diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/IntraMonoSolver.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/IntraMonoSolver.h index 90a5bb0c1..32d397914 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/IntraMonoSolver.h +++ b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/IntraMonoSolver.h @@ -46,7 +46,7 @@ template class IntraMonoSolver { const c_t *CFG; void initialize() { - auto EntryPoints = IMProblem.getEntryPoints(); + const auto &EntryPoints = IMProblem.getEntryPoints(); for (const auto &EntryPoint : EntryPoints) { auto Function = IMProblem.getProjectIRDB()->getFunctionDefinition(EntryPoint); diff --git a/include/phasar/PhasarLLVM/Domain/AnalysisDomain.h b/include/phasar/PhasarLLVM/Domain/AnalysisDomain.h index c941a8328..02a76f4a8 100644 --- a/include/phasar/PhasarLLVM/Domain/AnalysisDomain.h +++ b/include/phasar/PhasarLLVM/Domain/AnalysisDomain.h @@ -10,14 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DOMAIN_ANALYSISDOMAIN_H #define PHASAR_PHASARLLVM_DOMAIN_ANALYSISDOMAIN_H -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Value.h" - -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" -#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" +#include namespace psr { @@ -57,6 +50,9 @@ struct AnalysisDomain { // Inter-procedural control flow --- Specifies the type of the // inter-procedural control-flow graph to be used. using i_t = void; + // The ProjectIRDB type to use. Must inherit from the ProjectIRDBBase CRTP + // template + using db_t = void; // Lattice element --- Specifies the type of the underlying lattice; the value // computation domain IDE's edge functions or WPDS's weights operate on. using l_t = void; @@ -64,20 +60,28 @@ struct AnalysisDomain { using mono_container_t = void; }; -struct LLVMAnalysisDomainDefault : public AnalysisDomain { - using d_t = const llvm::Value *; - using n_t = const llvm::Instruction *; - using f_t = const llvm::Function *; - using t_t = const llvm::StructType *; - using v_t = const llvm::Value *; - using c_t = LLVMBasedCFG; - using i_t = LLVMBasedICFG; -}; +enum class BinaryDomain; + +namespace detail { +template +struct HasBinaryValueDomain : std::false_type {}; +template +struct HasBinaryValueDomain + : std::true_type {}; -struct LLVMIFDSAnalysisDomainDefault : LLVMAnalysisDomainDefault { +template +struct WithBinaryValueDomainExtender : AnalysisDomainTy { using l_t = BinaryDomain; }; +} // namespace detail + +template +using WithBinaryValueDomain = + std::conditional_t::value, + AnalysisDomainTy, + detail::WithBinaryValueDomainExtender>; + } // namespace psr #endif diff --git a/include/phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h b/include/phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h new file mode 100644 index 000000000..68ec9fda9 --- /dev/null +++ b/include/phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert, Richard Leer, and Florian Sattler. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Philipp Schubert, Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_DOMAIN_LLVMANALYSISDOMAIN_H +#define PHASAR_PHASARLLVM_DOMAIN_LLVMANALYSISDOMAIN_H + +#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" + +namespace llvm { +class Value; +class Instruction; +class StructType; +class Function; +} // namespace llvm + +namespace psr { +class LLVMProjectIRDB; +class LLVMBasedICFG; +class LLVMBasedCFG; + +struct LLVMAnalysisDomainDefault : public AnalysisDomain { + using d_t = const llvm::Value *; + using n_t = const llvm::Instruction *; + using f_t = const llvm::Function *; + using t_t = const llvm::StructType *; + using v_t = const llvm::Value *; + using c_t = LLVMBasedCFG; + using i_t = LLVMBasedICFG; + using db_t = LLVMProjectIRDB; +}; + +using LLVMIFDSAnalysisDomainDefault = + WithBinaryValueDomain; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DOMAIN_LLVMANALYSISDOMAIN_H diff --git a/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h b/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h index cab602d7f..0891893cc 100644 --- a/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h +++ b/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h @@ -45,6 +45,9 @@ class GeneralStatistics { size_t LoadInstructions = 0; size_t MemIntrinsics = 0; size_t GlobalPointers = 0; + size_t Branches = 0; + size_t GetElementPtrs = 0; + size_t PhiNodes = 0; std::set AllocatedTypes; std::set AllocaInstructions; std::set RetResInstructions; @@ -104,20 +107,24 @@ class GeneralStatistics { /** * @brief Returns all possible Types. */ - [[nodiscard]] std::set getAllocatedTypes() const; + [[nodiscard]] const std::set &getAllocatedTypes() const; /** * @brief Returns all stack and heap allocating instructions. */ - [[nodiscard]] std::set + [[nodiscard]] const std::set & getAllocaInstructions() const; /** * @brief Returns all Return and Resume Instructions. */ - [[nodiscard]] std::set + [[nodiscard]] const std::set & getRetResInstructions() const; [[nodiscard]] nlohmann::json getAsJson() const; + void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const GeneralStatistics &Statistics); }; /** @@ -150,7 +157,12 @@ class GeneralStatisticsAnalysis explicit GeneralStatisticsAnalysis() = default; - GeneralStatistics run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); + GeneralStatistics runOnModule(llvm::Module &M); + + inline GeneralStatistics run(llvm::Module &M, + llvm::ModuleAnalysisManager & /*AM*/) { + return runOnModule(M); + } }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h b/include/phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h index 1098e9dd1..899b2cb87 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h @@ -26,7 +26,7 @@ class Instruction; namespace psr { -class ProjectIRDB; +class LLVMProjectIRDB; class LLVMBasedPointsToAnalysis { private: @@ -43,7 +43,7 @@ class LLVMBasedPointsToAnalysis { public: LLVMBasedPointsToAnalysis( - ProjectIRDB &IRDB, bool UseLazyEvaluation = true, + LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, PointerAnalysisType PATy = PointerAnalysisType::CFLAnders); ~LLVMBasedPointsToAnalysis() = default; diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToGraph.h b/include/phasar/PhasarLLVM/Pointer/LLVMPointsToGraph.h index 3d7a9b625..d7d8ff281 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToGraph.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMPointsToGraph.h @@ -130,7 +130,7 @@ class LLVMPointsToGraph : public LLVMPointsToInfo { * considered. False, if May and Must Aliases should be * considered. */ - LLVMPointsToGraph(ProjectIRDB &IRDB, bool UseLazyEvaluation = true, + LLVMPointsToGraph(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, PointerAnalysisType PATy = PointerAnalysisType::CFLAnders); ~LLVMPointsToGraph() override = default; diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h b/include/phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h index b874c87e2..d860c6e45 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h @@ -10,7 +10,6 @@ #ifndef PHASAR_PHASARLLVM_POINTER_LLVMPOINTSTOSET_H #define PHASAR_PHASARLLVM_POINTER_LLVMPOINTSTOSET_H -#include "phasar/DB/ProjectIRDB.h" #include "phasar/PhasarLLVM/Pointer/DynamicPointsToSetPtr.h" #include "phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h" #include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" @@ -34,6 +33,8 @@ class Type; namespace psr { +class LLVMProjectIRDB; + class LLVMPointsToSet : public LLVMPointsToInfo { private: using PointsToSetMap = @@ -80,10 +81,10 @@ class LLVMPointsToSet : public LLVMPointsToInfo { * not use global variables on the fly */ explicit LLVMPointsToSet( - ProjectIRDB &IRDB, bool UseLazyEvaluation = true, + LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, PointerAnalysisType PATy = PointerAnalysisType::CFLAnders); - explicit LLVMPointsToSet(ProjectIRDB &IRDB, + explicit LLVMPointsToSet(LLVMProjectIRDB &IRDB, const nlohmann::json &SerializedPTS); ~LLVMPointsToSet() override = default; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/SyncPDS/Solver/SyncPDSSolver.h b/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.def similarity index 50% rename from include/phasar/PhasarLLVM/DataFlowSolver/SyncPDS/Solver/SyncPDSSolver.h rename to include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.def index 9167963f8..76c75b779 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/SyncPDS/Solver/SyncPDSSolver.h +++ b/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.def @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2018 Philipp Schubert. + * Copyright (c) 2022 Philipp Schubert. * All rights reserved. This program and the accompanying materials are made * available under the terms of LICENSE.txt. * @@ -7,17 +7,11 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_SYNCPDS_SOLVER_SYNCPDSSOLVER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_SYNCPDS_SOLVER_SYNCPDSSOLVER_H - -namespace psr { - -class SyncPDSSolver { -private: -public: - ~SyncPDSSolver() = default; -}; +#ifndef POINTER_ANALYSIS_TYPE +#define POINTER_ANALYSIS_TYPE(NAME, CMDFLAG, DESC) +#endif -} // namespace psr +POINTER_ANALYSIS_TYPE(CFLSteens, "cflsteens", "Steensgaard-style alias analysis (equality-based)") +POINTER_ANALYSIS_TYPE(CFLAnders, "cflanders", "Andersen-style alias analysis (subset-based)") -#endif +#undef POINTER_ANALYSIS_TYPE diff --git a/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.h b/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.h new file mode 100644 index 000000000..771d43a85 --- /dev/null +++ b/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.h @@ -0,0 +1,44 @@ + +/****************************************************************************** + * Copyright (c) 2022 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_POINTER_POINTERANALYSISTYPE_H_ +#define PHASAR_PHASARLLVM_POINTER_POINTERANALYSISTYPE_H_ + +#include "llvm/ADT/StringRef.h" + +#include + +namespace llvm { +class raw_ostream; +} // namespace llvm + +namespace psr { +enum class AliasResult { NoAlias, MayAlias, PartialAlias, MustAlias }; + +std::string toString(AliasResult AR); + +AliasResult toAliasResult(llvm::StringRef S); + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, AliasResult AR); + +enum class PointerAnalysisType { +#define POINTER_ANALYSIS_TYPE(NAME, CMDFLAG, TYPE) NAME, +#include "phasar/PhasarLLVM/Pointer/PointerAnalysisType.def" + Invalid +}; + +std::string toString(PointerAnalysisType PA); + +PointerAnalysisType toPointerAnalysisType(llvm::StringRef S); + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, PointerAnalysisType PA); +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_POINTERANALYSISTYPE_H_ diff --git a/include/phasar/PhasarLLVM/Pointer/PointsToInfo.h b/include/phasar/PhasarLLVM/Pointer/PointsToInfo.h index dfd042c10..a969b0e8a 100644 --- a/include/phasar/PhasarLLVM/Pointer/PointsToInfo.h +++ b/include/phasar/PhasarLLVM/Pointer/PointsToInfo.h @@ -10,36 +10,16 @@ #ifndef PHASAR_PHASARLLVM_POINTER_POINTSTOINFO_H_ #define PHASAR_PHASARLLVM_POINTER_POINTSTOINFO_H_ +#include "phasar/PhasarLLVM/Pointer/DynamicPointsToSetPtr.h" +#include "phasar/PhasarLLVM/Pointer/PointerAnalysisType.h" + #include "llvm/ADT/DenseSet.h" #include "llvm/Support/raw_ostream.h" #include "nlohmann/json.hpp" -#include "phasar/PhasarLLVM/Pointer/DynamicPointsToSetPtr.h" - namespace psr { -enum class AliasResult { NoAlias, MayAlias, PartialAlias, MustAlias }; - -std::string toString(AliasResult AR); - -AliasResult toAliasResult(const std::string &S); - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const AliasResult &AR); - -enum class PointerAnalysisType { -#define ANALYSIS_SETUP_POINTER_TYPE(NAME, CMDFLAG, TYPE) TYPE, -#include "phasar/PhasarLLVM/Utils/AnalysisSetups.def" - Invalid -}; - -std::string toString(const PointerAnalysisType &PA); - -PointerAnalysisType toPointerAnalysisType(const std::string &S); - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const PointerAnalysisType &PA); - template class PointsToInfo { public: using PointsToSetTy = llvm::DenseSet; diff --git a/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h b/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h index 2e9b27678..bce6d47d3 100644 --- a/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h +++ b/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h @@ -23,17 +23,16 @@ #include #include +#include "phasar/Utils/MemoryResource.h" + /// On some MAC systems, is still not fully implemented, so do /// a workaround here -#if !defined(__has_include) || __has_include() -#define HAS_MEMORY_RESOURCE 1 +#if HAS_MEMORY_RESOURCE #include #else -#define HAS_MEMORY_RESOURCE 0 #include "llvm/Support/RecyclingAllocator.h" #endif - namespace llvm { class Value; } // namespace llvm diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfig.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfig.h index 51ac0aede..b0bcbe586 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfig.h +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfig.h @@ -23,9 +23,8 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Value.h" -#include "phasar/DB/ProjectIRDB.h" - namespace psr { +class LLVMProjectIRDB; enum class TaintCategory { Source, Sink, Sanitizer, None }; @@ -52,14 +51,15 @@ TaintCategory toTaintCategory(llvm::StringRef Str); // analysis. class TaintConfig { - void addAllFunctions(const ProjectIRDB &IRDB, const nlohmann::json &Config); + void addAllFunctions(const LLVMProjectIRDB &IRDB, + const nlohmann::json &Config); public: using TaintDescriptionCallBackTy = std::function(const llvm::Instruction *)>; - TaintConfig(const psr::ProjectIRDB &Code, const nlohmann::json &Config); - TaintConfig(const psr::ProjectIRDB &AnnotatedCode); + TaintConfig(const psr::LLVMProjectIRDB &Code, const nlohmann::json &Config); + TaintConfig(const psr::LLVMProjectIRDB &AnnotatedCode); TaintConfig( TaintDescriptionCallBackTy SourceCB, TaintDescriptionCallBackTy SinkCB, TaintDescriptionCallBackTy SanitizerCB = TaintDescriptionCallBackTy{}); diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h index 6c92987be..fba7497e4 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h @@ -10,15 +10,15 @@ #ifndef PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGUTILITIES_H #define PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGUTILITIES_H -#include -#include -#include +#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" -#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include +#include +#include namespace psr { template -#include -#include -#include -#include -#include +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" +#include "phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h" #include "boost/graph/adjacency_list.hpp" #include "boost/graph/graph_traits.hpp" @@ -33,8 +29,12 @@ #include "nlohmann/json.hpp" -#include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" -#include "phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h" +#include +#include +#include +#include +#include +#include namespace llvm { class Module; @@ -45,7 +45,7 @@ class GlobalVariable; namespace psr { -class ProjectIRDB; +class LLVMProjectIRDB; /** * @brief Owns the class hierarchy of the analyzed program. * @@ -147,7 +147,7 @@ class LLVMTypeHierarchy * given ProjectIRCompiledDB. * @param IRDB ProjectIRCompiledDB object. */ - LLVMTypeHierarchy(ProjectIRDB &IRDB); + LLVMTypeHierarchy(LLVMProjectIRDB &IRDB); /** * @brief Creates a LLVMStructTypeHierarchy based on the diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h b/include/phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h index 883707d55..c09e82dc1 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h @@ -17,6 +17,8 @@ #include "phasar/PhasarLLVM/TypeHierarchy/VFTable.h" +#include "llvm/Support/raw_ostream.h" + namespace psr { template class TypeHierarchy { diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/VFTable.h b/include/phasar/PhasarLLVM/TypeHierarchy/VFTable.h index 14e406941..146c29ccf 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/VFTable.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/VFTable.h @@ -13,6 +13,11 @@ #include #include "nlohmann/json.hpp" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +class raw_ostream; +} // namespace llvm namespace psr { diff --git a/include/phasar/PhasarLLVM/Utils/AnalysisSetups.def b/include/phasar/PhasarLLVM/Utils/AnalysisSetups.def deleted file mode 100644 index 528127c80..000000000 --- a/include/phasar/PhasarLLVM/Utils/AnalysisSetups.def +++ /dev/null @@ -1,29 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2019 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 ANALYSIS_SETUP_CALLGRAPH_TYPE -#define ANALYSIS_SETUP_CALLGRAPH_TYPE(NAME, CMDFLAG, TYPE) -#endif - -ANALYSIS_SETUP_CALLGRAPH_TYPE("NORESOLVE", "nores", NORESOLVE) -ANALYSIS_SETUP_CALLGRAPH_TYPE("CHA", "cha", CHA) -ANALYSIS_SETUP_CALLGRAPH_TYPE("RTA", "rta", RTA) -ANALYSIS_SETUP_CALLGRAPH_TYPE("DTA", "dta", DTA) -ANALYSIS_SETUP_CALLGRAPH_TYPE("VTA", "vta", VTA) -ANALYSIS_SETUP_CALLGRAPH_TYPE("OTF", "otf", OTF) - -#ifndef ANALYSIS_SETUP_POINTER_TYPE -#define ANALYSIS_SETUP_POINTER_TYPE(NAME, CMDFLAG, TYPE) -#endif - -ANALYSIS_SETUP_POINTER_TYPE("CFLSteens", "cflsteens", CFLSteens) -ANALYSIS_SETUP_POINTER_TYPE("CFLAnders", "cflanders", CFLAnders) - -#undef ANALYSIS_SETUP_CALLGRAPH_TYPE -#undef ANALYSIS_SETUP_POINTER_TYPE diff --git a/include/phasar/PhasarLLVM/Utils/BinaryDomain.h b/include/phasar/PhasarLLVM/Utils/BinaryDomain.h index 41a419d65..8e159062a 100644 --- a/include/phasar/PhasarLLVM/Utils/BinaryDomain.h +++ b/include/phasar/PhasarLLVM/Utils/BinaryDomain.h @@ -17,21 +17,17 @@ #ifndef PHASAR_PHASARLLVM_UTILS_BINARYDOMAIN_H_ #define PHASAR_PHASARLLVM_UTILS_BINARYDOMAIN_H_ -#include +#include namespace llvm { class raw_ostream; -} +} // namespace llvm namespace psr { enum class BinaryDomain { BOTTOM = 0, TOP = 1 }; -extern const std::map StringToBinaryDomain; - -extern const std::map BinaryDomainToString; - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const BinaryDomain &B); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, BinaryDomain B); } // namespace psr diff --git a/include/phasar/PhasarLLVM/Utils/ByRef.h b/include/phasar/PhasarLLVM/Utils/ByRef.h new file mode 100644 index 000000000..4573956b9 --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils/ByRef.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_UTILS_BYREF_H +#define PHASAR_PHASARLLVM_UTILS_BYREF_H + +#include + +namespace psr { +template +using ByConstRef = std::conditional_t, + T, const T &>; +template +using ByMoveRef = std::conditional_t, + T, T &&>; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_UTILS_BYREF_H diff --git a/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.def b/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.def index 5dbb7b1be..3f3e28788 100644 --- a/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.def +++ b/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.def @@ -8,27 +8,27 @@ *****************************************************************************/ #ifndef DATA_FLOW_ANALYSIS_TYPES -#define DATA_FLOW_ANALYSIS_TYPES(NAME, CMDFLAG, TYPE) +#define DATA_FLOW_ANALYSIS_TYPES(NAME, CMDFLAG, DESC) #endif -DATA_FLOW_ANALYSIS_TYPES("IFDSUninitializedVariables", "ifds-uninit", IFDSUninitializedVariables) -DATA_FLOW_ANALYSIS_TYPES("IFDSConstAnalysis", "ifds-const", IFDSConstAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IFDSTaintAnalysis", "ifds-taint", IFDSTaintAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IDETaintAnalysis", "ide-taint", IDETaintAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IDEXTaintAnalysis", "ide-xtaint", IDEExtendedTaintAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IFDSTypeAnalysis", "ifds-type", IFDSTypeAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IDECSTDIOTypeStateAnalysis", "ide-stdio-ts", IDECSTDIOTypeStateAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IDEOpenSSLTypeStateAnalysis", "ide-openssl-ts", IDEOpenSSLTypeStateAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IFDSSolverTest", "ifds-solvertest", IFDSSolverTest) -DATA_FLOW_ANALYSIS_TYPES("IFDSLinearConstantAnalysis", "ifds-lca", IFDSLinearConstantAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IFDSFieldSensTaintAnalysis", "ifds-fstaint", IFDSFieldSensTaintAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IDELinearConstantAnalysis", "ide-lca", IDELinearConstantAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IDESolverTest", "ide-solvertest", IDESolverTest) -DATA_FLOW_ANALYSIS_TYPES("IDEInstInteractionAnalysis", "ide-iia", IDEInstInteractionAnalysis) -DATA_FLOW_ANALYSIS_TYPES("IntraMonoFullConstantPropagation", "intra-mono-fca", IntraMonoFullConstantPropagation) -DATA_FLOW_ANALYSIS_TYPES("IntraMonoSolverTest", "intra-mono-solvertest", IntraMonoSolverTest) -DATA_FLOW_ANALYSIS_TYPES("InterMonoSolverTest", "inter-mono-solvertest", InterMonoSolverTest) -DATA_FLOW_ANALYSIS_TYPES("InterMonoTaintAnalysis", "inter-mono-taint", InterMonoTaintAnalysis) -DATA_FLOW_ANALYSIS_TYPES("None", "none", None) +DATA_FLOW_ANALYSIS_TYPES(IFDSUninitializedVariables, "ifds-uninit", "Find usages of uninitialized variables.") +DATA_FLOW_ANALYSIS_TYPES(IFDSConstAnalysis, "ifds-const", "Find variables that are actually mutated through the program") +DATA_FLOW_ANALYSIS_TYPES(IFDSTaintAnalysis, "ifds-taint", "Simple, alias-aware taint-analysis. Use with --analysis-config") +DATA_FLOW_ANALYSIS_TYPES(IDETaintAnalysis, "ide-taint", "Not implemented yet") +DATA_FLOW_ANALYSIS_TYPES(IDEExtendedTaintAnalysis, "ide-xtaint", "More advanced alias-aware taint analysis that provides limited field-sensitivity. Use with --analysis-config") +DATA_FLOW_ANALYSIS_TYPES(IFDSTypeAnalysis, "ifds-type", "Simple type analysis") +DATA_FLOW_ANALYSIS_TYPES(IDECSTDIOTypeStateAnalysis, "ide-stdio-ts", "Find invalid usages of the libc file-io") +DATA_FLOW_ANALYSIS_TYPES(IDEOpenSSLTypeStateAnalysis, "ide-openssl-ts", "Find invalid usages of a subset of the OpenSSL EVP library") +DATA_FLOW_ANALYSIS_TYPES(IFDSSolverTest, "ifds-solvertest", "Empty analysis. Just to see that the IFDS solver works") +DATA_FLOW_ANALYSIS_TYPES(IFDSLinearConstantAnalysis, "ifds-lca", "IFDS-based constant analysis. Use ide-lca instead") +DATA_FLOW_ANALYSIS_TYPES(IFDSFieldSensTaintAnalysis, "ifds-fstaint", "Specialized taint analysis for tracing environment variables.") +DATA_FLOW_ANALYSIS_TYPES(IDELinearConstantAnalysis, "ide-lca", "Simple linear constant propagation") +DATA_FLOW_ANALYSIS_TYPES(IDESolverTest, "ide-solvertest", "Empty analysis. Just to see that the IDE solver works") +DATA_FLOW_ANALYSIS_TYPES(IDEInstInteractionAnalysis, "ide-iia", "Which instruction has influence on which other instructions?") +DATA_FLOW_ANALYSIS_TYPES(IntraMonoFullConstantPropagation, "intra-mono-fca", "Simple constant propagation without the restriction to linear binary operations. Only works inTRA-procedurally") +DATA_FLOW_ANALYSIS_TYPES(IntraMonoSolverTest, "intra-mono-solvertest", "Empty analysis. Just to see that the intraprocedural monotone solver works") +DATA_FLOW_ANALYSIS_TYPES(InterMonoSolverTest, "inter-mono-solvertest", "Empty analysis. Just to see that the interprocedural monotone solver works") +DATA_FLOW_ANALYSIS_TYPES(InterMonoTaintAnalysis, "inter-mono-taint", "Simple taint analysis using the monotone framework with k-limited call-strings. Use ifds-taint or ide-xtaint instead.") + #undef DATA_FLOW_ANALYSIS_TYPES diff --git a/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h b/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h index 13281833b..66a38efcd 100644 --- a/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h +++ b/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h @@ -10,31 +10,23 @@ #ifndef PHASAR_PHASARLLVM_UTILS_DATAFLOWANALYSISTYPE_H_ #define PHASAR_PHASARLLVM_UTILS_DATAFLOWANALYSISTYPE_H_ -#include -#include +#include "llvm/Support/raw_ostream.h" -namespace llvm { -class raw_ostream; -} +#include namespace psr { enum class DataFlowAnalysisType { -#define DATA_FLOW_ANALYSIS_TYPES(NAME, CMDFLAG, TYPE) TYPE, + None, +#define DATA_FLOW_ANALYSIS_TYPES(NAME, CMDFLAG, DESC) NAME, #include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.def" }; -class ProjectIRDB; -class LLVMTypeHierarchy; -class LLVMBasedICFG; -class LLVMPointsToInfo; - -std::string toString(const DataFlowAnalysisType &D); +std::string toString(DataFlowAnalysisType D); -DataFlowAnalysisType toDataFlowAnalysisType(const std::string &S); +DataFlowAnalysisType toDataFlowAnalysisType(llvm::StringRef S); -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const DataFlowAnalysisType &D); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, DataFlowAnalysisType D); } // namespace psr diff --git a/include/phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h b/include/phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h new file mode 100644 index 000000000..abdc5b70f --- /dev/null +++ b/include/phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_UTILS_LLVMBASEDCONTAINERCONFIG_H +#define PHASAR_PHASARLLVM_UTILS_LLVMBASEDCONTAINERCONFIG_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/Module.h" + +#include + +namespace psr { + +template struct Ref2PointerConverter { + T *operator()(T &Ref) const noexcept { return std::addressof(Ref); } + const T *operator()(const T &Ref) const noexcept { + return std::addressof(Ref); + } +}; + +using FunctionRange = llvm::iterator_range>>; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_UTILS_LLVMBASEDCONTAINERCONFIG_H diff --git a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h index ccca02e27..18599565e 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h @@ -17,18 +17,28 @@ #ifndef PHASAR_UTILS_LLVMSHORTHANDS_H_ #define PHASAR_UTILS_LLVMSHORTHANDS_H_ +#include "phasar/Utils/Utilities.h" + +#include "llvm/ADT/DenseMap.h" + #include #include -#include "llvm/IR/Function.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/ModuleSlotTracker.h" -#include "llvm/IR/Value.h" -#include "llvm/Support/Compiler.h" - -#include "phasar/Utils/Utilities.h" +namespace llvm { +class Value; +class Function; +class FunctionType; +class ModuleSlotTracker; +class Argument; +class Instruction; +class StoreInst; +class BranchInst; +class Module; +class CallInst; +} // namespace llvm namespace psr { +class LLVMProjectIRDB; /** * @brief Checks if the given LLVM Value is a LLVM Function Pointer. @@ -164,10 +174,11 @@ const llvm::Instruction *getNthTermInstruction(const llvm::Function *F, const llvm::StoreInst *getNthStoreInstruction(const llvm::Function *F, unsigned StoNo); -std::vector +llvm::SmallVector getAllExitPoints(const llvm::Function *F); -void appendAllExitPoints(const llvm::Function *F, - std::vector &ExitPoints); +void appendAllExitPoints( + const llvm::Function *F, + llvm::SmallVectorImpl &ExitPoints); /** * @brief Returns the LLVM Module to which the given LLVM Value belongs to. @@ -230,15 +241,12 @@ bool isVarAnnotationIntrinsic(const llvm::Function *F); llvm::StringRef getVarAnnotationIntrinsicName(const llvm::CallInst *CallInst); class ModulesToSlotTracker { - friend class ProjectIRDB; + friend class LLVMProjectIRDB; friend class LLVMBasedICFG; friend class LLVMZeroValue; private: - static inline llvm::SmallDenseMap, 2> - MToST{}; - + static void setMSTForModule(const llvm::Module *Module); static void updateMSTForModule(const llvm::Module *Module); static void deleteMSTForModule(const llvm::Module *Module); diff --git a/include/phasar/PhasarLLVM/Utils/Scopes.h b/include/phasar/PhasarLLVM/Utils/Scopes.h index af1754542..b43d7e9bf 100644 --- a/include/phasar/PhasarLLVM/Utils/Scopes.h +++ b/include/phasar/PhasarLLVM/Utils/Scopes.h @@ -15,17 +15,13 @@ namespace llvm { class raw_ostream; -} +} // namespace llvm namespace psr { enum class Scope { function, module, project }; -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Scope &S); - -extern const std::map StringToScope; - -extern const std::map ScopeToString; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Scope S); } // namespace psr diff --git a/include/phasar/Utils/GraphExtensions.h b/include/phasar/Utils/GraphExtensions.h deleted file mode 100644 index 6f5deff4a..000000000 --- a/include/phasar/Utils/GraphExtensions.h +++ /dev/null @@ -1,141 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * GraphExtensions.hh - * - * Created on: 06.04.2017 - * Author: philipp - */ - -#ifndef PHASAR_UTILS_GRAPHEXTENSIONS_H_ -#define PHASAR_UTILS_GRAPHEXTENSIONS_H_ - -#include // std::pair -#include - -#include "boost/graph/adjacency_list.hpp" -#include "boost/graph/copy.hpp" -#include "boost/graph/graph_utility.hpp" - -namespace psr { - -template -void contractVertices(VertexTy Replacement, VertexTy Replace, GraphTy &Graph) { - auto Be = boost::adjacent_vertices(Replace, Graph); - auto BeIt = Be.first; - while (BeIt != Be.second) { - typename boost::graph_traits::out_edge_iterator OutEdge, End; - boost::tie(OutEdge, End) = boost::out_edges(Replace, Graph); - while (OutEdge != End) { - add_edge(Replacement, *BeIt, EdgeProp(Graph[*OutEdge]), Graph); - remove_edge(*OutEdge, Graph); - boost::tie(OutEdge, End) = boost::out_edges(Replace, Graph); - } - Be = boost::adjacent_vertices(Replace, Graph); - BeIt = Be.first; - } - remove_vertex(Replace, Graph); -} - -template -void mergeByStitching(GraphTy &Graph1, const GraphTy &Graph2, - std::vector> VsInG1UsInG2, - Args &&...Arguments) { - using index_map_t = - typename boost::property_map::type; - // for simple adjacency_list<> this type would be more efficient: - using IsoMap = typename boost::iterator_property_map< - typename std::vector::iterator, index_map_t, VertexTy, - VertexTy &>; - // for more generic graphs, one can try //typedef std::map IsoMap; - std::vector OrigToCopyData(num_vertices(Graph2)); - IsoMap MapV = make_iterator_property_map(OrigToCopyData.begin(), - get(boost::vertex_index, Graph2)); - boost::copy_graph(Graph2, Graph1, - boost::orig_to_copy(MapV)); // means g1 += g2 - for (auto VInG1UInG2 : VsInG1UsInG2) { - VertexTy UInG1 = MapV[VInG1UInG2.second]; - boost::add_edge(VInG1UInG2.first, UInG1, EdgeProperties(Arguments...), - Graph1); - } -} - -// merges two graph by vertex-contraction -template -void mergeGraphs(GraphTy &Graph1, const GraphTy &Graph2, - std::vector> VInG1UInG2, - Args &&...Arguments) { - using index_map_t = - typename boost::property_map::type; - // for simple adjacency_list<> this type would be more efficient: - using IsoMap = typename boost::iterator_property_map< - typename std::vector::iterator, index_map_t, VertexTy, - VertexTy &>; - // for more generic graphs, one can try typedef std::map - // IsoMap; - std::vector OrigToCopyData(boost::num_vertices(Graph2)); - IsoMap MapV = boost::make_iterator_property_map( - OrigToCopyData.begin(), get(boost::vertex_index, Graph2)); - boost::copy_graph(Graph2, Graph1, - boost::orig_to_copy(MapV)); // means g1 += g2 - for (auto &Entry : VInG1UInG2) { - VertexTy UInG1 = MapV[Entry.second]; - boost::add_edge(Entry.first, UInG1, EdgeProperty(Arguments...), Graph1); - } -} - -// merges two graph by vertex-contraction -template -void mergeGraphs( - GraphTy &Graph1, const GraphTy &Graph2, - std::vector> VInG1UInG2Prop) { - using index_map_t = - typename boost::property_map::type; - // for simple adjacency_list<> this type would be more efficient: - using IsoMap = typename boost::iterator_property_map< - typename std::vector::iterator, index_map_t, VertexTy, - VertexTy &>; - // for more generic graphs, one can try typedef std::map - // IsoMap; - std::vector OrigToCopyData(boost::num_vertices(Graph2)); - IsoMap MapV = boost::make_iterator_property_map( - OrigToCopyData.begin(), get(boost::vertex_index, Graph2)); - boost::copy_graph(Graph2, Graph1, - boost::orig_to_copy(MapV)); // means g1 += g2 - for (auto &Entry : VInG1UInG2Prop) { - VertexTy UInG1 = MapV[get<1>(Entry)]; - boost::add_edge(get<0>(Entry), UInG1, EdgeProperty(get<2>(Entry)), Graph1); - } -} - -template -void copyGraph(GraphTy &Graph1, const GraphTy &Graph2) { - using index_map_t = - typename boost::property_map::type; - // for simple adjacency_list<> this type would be more efficient: - using IsoMap = typename boost::iterator_property_map< - typename std::vector::iterator, index_map_t, VertexTy, - VertexTy &>; - // for more generic graphs, one can try typedef std::map - // IsoMap; - std::vector OrigToCopyData(boost::num_vertices(Graph2)); - IsoMap MapV = boost::make_iterator_property_map( - OrigToCopyData.begin(), get(boost::vertex_index, Graph2)); - boost::copy_graph(Graph2, Graph1, - boost::orig_to_copy(MapV)); // means g1 += g2 -} - -} // namespace psr - -#endif diff --git a/include/phasar/Utils/IO.h b/include/phasar/Utils/IO.h index 58bb3e7ff..33791f54e 100644 --- a/include/phasar/Utils/IO.h +++ b/include/phasar/Utils/IO.h @@ -23,7 +23,13 @@ #include "nlohmann/json.hpp" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { +class MemoryBuffer; +class raw_fd_ostream; +class Twine; +} // namespace llvm namespace psr { @@ -35,6 +41,9 @@ nlohmann::json readJsonFile(const llvm::Twine &Path); void writeTextFile(const llvm::Twine &Path, llvm::StringRef Content); +std::unique_ptr +openFileStream(const llvm::Twine &Filename); + } // namespace psr #endif diff --git a/include/phasar/Utils/Logger.h b/include/phasar/Utils/Logger.h index 4aea2812b..825c86963 100644 --- a/include/phasar/Utils/Logger.h +++ b/include/phasar/Utils/Logger.h @@ -17,6 +17,7 @@ #include #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" // LLVM_UNLIKELY #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -29,6 +30,8 @@ enum SeverityLevel { INVALID }; +SeverityLevel parseSeverityLevel(llvm::StringRef Str); + class Logger final { public: /** @@ -91,12 +94,21 @@ class Logger final { const std::variant &StreamVariant); }; -#define IF_LOG_ENABLED(computation) \ - IF_LOG_ENABLED_BOOL(Logger::isLoggingEnabled(), computation) - #ifdef DYNAMIC_LOG -#define PHASAR_LOG(message) PHASAR_LOG_LEVEL(DEBUG, message) +// For performance reason, we want to disable any +// formatting computation that would go straight into +// logs if logs are deactivated This macro does just +// that +#define IF_LOG_ENABLED_BOOL(condition, computation) \ + if (LLVM_UNLIKELY(condition)) { \ + computation; \ + } + +#define IS_LOG_ENABLED Logger::isLoggingEnabled() + +#define IF_LOG_ENABLED(computation) \ + IF_LOG_ENABLED_BOOL(Logger::isLoggingEnabled(), computation) #define PHASAR_LOG_LEVEL(level, message) \ IF_LOG_ENABLED_BOOL( \ @@ -108,6 +120,8 @@ class Logger final { S << message << '\n'; \ } while (false);) +#define PHASAR_LOG(message) PHASAR_LOG_LEVEL(DEBUG, message) + #define PHASAR_LOG_LEVEL_CAT(level, cat, message) \ IF_LOG_ENABLED_BOOL( \ Logger::isLoggingEnabled() && \ @@ -130,19 +144,11 @@ class Logger final { S << message << '\n'; \ } while (false);) -// For performance reason, we want to disable any -// formatting computation that would go straight into -// logs if logs are deactivated This macro does just -// that -#define IF_LOG_ENABLED_BOOL(condition, computation) \ - if (LLVM_UNLIKELY(condition)) { \ - computation; \ - } - -#define IS_LOG_ENABLED Logger::isLoggingEnabled() - #else -#define IF_LOG_ENABLED_BOOL(condition, computation) ((void)0) +#define IF_LOG_ENABLED_BOOL(condition, computation) \ + {} +#define IF_LOG_ENABLED(computation) \ + {} #define PHASAR_LOG(computation) ((void)0) #define PHASAR_LOG_CAT(cat, message) ((void)0) #define PHASAR_LOG_LEVEL_CAT(level, cat, message) ((void)0) diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h new file mode 100644 index 000000000..a755c31b4 --- /dev/null +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -0,0 +1,178 @@ +/****************************************************************************** + * Copyright (c) 2022 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_UTILS_MAYBEUNIQUEPTR_H_ +#define PHASAR_UTILS_MAYBEUNIQUEPTR_H_ + +#include "llvm/ADT/PointerIntPair.h" + +#include +#include +#include + +namespace psr { + +namespace detail { +template class MaybeUniquePtrBase { +protected: + struct PointerBoolPairFallback { + T *Pointer = nullptr; + bool Flag = false; + + /// Compatibility with llvm::PointerIntPair: + [[nodiscard]] T *getPointer() const noexcept { return Pointer; } + [[nodiscard]] bool getInt() const noexcept { return Flag; } + void setInt(bool Flag) noexcept { this->Flag = Flag; } + }; + + std::conditional_t<(alignof(T) > 1), llvm::PointerIntPair, + PointerBoolPairFallback> + Data{}; + + MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} + MaybeUniquePtrBase() noexcept = default; +}; + +template class MaybeUniquePtrBase { +protected: + llvm::PointerIntPair Data{}; + + MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} + MaybeUniquePtrBase() noexcept = default; +}; +} // namespace detail + +/// A smart-pointer, similar to std::unique_ptr that can be used as both, +/// owning and non-owning pointer. +/// +/// \tparam T The pointee type +/// \tparam RequireAlignment If true, the datastructure only works if alignof(T) +/// > 1 holds. Enables incomplete T types +template +class MaybeUniquePtr : detail::MaybeUniquePtrBase { + using detail::MaybeUniquePtrBase::Data; + +public: + MaybeUniquePtr() noexcept = default; + + MaybeUniquePtr(T *Pointer, bool Owns = false) noexcept + : detail::MaybeUniquePtrBase( + Pointer, Owns && Pointer != nullptr) {} + + MaybeUniquePtr(std::unique_ptr &&Owner) noexcept + : MaybeUniquePtr(Owner.release(), true) {} + + template + MaybeUniquePtr(std::unique_ptr &&Owner) noexcept + : MaybeUniquePtr(Owner.release(), true) {} + + MaybeUniquePtr(MaybeUniquePtr &&Other) noexcept + : detail::MaybeUniquePtrBase( + std::exchange(Other.Data, {})) {} + + void swap(MaybeUniquePtr &Other) noexcept { std::swap(Data, Other, Data); } + + friend void swap(MaybeUniquePtr &LHS, MaybeUniquePtr &RHS) noexcept { + LHS.swap(RHS); + } + + MaybeUniquePtr &operator=(MaybeUniquePtr &&Other) noexcept { + swap(Other); + return *this; + } + + MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { + if (owns()) { + delete Data.getPointer(); + } + Data = {Owner.release(), true}; + return *this; + } + + template + MaybeUniquePtr &operator=(std::unique_ptr &&Owner) noexcept { + if (owns()) { + delete Data.getPointer(); + } + Data = {Owner.release(), true}; + return *this; + } + + MaybeUniquePtr(const MaybeUniquePtr &) = delete; + MaybeUniquePtr &operator=(const MaybeUniquePtr &) = delete; + + ~MaybeUniquePtr() { + if (owns()) { + delete Data.getPointer(); + Data = {}; + } + } + + [[nodiscard]] T *get() noexcept { return Data.getPointer(); } + [[nodiscard]] const T *get() const noexcept { return Data.getPointer(); } + + [[nodiscard]] T *operator->() noexcept { return get(); } + [[nodiscard]] const T *operator->() const noexcept { return get(); } + + [[nodiscard]] T &operator*() noexcept { + assert(get() != nullptr); + return *get(); + } + [[nodiscard]] const T &operator*() const noexcept { + assert(get() != nullptr); + return *get(); + } + + T *release() noexcept { + Data.setInt(false); + return Data.getPointer(); + } + + void reset() noexcept { + if (owns()) { + delete Data.getPointer(); + } + Data = {}; + } + + [[nodiscard]] bool owns() const noexcept { + return Data.getInt() && Data.getPointer(); + } + + friend bool operator==(const MaybeUniquePtr &LHS, + const MaybeUniquePtr &RHS) noexcept { + return LHS.Data.getPointer() == RHS.Data.getPointer(); + } + friend bool operator!=(const MaybeUniquePtr &LHS, + const MaybeUniquePtr &RHS) noexcept { + return !(LHS == RHS); + } + + friend bool operator==(const MaybeUniquePtr &LHS, const T *RHS) noexcept { + return LHS.Data.getPointer() == RHS; + } + friend bool operator!=(const MaybeUniquePtr &LHS, const T *RHS) noexcept { + return !(LHS == RHS); + } + + friend bool operator==(const T *LHS, const MaybeUniquePtr &RHS) noexcept { + return LHS == RHS.Data.getPointer(); + } + friend bool operator!=(const T *LHS, const MaybeUniquePtr &RHS) noexcept { + return !(LHS == RHS); + } + + explicit operator bool() const noexcept { + return Data.getPointer() != nullptr; + } +}; + +} // namespace psr + +#endif // PHASAR_UTILS_MAYBEUNIQUEPTR_H_ diff --git a/include/phasar/Utils/MemoryResource.h b/include/phasar/Utils/MemoryResource.h new file mode 100644 index 000000000..886e373d8 --- /dev/null +++ b/include/phasar/Utils/MemoryResource.h @@ -0,0 +1,10 @@ +/// On some MAC systems, is still not fully implemented, so do +/// a workaround here + +#ifndef HAS_MEMORY_RESOURCE +#if !defined(__has_include) || __has_include() +#define HAS_MEMORY_RESOURCE 1 +#else +#define HAS_MEMORY_RESOURCE 0 +#endif +#endif diff --git a/include/phasar/Utils/MultiIndexTable.h b/include/phasar/Utils/MultiIndexTable.h deleted file mode 100644 index 769c5f3f1..000000000 --- a/include/phasar/Utils/MultiIndexTable.h +++ /dev/null @@ -1,81 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * Table.h - * - * Created on: 31.08.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_UTILS_MULTIINTEXTABLE_H_ -#define PHASAR_UTILS_MULTIINTEXTABLE_H_ - -#include - -#include "boost/multi_index/composite_key.hpp" -#include "boost/multi_index/hashed_index.hpp" -#include "boost/multi_index/member.hpp" -#include "boost/multi_index/ordered_index.hpp" -#include "boost/multi_index_container.hpp" - -namespace psr { - -struct ORDERED_ROW_COL_KEY_TAG {}; -struct HASHED_ROW_COL_KEY_TAG {}; - -template struct MultiIndexTable { - struct TableData { - R rowkey; - C columnkey; - V value; - TableData(const R r, const C c, const V v) - : rowkey(r), columnkey(c), value(v) {} - }; - - struct row_col_key - : boost::multi_index::composite_key< - TableData, BOOST_MULTI_INDEX_MEMBER(TableData, R, rowkey), - BOOST_MULTI_INDEX_MEMBER(TableData, C, columnkey)> {}; - - typedef boost::multi_index_container< - TableData, - boost::multi_index::indexed_by< - boost::multi_index::ordered_unique< - boost::multi_index::tag, row_col_key>, - boost::multi_index::hashed_unique< - boost::multi_index::tag, row_col_key>>> - InternTable; - - // ordered indices - typedef typename boost::multi_index::index< - InternTable, ORDERED_ROW_COL_KEY_TAG>::type ordered_row_col_key_view_t; - typedef - typename boost::multi_index::index:: - type::const_iterator ordered_row_col_key_iterator_t; - - // hashed indices - typedef typename boost::multi_index::index< - InternTable, HASHED_ROW_COL_KEY_TAG>::type hashed_row_col_key_view_t; - typedef - typename boost::multi_index::index:: - type::const_iterator hashed_row_col_key_iterator_t; - - // the indexed table containing instances of TableData - InternTable IndexedTable; - - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, - const InternTable &itab) { - return os << "error: unsupported operation!"; - } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/Utils/NlohmannLogging.h b/include/phasar/Utils/NlohmannLogging.h index 4a36d724a..ce04280a7 100644 --- a/include/phasar/Utils/NlohmannLogging.h +++ b/include/phasar/Utils/NlohmannLogging.h @@ -15,10 +15,6 @@ #include "nlohmann/json.hpp" -namespace llvm { -class raw_ostream; -} - namespace nlohmann::detail { class llvm_output_stream_adapter : public output_adapter_protocol { public: @@ -52,6 +48,6 @@ class llvm_output_adapter { namespace psr { llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const nlohmann::json &J); -}; +} // namespace psr #endif /* PHASAR_UTILS_NLOHMANNLOGGING_H */ diff --git a/include/phasar/Utils/PAMM.h b/include/phasar/Utils/PAMM.h index 2129523ad..2f9265516 100644 --- a/include/phasar/Utils/PAMM.h +++ b/include/phasar/Utils/PAMM.h @@ -17,9 +17,8 @@ #ifndef PHASAR_UTILS_PAMM_H_ #define PHASAR_UTILS_PAMM_H_ -#include "boost/program_options/variables_map.hpp" - -#include // high_resolution_clock::time_point, milliseconds +#include // high_resolution_clock::time_point, milliseconds +#include #include // set #include // string #include // unordered_map @@ -190,8 +189,12 @@ class PAMM { /// \brief Exports the measured data to JSON - associated macro: /// EXPORT_MEASURED_DATA(PATH). /// \param OutputPath to exported JSON file. - void exportMeasuredData(std::string OutputPath, - boost::program_options::variables_map &Config); + void exportMeasuredData( + const std::string &OutputPath, + const std::string &ProjectId = "default-phasar-project", + const std::optional> &Modules = std::nullopt, + const std::optional> &DataFlowAnalyses = + std::nullopt); }; } // namespace psr diff --git a/include/phasar/Utils/Singleton.h b/include/phasar/Utils/Singleton.h deleted file mode 100644 index 1dcef7a4e..000000000 --- a/include/phasar/Utils/Singleton.h +++ /dev/null @@ -1,40 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * Singleton.h - * - * Created on: 30.08.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_UTILS_SINGLETON_H_ -#define PHASAR_UTILS_SINGLETON_H_ - -namespace psr { - -template class Singleton { -public: - Singleton(const Singleton &s) = delete; - Singleton(Singleton &&s) = delete; - Singleton &operator=(const Singleton &s) = delete; - Singleton &operator=(Singleton &&s) = delete; - static T &Instance() { - static T value; - return value; - } - -protected: - Singleton() = default; - ~Singleton() = default; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/Utils/Soundness.def b/include/phasar/Utils/Soundness.def index 8d8641100..37b4977f6 100644 --- a/include/phasar/Utils/Soundness.def +++ b/include/phasar/Utils/Soundness.def @@ -8,12 +8,11 @@ *****************************************************************************/ #ifndef SOUNDNESS_FLAG_TYPE -#define SOUNDNESS_FLAG_TYPE(NAME, TYPE) +#define SOUNDNESS_FLAG_TYPE(NAME, CMDFLAG, DESC) #endif -SOUNDNESS_FLAG_TYPE("Sound", Sound) -SOUNDNESS_FLAG_TYPE("Soundy", Soundy) -SOUNDNESS_FLAG_TYPE("Unsound", Unsound) -SOUNDNESS_FLAG_TYPE("Unused", Unused) +SOUNDNESS_FLAG_TYPE(Sound, "sound", "As sound as possible (do not tolerate any false negative results)") +SOUNDNESS_FLAG_TYPE(Soundy, "soundy", "A reasonable soundness level that tries to minimize false negative results without giving up too much of precision and performance") +SOUNDNESS_FLAG_TYPE(Unsound, "unsound", "Trade soundness for increased precision") #undef SOUNDNESS_FLAG_TYPE diff --git a/include/phasar/Utils/Soundness.h b/include/phasar/Utils/Soundness.h index 9a1357dfd..619ff6de0 100644 --- a/include/phasar/Utils/Soundness.h +++ b/include/phasar/Utils/Soundness.h @@ -10,21 +10,28 @@ #ifndef PHASAR_UTILS_SOUNDNESS_H_ #define PHASAR_UTILS_SOUNDNESS_H_ +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + #include +namespace llvm { +class raw_ostream; +} // namespace llvm + namespace psr { enum class Soundness { -#define SOUNDNESS_FLAG_TYPE(NAME, TYPE) TYPE, +#define SOUNDNESS_FLAG_TYPE(NAME, CMDFLAG, DESC) NAME, #include "phasar/Utils/Soundness.def" Invalid }; -std::string toString(const Soundness &S); +std::string toString(Soundness S); -Soundness toSoundness(const std::string &S); +Soundness toSoundness(llvm::StringRef S); -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Soundness &S); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Soundness S); } // namespace psr diff --git a/include/phasar/Utils/TwoElementSet.h b/include/phasar/Utils/TwoElementSet.h deleted file mode 100644 index c8dd0e73a..000000000 --- a/include/phasar/Utils/TwoElementSet.h +++ /dev/null @@ -1,36 +0,0 @@ -/****************************************************************************** - * 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 - *****************************************************************************/ - -/* - * TwoElementSet.h - * - * Created on: 04.08.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_UTILS_TWOELEMENTSET_H_ -#define PHASAR_UTILS_TWOELEMENTSET_H_ - -#include - -namespace psr { - -template class TwoElementSet { -private: - const E first, second; - -public: - TwoElementSet(E first, E second) : first(first), second(second){}; - std::size_t size() { return 2; } - virtual ~TwoElementSet() = default; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index 6f1ee8281..fec3553d5 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -10,6 +10,7 @@ #ifndef PHASAR_UTILS_TYPETRAITS_H #define PHASAR_UTILS_TYPETRAITS_H +#include #include #include #include @@ -25,10 +26,19 @@ namespace detail { template struct is_iterable : public std::false_type {}; // NOLINT template -struct is_iterable().begin()), - decltype(std::declval().end())>> +struct is_iterable().begin()), + decltype(std::declval().end())>> : public std::true_type {}; +template +struct is_iterable_over : std::false_type {}; // NOLINT +template +struct is_iterable_over< + T, U, + std::enable_if_t< + is_iterable::value && + std::is_convertible_v().begin()), U>>> + : std::true_type {}; template struct is_pair : public std::false_type {}; // NOLINT template @@ -83,11 +93,37 @@ struct has_setIFDSIDESolverConfig< T, decltype(std::declval().setIFDSIDESolverConfig( std::declval()))> : std::true_type {}; +template