diff --git a/.clang-format b/.clang-format index 9b3aa8b72..cab7e234f 100644 --- a/.clang-format +++ b/.clang-format @@ -1 +1,13 @@ BasedOnStyle: LLVM +SortIncludes: true +IncludeBlocks: Regroup +BreakStringLiterals: true +IncludeCategories: + - Regex: '^"phasar/' + Priority: 1 + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '".*"' + Priority: 3 + - Regex: '<[[:alnum:]_]+>' + Priority: 4 diff --git a/.clang-tidy b/.clang-tidy index 6b2721354..93ad42fe9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -55,7 +55,7 @@ CheckOptions: - key: readability-identifier-naming.ParameterIgnoredRegexp value: (d|d1|d2|d3|d4|d5|eP|f|n) - key: readability-identifier-naming.FunctionIgnoredRegexp - value: (try_emplace|from_json|to_json|equal_to) + value: (try_emplace|from_json|to_json|equal_to|to_string) - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor value: 1 - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5a7c35be2..bfd339c16 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,16 +7,18 @@ /include/phasar/PhasarLLVM/DataflowSolver/IfdsIde/Solver/IDESolver.h @pdschubert /include/phasar/PhasarLLVM/DataflowSolver/IfdsIde/FlowEdgeFunctionCache.h @vulder +/include/phasar/PhasarLLVM/DataflowSolver/IfdsIde/EdgeFunctionSingletonFactory.h @vulder +/unittests/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionSingletonFactoryTest.cpp @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/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @pdschubert @vulder +/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/ @fabianbs96 +/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @fabianbs96 +/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.cpp @fabianbs96 +/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/ @fabianbs96 /include/phasar/PhasarLLVM/AnalysisStrategy/ @pdschubert diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c37ea8fa7..6e4c32f0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,8 +51,10 @@ jobs: libclang-common-14-dev \ libclang-14-dev \ libclang-cpp14-dev \ - clang-tidy-14 + clang-tidy-14 \ + libclang-rt-14-dev + - uses: swift-actions/setup-swift@v1 - name: Building Phasar in ${{ matrix.build }} with ${{ matrix.compiler[0] }} env: BUILD_TYPE: ${{ matrix.build }} @@ -65,6 +67,7 @@ jobs: cmake .. \ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ -DCMAKE_CXX_COMPILER=$CXX \ + -DBUILD_SWIFT_TESTS=1 \ -G Ninja cmake --build . diff --git a/BreakingChanges.md b/BreakingChanges.md new file mode 100644 index 000000000..2d73d94c6 --- /dev/null +++ b/BreakingChanges.md @@ -0,0 +1,43 @@ +# Breaking Changes + +## v0323 + +- `EdgeFunctionPtrType` is no longer a `std::shared_ptr`. Instead `EdgeFunction` should be used directly. `EdgeFunction` is now a *value-type* that encapsulates its memory management by itself. +- Concrete `EdgeFunction` types no longer derive from any base-class. Instead they just need to implement the required API functions. `EdgeFunction` implementations should me move-constructible and can be implicitly cast to `EdgeFunction`. To verify that your type implements the edge function interface use the `IsEdgeFunction` type trait. The API functions have been changed as follows: + - All API functions of `EdgeFunction` must be `const` qualified. + - `EdgeFunctionPtrType composeWith(EdgeFunctionPtrType SecondFunction)` and `EdgeFunctionPtrType joinWith(EdgeFunctionPtrType OtherFunction)` have been changed to `static EdgeFunction compose(EdgeFunctionRef This, const EdgeFunction& SecondFunction)` and `static EdgeFunction join(EdgeFunctionRef This, const EdgeFunction& OtherFunction)` respectively. Here, the `This` parameter models the former `shared_from_this()`. + - `bool equal_to(EdgeFunctionPtrType Other)const` has been changed to `bool operator==(const T &Other)const noexcept`, where `T` is your concrete edge function type. + - `void print(llvm::raw_ostream &OS, bool IsForDebug)` has been changed to `friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const T& EF)`. +- `EdgeFunction` is tagged with `[[clang::trivial_abi]]`. Hence, you should not rely on any destruction order within a top-level statement that uses temporary `EdgeFunction` objects. +- `EdgeFunctionSingletonFactory` has been removed. Use `EdgeFunctionSingletonCache` instead. +- `TaintConfig` has been renamed to `LLVMTaintConfig`. For generic code you may want to use the LLVM-independent `TaintConfigBase` CRTP interface instead. +- Renamed `phasar/PhasarLLVM/DataFlowSolver/` to either `phasar/DataFlow/` or `phasar/PhasarLLVM/DataFlow/` depending on whether the components need LLVMCore. Analoguous changes in `lib/` and `unittests/`. + An incomplete list of moved/renamed files: + - `phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/*` => `phasar/DataFlow/IfdsIde/Solver/*` + - `phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h` => `phasar/DataFlow/IfdsIde/IDETabulationProblem.h` + - `phasar/DB/LLVMProjectIRDB.h` => `phasar/PhasarLLVM/DB/LLVMProjectIRDB.h` + - ... +- Renamed and split up some libraries: + - `phasar_phasarllvm_utils` => `phasar_llvm_utils` + - `phasar_typehierarchy` => `phasar_llvm_typehierarchy` + - `phasar_ifdside` => `phasar_llvm_ifdside` + - `phasar_controlflow` has its LLVM dependent stuff moved to `phasar_llvm_controlflow` + - `phasar_db` has its LLVM dependent stuff moved to `phasar_llvm_db` + - `phasar_pointer` has its LLVM dependent stuff moved to `phasar_llvm_pointer` +- Renamed the phasar tool `phasar-llvm` to `phasar-cli` +- `LLVMPointsTo[.*]` has been renamed to `LLVMAlias[.*]` +- The ctor of `LLVMAliasSet` now takes the `LLVMProjectIRDB` as pointer instead of a reference to better document that it may capture the IRDB by reference. +- The `PointsToInfo` interface has been replaced by the CRTP interface `AliasInfoBase`. Introduced two type-erased implementations of that interface: `AliasInfo` and `AliasInfoRef`. In most cases you should replace `PointsToInfo *` and `LLVMPointsToInfo *` by `AliasInfoRef`, bzw. `LLVMAliasInfoRef`. +- Introduced a new interface `PointsToInfoBase` and type-erased implementations `PointstoInfo` and `PointsToInfoRef`. Don't confuse them with the old `PointsToInfo`!!! (However, they have different APIs, so you should encounter compilation errors then) + +## v1222 + +- Removed virtual interfaces `CFG` and `ICFG` and replaced by CRTP interfaces `CFGBase` and `ICFGBase`. Use the concrete types `LLVMBasedICFG` and `LLVMBasedCFG` instead. In template code you can use the type traits `is_crtp_base_of_v` and `is_icfg_v` to check for conformance to the interfaces. +- The `LLVMBasedICFG` now takes the IRDB as pointer instead of a reference to better document that it may capture the IRDB by reference. +- Renamed `ProjectIRDB` to `LLVMProjectIRDB` and added a generic CRTP interface `ProjectIRDBBase` that does not depend on LLVM +- Changed the API of `LLVMProjectIRDB`: The IRDB does no longer link multiple LLVM modules together, i.e. the ctor that reads a module from a file now takes a single filename instead of a vector. If you still want to link multiple LLVM modules together, use LLVM's Linker functionality instead. `ProjecIRDB::getAllModules()` has been removed and `ProjectIRDB::getWPAModule()` has been renamed to `LLVMProjectIRDB::getModule()`. +- The `LLVMProjectIRDB` ctor that takes a raw-pointer to `llvm::Module` does no longer preprocess the module (i.e. attaching metadata IDs to it). You can still explicitly use the `ValueAnnotationPass` to do so manually. +- The type `WholeProgramAnalysis` has been removed. Use `AnalysisController` instead. +- The IFDS and IDE TabulationProblems no longer take all of `LLVMProjectIRDB*`, `LLVMTypeHierarchy*`, `LLVMPointsToInfo*` and `LLVMBasedICFG*` as an argument. Instead, they only get what they need. +- The `IFDSSolver` and `IDESolver` now take an instance of the `ICFGBase` interface as additional argument to their ctor (because the analysis problems now not necessarily store a reference to it anymore). +- The `IDETabulationProblem` is now a base class of `IFDSTabulationProblem` (and not vice versa as it was previously). In their ctors they only take the bare minimum of arguments: The IRDB, the entrypoints and optionally the special zero-value. If the zero-value is not passed in the ctor (as it was previously), it has to be set from within the client analysis' ctor. You may use the new function `initializeZeroValue(d_t)` for this. diff --git a/CMakeLists.txt b/CMakeLists.txt index eaf494d15..7f80a1ca2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,13 @@ include("phasar_macros") option(PHASAR_BUILD_UNITTESTS "Build all tests (default is ON)" ON) +option(BUILD_SWIFT_TESTS "Builds the Swift tests (Swift compiler has to be installed manually beforehand!)" OFF) +if (BUILD_SWIFT_TESTS) + set(CMAKE_Swift_FLAGS_RELEASE "-g") + set(CMAKE_Swift_FLAGS_RELWITHDEBINFO "-g") + enable_language(Swift) +endif(BUILD_SWIFT_TESTS) + option(PHASAR_BUILD_OPENSSL_TS_UNITTESTS "Build OPENSSL typestate tests (require OpenSSL, default is OFF)" OFF) option(PHASAR_BUILD_IR "Build IR test code (default is ON)" ON) @@ -107,10 +114,14 @@ include_directories( ${PHASAR_SRC_DIR}/include ) -set(PHASAR_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}/phasar) - if (NOT PHASAR_IN_TREE) - set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${PHASAR_INSTALL_LIBDIR}) + set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) + + if (NOT "${CMAKE_INSTALL_LIBDIR}" STREQUAL "lib") + message(STATUS "Detected CMAKE_INSTALL_LIBDIR that deviates from 'lib': ${CMAKE_INSTALL_LIBDIR}. Add ${CMAKE_INSTALL_PREFIX}/lib to the RPATH as json-schema-validator needs it") + list(APPEND CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) + endif() + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif() @@ -120,6 +131,17 @@ else() set(PHASAR_STD_FILESYSTEM stdc++fs) endif() +set(PHASAR_CUSTOM_CONFIG_INSTALL_DIR "" CACHE STRING "If set, customizes the directory, where configuration files for PhASAR are installed (default is /usr/local/.phasar-config)") +if ("${PHASAR_CUSTOM_CONFIG_INSTALL_DIR}" STREQUAL "") + set(PHASAR_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/.phasar-config/") +else() + set(PHASAR_CONFIG_INSTALL_DIR "${PHASAR_CUSTOM_CONFIG_INSTALL_DIR}") +endif() + +add_compile_definitions(PHASAR_CONFIG_DIR="${PHASAR_CONFIG_INSTALL_DIR}") +add_compile_definitions(PHASAR_DIR="${PHASAR_SRC_DIR}") + + ### Adding external libraries # Threads find_package(Threads) @@ -144,7 +166,7 @@ set(CMAKE_CXX_CLANG_TIDY "") set(BUILD_TESTS OFF CACHE BOOL "Build json-schema-validator-tests") # Make nlohmann_json_schema_validator happy by telling it how to find the single include of nlohmann_json -include_directories(external/json/single_include/) +include_directories(SYSTEM external/json/single_include/) if (PHASAR_IN_TREE) set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS nlohmann_json_schema_validator) @@ -301,7 +323,7 @@ endif() set(INCLUDE_INSTALL_DIR include/ CACHE PATH "Install dir of headers") -# Install targets of phasar-llvm, other executables, and libraries are to be +# Install targets of phasar-cli, other executables, and libraries are to be # found in the individual subdirectories of tools/ # Install Phasar include directory @@ -326,15 +348,17 @@ install(DIRECTORY external/googletest/googletest/include/gtest/ # Install Phasar utils helper scripts install(DIRECTORY utils/ DESTINATION bin - FILES_MATCHING PATTERN "phasar-*" + FILES_MATCHING + PATTERN "CodeGen" EXCLUDE # CodeGen does not contain files to install + PATTERN "phasar-*" PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ ) -# Install the Phasar config files into ~/.config/phasar/ +# Install the Phasar config files into CMAKE_INSTALL_PREFIX/.phasar-config/ install(DIRECTORY config/ - DESTINATION $ENV{HOME}/.config/phasar + DESTINATION ${PHASAR_CONFIG_INSTALL_DIR} PATTERN "config/*" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_WRITE GROUP_READ diff --git a/Config.cmake.in b/Config.cmake.in index 315a673ec..78e7bb723 100644 --- a/Config.cmake.in +++ b/Config.cmake.in @@ -12,15 +12,24 @@ find_package(Boost 1.65.1 COMPONENTS program_options graph REQUIRED) set(PHASAR_COMPONENTS utils - config - phasarllvm_utils passes + config db pointer - typehierarchy controlflow + + llvm_utils + llvm_db + llvm_pointer + llvm_typehierarchy + llvm_controlflow + taintconfig - ifdside + mono + llvm + llvm_ifdside + analysis_strategy + controller ) foreach(component ${PHASAR_COMPONENTS}) diff --git a/Dockerfile b/Dockerfile index 2079e03ea..f91375c66 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,12 +33,11 @@ RUN apt-key adv --fetch-keys https://apt.llvm.org/llvm-snapshot.gpg.key && \ libclang-common-14-dev \ libclang-14-dev \ libclang-cpp14-dev \ - clang-tidy-14 + clang-tidy-14 \ + libclang-rt-14-dev RUN pip3 install Pygments pyyaml -# installing boost -RUN apt install libboost-all-dev -y # installing wllvm @@ -58,4 +57,4 @@ RUN mkdir -p build && cd build && \ -G Ninja && \ cmake --build . -ENTRYPOINT [ "./build/tools/phasar-llvm/phasar-llvm" ] +ENTRYPOINT [ "./build/tools/phasar-cli/phasar-cli" ] diff --git a/README.md b/README.md index c8cff2395..1c82c87c5 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ PhASAR a LLVM-based Static Analysis Framework [![C++ Standard](https://img.shields.io/badge/C++_Standard-C%2B%2B17-blue.svg?style=flat&logo=c%2B%2B)](https://isocpp.org/) [![GitHub license](https://img.shields.io/badge/license-MIT-blueviolet.svg)](https://raw.githubusercontent.com/secure-software-engineering/phasar/master/LICENSE.txt) -Version 1222 +Version 0323 Secure Software Engineering Group --------------------------------- -+ Philipp Dominik Schubert (philipp.schubert@upb.de) and others ++ Fabian Schiebel (fabian.schiebel@iem.fraunhofer.de), Martin Mory (martin.mory@upb.de), Philipp Dominik Schubert (philipp.schubert@upb.de) and others + Please also refer to https://phasar.org/ Required version of the C++ standard @@ -30,9 +30,13 @@ fully-automated manner on the specified LLVM IR target code. Computing points-to information, call-graph(s), etc. is done by the framework, thus you can focus on what matters. +Breaking Changes +---------------- +To keep PhASAR in a state that it is well suited for state-of-the-art research in static analysis, as well as for productive use, we have to make breaking changes. Please refer to [Breaking Changes](./BreakingChanges.md) for detailed information on what was broken recently and how to migrate. + How do I get started with PhASAR? --------------------------------- -We have some documentation on PhASAR in our [_**wiki**_](https://github.com/secure-software-engineering/phasar/wiki). You probably would like to read +We have some documentation on PhASAR in our [_**Wiki**_](https://github.com/secure-software-engineering/phasar/wiki). You probably would like to read this README first and then have a look on the material provided on https://phasar.org/ as well. Please also have a look on PhASAR's project directory and notice the project directory examples/ as well as the custom tool tools/myphasartool.cpp. @@ -45,6 +49,21 @@ prerequisites and compilation. It is recommended to compile PhASAR yourself in order to get the full C++ experience and to have full control over the build mode. +As a shortcut for the very first PhASAR build on your system, you can use our [bootstrap](./bootstrap.sh) script: + +```bash +$ ./bootstrap.sh +``` + +Note: If you want to do changes within PhASAR, it is recommended to build it in Debug mode: +```bash +$ ./bootstrap.sh -DCMAKE_BUILD_TYPE=Debug +``` + +The bootstrap script may ask for superuser permissions (to install the dependencies); however it is not recommended to start the whole script with `sudo`. + +For subsequent builds, see [Compiling PhASAR](#compiling-phasar-if-not-already-done-using-the-installation-scripts). + Please help us to improve PhASAR -------------------------------- You are using PhASAR and would like to help us in the future? Then please @@ -65,10 +84,12 @@ PhASAR using an Ubuntu or Unix-like system. Therefore, we provide an installation script. To install PhASAR, just navigate to the top-level directory of PhASAR and use the following command: -``` -$ sudo ./bootstrap.sh +```bash +$ ./bootstrap.sh --install ``` +The bootstrap script may ask for superuser permissions. + Done! @@ -86,8 +107,7 @@ $ export CXX=/usr/local/bin/clang++ You may need to adjust the paths according to your system. When you cloned PhASAR from Github you need to initialize PhASAR's submodules before building it: ``` -$ git submodule init -$ git submodule update +$ git submodule update --init ``` If you downloaded PhASAR as a compressed release (e.g. .zip or .tar.gz) you can use the `init-submodules-release.sh` script that manually clones the required submodules: @@ -101,9 +121,9 @@ Navigate into the PhASAR directory. The following commands will do the job and c ``` $ mkdir build $ cd build/ -$ cmake -DCMAKE_BUILD_TYPE=Release .. -$ make -j $(nproc) # or use a different number of cores to compile it -$ sudo make install # if you wish to install PhASAR system wide +$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. +$ ninja -j $(nproc) # or use a different number of cores to compile it +$ sudo ninja install # only if you wish to install PhASAR system wide ``` When you have used the `bootstrap.sh` script to install PhASAR, the above steps are already done. @@ -111,17 +131,15 @@ Use them as a reference if you wish to modify PhASAR and recompile it. After compilation using cmake the following two binaries can be found in the build/ directory: -+ phasar-llvm - the actual PhASAR command-line tool ++ phasar-cli - the actual PhASAR command-line tool (previously called `phasar-llvm`) + myphasartool - an example tool that shows how tools can be build on top of PhASAR Use the command: -`$ ./phasar-llvm --help` +`$ ./phasar-cli --help` in order to display the manual and help message. -`$ sudo make install` - Please be careful and check if errors occur during the compilation. When using CMake to compile PhASAR the following optional parameters can be used: @@ -130,7 +148,8 @@ When using CMake to compile PhASAR the following optional parameters can be used |-----------|--------| | BUILD_SHARED_LIBS : BOOL | Build shared libraries (default is ON) | | CMAKE_BUILD_TYPE : STRING | Build PhASAR in 'Debug' or 'Release' mode
(default is 'Debug') | -| CMAKE_INSTALL_PREFIX : PATH | Path where PhASAR will be installed if
“make install” is invoked or the “install”
target is built (default is /usr/local/phasar) | +| CMAKE_INSTALL_PREFIX : PATH | Path where PhASAR will be installed if
"ninja install” is invoked or the “install”
target is built (default is /usr/local/phasar) | +| PHASAR_CONFIG_INSTALL_PREFIX : PATH | Path where PhASAR's configuration files will be installed if
ninja install” is invoked or the “install”
target is built. Expression will be evaluated within CMAKE_INSTALL_PREFIX, so prefer absolute paths (default is $(HOME)/.config/) | | PHASAR_BUILD_DOC : BOOL | Build PhASAR documentation (default is OFF) | | PHASAR_BUILD_UNITTESTS : BOOL | Build PhASAR unit tests (default is ON) | | PHASAR_BUILD_IR : BOOL | Build PhASAR IR (required for running the unit tests) (default is ON) | @@ -148,7 +167,7 @@ C++'s long compile times are always a pain. As shown in the above, when using cm ### Running a test solver To test if everything works as expected please run the following command: -`$ phasar-llvm --module test/build_systems_tests/installation_tests/module.ll -D ifds-solvertest` +`$ phasar-cli -m test/build_systems_tests/installation_tests/module.ll -D ifds-solvertest` If you obtain output other than a segmentation fault or an exception terminating the program abnormally everything works as expected. diff --git a/bootstrap.sh b/bootstrap.sh index b6193fdee..c49d0a728 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,5 +1,6 @@ #!/bin/bash -set -e + +set -eo pipefail source ./utils/safeCommandsSet.sh @@ -10,6 +11,8 @@ readonly LLVM_INSTALL_DIR="/usr/local/llvm-14" NUM_THREADS=$(nproc) LLVM_RELEASE=llvmorg-14.0.0 DO_UNIT_TEST=true +DO_INSTALL=false +BUILD_TYPE=Release # Parsing command-line-parameters @@ -48,6 +51,14 @@ case $key in DESIRED_BOOST_VERSION="${key#*=}" shift # past argument=value ;; + -DCMAKE_BUILD_TYPE=*) + BUILD_TYPE="${key#*=}" + shift # past argument=value + ;; + --install) + DO_INSTALL=true + shift # past argument + ;; *) # unknown option POSITIONAL+=("$1") # save it in an array for later shift # past argument @@ -60,12 +71,13 @@ set -- "${POSITIONAL[@]}" # restore positional parameters echo "installing phasar dependencies..." if [ -x "$(command -v pacman)" ]; then - yes | sudo pacman -Syu --needed which zlib sqlite3 ncurses make python3 doxygen libxml2 swig gcc cmake z3 libedit graphviz python-sphinx openmp curl python-pip + yes | sudo pacman -Syu --needed which zlib sqlite3 ncurses make python3 doxygen libxml2 swig gcc z3 libedit graphviz python-sphinx openmp curl python-pip ninja ./utils/installBuildEAR.sh else ./utils/InstallAptDependencies.sh fi -sudo pip3 install Pygments pyyaml + +pip3 install cmake if [ ! -z "${DESIRED_BOOST_DIR}" ]; then BOOST_PARAMS="-DBOOST_ROOT=${DESIRED_BOOST_DIR}" @@ -111,49 +123,61 @@ else done if [ ${#additional_boost_libs[@]} -gt 0 ] ;then echo "Installing additional ${#additional_boost_libs[@]} boost packages: ${additional_boost_libs[*]}" - sudo apt install "${additional_boost_libs[@]}" -y + sudo apt install "${additional_boost_libs[@]}" -y || true fi fi fi fi # installing LLVM -tmp_dir=$(mktemp -d "llvm-10_build.XXXXXXXX" --tmpdir) +tmp_dir=$(mktemp -d "llvm-build.XXXXXXXX" --tmpdir) ./utils/install-llvm.sh "${NUM_THREADS}" "${tmp_dir}" ${LLVM_INSTALL_DIR} ${LLVM_RELEASE} rm -rf "${tmp_dir}" -sudo pip3 install wllvm echo "dependencies successfully installed" +echo "Updating the submodules..." +git submodule update --init +echo "Submodules successfully updated" echo "Building PhASAR..." ${DO_UNIT_TEST} && echo "with unit tests." -git submodule init -git submodule update export CC=${LLVM_INSTALL_DIR}/bin/clang export CXX=${LLVM_INSTALL_DIR}/bin/clang++ mkdir -p "${PHASAR_DIR}"/build safe_cd "${PHASAR_DIR}"/build -cmake -G Ninja -DCMAKE_BUILD_TYPE=Release "${BOOST_PARAMS}" -DPHASAR_BUILD_UNITTESTS=${DO_UNIT_TEST} "${PHASAR_DIR}" -cmake --build . +cmake -G Ninja -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" "${BOOST_PARAMS}" -DPHASAR_BUILD_UNITTESTS="${DO_UNIT_TEST}" "${PHASAR_DIR}" +cmake --build . -j "${NUM_THREADS}" + +echo "phasar successfully built" if ${DO_UNIT_TEST}; then echo "Running PhASAR unit tests..." + + NUM_FAILED_TESTS=0 + pushd unittests for x in $(find . -type f -executable -print); do - pushd "${x%/*}" && ./"${x##*/}" && popd || { echo "Test ${x} failed, aborting."; exit 1; }; + pushd "${x%/*}" && ./"${x##*/}" || { echo "Test ${x} failed."; NUM_FAILED_TESTS=$((NUM_FAILED_TESTS+1)); }; + popd; done popd + + echo "Finished running PhASAR unittests" + echo "${NUM_FAILED_TESTS} tests failed" fi -echo "phasar successfully built" -echo "install phasar..." -sudo cmake -DCMAKE_INSTALL_PREFIX=${PHASAR_INSTALL_DIR} -P cmake_install.cmake -sudo ldconfig -safe_cd .. -echo "phasar successfully installed to ${PHASAR_INSTALL_DIR}" +if ${DO_INSTALL}; then + echo "install phasar..." + sudo cmake -DCMAKE_INSTALL_PREFIX=${PHASAR_INSTALL_DIR} -P cmake_install.cmake + sudo ldconfig + safe_cd .. + echo "phasar successfully installed to ${PHASAR_INSTALL_DIR}" + + echo "Set environment variables" + ./utils/setEnvironmentVariables.sh ${LLVM_INSTALL_DIR} ${PHASAR_INSTALL_DIR} +fi -echo "Set environment variables" -./utils/setEnvironmentVariables.sh ${LLVM_INSTALL_DIR} ${PHASAR_INSTALL_DIR} +echo "done." diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index 67411042f..9fe7102f9 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -16,17 +16,21 @@ function(add_phasar_unittest test_name) LINK_PUBLIC phasar_config phasar_controller + phasar_llvm_controlflow phasar_controlflow - phasar_phasarllvm_utils + phasar_llvm_utils phasar_analysis_strategy - phasar_ifdside + phasar_llvm_ifdside phasar_utils phasar_mono + phasar_llvm_db phasar_db # phasar_clang phasar_passes + phasar_llvm_pointer phasar_pointer - phasar_typehierarchy + phasar_llvm_typehierarchy + phasar_llvm phasar_taintconfig nlohmann_json_schema_validator ${SQLITE3_LIBRARY} @@ -80,8 +84,8 @@ function(generate_ll_file) set(test_code_file_target "${parent_dir}_${test_code_file_name}${ll_file_suffix}") # define compilation flags - 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_CXX_FLAGS -std=c++17 -fno-discard-value-names -emit-llvm -S -w) + set(GEN_C_FLAGS -fno-discard-value-names -emit-llvm -S -w) set(GEN_CMD_COMMENT "[LL]") if(GEN_LL_MEM2REG) @@ -236,6 +240,9 @@ macro(add_phasar_library name) EXPORT ${name}-targets COMPONENT ${component_name} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + # NOTE: Library, archive and runtime destination are automatically set by # GNUInstallDirs which is included in the top-level CMakeLists.txt ) diff --git a/examples/llvm-hello-world/main.cpp b/examples/llvm-hello-world/main.cpp index fe8d6f776..3cb439b21 100644 --- a/examples/llvm-hello-world/main.cpp +++ b/examples/llvm-hello-world/main.cpp @@ -1,6 +1,3 @@ -#include -#include - #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" @@ -15,6 +12,9 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include +#include + int main(int argc, char **argv) { if (argc != 2) { llvm::errs() << "usage: \n"; diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/AnalysisSetup.h b/include/phasar/AnalysisStrategy/AnalysisSetup.h similarity index 91% rename from include/phasar/PhasarLLVM/AnalysisStrategy/AnalysisSetup.h rename to include/phasar/AnalysisStrategy/AnalysisSetup.h index 84dfc20bf..51edc8889 100644 --- a/include/phasar/PhasarLLVM/AnalysisStrategy/AnalysisSetup.h +++ b/include/phasar/AnalysisStrategy/AnalysisSetup.h @@ -11,7 +11,7 @@ #define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_ANALYSISSETUP_H_ #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" namespace psr { @@ -27,7 +27,7 @@ struct AnalysisSetup { }; struct DefaultAnalysisSetup : AnalysisSetup { - using PointerAnalysisTy = LLVMPointsToSet; + using PointerAnalysisTy = LLVMAliasSet; using CallGraphAnalysisTy = LLVMBasedICFG; using TypeHierarchyTy = LLVMTypeHierarchy; }; diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/DemandDrivenAnalysis.h b/include/phasar/AnalysisStrategy/DemandDrivenAnalysis.h similarity index 100% rename from include/phasar/PhasarLLVM/AnalysisStrategy/DemandDrivenAnalysis.h rename to include/phasar/AnalysisStrategy/DemandDrivenAnalysis.h diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/IncrementalUpdateAnalysis.h b/include/phasar/AnalysisStrategy/IncrementalUpdateAnalysis.h similarity index 100% rename from include/phasar/PhasarLLVM/AnalysisStrategy/IncrementalUpdateAnalysis.h rename to include/phasar/AnalysisStrategy/IncrementalUpdateAnalysis.h diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/ModuleWiseAnalysis.h b/include/phasar/AnalysisStrategy/ModuleWiseAnalysis.h similarity index 100% rename from include/phasar/PhasarLLVM/AnalysisStrategy/ModuleWiseAnalysis.h rename to include/phasar/AnalysisStrategy/ModuleWiseAnalysis.h diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.def b/include/phasar/AnalysisStrategy/Strategies.def similarity index 100% rename from include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.def rename to include/phasar/AnalysisStrategy/Strategies.def diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.h b/include/phasar/AnalysisStrategy/Strategies.h similarity index 94% rename from include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.h rename to include/phasar/AnalysisStrategy/Strategies.h index 91c38d0f1..16c17655e 100644 --- a/include/phasar/PhasarLLVM/AnalysisStrategy/Strategies.h +++ b/include/phasar/AnalysisStrategy/Strategies.h @@ -24,7 +24,7 @@ namespace psr { enum class AnalysisStrategy { None, #define ANALYSIS_STRATEGY_TYPES(NAME, CMDFLAG, DESC) NAME, -#include "phasar/PhasarLLVM/AnalysisStrategy/Strategies.def" +#include "phasar/AnalysisStrategy/Strategies.def" }; diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/VariationalAnalysis.h b/include/phasar/AnalysisStrategy/VariationalAnalysis.h similarity index 86% rename from include/phasar/PhasarLLVM/AnalysisStrategy/VariationalAnalysis.h rename to include/phasar/AnalysisStrategy/VariationalAnalysis.h index 90e3f753f..3211a0091 100644 --- a/include/phasar/PhasarLLVM/AnalysisStrategy/VariationalAnalysis.h +++ b/include/phasar/AnalysisStrategy/VariationalAnalysis.h @@ -10,10 +10,9 @@ #ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_VARIATIONALANALYSIS_H_ #define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_VARIATIONALANALYSIS_H_ -#include +#include "phasar/AnalysisStrategy/AnalysisSetup.h" -#include "phasar/PhasarLLVM/AnalysisStrategy/AnalysisSetup.h" -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/IntraMonoSolver.h" +#include namespace psr { diff --git a/include/phasar/Config/Configuration.h b/include/phasar/Config/Configuration.h index 74d9f8401..24db00a2d 100644 --- a/include/phasar/Config/Configuration.h +++ b/include/phasar/Config/Configuration.h @@ -19,9 +19,12 @@ #include "phasar/Config/Version.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Support/MemoryBuffer.h" #include +#include #include #include @@ -34,58 +37,87 @@ class PhasarConfig { public: /// Current Phasar version // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static std::string PhasarVersion() { - return XSTR(PHASAR_VERSION); - } + [[nodiscard]] static llvm::StringRef PhasarVersion() noexcept; /// Stores the label/ tag with which we annotate the LLVM IR. // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static std::string MetaDataKind() { return "psr.id"; } + [[nodiscard]] static constexpr llvm::StringRef MetaDataKind() noexcept { + return "psr.id"; + } /// Specifies the directory in which important configuration files are /// located. + [[nodiscard]] static llvm::StringRef + // NOLINTNEXTLINE(readability-identifier-naming) + GlobalConfigurationDirectory() noexcept; + + [[nodiscard]] static std::optional // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static const std::string &ConfigurationDirectory(); + LocalConfigurationDirectory() noexcept; + + [[nodiscard]] std::unique_ptr + readConfigFile(const llvm::Twine &FileName); + [[nodiscard]] std::string readConfigFileAsText(const llvm::Twine &FileName); + + [[nodiscard]] llvm::ErrorOr> + readConfigFileOrErr(const llvm::Twine &FileName); + [[nodiscard]] llvm::ErrorOr + readConfigFileAsTextOrErr(const llvm::Twine &FileName); + + [[nodiscard]] std::unique_ptr + readConfigFileOrNull(const llvm::Twine &FileName); + [[nodiscard]] std::optional + readConfigFileAsTextOrNull(const llvm::Twine &FileName); /// Specifies the directory in which Phasar is located. // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static const std::string &PhasarDirectory(); + [[nodiscard]] static llvm::StringRef PhasarDirectory() noexcept; /// Name of the file storing all standard header search paths used for /// compilation. + [[nodiscard]] static constexpr llvm::StringRef // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static std::string HeaderSearchPathsFileName() { + HeaderSearchPathsFileName() noexcept { return "standard_header_paths.conf"; } /// Name of the compile_commands.json file (in case we wish to rename) + [[nodiscard]] static constexpr llvm::StringRef // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static std::string CompileCommandsJson() { + CompileCommandsJson() noexcept { return "compile_commands.json"; } /// Default Source- and Sink-Functions path + [[nodiscard]] static llvm::StringRef // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static std::string DefaultSourceSinkFunctionsPath() { - return PhasarDirectory() + "config/phasar-source-sink-function.json"; - } + DefaultSourceSinkFunctionsPath() noexcept; // Variables to be used in JSON export format /// Identifier for call graph export // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static std::string JsonCallGraphID() { return "psr.cg"; } + [[nodiscard]] static constexpr llvm::StringRef JsonCallGraphID() noexcept { + return "psr.cg"; + } /// Identifier for type hierarchy graph export + [[nodiscard]] static constexpr llvm::StringRef // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static std::string JsonTypeHierarchyID() { return "psr.th"; } + JsonTypeHierarchyID() noexcept { + return "psr.th"; + } /// Identifier for points-to graph export // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static std::string JsonPointsToGraphID() { return "psr.pt"; } + [[nodiscard]] static constexpr llvm::StringRef JsonAliasGraphID() noexcept { + return "psr.pt"; + } /// Identifier for data-flow results export // NOLINTNEXTLINE(readability-identifier-naming) - [[nodiscard]] static std::string JsonDataFlowID() { return "psr.df"; } + [[nodiscard]] static constexpr llvm::StringRef JsonDataFlowID() noexcept { + return "psr.df"; + } [[nodiscard]] static PhasarConfig &getPhasarConfig(); @@ -113,21 +145,24 @@ class PhasarConfig { private: PhasarConfig(); + bool loadConfigFileInto(llvm::StringRef FileName, + std::set &Lines); + void loadGlibcSpecialFunctionNames(); void loadLLVMSpecialFunctionNames(); std::set SpecialFuncNames; /// Name of the file storing all glibc function names. - static inline auto GLIBCFunctionListFileName = + static constexpr llvm::StringLiteral GLIBCFunctionListFileName = "glibc_function_list_v1-04.05.17.conf"; /// Name of the file storing all LLVM intrinsic function names. - static inline auto LLVMIntrinsicFunctionListFileName = + static constexpr llvm::StringLiteral LLVMIntrinsicFunctionListFileName = "llvm_intrinsics_function_list_v1-04.05.17.conf"; /// Log file directory - static inline auto LogFileDirectory = "log/"; + static constexpr llvm::StringLiteral LogFileDirectory = "log/"; }; } // namespace psr diff --git a/include/phasar/Config/Version.h b/include/phasar/Config/Version.h index 4a4f2366e..ba61df9c8 100644 --- a/include/phasar/Config/Version.h +++ b/include/phasar/Config/Version.h @@ -1,6 +1,6 @@ #ifndef PHASAR_CONFIG_VERSION_H #define PHASAR_CONFIG_VERSION_H -#define PHASAR_VERSION v1222 +#define PHASAR_VERSION v0323 #endif diff --git a/include/phasar/PhasarLLVM/ControlFlow/CFGBase.h b/include/phasar/ControlFlow/CFGBase.h similarity index 99% rename from include/phasar/PhasarLLVM/ControlFlow/CFGBase.h rename to include/phasar/ControlFlow/CFGBase.h index a3e707e3b..bee58d4d8 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/CFGBase.h +++ b/include/phasar/ControlFlow/CFGBase.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H #define PHASAR_PHASARLLVM_CONTROLFLOW_CFGBASE_H -#include "phasar/PhasarLLVM/Utils/ByRef.h" +#include "phasar/Utils/ByRef.h" #include "phasar/Utils/TypeTraits.h" #include "nlohmann/json.hpp" diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.def b/include/phasar/ControlFlow/CallGraphAnalysisType.def similarity index 100% rename from include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.def rename to include/phasar/ControlFlow/CallGraphAnalysisType.def diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h b/include/phasar/ControlFlow/CallGraphAnalysisType.h similarity index 92% rename from include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h rename to include/phasar/ControlFlow/CallGraphAnalysisType.h index 99bbda20c..31d6193ce 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h +++ b/include/phasar/ControlFlow/CallGraphAnalysisType.h @@ -18,7 +18,7 @@ namespace psr { enum class CallGraphAnalysisType { #define CALL_GRAPH_ANALYSIS_TYPE(NAME, CMDFLAG, DESC) NAME, -#include "phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.def" +#include "phasar/ControlFlow/CallGraphAnalysisType.def" Invalid }; diff --git a/include/phasar/PhasarLLVM/ControlFlow/ICFGBase.h b/include/phasar/ControlFlow/ICFGBase.h similarity index 99% rename from include/phasar/PhasarLLVM/ControlFlow/ICFGBase.h rename to include/phasar/ControlFlow/ICFGBase.h index 680a4e393..e85520de2 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/ICFGBase.h +++ b/include/phasar/ControlFlow/ICFGBase.h @@ -10,14 +10,14 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H #define PHASAR_PHASARLLVM_CONTROLFLOW_ICFGBASE_H -#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" +#include "phasar/ControlFlow/CFGBase.h" #include "phasar/Utils/TypeTraits.h" -#include "nlohmann/json.hpp" - #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" +#include "nlohmann/json.hpp" + #include namespace psr { diff --git a/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def b/include/phasar/ControlFlow/SpecialMemberFunctionType.def similarity index 100% rename from include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def rename to include/phasar/ControlFlow/SpecialMemberFunctionType.def diff --git a/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h b/include/phasar/ControlFlow/SpecialMemberFunctionType.h similarity index 93% rename from include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h rename to include/phasar/ControlFlow/SpecialMemberFunctionType.h index 9f6e488b0..b6e86f6c2 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.h +++ b/include/phasar/ControlFlow/SpecialMemberFunctionType.h @@ -29,7 +29,7 @@ namespace psr { enum class SpecialMemberFunctionType { #define SPECIAL_MEMBER_FUNCTION_TYPES(NAME, TYPE) TYPE, -#include "phasar/PhasarLLVM/ControlFlow/SpecialMemberFunctionType.def" +#include "phasar/ControlFlow/SpecialMemberFunctionType.def" }; std::string toString(SpecialMemberFunctionType SMFT); diff --git a/include/phasar/Controller/AnalysisController.h b/include/phasar/Controller/AnalysisController.h index ae057daba..5ded47b64 100644 --- a/include/phasar/Controller/AnalysisController.h +++ b/include/phasar/Controller/AnalysisController.h @@ -10,20 +10,20 @@ #ifndef PHASAR_CONTROLLER_ANALYSISCONTROLLER_H #define PHASAR_CONTROLLER_ANALYSISCONTROLLER_H +#include "phasar/AnalysisStrategy/Strategies.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/DataFlow/IfdsIde/IFDSIDESolverConfig.h" +#include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h" +#include "phasar/DataFlow/IfdsIde/SolverResults.h" +#include "phasar/DataFlow/Mono/Solver/InterMonoSolver.h" +#include "phasar/DataFlow/Mono/Solver/IntraMonoSolver.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" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h" -#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/HelperAnalyses.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasSet.h" +#include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h" +#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/DataFlowAnalysisType.h" #include "phasar/Utils/EnumFlags.h" @@ -83,33 +83,49 @@ class AnalysisController { void executeInterMonoSolverTest(); void executeInterMonoTaint(); - template - void executeIntraMonoAnalysis(ProblemTy &Problem) { - IntraMonoSolver Solver(Problem); + template + void executeMonoAnalysis(ArgTys &&...Args) { + auto Problem = + createAnalysisProblem(HA, std::forward(Args)...); + SolverTy Solver(Problem); Solver.solve(); emitRequestedDataFlowResults(Solver); } - template - void executeInterMonoAnalysis(ProblemTy &Problem) { - InterMonoSolver_P Solver(Problem); - Solver.solve(); - emitRequestedDataFlowResults(Solver); + template + void executeIntraMonoAnalysis(ArgTys &&...Args) { + executeMonoAnalysis, ProblemTy>( + std::forward(Args)...); } - template void executeIFDSAnalysis(ProblemTy &Problem) { - IFDSSolver Solver(Problem, &HA.getICFG()); - Solver.solve(); - emitRequestedDataFlowResults(Solver); + template + void executeInterMonoAnalysis(ArgTys &&...Args) { + executeMonoAnalysis, ProblemTy>( + std::forward(Args)...); } - template void executeIDEAnalysis(ProblemTy &Problem) { - IDESolver Solver(Problem, &HA.getICFG()); + template + void executeIfdsIdeAnalysis(ArgTys &&...Args) { + auto Problem = + createAnalysisProblem(HA, std::forward(Args)...); + SolverTy Solver(Problem, &HA.getICFG()); Solver.solve(); emitRequestedDataFlowResults(Solver); } - TaintConfig makeTaintConfig(); + template + void executeIFDSAnalysis(ArgTys &&...Args) { + executeIfdsIdeAnalysis, ProblemTy>( + std::forward(Args)...); + } + + template + void executeIDEAnalysis(ArgTys &&...Args) { + executeIfdsIdeAnalysis, ProblemTy>( + std::forward(Args)...); + } + + LLVMTaintConfig makeTaintConfig(); template void emitRequestedDataFlowResults(T &Solver) { if (EmitterOptions & AnalysisControllerEmitterOptions::EmitTextReport) { @@ -156,8 +172,8 @@ class AnalysisController { std::vector EntryPoints, AnalysisStrategy Strategy, AnalysisControllerEmitterOptions EmitterOptions, IFDSIDESolverConfig SolverConfig, - const std::string &ProjectID = "default-phasar-project", - const std::string &OutDirectory = ""); + std::string ProjectID = "default-phasar-project", + std::string OutDirectory = ""); ~AnalysisController() = default; diff --git a/include/phasar/DB/Hexastore.h b/include/phasar/DB/Hexastore.h index 42589c401..02bfb698a 100644 --- a/include/phasar/DB/Hexastore.h +++ b/include/phasar/DB/Hexastore.h @@ -10,17 +10,16 @@ #ifndef PHASAR_DB_HEXASTORE_H_ #define PHASAR_DB_HEXASTORE_H_ -#include -#include -#include +#include "phasar/DB/Queries.h" #include "llvm/Support/raw_ostream.h" #include "boost/format.hpp" - #include "sqlite3.h" -#include "phasar/DB/Queries.h" +#include +#include +#include namespace psr { /** diff --git a/include/phasar/DB/ProjectIRDBBase.h b/include/phasar/DB/ProjectIRDBBase.h index 1821491a1..78c946417 100644 --- a/include/phasar/DB/ProjectIRDBBase.h +++ b/include/phasar/DB/ProjectIRDBBase.h @@ -158,6 +158,15 @@ template class ProjectIRDBBase { return static_cast(*this); } }; + +template +// NOLINTNEXTLINE(readability-identifier-naming) +auto IRDBGetFunctionDef(const ProjectIRDBBase *IRDB) noexcept { + return [IRDB](llvm::StringRef Name) { + return IRDB->getFunctionDefinition(Name); + }; +} + } // namespace psr #endif // PHASAR_DB_PROJECTIRDBBASE_H diff --git a/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h b/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h new file mode 100644 index 000000000..4b631fe08 --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h @@ -0,0 +1,117 @@ +/****************************************************************************** + * 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_DATAFLOWSOLVER_IFDSIDE_DEFAULTEDGEFUNCTIONSINGLETONCACHE_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_DEFAULTEDGEFUNCTIONSINGLETONCACHE_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h" + +namespace psr { + +/// Default implementation of EdgeFunctionSingletonCache. +/// +/// For an edge function EdgeFunctionTy to be cached, it must be hashable, i.e. +/// it must implement the friend- or nonmember function llvm::hash_code +/// hash_value(const EdgeFunctionTy&). +/// +/// This cache is *not* thread-safe. +template +class DefaultEdgeFunctionSingletonCache + : public EdgeFunctionSingletonCache { +public: + DefaultEdgeFunctionSingletonCache() noexcept = default; + + DefaultEdgeFunctionSingletonCache(const DefaultEdgeFunctionSingletonCache &) = + delete; + DefaultEdgeFunctionSingletonCache & + operator=(const DefaultEdgeFunctionSingletonCache &) = delete; + + DefaultEdgeFunctionSingletonCache( + DefaultEdgeFunctionSingletonCache &&) noexcept = default; + DefaultEdgeFunctionSingletonCache & + operator=(DefaultEdgeFunctionSingletonCache &&) noexcept = delete; + ~DefaultEdgeFunctionSingletonCache() override = default; + + [[nodiscard]] const void * + lookup(ByConstRef EF) const noexcept override { + return Cache.lookup(&EF); + } + + void insert(const EdgeFunctionTy *EF, const void *Mem) override { + assert(EF != nullptr); + auto [It, Inserted] = Cache.try_emplace(EF, Mem); + assert(Inserted); + } + + void erase(ByConstRef EF) noexcept override { + Cache.erase(&EF); + } + + template + [[nodiscard]] EdgeFunction + createEdgeFunction(ArgTys &&...Args) { + return CachedEdgeFunction{ + EdgeFunctionTy{std::forward(Args)...}, this}; + } + +private: + struct DSI : public llvm::DenseMapInfo { + static bool isEqual(const EdgeFunctionTy *LHS, + const EdgeFunctionTy *RHS) noexcept { + if (LHS == RHS) { + return true; + } + auto Empty = llvm::DenseMapInfo::getEmptyKey(); + auto Tombstone = + llvm::DenseMapInfo::getTombstoneKey(); + if (LHS == Empty || LHS == Tombstone || RHS == Empty || + RHS == Tombstone) { + return false; + } + + return *LHS == *RHS; + } + + static auto getHashValue(const EdgeFunctionTy *EF) noexcept { + assert(EF != llvm::DenseMapInfo::getEmptyKey()); + assert(EF != + llvm::DenseMapInfo::getTombstoneKey()); + + return hash_value(*EF); + } + }; + + llvm::DenseMap Cache; +}; + +template +class DefaultEdgeFunctionSingletonCache< + EdgeFunctionTy, + std::enable_if_t>> { +public: + [[nodiscard]] const void * + lookup(ByConstRef /*EF*/) const noexcept override { + return nullptr; + } + void insert(const EdgeFunctionTy * /*EF*/, const void * /*Mem*/) override { + assert(false && "We should never go here"); + } + void erase(ByConstRef /*EF*/) noexcept override { + assert(false && "We should never go here"); + } + [[nodiscard]] EdgeFunction + createEdgeFunction(EdgeFunctionTy EF) { + return EF; + } +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_DEFAULTEDGEFUNCTIONSINGLETONCACHE_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunction.h b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h new file mode 100644 index 000000000..ca75fd53d --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunction.h @@ -0,0 +1,809 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTION_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/TypeName.h" +#include "llvm/Support/raw_os_ostream.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include + +namespace psr { + +template class EdgeFunction; +template class EdgeFunctionRef; + +#if __cplusplus < 202002L + +namespace detail { +template +struct IsEdgeFunction : std::false_type {}; +template +struct IsEdgeFunction< + T, std::void_t< + typename T::l_t, + decltype(std::declval().computeTarget( + std::declval())), + decltype(T::compose(std::declval>(), + std::declval>())), + decltype(T::join(std::declval>(), + std::declval>()))>> + : std::true_type {}; + +} // namespace detail +template +static inline constexpr bool IsEdgeFunction = detail::IsEdgeFunction::value; + +#else +// clang-format off +template +concept IsEdgeFunction = requires(const T &EF, const EdgeFunction& TEEF, EdgeFunctionRef CEF, typename T::l_t Src) { + typename T::l_t; + {EF.computeTarget(Src)} -> std::convertible_to; + {T::compose(CEF, TEEF)} -> std::convertible_to>; + {T::join(CEF, TEEF)} -> std::convertible_to>; +}; + // clang-format on + +#endif + +class EdgeFunctionBase { +public: + template + static constexpr bool + IsSOOCandidate = sizeof(ConcreteEF) <= sizeof(void *) && // NOLINT + alignof(ConcreteEF) <= alignof(void *) && + std::is_trivially_copyable_v; + +protected: + enum class AllocationPolicy { + SmallObjectOptimized, + DefaultHeapAllocated, + CustomHeapAllocated, + }; + struct RefCountedBase { + mutable std::atomic_size_t Rc = 0; + }; + template struct RefCounted : RefCountedBase { T Value; }; + + template struct CachedRefCounted : RefCounted { + EdgeFunctionSingletonCache *Cache{}; + }; + + template + constexpr static inline const ConcreteEF * + getPtr(const void *const &EF) noexcept { + if constexpr (!IsSOOCandidate) { + return &static_cast *>(EF)->Value; + } else { + return static_cast(static_cast(&EF)); + } + } + template + constexpr static inline const ConcreteEF * + getPtr(const void *const &&EF) = delete; // NOLINT + + template + static constexpr AllocationPolicy DefaultAllocPolicy = + IsSOOCandidate ? AllocationPolicy::SmallObjectOptimized + : AllocationPolicy::DefaultHeapAllocated; + template + static constexpr AllocationPolicy CustomAllocPolicy = + IsSOOCandidate ? AllocationPolicy::SmallObjectOptimized + : AllocationPolicy::CustomHeapAllocated; +}; + +/// Non-null reference to an edge function that is guarenteed to be managed by +/// an EdgeFunction object. +template +class [[clang::trivial_abi]] EdgeFunctionRef final : EdgeFunctionBase { + template friend class EdgeFunction; + +public: + using l_t = typename EF::l_t; + + EdgeFunctionRef(const EdgeFunctionRef &) noexcept = default; + EdgeFunctionRef &operator=(const EdgeFunctionRef &) noexcept = default; + ~EdgeFunctionRef() = default; + + const EF *operator->() const noexcept { return getPtr(Instance); } + const EF *get() const noexcept { return getPtr(Instance); } + const EF &operator*() const noexcept { return *getPtr(Instance); } + + [[nodiscard]] bool isCached() const noexcept { + if constexpr (IsSOOCandidate) { + return false; + } else { + return IsCached; + } + } + + [[nodiscard]] EdgeFunctionSingletonCache * + getCacheOrNull() const noexcept { + if (isCached()) { + return static_cast *>(Instance)->Cache; + } + + return nullptr; + } + +private: + explicit EdgeFunctionRef(const void *Instance, bool IsCached) noexcept + : Instance(Instance) { + if constexpr (!IsSOOCandidate) { + this->IsCached = IsCached; + } + } + const void *Instance{}; + [[no_unique_address]] std::conditional_t, EmptyType, bool> + IsCached{}; +}; + +/// Ref-counted and type-erased edge function with small-object optimization. +/// Supports caching. +template +// -- combined copy and move assignment +// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) +class [[clang::trivial_abi]] EdgeFunction final : EdgeFunctionBase { +public: + using l_t = L; + + // --- Constructors + + /// Default-initializes the edge-function with nullptr + EdgeFunction() noexcept = default; + /// Default-initializes the edge-function with nullptr + EdgeFunction(std::nullptr_t) noexcept : EdgeFunction() {} + /// Copy constructor. Increments the ref-count, if not small-object-optimized. + EdgeFunction(const EdgeFunction &Other) noexcept + : EdgeFunction(Other.EF, Other.VTAndHeapAlloc) {} + /// Move constructor. Does not increment the ref-count, but instead leaves the + /// moved-from edge function in the nullptr state. + EdgeFunction(EdgeFunction &&Other) noexcept + : EF(std::exchange(Other.EF, nullptr)), + VTAndHeapAlloc( + std::exchange(Other.VTAndHeapAlloc, decltype(VTAndHeapAlloc){})) {} + + /// Standard swap; does not affect ref-counts + void swap(EdgeFunction &Other) noexcept { + std::swap(EF, Other.EF); + std::swap(VTAndHeapAlloc, Other.VTAndHeapAlloc); + } + /// Standard swap; does not affect ref-counts + friend void swap(EdgeFunction &LHS, EdgeFunction &RHS) noexcept { + LHS.swap(RHS); + } + + /// Combined copy- and move assignment. If the assigned-to edge function is + /// not null, invokes the destructor on it, before overwriting its content. + EdgeFunction &operator=(EdgeFunction Other) noexcept { + std::destroy_at(this); + return *new (this) EdgeFunction(std::move(Other)); // NOLINT + } + /// Null-assignment operator. Decrements the ref-count if not + /// small-object-optimized or already null. Leaves the assigned-to edge + /// function in the nullptr state. + EdgeFunction &operator=(std::nullptr_t) noexcept { + std::destroy_at(this); + return *new (this) EdgeFunction(); // NOLINT + } + + /// Destructor. Decrements the ref-count if not small-object-optimized and + /// destroyes the held edge function once the ref-count reaches 0. + ~EdgeFunction() noexcept { + AllocationPolicy Policy = VTAndHeapAlloc.getInt(); + if (Policy != AllocationPolicy::SmallObjectOptimized) { + assert(VTAndHeapAlloc.getPointer() != nullptr && "Heap-alloc'd nullptr?"); + // Note: Memory-order taken from llvm::ThreadSafeRefCountedBase + if (static_cast(EF)->Rc.fetch_sub( + 1, std::memory_order_acq_rel) == 1) { + VTAndHeapAlloc.getPointer()->destroy(EF, Policy); + } + } + } + + /// Implicit-conversion constructor from EdgeFunctionRef. Increments the + /// ref-count if not small-object optimized + template > && + IsEdgeFunction>> + EdgeFunction(EdgeFunctionRef CEF) noexcept + : EdgeFunction(CEF.Instance, + {&VTableFor, [CEF] { + if constexpr (IsSOOCandidate) { + (void)CEF; + return AllocationPolicy::SmallObjectOptimized; + } else { + return CEF.IsCached + ? AllocationPolicy::CustomHeapAllocated + : AllocationPolicy::DefaultHeapAllocated; + } + }()}) {} + + /// Conversion-constructor from any edge function (that satisfies the + /// IsEdgeFunction trait). Stores a type-erased copy of CEF and allocates + /// space for it on the heap if small-object-optimization cannot be applied. + template > && + IsEdgeFunction>> + EdgeFunction(ConcreteEF &&CEF) noexcept( + IsSOOCandidate>) + : EdgeFunction(std::in_place_type>, + std::forward(CEF)) {} + + /// Emplacement-constructor for any edge function. Constructs a new object of + /// type ConcreteEF with the given constructor arguments and allocates space + /// for it on the heap if small-object-optimization cannot be applied. + /// No extra copy- or move construction/assignment is performed. Use this ctor + /// if even moving is expensive. + template + explicit EdgeFunction( + std::in_place_type_t /*unused*/, + ArgTys &&...Args) noexcept(IsSOOCandidate> && + std::is_nothrow_constructible_v) + : EdgeFunction( + [](auto &&...Args) { + if constexpr (IsSOOCandidate>) { + void *Ret; + new (&Ret) ConcreteEF(std::forward(Args)...); + return Ret; + } else { + return new RefCounted{ + {}, {std::forward(Args)...}}; + } + }(std::forward(Args)...), + {&VTableFor, DefaultAllocPolicy}) { + static_assert(std::is_same_v, + "Cannot construct EdgeFunction with incompatible " + "lattice domain"); + } + + /// Conversion-constructor for any edge function with enabled caching. Stores + /// a type-erased copy of EF.EF and allocates space for it on the heap if + /// small-object-optimization cannot be applied. If a heap allocation is + /// requires, first consults the EF.Cache to check whether an equivalent edge + /// function is already allocated. If so, takes the one from the cache and + /// increases its ref-count. Otherwise, performs a fresh allocation and + /// inserts the edge function into EF.Cache. + /// When all references to this edge function are out-of-scope, the destructor + /// automatically removes the edge function from EF.Cache. Hence, make sure + /// that EF.Cache lives at least as long as the last edge function cached in + /// it. + template && + std::is_move_constructible_v>> + EdgeFunction(CachedEdgeFunction EF) + : EdgeFunction( + [&EF] { + assert(EF.Cache != nullptr); + if constexpr (IsSOOCandidate>) { + void *Ret; + new (&Ret) ConcreteEF(std::move(EF.EF)); + return Ret; + } else { + if (auto Mem = EF.Cache->lookup(EF.EF)) { + return static_cast *>(Mem); + } + + auto Ret = new CachedRefCounted{ + {{}, {std::move(EF.EF)}}, EF.Cache}; + EF.Cache->insert(&Ret->Value, Ret); + return static_cast *>(Ret); + } + }(), + {&VTableFor, CustomAllocPolicy}) {} + + // --- API functions + + /// + /// This function describes the concrete value computation for its respective + /// exploded supergraph edge. The function(s) will be evaluated once the + /// exploded supergraph has been constructed and the concrete values of the + /// various value computation problems along the supergraph edges are + /// evaluated. + /// + /// Please also refer to the various edge function factories of the + /// EdgeFunctions interface: EdgeFunctions::get*EdgeFunction() for more + /// details. + /// + [[nodiscard]] l_t computeTarget(ByConstRef Source) const { + assert(!!*this && "computeTarget() called on nullptr!"); + return VTAndHeapAlloc.getPointer()->computeTarget(EF, Source); + } + + /// + /// This function composes the two edge functions this and SecondEF. This + /// function is used to extend an edge function in order to construct + /// so-called jump functions that describe the effects of everlonger sequences + /// of code. + /// + /// Calls the static function EF::compose(*this, SecondEF) for your concrete + /// edge function EF. + /// + /// For semantic correctness, please make sure that for all inputs x in l_t, + /// it holds: this->composeWith(SecondEF).computeTarget(x) == + /// SecondEF.computeTarget(this->computeTarget(x)). + [[nodiscard]] EdgeFunction composeWith(const EdgeFunction &SecondEF) const { + return compose(*this, SecondEF); + } + + /// + /// This function composes the two edge functions this and SecondEF. This + /// function is used to extend an edge function in order to construct + /// so-called jump functions that describe the effects of everlonger sequences + /// of code. + /// + /// For semantic correctness, please make sure that for all inputs x in l_t, + /// it holds: compose(FirstEF, SecondEF).computeTarget(x) == + /// SecondEF.computeTarget(FirstEF.computeTarget(x)). + [[nodiscard]] static EdgeFunction compose(const EdgeFunction &FirstEF, + const EdgeFunction &SecondEF) { + assert(!!FirstEF && "compose() called on LHS nullptr!"); + assert(!!SecondEF && "compose() called on RHS nullptr!"); + return FirstEF.VTAndHeapAlloc.getPointer()->compose( + FirstEF.EF, SecondEF, FirstEF.VTAndHeapAlloc.getInt()); + } + + /// + /// This function describes the join of the two edge functions this and + /// OtherEF. The function is called whenever two edge functions need to + /// be joined, for instance, when two branches lead to a common successor + /// instruction. + /// + /// Calls the static function EF::join(*this, OtherEF) for your concrete + /// edge function EF. + /// + /// For semantic correctness, please make sure that for all inputs x in l_t, + /// it holds (with join = JoinLatticeTraits::join): + /// join(this->joinWith(OtherEF).computeTarget(x)), + /// join(this->computeTarget(x), OtherEF.computeTarget(x))) == + /// this->joinWith(OtherEF).computeTarget(x) + /// i.e. that joining on edge functions only goes up the lattice that is + /// connected with the value-lattice on l_t + [[nodiscard]] EdgeFunction joinWith(const EdgeFunction &OtherEF) const { + return join(*this, OtherEF); + } + + /// + /// This function describes the join of the two edge functions this and + /// OtherEF. The function is called whenever two edge functions need to + /// be joined, for instance, when two branches lead to a common successor + /// instruction. + /// + /// For semantic correctness, please make sure that for all inputs x in l_t, + /// it holds (with joinl = JoinLatticeTraits::join): + /// joinl(join(FirstEF, SecondEF).computeTarget(x)), + /// joinl(FirstEF.computeTarget(x), SecondEF.computeTarget(x))) == + /// this->joinWith(OtherEF).computeTarget(x) + /// i.e. that joining on edge functions only goes up the lattice that is + /// connected with the value-lattice on l_t + [[nodiscard]] static EdgeFunction join(const EdgeFunction &FirstEF, + const EdgeFunction &SecondEF) { + assert(!!FirstEF && "join() called on LHS nullptr!"); + assert(!!SecondEF && "join() called on RHS nullptr!"); + return FirstEF.VTAndHeapAlloc.getPointer()->join( + FirstEF.EF, SecondEF, FirstEF.VTAndHeapAlloc.getInt()); + } + + /// Checks for equality of two edge functions. Equality requires exact + /// type-equality and value-equality based on operator== of the concrete edge + /// functions that are compared. + /// + /// If the concrete edge function has no nonstatic data members, the equality + /// is defaulted to only compare the types. However, by explicitly defining + /// operator==, this behavior can be overridden. + [[nodiscard]] friend bool operator==(const EdgeFunction &LHS, + const EdgeFunction &RHS) noexcept { + if (LHS.VTAndHeapAlloc.getPointer() != RHS.VTAndHeapAlloc.getPointer()) { + return false; + } + if (LHS.VTAndHeapAlloc.getOpaqueValue() == nullptr) { + return true; + } + return LHS.EF == RHS.EF || + LHS.VTAndHeapAlloc.getPointer()->equals(LHS.EF, RHS.EF); + } + + template > && + IsEdgeFunction>> + [[nodiscard]] friend bool operator==(EdgeFunctionRef LHS, + const EdgeFunction &RHS) noexcept { + if (!RHS.template isa()) { + return false; + } + if (LHS.Instance == RHS.EF) { + return true; + } + if constexpr (IsEqualityComparable) { + return *LHS == *getPtr(RHS.EF); + } else { + return true; + } + } + + template > && + IsEdgeFunction>> + [[nodiscard]] friend bool + operator==(const EdgeFunction &LHS, + EdgeFunctionRef RHS) noexcept { + return RHS == LHS; + } + [[nodiscard]] friend bool operator==(const EdgeFunction &EF, + std::nullptr_t) noexcept { + return EF.VTAndHeapAlloc.getOpaqueValue() == nullptr; + } + [[nodiscard]] friend bool operator==(std::nullptr_t, + const EdgeFunction &EF) noexcept { + return EF.VTAndHeapAlloc.getOpaqueValue() == nullptr; + } + [[nodiscard]] friend bool operator!=(const EdgeFunction &LHS, + const EdgeFunction &RHS) noexcept { + return !(LHS == RHS); + } + [[nodiscard]] friend bool operator!=(const EdgeFunction &EF, + std::nullptr_t) noexcept { + return !(EF == nullptr); + } + [[nodiscard]] friend bool operator!=(std::nullptr_t, + const EdgeFunction &EF) noexcept { + return !(EF == nullptr); + } + + template > && + IsEdgeFunction>> + [[nodiscard]] friend bool operator!=(EdgeFunctionRef LHS, + const EdgeFunction &RHS) noexcept { + return !(LHS == RHS); + } + template > && + IsEdgeFunction>> + [[nodiscard]] friend bool + operator!=(const EdgeFunction &LHS, + EdgeFunctionRef RHS) noexcept { + return !(LHS == RHS); + } + + /// Printing function. Based on llvm::raw_ostream + /// &operator<<(llvm::raw_ostream &OS, const ConcreteEF &EF) for the concrete + /// type ConcreteEF of EF. + /// + /// If the ConcreteEF does not define a fitting printing function, defaults to + /// printing the concrete type ConcreteEF. + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const EdgeFunction &EF) { + if (!EF) { + return OS << ""; + } + + EF.VTAndHeapAlloc.getPointer()->print(EF.EF, OS); + return OS; + } + + /// Printing function. Based on llvm::raw_ostream + /// &operator<<(llvm::raw_ostream &OS, const EdgeFunction &EF). + /// + /// Useful for unittests (gtest works with std::ostream instead of + /// llvm::raw_ostream). + friend std::ostream &operator<<(std::ostream &OS, const EdgeFunction &EF) { + llvm::raw_os_ostream ROS(OS); + ROS << EF; + return OS; + } + + /// Stringify function. Based on llvm::raw_ostream + /// &operator<<(llvm::raw_ostream &OS, const EdgeFunction &EF). + /// + /// Useful for ADL calls to to_string (overloads with all the to_string + /// functions of the STL). Do not rename! + [[nodiscard]] friend std::string to_string(const EdgeFunction &EF) { + std::string Ret; + llvm::raw_string_ostream ROS(Ret); + ROS << EF; + return Ret; + } + + /// Arbitrary partial ordering for being able to sort edge + /// functions. + [[nodiscard]] friend bool operator<(const EdgeFunction &LHS, + const EdgeFunction &RHS) noexcept { + if (LHS == RHS) { + return false; + } + return std::tuple(LHS.EF, LHS.VTAndHeapAlloc.getOpaqueValue()) < + std::tuple(RHS.EF, RHS.VTAndHeapAlloc.getOpaqueValue()); + } + + /// True, if the concrete edge function defines itself as constant, i.e. + /// for all x,y in l_t it holds: computeTarget(x) == computeTarget(y). + /// + /// Allows for better optimizations in compose and join and should be + /// provided, whehever this knowledge is available. + [[nodiscard]] bool isConstant() const noexcept { + assert(!!*this && "isConstant() called on nullptr!"); + return VTAndHeapAlloc.getPointer()->isConstant(EF); + } + + /// Performs a null-check. True, iff thie edge function is not null. + [[nodiscard]] explicit operator bool() const noexcept { + return VTAndHeapAlloc.getOpaqueValue(); + } + + /// Performs a runtime-typecheck. True, if the concrete type of the held edge + /// function *exactly* equals ConcreteEF. + /// + /// CAUTION: This model of isa-relation does not care about inheritance. Edge + /// functions of a base class BaseEF and a derived class DerivedEF are + /// considered unrelated! + template [[nodiscard]] bool isa() const noexcept { + if constexpr (IsEdgeFunction && + std::is_same_v) { + return VTAndHeapAlloc.getPointer() == &VTableFor; + } else { + return false; + } + } + + /// Performs an *unchecked* typecast to ConcreteEF. In debug builds, asserts + /// isa. + /// + /// Compatible with the llvm::isa API. + /// + /// Use with caution! + template + [[nodiscard]] const ConcreteEF *cast() const noexcept { + assert(this->template isa() && "Cast on incompatible type!"); + return getPtr(EF); + } + + /// Performs an *checked* typecast to ConcreteEF. If this edge function is not + /// *exactly* of type ConcreteEF, returns nullptr. + /// + /// Compatible with the llvm::dyn_cast API. + template + // NOLINTNEXTLINE(readability-identifier-naming) + [[nodiscard]] const ConcreteEF *dyn_cast() const noexcept { + return this->template isa() ? getPtr(EF) : nullptr; + } + + // -- misc + + /// True, iff this edge function is not small-object-optimized and thus its + /// lifetime is managed by ref-counting. + /// + /// False for null-EF. + [[nodiscard]] bool isRefCounted() const noexcept { + return VTAndHeapAlloc.getInt() != AllocationPolicy::SmallObjectOptimized; + } + + /// True, iff this edge function is cached in a EdgeFunctionSingletonCache. + /// + /// False for small-object-optimized- and null-EF. + [[nodiscard]] bool isCached() const noexcept { + return VTAndHeapAlloc.getInt() == AllocationPolicy::CustomHeapAllocated; + } + + /// Gets an opaque identifier for this edge function. Only meant for + /// comparisons of object-identity. Do not dereference! + [[nodiscard]] const void *getOpaqueValue() const noexcept { return EF; } + + /// Gets the cache where this edge function is being cached in. If this edge + /// function is not cached (i.e., isCached() returns false), returns nullptr. + /// Assumes that the held edge function is *exactly* of type ConcreteEF. In + /// debug builds, asserts isa. + /// + /// Use with caution! + template + [[nodiscard]] EdgeFunctionSingletonCache * + getCacheOrNull() const noexcept { + assert(isa()); + if (IsSOOCandidate || + VTAndHeapAlloc.getInt() == AllocationPolicy::DefaultHeapAllocated) { + return nullptr; + } + return static_cast *>(EF)->Cache; + } + +private: + struct VTable { + // NOLINTBEGIN(readability-identifier-naming) + l_t (*computeTarget)(const void *, ByConstRef); + EdgeFunction (*compose)(const void *, const EdgeFunction &, + AllocationPolicy); + EdgeFunction (*join)(const void *, const EdgeFunction &, AllocationPolicy); + bool (*equals)(const void *, const void *) noexcept; + void (*print)(const void *, llvm::raw_ostream &); + bool (*isConstant)(const void *) noexcept; + void (*destroy)(const void *, AllocationPolicy) noexcept; + // NOLINTEND(readability-identifier-naming) + }; + + template + static constexpr VTable VTableFor = { + [](const void *EF, ByConstRef Source) { + return getPtr(EF)->computeTarget(Source); + }, + [](const void *EF, const EdgeFunction &SecondEF, + AllocationPolicy Policy) { + return ConcreteEF::compose( + EdgeFunctionRef( + EF, Policy == AllocationPolicy::CustomHeapAllocated), + SecondEF); + }, + [](const void *EF, const EdgeFunction &OtherEF, AllocationPolicy Policy) { + return ConcreteEF::join( + EdgeFunctionRef( + EF, Policy == AllocationPolicy::CustomHeapAllocated), + OtherEF); + }, + [](const void *EF1, const void *EF2) noexcept { + static_assert(IsEqualityComparable || + std::is_empty_v, + "An EdgeFunction must be equality comparable with " + "operator==. Only if the type is empty, i.e. has no " + "members, the comparison can be inferred."); + if constexpr (IsEqualityComparable) { + return *getPtr(EF1) == *getPtr(EF2); + } else { + return true; + } + }, + [](const void *EF, llvm::raw_ostream &OS) { + if constexpr (is_llvm_printable_v) { + OS << *getPtr(EF); + } else { + OS << llvm::getTypeName(); + } + }, + [](const void *EF) noexcept { + if constexpr (HasIsConstant) { + static_assert( + std::is_nothrow_invocable_v, + "The function isConstant() must be noexcept!"); + return getPtr(EF)->isConstant(); + } else { + return false; + } + }, + [](const void *EF, AllocationPolicy Policy) noexcept { + if constexpr (!IsSOOCandidate) { + if (Policy != AllocationPolicy::CustomHeapAllocated) { + assert(Policy == AllocationPolicy::DefaultHeapAllocated); + delete static_cast *>(EF); + } else { + auto CEF = static_cast *>(EF); + CEF->Cache->erase(CEF->Value); + delete CEF; + } + } + }, + }; + + // Utility ctor for (copy) construction. Increments the ref-count if + // necessary + explicit EdgeFunction( + const void *EF, llvm::PointerIntPair + VTAndHeapAlloc) noexcept + : EF(EF), VTAndHeapAlloc(VTAndHeapAlloc) { + if (VTAndHeapAlloc.getInt() != AllocationPolicy::SmallObjectOptimized) { + // Note: Memory-order taken from llvm::ThreadSafeRefCountedBase + static_cast(EF)->Rc.fetch_add( + 1, std::memory_order_relaxed); + } + } + + // -- data members + + const void *EF{}; + llvm::PointerIntPair VTAndHeapAlloc{}; +}; + +} // namespace psr + +namespace llvm { + +// LLVM is currently overhauling its casting system. Use the new variant once +// possible! +// Note: The new variant (With CastInfo) is not tested yet! +#if LLVM_MAJOR < 15 + +template +struct isa_impl_cl> { + static inline bool doit(const psr::EdgeFunction &Val) noexcept { + assert(Val && "isa<> used on a null pointer"); + return Val.template isa>(); + } +}; + +template +struct cast_retty_impl> { + using ret_type = const To *; +}; + +template +struct cast_retty_impl> + : cast_retty_impl> {}; + +template +struct cast_convert_val, + const psr::EdgeFunction> { + static typename cast_retty>::ret_type + doit(const psr::EdgeFunction &Val) noexcept { + return Val.template cast(); + } +}; +template +struct cast_convert_val, psr::EdgeFunction> + : cast_convert_val, + const psr::EdgeFunction> {}; + +template +[[nodiscard]] inline typename cast_retty>::ret_type +dyn_cast_or_null(const psr::EdgeFunction &EF) noexcept { // NOLINT + return (EF && isa(EF)) ? cast(EF) : nullptr; +} + +template +[[nodiscard]] inline typename cast_retty>::ret_type +cast_or_null(const psr::EdgeFunction &EF) noexcept { // NOLINT + return EF ? cast(EF) : nullptr; +} +#else + +template +struct CastIsPossible> { + static inline bool isPossible(const psr::EdgeFunction &EF) noexcept { + return EF->template isa(); + } +}; + +template +struct CastInfo> + : public CastIsPossible>, + public NullableValueCastFailed, + public DefaultDoCastIfPossible &, + CastInfo>> { + static inline const To *doCast(const psr::EdgeFunction &EF) noexcept { + return EF.template cast(); + } +}; + +template +struct CastInfo> + : public ConstStrippingForwardingCast, + CastInfo>> { +}; + +#endif +} // namespace llvm + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTION_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h new file mode 100644 index 000000000..d2aadfe6f --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionSingletonCache.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * 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_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONSINGLETONCACHE_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONSINGLETONCACHE_H + +#include "phasar/Utils/ByRef.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/ErrorHandling.h" + +#include + +namespace psr { + +template class EdgeFunctionSingletonCache; + +/// Wrapper over an edge function and a pointer to a compatible +/// EdgeFunctionSingletonCache. +/// +/// When converting CachedEdgeFunction to EdgeFunction, signals to the +/// EdgeFunction-allocator that, if not small-object-optimized, this edge +/// function EF wishes to be allocated within the provided cache. +/// +/// Cache may not be nullptr. +template struct CachedEdgeFunction { + using EdgeFunctionType = EdgeFunctionTy; + + EdgeFunctionTy EF{}; + EdgeFunctionSingletonCache *Cache{}; +}; + +/// Base-class for edge function caches. Compatible with the caching mechanism +/// built in EdgeFunction. +template class EdgeFunctionSingletonCache { +public: + virtual ~EdgeFunctionSingletonCache() = default; + + /// Checks whether the edge function EF is cached in this cache. Returns the + /// cached entry if found, else nullptr. + [[nodiscard]] virtual const void * + lookup(ByConstRef EF) const noexcept = 0; + + /// Inserts the cache-entry Mem for the edge function *EF into the cache. + /// Typically, EF points into the buffer pointed to by Mem. Both pointers are + /// being stored and should not be null. + /// + /// Precondition: *EF Must not be in the cache. + virtual void insert(const EdgeFunctionTy *EF, const void *Mem) = 0; + + /// Erases the cache-entry associated with the edge function EF from the + /// cache. + virtual void erase(ByConstRef EF) noexcept = 0; + + template + [[nodiscard]] auto createEdgeFunction(ArgTys &&...Args) { + return CachedEdgeFunction{ + EdgeFunctionTy{std::forward(Args)...}, this}; + } +}; + +template +CachedEdgeFunction(EdgeFunctionTy, EdgeFunctionSingletonCache *) + -> CachedEdgeFunction; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONSINGLETONCACHE_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h new file mode 100644 index 000000000..7d07cc5fa --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h @@ -0,0 +1,470 @@ +/****************************************************************************** + * 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_DATAFLOW_IFDSIDE_EDGEFUNCTIONUTILS_H_ +#define PHASAR_DATAFLOW_IFDSIDE_EDGEFUNCTIONUTILS_H_ + +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/JoinLattice.h" + +#include "llvm/ADT/ArrayRef.h" + +#include + +namespace psr { +template struct EdgeIdentity final { + using l_t = L; + + [[nodiscard]] ByConstRef computeTarget(ByConstRef Source) const + noexcept(std::is_nothrow_move_constructible_v) { + static_assert(std::is_trivially_copyable_v); + static_assert(IsEdgeFunction); + return Source; + } + + [[nodiscard]] static EdgeFunction + compose(EdgeFunctionRef /*This*/, + const EdgeFunction &SecondFunction) { + return SecondFunction; + } + [[nodiscard]] static EdgeFunction + join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction); +}; + +template struct AllBottom final { + using l_t = L; + using JLattice = JoinLatticeTraits; + + [[no_unique_address]] std::conditional_t, EmptyType, + l_t> + BottomValue; + + [[nodiscard]] l_t computeTarget(ByConstRef /*Source*/) const noexcept { + static_assert(std::is_trivially_copyable_v); + static_assert(IsEdgeFunction); + if constexpr (HasJoinLatticeTraits) { + return JLattice::bottom(); + } else { + return BottomValue; + } + } + + [[nodiscard]] static EdgeFunction + compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + return SecondFunction.isConstant() ? SecondFunction : This; + } + + [[nodiscard]] static EdgeFunction + join(EdgeFunctionRef This, + const EdgeFunction & /*OtherFunction*/) { + return This; + } + + [[nodiscard]] constexpr bool isConstant() const noexcept { return true; } + + template >> + friend bool operator==(const AllBottom &LHS, + const AllBottom &RHS) noexcept { + return LHS.BottomValue == RHS.BottomValue; + } +}; + +template struct AllTop final { + using l_t = L; + using JLattice = JoinLatticeTraits; + + [[no_unique_address]] std::conditional_t, EmptyType, + l_t> + TopValue; + + [[nodiscard]] l_t computeTarget(ByConstRef /*Source*/) const noexcept { + static_assert(std::is_trivially_copyable_v); + static_assert(IsEdgeFunction); + if constexpr (HasJoinLatticeTraits) { + return JLattice::top(); + } else { + return TopValue; + } + } + + [[nodiscard]] static EdgeFunction + compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + return llvm::isa>(SecondFunction) ? This : SecondFunction; + } + + [[nodiscard]] static EdgeFunction + join(EdgeFunctionRef /*This*/, + const EdgeFunction &OtherFunction) { + return OtherFunction; + } + + [[nodiscard]] constexpr bool isConstant() const noexcept { return true; } + + template >> + friend bool operator==(const AllTop &LHS, const AllTop &RHS) noexcept { + return LHS.TopValue == RHS.TopValue; + } +}; + +template +EdgeFunction +defaultComposeOrNull(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) noexcept { + if (llvm::isa>(SecondFunction)) { + return This; + } + if (SecondFunction.isConstant()) { + return SecondFunction; + } + return nullptr; +} + +template struct ConstantEdgeFunction { + using l_t = L; + using JLattice = JoinLatticeTraits; + using value_type = typename NonTopBotValue::type; + + [[nodiscard]] l_t computeTarget(ByConstRef /*Source*/) const + noexcept(std::is_nothrow_constructible_v) { + static_assert(IsEdgeFunction); + return Value; + } + + template >> + [[nodiscard]] static EdgeFunction + compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + + auto ConstVal = SecondFunction.computeTarget(This->Value); + if constexpr (!EdgeFunctionBase::IsSOOCandidate) { + if (ConstVal == This->Value) { + return This; + } + } + + if constexpr (AreEqualityComparable) { + if (JLattice::bottom() == ConstVal) { + return AllBottom{}; + } + } else { + if (l_t(JLattice::bottom()) == ConstVal) { + return AllBottom{}; + } + } + + if constexpr (AreEqualityComparable) { + if (JLattice::top() == ConstVal) { + /// TODO: Can this ever happen? + return AllTop{}; + } + } else { + if (l_t(JLattice::top()) == ConstVal) { + /// TODO: Can this ever happen? + return AllTop{}; + } + } + + return ConstantEdgeFunction{ + NonTopBotValue::unwrap(std::move(ConstVal))}; + } + + template >> + [[nodiscard]] static EdgeFunction + join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction); + + [[nodiscard]] constexpr bool isConstant() const noexcept { return true; } + + // -- constant data member + + value_type Value{}; +}; + +template >>> +[[nodiscard]] bool operator==(ConstantEdgeFunction LHS, + ConstantEdgeFunction RHS) noexcept { + return LHS.Value == RHS.Value; +} + +template >>> +[[nodiscard]] bool operator==(const ConstantEdgeFunction &LHS, + const ConstantEdgeFunction &RHS) noexcept { + return LHS.Value == RHS.Value; +} + +template +[[nodiscard]] llvm::raw_ostream & +operator<<(llvm::raw_ostream &OS, ByConstRef> Id) { + OS << "ConstantEF"; + if constexpr (is_llvm_printable_v< + typename ConstantEdgeFunction::value_type>) { + OS << '[' << Id.Value << ']'; + } + return OS; +} + +template struct EdgeFunctionComposer { + using l_t = L; + + [[nodiscard]] l_t computeTarget(ByConstRef Source) const { + return Second.computeTarget(First.computeTarget(Source)); + } + + /** + * Function composition is implemented as an explicit composition, i.e. + * (secondFunction * G) * F = EFC(F, EFC(G , otherFunction)) + * + * However, it is advised to immediately reduce the resulting edge function + * by providing an own implementation of this function. + */ + template >> + [[nodiscard]] static EdgeFunction + compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + static_assert(IsEdgeFunction); + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + return This->First.composeWith(This->Second.composeWith(SecondFunction)); + } + + /// This join function is to be provided by derived classes + + // static EdgeFunction join(EdgeFunctionRef This, + // const EdgeFunction &OtherFunction); + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const EdgeFunctionComposer &EF) { + OS << "EFComposer[" << EF.First << ", " << EF.Second << ']'; + return OS; + } + + [[nodiscard]] friend bool + operator==(const EdgeFunctionComposer &LHS, + const EdgeFunctionComposer &RHS) noexcept { + return LHS.First == RHS.First && LHS.Second == RHS.Second; + } + + // -- data members + + EdgeFunction First{}; + EdgeFunction Second{}; +}; + +template struct JoinEdgeFunction { + using l_t = L; + using JLattice = JoinLatticeTraits; + + [[nodiscard]] l_t computeTarget(ByConstRef Source) const { + static_assert(IsEdgeFunction); + auto Val = Seed; + for (const auto &EF : OtherEF) { + Val = JLattice::join(std::move(Val), EF.computeTarget(Source)); + if (Val == JLattice::bottom()) { + return Val; + } + } + return Val; + } + + [[nodiscard]] static EdgeFunction + compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + + struct DefaultJoinEdgeFunctionComposer : EdgeFunctionComposer { + static EdgeFunction + join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + // Copied from defaultJoinOrNull() + if (llvm::isa>(OtherFunction)) { + return OtherFunction; + } + if (llvm::isa>(OtherFunction) || OtherFunction == This) { + return This; + } + + return JoinEdgeFunction::create(This, OtherFunction); + } + }; + + return DefaultJoinEdgeFunctionComposer{This, SecondFunction}; + } + + [[nodiscard]] static EdgeFunction + join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction); + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const JoinEdgeFunction &EF) { + OS << "JoinEF<" << N << ">[ Seed: " << EF.Seed << "; EF: { "; + size_t Idx = 0; + for (const auto &EF : EF.OtherEF) { + if (Idx) { + OS << ", "; + } + OS << '#' << Idx << ": " << EF; + ++Idx; + } + return OS << ']'; + } + + [[nodiscard]] friend bool operator==(const JoinEdgeFunction &LHS, + const JoinEdgeFunction &RHS) noexcept { + if (LHS.Seed != RHS.Seed) { + return false; + } + + return llvm::equal(LHS.OtherEF, RHS.OtherEF); + } + + [[nodiscard]] static EdgeFunction create(EdgeFunction LHS, + EdgeFunction RHS) { + + auto GetEFArrayAndSeed = [](const EdgeFunction &EF) + -> std::pair>, l_t> { + if (const auto *Join = llvm::dyn_cast(EF)) { + return {Join->OtherEF, Join->Seed}; + } + return {llvm::makeArrayRef(EF), JLattice::top()}; + }; + + auto [LVec, LSeed] = GetEFArrayAndSeed(LHS); + auto [RVec, RSeed] = GetEFArrayAndSeed(RHS); + + auto JoinSeed = JLattice::join(std::move(LSeed), std::move(RSeed)); + if (JoinSeed == JLattice::bottom()) { + return AllBottom{}; + } + + llvm::SmallVector, N> JoinVec; + + std::set_union(LVec.begin(), LVec.end(), RVec.begin(), RVec.end(), + std::back_inserter(JoinVec)); + if (JoinVec.size() > N) { + return AllBottom{}; + } + + return JoinEdgeFunction{std::move(JoinSeed), std::move(JoinVec)}; + } + + // --- data members + l_t Seed{}; + llvm::SmallVector, N> OtherEF{}; +}; + +// +// --- nontrivial join impls +// + +/// Default implementation of EdgeFunction::join. Considers AllBottom, AllTop +/// and EdgeIdentity for OtherFunction as well as This==OtherFunction. +/// Joining with EdgeIdentity will overapproximate to (AllBottom if N==0, else +/// JoinEdgeFunction). +template +EdgeFunction defaultJoinOrNull(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (llvm::isa>(OtherFunction)) { + return OtherFunction; + } + if (llvm::isa>(OtherFunction) || OtherFunction == This) { + return This; + } + if (llvm::isa>(OtherFunction)) { + if constexpr (N > 0) { + return JoinEdgeFunction::create(This, OtherFunction); + } else if constexpr (HasJoinLatticeTraits) { + return AllBottom{}; + } + } + return nullptr; +} + +template +EdgeFunction EdgeIdentity::join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (llvm::isa>(OtherFunction) || + llvm::isa>(OtherFunction)) { + return This; + } + if (llvm::isa>(OtherFunction)) { + return OtherFunction; + } + + // do not know how to join; hence ask other function to decide on this + return OtherFunction.joinWith(This); +} + +template +template +EdgeFunction +ConstantEdgeFunction::join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + if (!OtherFunction.isConstant()) { + // do not know how to join; hence ask other function to decide on this + return OtherFunction.joinWith(This); + } + + auto OtherVal = OtherFunction.computeTarget(JLattice::top()); + auto JoinedVal = JLattice::join(This->Value, OtherVal); + + if constexpr (AreEqualityComparable) { + if (JLattice::bottom() == JoinedVal) { + return AllBottom{}; + } + } else { + if (l_t(JLattice::bottom()) == JoinedVal) { + return AllBottom{}; + } + } + if constexpr (!EdgeFunctionBase::IsSOOCandidate) { + if (JoinedVal == OtherVal) { + return OtherFunction; + } + if (JoinedVal == This->Value) { + return This; + } + } + return ConstantEdgeFunction{ + NonTopBotValue::unwrap(std::move(JoinedVal))}; +} + +template +EdgeFunction +JoinEdgeFunction::join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + + return create(This, OtherFunction); +} + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONUTILS_H diff --git a/include/phasar/DataFlow/IfdsIde/EdgeFunctions.h b/include/phasar/DataFlow/IfdsIde/EdgeFunctions.h new file mode 100644 index 000000000..520cba7b1 --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/EdgeFunctions.h @@ -0,0 +1,271 @@ +/****************************************************************************** + * 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 + *****************************************************************************/ + +/* + * AbstractEdgeFunctions.h + * + * Created on: 04.08.2016 + * Author: pdschbrt + */ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONS_H_ +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONS_H_ + +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/JoinLattice.h" +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include + +namespace psr { + +//===----------------------------------------------------------------------===// +// EdgeFunctions interface + +template class EdgeFunctions { +public: + using n_t = typename AnalysisDomainTy::n_t; + using d_t = typename AnalysisDomainTy::d_t; + using f_t = typename AnalysisDomainTy::f_t; + using l_t = typename AnalysisDomainTy::l_t; + + virtual ~EdgeFunctions() = default; + + // + // Also refer to FlowFunctions::getNormalFlowFunction() + // + // Describes a value computation problem along a normal (non-call, non-return) + // intra-procedural exploded supergraph edge. A normal edge function + // implementation is queried for each edge that has been generated by appling + // the flow function returned by FlowFunctions::getNormalFlowFunction(). The + // supergraph edge whose computation is requested is defined by the supergraph + // nodes CurrNode and SuccNode. + // + // Let instruction_1 := Curr, instruction_2 := Succ, and 0 the tautological + // lambda fact. + // + // The concrete implementation of an edge function e is depending on the + // analysis problem. In the following, we present a brief, contrived example: + // + // Consider the following flow function implementation (cf. + // FlowFunctions::getNormalFlowfunction()): + // + // f(0) -> {0} // pass the lambda (or zero fact) as identity + // f(o) -> {o, x} // generate a new fact x from o + // f(.) -> {.} // pass all other facts that hold before instruction_1 + // // as identity + // + // The above flow-function implementation corresponds to the following edges + // in the exploded supergraph. + // + // 0 o ... + // | |\ ... + // Curr := x = instruction_1 o p | | \ ... + // | | | ... + // v v v ... + // 0 o x ... + // + // Succ := y = instruction_2 q r + // + // For each edge generated by the respective flow function a normal edge + // function is queried that describes a value computation. This results in the + // following queries: + // + // getNormalEdgeFunction(0, Curr, 0 Succ); + // getNormalEdgeFunction(o, Curr, o Succ); + // getNormalEdgeFunction(o, Curr, x Succ); + // + virtual EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, + n_t Succ, d_t SuccNode) = 0; + + // + // Also refer to FlowFunctions::getCallFlowFunction() + // + // Describes a value computation problem along a call flow. A call edge + // function is queried for each edge that has been generated by applying the + // flow function that has been returned by FlowFunctions::getCallFlowFunction. + // The supergraph edge whose computation is requested is defined by the + // supergraph nodes SrcNode and DestNode. + // + // The concrete implementation of an edge function e is depending on the + // analysis problem. In the following, we present a brief, contrived example: + // + // Consider the following flow function implementation (cf. + // FlowFunctions::getCallFlowFunction()): + // + // f(0) -> {0} // pass as identity into the callee target + // f(o) -> {q} // map actual o into formal q + // f(p) -> {r} // map actual p into formal r + // f(.) -> {} // kill all other facts that are not visible to the + // // callee target + // + // The above implementation corresponds to the following edges in the exploded + // supergraph. + // + // 0 o p ... + // \ \ \ ... + // CallInst := x = CalleeFun(o, p, ...) \ \ +----------------+ + // \ +---------------- | + // +-------------+ + | + // ... | | | + // ... | | | + // 0 o p ... | | | + // | | | + // | | | + // | | | + // Ty CalleeFun(q, r, ...) | | | + // v v v + // 0 q r ... + // + // start point + // + // For each edge generated by the respective flow function a call edge + // function is queried that describes a value computation. This results in the + // following queries: + // + // getCallEdgeFunction(CallInst, 0, CalleeFun, 0); + // getCallEdgeFunction(CallInst, o, CalleeFun, q); + // getCallEdgeFunction(CallInst, p, CalleeFun, r); + // + virtual EdgeFunction getCallEdgeFunction(n_t CallInst, d_t SrcNode, + f_t CalleeFun, + d_t DestNode) = 0; + + // + // Also refer to FlowFunction::getRetFlowFunction() + // + // Describes a value computation problem along a return flow. A return edge + // function implementation is queried for each edge that has been generated by + // applying the flow function that has been returned by + // FlowFunctions::getRetFlowFunction(). The supergraph edge whose computation + // is requested is defined by the supergraph nodes ExitNode and RetNode. + // + // The concrete implementation of an edge function e is depending on the + // analysis problem. In the following, we present a brief, contrived example: + // + // Consider the following flow function implementation (cf. + // FlowFunctions::getRetFlowFunction()): + // + // f(0) -> {0} // pass as identity into the callee target + // f(r) -> {x} // map return value to lhs variable at CallSite + // f(q) -> {o} // map pointer-typed formal q to actual o + // f(.) -> {} // kill all other facts that are not visible to the + // // caller + // + // The above implementation corresponds to the following edges in the exploded + // supergraph. + // + // 0 o ... + // + // CallSite = RetSite := x = CalleeFun(o, ...) + // +------------------+ + // +--|---------------+ | + // +--|--|------------+ | | + // v v v ... | | | + // 0 o x ... | | | + // | | | + // | | | + // | | | + // Ty CalleeFun(q, ...) | | | + // | | | + // 0 q r + // + // ExitInst := return r + // + // For each edge generated by the respective flow function a return edge + // function is queried that describes a value computation. This results in the + // following queries: + // + // getReturnEdgeFunction(CallSite, CalleeFun, ExitInst, 0, RetSite, 0); + // getReturnEdgeFunction(CallSite, CalleeFun, ExitInst, q, RetSite, o); + // getReturnEdgeFunction(CallSite, CalleeFun, ExitInst, r, RetSite, x); + // + virtual EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeFun, + n_t ExitInst, d_t ExitNode, + n_t RetSite, d_t RetNode) = 0; + + // + // Also refer to FlowFunctions::getCallToRetFlowFunction() + // + // Describes a value computation problem along data-flows alongsite a + // CallSite. A return edge function implementation is queried for each edge + // that has been generated by applying the flow function that has been + // returned by FlowFunctions::getCallToRetFlowFunction(). The supergraph edge + // whose computation is requested is defined by the supergraph nodes CallNode + // and RetSiteNode. + // + // The concrete implementation of an edge function e is depending on the + // analysis problem. In the following, we present a brief, contrived example: + // + // Consider the following flow function implementation (cf. + // FlowFunctions::getCallToRetFlowFunction()): + // + // f(0) -> {0} // pass lambda as identity alongsite the CallSite + // f(o) -> {o} // assuming that o is passed by value, it is passed + // // alongsite the CallSite + // f(p) -> {} // assuming that p is a pointer-typed value, we need + // // to kill p, as it will be handled by the call- and + // // return-flow functions + // f(.) -> {.} // pass everything that is not involved in the call as + // // identity + // + // The above implementation corresponds to the following edges in the exploded + // supergraph. + // + // 0 o ... + // | | + // | +-------+ + // +--------+ | + // | | + // CallSite = RetSite := x = CalleeFun(o, p, ...) | | + // | | + // +--------+ | + // | +-------+ + // v v + // 0 o x ... + // + // For each edge generated by the respective flow function a call-to-return + // edge function is queried that describes a value computation. This results + // in the following queries: + // + // getCallToRetEdgeFunction(CallSite, 0, RetSite, 0, {CalleeFun}); + // getCallToRetEdgeFunction(CallSite, o, RetSite, o, {CalleeFun}); + // + virtual EdgeFunction + getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, + d_t RetSiteNode, llvm::ArrayRef Callees) = 0; + + // + // Also refer to FlowFunction::getSummaryFlowFunction() + // + // Describes a value computation problem along a summary data flow. A summary + // edge function implementation is queried for each edge that has been + // generated by FlowFunctions::getSummaryFlowFunction(). The supergraph edge + // whose computation is requested is defined by the supergraph nodes CurrNode + // and SuccNode. + // + // The default implementation returns a nullptr to indicate that the mechanism + // should not be used. + // + virtual EdgeFunction getSummaryEdgeFunction(n_t /*Curr*/, + d_t /*CurrNode*/, + n_t /*Succ*/, + d_t /*SuccNode*/) { + return nullptr; + } +}; + +} // namespace psr + +#endif diff --git a/include/phasar/DataFlow/IfdsIde/EntryPointUtils.h b/include/phasar/DataFlow/IfdsIde/EntryPointUtils.h new file mode 100644 index 000000000..800fe01e7 --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/EntryPointUtils.h @@ -0,0 +1,96 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_DATAFLOW_IFDSIDE_ENTRYPOINTUTILS_H +#define PHASAR_DATAFLOW_IFDSIDE_ENTRYPOINTUTILS_H + +#include "phasar/ControlFlow/CFGBase.h" +#include "phasar/DB/ProjectIRDBBase.h" + +#include "llvm/ADT/STLExtras.h" + +#include + +namespace psr { + +namespace detail { +template +void forallStartingPoints(const EntryRange &EntryPoints, const CFGBase &CFG, + HandlerFn Handler) { + for (const auto &EntryPointFn : EntryPoints) { + if constexpr (std::is_convertible_v, + bool>) { + if (!EntryPointFn) { + continue; + } + } + for (const auto &SP : CFG.getStartPointsOf(EntryPointFn)) { + std::invoke(Handler, SP); + } + } +} + +template +void forallStartingPoints(const EntryRange &EntryPoints, const ICFGorIRDB *ICDB, + const CFGBase &CFG, HandlerFn Handler) { + + if (llvm::hasSingleElement(EntryPoints) && + *llvm::adl_begin(EntryPoints) == "__ALL__") { + forallStartingPoints(ICDB->getAllFunctions(), CFG, std::move(Handler)); + } else { + forallStartingPoints(llvm::map_range(EntryPoints, + [ICDB](llvm::StringRef Name) { + return ICDB->getFunction(Name); + }), + CFG, std::move(Handler)); + } +} + +} // namespace detail + +template +void forallStartingPoints(const EntryRange &EntryPoints, + const ProjectIRDBBase *IRDB, + const CFGBase &CFG, HandlerFn Handler) { + return detail::forallStartingPoints(EntryPoints, IRDB, CFG, + std::move(Handler)); +} + +template +void forallStartingPoints(const EntryRange &EntryPoints, const I *ICF, + HandlerFn Handler) { + detail::forallStartingPoints(EntryPoints, ICF, *ICF, std::move(Handler)); +} + +template +void addSeedsForStartingPoints(const EntryRange &EntryPoints, + const ProjectIRDBBase *IRDB, + const CFGBase &CFG, SeedsT &Seeds, + const D &ZeroValue, const L &BottomValue) { + forallStartingPoints(EntryPoints, IRDB, CFG, + [&Seeds, &ZeroValue, &BottomValue](const auto &SP) { + Seeds.addSeed(SP, ZeroValue, BottomValue); + }); +} + +template +void addSeedsForStartingPoints(const EntryRange &EntryPoints, const I *ICF, + SeedsT &Seeds, const D &ZeroValue, + const L &BottomValue) { + forallStartingPoints(EntryPoints, ICF, + [&Seeds, &ZeroValue, &BottomValue](const auto &SP) { + Seeds.addSeed(SP, ZeroValue, BottomValue); + }); +} +} // namespace psr + +#endif // PHASAR_DATAFLOW_IFDSIDE_ENTRYPOINTUTILS_H diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h similarity index 99% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h rename to include/phasar/DataFlow/IfdsIde/FlowFunctions.h index d33ddc646..13fcb3bac 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/FlowFunctions.h @@ -855,8 +855,9 @@ class FlowFunctions { // The default implementation returns a nullptr to indicate that the mechanism // should not be used. // - virtual FlowFunctionPtrType getSummaryFlowFunction(n_t Curr, - f_t CalleeFun) = 0; + virtual FlowFunctionPtrType getSummaryFlowFunction(n_t Curr, f_t CalleeFun) { + return nullptr; + } }; //////////////////////////////////////////////////////////////////////////////// diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h similarity index 76% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h rename to include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h index c907b42ed..28bfc76a7 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h +++ b/include/phasar/DataFlow/IfdsIde/IDETabulationProblem.h @@ -7,22 +7,27 @@ * Philipp Schubert, Fabian Schiebel and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IDETABULATIONPROBLEM_H_ -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IDETABULATIONPROBLEM_H_ +#ifndef PHASAR_DATAFLOW_IFDSIDE_IDETABULATIONPROBLEM_H_ +#define PHASAR_DATAFLOW_IFDSIDE_IDETABULATIONPROBLEM_H_ +#include "phasar/ControlFlow/ICFGBase.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/DataFlow/IfdsIde/EdgeFunctions.h" +#include "phasar/DataFlow/IfdsIde/EntryPointUtils.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h" +#include "phasar/DataFlow/IfdsIde/InitialSeeds.h" +#include "phasar/DataFlow/IfdsIde/SolverResults.h" +#include "phasar/Utils/JoinLattice.h" +#include "phasar/Utils/Printer.h" #include "phasar/Utils/Soundness.h" +#include "llvm/ADT/StringRef.h" + #include +#include #include +#include #include #include #include @@ -51,24 +56,20 @@ class IDETabulationProblem : public FlowFunctions, using i_t = typename AnalysisDomainTy::i_t; using db_t = typename AnalysisDomainTy::db_t; - using typename EdgeFunctions::EdgeFunctionPtrType; - using ConfigurationTy = HasNoConfigurationType; - explicit IDETabulationProblem(const db_t *IRDB, + explicit IDETabulationProblem(const ProjectIRDBBase *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; + virtual EdgeFunction allTopFunction() = 0; /// Checks if the given data-flow fact is the special tautological lambda (or /// zero) fact. @@ -128,7 +129,23 @@ class IDETabulationProblem : public FlowFunctions, return generateFlow(std::move(FactToGenerate), getZeroValue()); } - const db_t *IRDB{}; + /// Seeds that just start with ZeroValue and bottomElement() at the starting + /// points of each EntryPoint function. + /// Takes the __ALL__ EntryPoint into account. + template < + typename CC = typename AnalysisDomainTy::c_t, + typename = std::enable_if_t>> + [[nodiscard]] InitialSeeds createDefaultSeeds() { + InitialSeeds Seeds; + CC C{}; + + addSeedsForStartingPoints(EntryPoints, IRDB, C, Seeds, getZeroValue(), + this->bottomElement()); + + return Seeds; + } + + const ProjectIRDBBase *IRDB{}; std::vector EntryPoints; std::optional ZeroValue; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h b/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h similarity index 85% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h rename to include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h index 7524e2911..e402ada1c 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h +++ b/include/phasar/DataFlow/IfdsIde/IFDSIDESolverConfig.h @@ -42,12 +42,6 @@ enum class SolverConfigOptions : uint32_t { struct IFDSIDESolverConfig { IFDSIDESolverConfig() noexcept = default; IFDSIDESolverConfig(SolverConfigOptions Options) noexcept; - ~IFDSIDESolverConfig() = default; - IFDSIDESolverConfig(const IFDSIDESolverConfig &) noexcept = default; - IFDSIDESolverConfig & - operator=(const IFDSIDESolverConfig &) noexcept = default; - IFDSIDESolverConfig(IFDSIDESolverConfig &&) noexcept = default; - IFDSIDESolverConfig &operator=(IFDSIDESolverConfig &&) noexcept = default; [[nodiscard]] bool followReturnsPastSeeds() const; [[nodiscard]] bool autoAddZero() const; diff --git a/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h new file mode 100644 index 000000000..656c80b46 --- /dev/null +++ b/include/phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h @@ -0,0 +1,88 @@ +/****************************************************************************** + * 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_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/Domain/AnalysisDomain.h" +#include "phasar/Domain/BinaryDomain.h" + +#include +#include + +namespace psr { + +template > +class IFDSTabulationProblem + : public IDETabulationProblem, + Container> { + using Base = + IDETabulationProblem, Container>; + +public: + using typename Base::d_t; + using typename Base::db_t; + 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 ProjectIRDBBase *IRDB, + std::vector EntryPoints, + d_t ZeroValue) + : Base(IRDB, std::move(EntryPoints), std::move(ZeroValue)) {} + ~IFDSTabulationProblem() override = default; + + EdgeFunction getNormalEdgeFunction(n_t /*Curr*/, d_t /*CurrNode*/, + n_t /*Succ*/, + d_t /*SuccNode*/) final { + return EdgeIdentity{}; + } + + EdgeFunction getCallEdgeFunction(n_t /*CallInst*/, d_t /*SrcNode*/, + f_t /*CalleeFun*/, + d_t /*DestNode*/) final { + return EdgeIdentity{}; + } + + EdgeFunction getReturnEdgeFunction(n_t /*CallSite*/, f_t /*CalleeFun*/, + n_t /*ExitInst*/, d_t /*ExitNode*/, + n_t /*RetSite*/, + d_t /*RetNode*/) final { + return EdgeIdentity{}; + } + + EdgeFunction + getCallToRetEdgeFunction(n_t /*CallSite*/, d_t /*CallNode*/, n_t /*RetSite*/, + d_t /*RetSiteNode*/, + llvm::ArrayRef /*Callees*/) final { + return EdgeIdentity{}; + } + + EdgeFunction getSummaryEdgeFunction(n_t /*Curr*/, d_t /*CurrNode*/, + n_t /*Succ*/, + d_t /*SuccNode*/) final { + return EdgeIdentity{}; + } + + EdgeFunction allTopFunction() final { return AllTop{}; } + + void printEdgeFact(llvm::raw_ostream &OS, BinaryDomain Val) const final { + OS << Val; + } +}; +} // namespace psr + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h rename to include/phasar/DataFlow/IfdsIde/InitialSeeds.h index 7f89d566d..d12fca954 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/InitialSeeds.h +++ b/include/phasar/DataFlow/IfdsIde/InitialSeeds.h @@ -10,8 +10,10 @@ #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 "phasar/Domain/BinaryDomain.h" +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/Support/Compiler.h" #include #include @@ -72,19 +74,21 @@ template class InitialSeeds { [[nodiscard]] const GeneralizedSeeds &getSeeds() const & { return Seeds; } [[nodiscard]] GeneralizedSeeds getSeeds() && { return std::move(Seeds); } - void dump(llvm::raw_ostream &OS = llvm::errs()) { + void dump(llvm::raw_ostream &OS = llvm::errs()) const { auto printNode = [&](auto &&Node) { // NOLINT - if constexpr (std::is_same_v) { - OS << llvmIRToString(Node); + if constexpr (std::is_pointer_v && + is_llvm_printable_v>) { + OS << *Node; } else { OS << Node; } }; auto printFact = [&](auto &&Node) { // NOLINT - if constexpr (std::is_same_v) { - OS << llvmIRToString(Node); + if constexpr (std::is_pointer_v && + is_llvm_printable_v>) { + OS << *Node; } else { OS << Node; } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h similarity index 92% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h rename to include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h index d79581fc9..0db214065 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h @@ -10,6 +10,14 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWEDGEFUNCTIONCACHE_H_ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_FLOWEDGEFUNCTIONCACHE_H_ +#include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/Utils/EquivalenceClassMap.h" +#include "phasar/Utils/Logger.h" +#include "phasar/Utils/PAMMMacros.h" + +#include "llvm/ADT/DenseMap.h" + #include #include #include @@ -18,13 +26,9 @@ #include #include -#include "llvm/ADT/DenseMap.h" - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/Utils/EquivalenceClassMap.h" -#include "phasar/Utils/Logger.h" -#include "phasar/Utils/PAMMMacros.h" +namespace llvm { +class Value; +} // namespace llvm namespace psr { template class DefaultMapKeyCompressor { @@ -68,12 +72,12 @@ template ; using FlowFunctionPtrType = typename IDEProblemType::FlowFunctionPtrType; - using EdgeFunctionPtrType = typename IDEProblemType::EdgeFunctionPtrType; using n_t = typename AnalysisDomainTy::n_t; using d_t = typename AnalysisDomainTy::d_t; using f_t = typename AnalysisDomainTy::f_t; using t_t = typename AnalysisDomainTy::t_t; + using l_t = typename AnalysisDomainTy::l_t; using DTKeyCompressorType = std::conditional_t< std::is_base_of_v>, @@ -95,7 +99,7 @@ class FlowEdgeFunctionCache { std::is_base_of_v>, uint64_t, std::pair>; using InnerEdgeFunctionMapType = - EquivalenceClassMap; + EquivalenceClassMap>; IDETabulationProblem &Problem; // Auto add zero @@ -122,13 +126,13 @@ class FlowEdgeFunctionCache { std::map, FlowFunctionPtrType> CallToRetFlowFunctionCache; // Caches for the edge functions - std::map, EdgeFunctionPtrType> + std::map, EdgeFunction> CallEdgeFunctionCache; - std::map, EdgeFunctionPtrType> + std::map, EdgeFunction> ReturnEdgeFunctionCache; std::map CallToRetEdgeFunctionCache; - std::map, EdgeFunctionPtrType> + std::map, EdgeFunction> SummaryEdgeFunctionCache; public: @@ -316,8 +320,8 @@ class FlowEdgeFunctionCache { return FF; } - EdgeFunctionPtrType getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, - d_t SuccNode) { + EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, + d_t SuccNode) { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Normal edge function factory call"); @@ -336,8 +340,8 @@ class FlowEdgeFunctionCache { if (SearchEdgeFunc != SearchInnerMap->second.EdgeFunctionMap.end()) { INC_COUNTER("Normal-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); - PHASAR_LOG_LEVEL( - DEBUG, "Provide Edge Function: " << SearchEdgeFunc->second->str()); + PHASAR_LOG_LEVEL(DEBUG, + "Provide Edge Function: " << SearchEdgeFunc->second); return SearchEdgeFunc->second; } INC_COUNTER("Normal-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); @@ -347,7 +351,7 @@ class FlowEdgeFunctionCache { createEdgeFunctionNodeKey(CurrNode, SuccNode), EF); PHASAR_LOG_LEVEL(DEBUG, "Edge function constructed"); - PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF->str()); + PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF); return EF; } INC_COUNTER("Normal-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); @@ -358,13 +362,12 @@ class FlowEdgeFunctionCache { createEdgeFunctionNodeKey(CurrNode, SuccNode), EF)})); PHASAR_LOG_LEVEL(DEBUG, "Edge function constructed"); - PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF->str()); + PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF); return EF; } - EdgeFunctionPtrType getCallEdgeFunction(n_t CallSite, d_t SrcNode, - f_t DestinationFunction, - d_t DestNode) { + EdgeFunction getCallEdgeFunction(n_t CallSite, d_t SrcNode, + f_t DestinationFunction, d_t DestNode) { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call edge function factory call"); @@ -382,8 +385,8 @@ class FlowEdgeFunctionCache { if (SearchCallEdgeFunction != CallEdgeFunctionCache.end()) { INC_COUNTER("Call-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); - PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " - << SearchCallEdgeFunction->second->str()); + PHASAR_LOG_LEVEL( + DEBUG, "Provide Edge Function: " << SearchCallEdgeFunction->second); return SearchCallEdgeFunction->second; } INC_COUNTER("Call-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); @@ -391,13 +394,13 @@ class FlowEdgeFunctionCache { DestinationFunction, DestNode); CallEdgeFunctionCache.insert(std::make_pair(Key, EF)); PHASAR_LOG_LEVEL(DEBUG, "Edge function constructed"); - PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF->str()); + PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF); return EF; } - EdgeFunctionPtrType getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, - n_t ExitInst, d_t ExitNode, - n_t RetSite, d_t RetNode) { + EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, + n_t ExitInst, d_t ExitNode, + n_t RetSite, d_t RetNode) { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Return edge function factory call"); @@ -419,8 +422,8 @@ class FlowEdgeFunctionCache { if (SearchReturnEdgeFunction != ReturnEdgeFunctionCache.end()) { INC_COUNTER("Return-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); - PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " - << SearchReturnEdgeFunction->second->str()); + PHASAR_LOG_LEVEL( + DEBUG, "Provide Edge Function: " << SearchReturnEdgeFunction->second); return SearchReturnEdgeFunction->second; } INC_COUNTER("Return-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); @@ -428,13 +431,13 @@ class FlowEdgeFunctionCache { ExitNode, RetSite, RetNode); ReturnEdgeFunctionCache.insert(std::make_pair(Key, EF)); PHASAR_LOG_LEVEL(DEBUG, "Edge function constructed"); - PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF->str()); + PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF); return EF; } - EdgeFunctionPtrType getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, - n_t RetSite, d_t RetSiteNode, - llvm::ArrayRef Callees) { + EdgeFunction getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, + n_t RetSite, d_t RetSiteNode, + llvm::ArrayRef Callees) { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Call-to-Return edge function factory call"); @@ -461,8 +464,8 @@ class FlowEdgeFunctionCache { if (SearchEdgeFunc != SearchInnerMap->second.end()) { INC_COUNTER("CallToRet-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); - PHASAR_LOG_LEVEL( - DEBUG, "Provide Edge Function: " << SearchEdgeFunc->second->str()); + PHASAR_LOG_LEVEL(DEBUG, + "Provide Edge Function: " << SearchEdgeFunc->second); return SearchEdgeFunc->second; } INC_COUNTER("CallToRet-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); @@ -473,7 +476,7 @@ class FlowEdgeFunctionCache { createEdgeFunctionNodeKey(CallNode, RetSiteNode), EF); PHASAR_LOG_LEVEL(DEBUG, "Edge function constructed"); - PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF->str()); + PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF); return EF; } @@ -486,12 +489,12 @@ class FlowEdgeFunctionCache { InnerEdgeFunctionMapType{std::make_pair( createEdgeFunctionNodeKey(CallNode, RetSiteNode), EF)}); PHASAR_LOG_LEVEL(DEBUG, "Edge function constructed"); - PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF->str()); + PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF); return EF; } - EdgeFunctionPtrType getSummaryEdgeFunction(n_t CallSite, d_t CallNode, - n_t RetSite, d_t RetSiteNode) { + EdgeFunction getSummaryEdgeFunction(n_t CallSite, d_t CallNode, + n_t RetSite, d_t RetSiteNode) { PAMM_GET_INSTANCE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "Summary edge function factory call"); @@ -510,7 +513,7 @@ class FlowEdgeFunctionCache { INC_COUNTER("Summary-EF Cache Hit", 1, PAMM_SEVERITY_LEVEL::Full); PHASAR_LOG_LEVEL(DEBUG, "Edge function fetched from cache"); PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " - << SearchSummaryEdgeFunction->second->str()); + << SearchSummaryEdgeFunction->second); return SearchSummaryEdgeFunction->second; } INC_COUNTER("Summary-EF Construction", 1, PAMM_SEVERITY_LEVEL::Full); @@ -518,7 +521,7 @@ class FlowEdgeFunctionCache { RetSiteNode); SummaryEdgeFunctionCache.insert(std::make_pair(Key, EF)); PHASAR_LOG_LEVEL(DEBUG, "Edge function constructed"); - PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF->str()); + PHASAR_LOG_LEVEL(DEBUG, "Provide Edge Function: " << EF); return EF; } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h similarity index 90% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h rename to include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h index c2ad9949a..555a69bf5 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IDESolver.h @@ -18,28 +18,29 @@ #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IDESOLVER_H #include "phasar/Config/Configuration.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowEdgeFunctionCache.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#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/Solver/JumpFunctions.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" +#include "phasar/DB/ProjectIRDBBase.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/InitialSeeds.h" +#include "phasar/DataFlow/IfdsIde/Solver/FlowEdgeFunctionCache.h" +#include "phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h" +#include "phasar/DataFlow/IfdsIde/Solver/PathEdge.h" +#include "phasar/DataFlow/IfdsIde/SolverResults.h" +#include "phasar/Domain/AnalysisDomain.h" +#include "phasar/Utils/DOTGraph.h" +#include "phasar/Utils/JoinLattice.h" #include "phasar/Utils/Logger.h" #include "phasar/Utils/PAMMMacros.h" #include "phasar/Utils/Table.h" - -#include "nlohmann/json.hpp" +#include "phasar/Utils/Utilities.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" +#include "nlohmann/json.hpp" + #include #include #include @@ -49,7 +50,14 @@ #include #include +namespace llvm { +class Instruction; +class Value; +} // namespace llvm + namespace psr { +// For sorting the results in dumpResults() +std::string getMetaDataID(const llvm::Value *V); /// Solves the given IDETabulationProblem as described in the 1996 paper by /// Sagiv, Horwitz and Reps. To solve the problem, call solve(). Results @@ -61,7 +69,6 @@ class IDESolver { using ProblemTy = IDETabulationProblem; using container_type = typename ProblemTy::container_type; using FlowFunctionPtrType = typename ProblemTy::FlowFunctionPtrType; - using EdgeFunctionPtrType = typename ProblemTy::EdgeFunctionPtrType; using l_t = typename AnalysisDomainTy::l_t; using n_t = typename AnalysisDomainTy::n_t; @@ -77,7 +84,7 @@ class IDESolver { SolverConfig(Problem.getIFDSIDESolverConfig()), CachedFlowEdgeFunctions(Problem), AllTop(Problem.allTopFunction()), JumpFn(std::make_shared>( - AllTop, IDEProblem)), + IDEProblem)), Seeds(Problem.initialSeeds()) { assert(ICF != nullptr); } @@ -143,7 +150,7 @@ class IDESolver { REG_COUNTER("Process Call", 0, PAMM_SEVERITY_LEVEL::Full); REG_COUNTER("Process Normal", 0, PAMM_SEVERITY_LEVEL::Full); REG_COUNTER("Process Exit", 0, PAMM_SEVERITY_LEVEL::Full); - REG_COUNTER("[Calls] getPointsToSet", 0, PAMM_SEVERITY_LEVEL::Full); + REG_COUNTER("[Calls] getAliasSet", 0, PAMM_SEVERITY_LEVEL::Full); REG_HISTOGRAM("Data-flow facts", PAMM_SEVERITY_LEVEL::Full); REG_HISTOGRAM("Points-to", PAMM_SEVERITY_LEVEL::Full); @@ -268,7 +275,7 @@ class IDESolver { IDEProblem.emitGraphicalReport(getSolverResults(), OS); } - virtual void dumpResults(llvm::raw_ostream &OS = llvm::outs()) { + void dumpResults(llvm::raw_ostream &OS = llvm::outs()) { PAMM_GET_INSTANCE; START_TIMER("DFA IDE Result Dumping", PAMM_SEVERITY_LEVEL::Full); OS << "\n***************************************************************\n" @@ -278,12 +285,11 @@ class IDESolver { if (Cells.empty()) { OS << "No results computed!" << '\n'; } else { - LLVMValueIDLess LLVMIDLess; std::sort( - Cells.begin(), Cells.end(), - [&LLVMIDLess](const auto &Lhs, const auto &Rhs) { + Cells.begin(), Cells.end(), [](const auto &Lhs, const auto &Rhs) { if constexpr (std::is_same_v) { - return LLVMIDLess(Lhs.getRowKey(), Rhs.getRowKey()); + return StringIDLess{}(getMetaDataID(Lhs.getRowKey()), + getMetaDataID(Rhs.getRowKey())); } else { // If non-LLVM IR is used return Lhs.getRowKey() < Rhs.getRowKey(); @@ -374,16 +380,16 @@ class IDESolver { Table> ComputedInterPathEdges; - EdgeFunctionPtrType AllTop; + EdgeFunction AllTop; std::shared_ptr> JumpFn; - std::map, std::vector> + std::map, std::vector>> IntermediateEdgeFunctions; // stores summaries that were queried before they were computed // see CC 2010 paper by Naeem, Lhotak and Rodriguez - Table> EndsummaryTab; + Table>> EndsummaryTab; // edges going along calls // see CC 2010 paper by Naeem, Lhotak and Rodriguez @@ -425,7 +431,7 @@ class IDESolver { n_t n = Edge.getTarget(); // a call node; line 14... d_t d2 = Edge.factAtTarget(); - EdgeFunctionPtrType f = jumpFunction(Edge); + EdgeFunction f = jumpFunction(Edge); const auto &ReturnSiteNs = ICF->getReturnSitesOfCallAt(n); const auto &Callees = ICF->getCalleesOfCallAt(n); @@ -456,17 +462,17 @@ class IDESolver { PAMM_SEVERITY_LEVEL::Full); saveEdges(n, ReturnSiteN, d2, Res, false); for (d_t d3 : Res) { - EdgeFunctionPtrType SumEdgFnE = + EdgeFunction SumEdgFnE = CachedFlowEdgeFunctions.getSummaryEdgeFunction(n, d2, ReturnSiteN, d3); INC_COUNTER("SpecialSummary-EF Queries", 1, PAMM_SEVERITY_LEVEL::Full); IF_LOG_ENABLED( - PHASAR_LOG_LEVEL(DEBUG, "Queried Summary Edge Function: " - << SumEdgFnE->str()); - PHASAR_LOG_LEVEL(DEBUG, "Compose: " << SumEdgFnE->str() << " * " - << f->str() << '\n')); - propagate(d1, ReturnSiteN, d3, f->composeWith(SumEdgFnE), n, false); + PHASAR_LOG_LEVEL( + DEBUG, "Queried Summary Edge Function: " << SumEdgFnE); + PHASAR_LOG_LEVEL(DEBUG, "Compose: " << SumEdgFnE << " * " << f + << '\n')); + propagate(d1, ReturnSiteN, d3, f.composeWith(SumEdgFnE), n, false); } } } else { @@ -489,12 +495,11 @@ class IDESolver { saveEdges(n, SP, d2, Res, true); // for each result node of the call-flow function for (d_t d3 : Res) { - using TableCell = - typename Table::Cell; + using TableCell = typename Table>::Cell; // create initial self-loop PHASAR_LOG_LEVEL(DEBUG, "Create initial self-loop with D: " << IDEProblem.DtoString(d3)); - propagate(d3, SP, d3, EdgeIdentity::getInstance(), n, + propagate(d3, SP, d3, EdgeIdentity{}, n, false); // line 15 // register the fact that has an incoming edge from // line 15.1 of Naeem/Lhotak/Rodriguez @@ -516,7 +521,7 @@ class IDESolver { for (const TableCell &Entry : endSummary(SP, d3)) { n_t eP = Entry.getRowKey(); d_t d4 = Entry.getColumnKey(); - EdgeFunctionPtrType fCalleeSummary = Entry.getValue(); + EdgeFunction fCalleeSummary = Entry.getValue(); // for each return site for (n_t RetSiteN : ReturnSiteNs) { // compute return-flow function @@ -533,17 +538,16 @@ class IDESolver { for (d_t d5 : ReturnedFacts) { // update the caller-side summary function // get call edge function - EdgeFunctionPtrType f4 = + EdgeFunction f4 = CachedFlowEdgeFunctions.getCallEdgeFunction( n, d2, SCalledProcN, d3); - PHASAR_LOG_LEVEL(DEBUG, - "Queried Call Edge Function: " << f4->str()); + PHASAR_LOG_LEVEL(DEBUG, "Queried Call Edge Function: " << f4); // get return edge function - EdgeFunctionPtrType f5 = + EdgeFunction f5 = CachedFlowEdgeFunctions.getReturnEdgeFunction( n, SCalledProcN, eP, d4, RetSiteN, d5); - PHASAR_LOG_LEVEL( - DEBUG, "Queried Return Edge Function: " << f5->str()); + PHASAR_LOG_LEVEL(DEBUG, + "Queried Return Edge Function: " << f5); if (SolverConfig.emitESG()) { for (auto SP : ICF->getStartPointsOf(SCalledProcN)) { IntermediateEdgeFunctions[std::make_tuple(n, d2, SP, d3)] @@ -555,20 +559,19 @@ class IDESolver { } INC_COUNTER("EF Queries", 2, PAMM_SEVERITY_LEVEL::Full); // compose call * calleeSummary * return edge functions - PHASAR_LOG_LEVEL(DEBUG, "Compose: " << f5->str() << " * " - << fCalleeSummary->str() - << " * " << f4->str()); + PHASAR_LOG_LEVEL(DEBUG, "Compose: " << f5 << " * " + << fCalleeSummary << " * " + << f4); PHASAR_LOG_LEVEL(DEBUG, " (return * calleeSummary * call)"); - EdgeFunctionPtrType fPrime = - f4->composeWith(fCalleeSummary)->composeWith(f5); - PHASAR_LOG_LEVEL(DEBUG, " = " << fPrime->str()); + EdgeFunction fPrime = + f4.composeWith(fCalleeSummary).composeWith(f5); + PHASAR_LOG_LEVEL(DEBUG, " = " << fPrime); d_t d5_restoredCtx = restoreContextOnReturnedFact(n, d2, d5); // propagte the effects of the entire call - PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime->str() << " * " - << f->str()); - propagate(d1, RetSiteN, d5_restoredCtx, - f->composeWith(fPrime), n, false); + PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime << " * " << f); + propagate(d1, RetSiteN, d5_restoredCtx, f.composeWith(fPrime), + n, false); } } } @@ -589,20 +592,19 @@ class IDESolver { PAMM_SEVERITY_LEVEL::Full); saveEdges(n, ReturnSiteN, d2, ReturnFacts, false); for (d_t d3 : ReturnFacts) { - EdgeFunctionPtrType EdgeFnE = + EdgeFunction EdgeFnE = CachedFlowEdgeFunctions.getCallToRetEdgeFunction(n, d2, ReturnSiteN, d3, Callees); - PHASAR_LOG_LEVEL( - DEBUG, "Queried Call-to-Return Edge Function: " << EdgeFnE->str()); + PHASAR_LOG_LEVEL(DEBUG, + "Queried Call-to-Return Edge Function: " << EdgeFnE); if (SolverConfig.emitESG()) { IntermediateEdgeFunctions[std::make_tuple(n, d2, ReturnSiteN, d3)] .push_back(EdgeFnE); } INC_COUNTER("EF Queries", 1, PAMM_SEVERITY_LEVEL::Full); - auto fPrime = f->composeWith(EdgeFnE); - PHASAR_LOG_LEVEL(DEBUG, "Compose: " << EdgeFnE->str() << " * " - << f->str() << " = " - << fPrime->str()); + auto fPrime = f.composeWith(EdgeFnE); + PHASAR_LOG_LEVEL(DEBUG, "Compose: " << EdgeFnE << " * " << f << " = " + << fPrime); propagate(d1, ReturnSiteN, d3, fPrime, n, false); } } @@ -620,7 +622,7 @@ class IDESolver { d_t d1 = Edge.factAtSource(); n_t n = Edge.getTarget(); d_t d2 = Edge.factAtTarget(); - EdgeFunctionPtrType f = jumpFunction(Edge); + EdgeFunction f = jumpFunction(Edge); for (const auto nPrime : ICF->getSuccsOf(n)) { FlowFunctionPtrType FlowFunc = CachedFlowEdgeFunctions.getNormalFlowFunction(n, nPrime); @@ -630,16 +632,16 @@ class IDESolver { PAMM_SEVERITY_LEVEL::Full); saveEdges(n, nPrime, d2, Res, false); for (d_t d3 : Res) { - EdgeFunctionPtrType g = + EdgeFunction g = CachedFlowEdgeFunctions.getNormalEdgeFunction(n, d2, nPrime, d3); - PHASAR_LOG_LEVEL(DEBUG, "Queried Normal Edge Function: " << g->str()); - EdgeFunctionPtrType fPrime = f->composeWith(g); + PHASAR_LOG_LEVEL(DEBUG, "Queried Normal Edge Function: " << g); + EdgeFunction fPrime = f.composeWith(g); if (SolverConfig.emitESG()) { IntermediateEdgeFunctions[std::make_tuple(n, d2, nPrime, d3)] .push_back(g); } - PHASAR_LOG_LEVEL(DEBUG, "Compose: " << g->str() << " * " << f->str() - << " = " << fPrime->str()); + PHASAR_LOG_LEVEL(DEBUG, + "Compose: " << g << " * " << f << " = " << fPrime); INC_COUNTER("EF Queries", 1, PAMM_SEVERITY_LEVEL::Full); propagate(d1, nPrime, d3, fPrime, nullptr, false); } @@ -658,11 +660,11 @@ class IDESolver { for (size_t I = 0; I < LookupResults->get().size(); ++I) { auto Entry = LookupResults->get()[I]; d_t dPrime = Entry.first; - EdgeFunctionPtrType fPrime = Entry.second; + auto fPrime = Entry.second; n_t SP = Stmt; l_t Val = val(SP, Fact); INC_COUNTER("Value Propagation", 1, PAMM_SEVERITY_LEVEL::Full); - propagateValue(CallSite, dPrime, fPrime->computeTarget(Val)); + propagateValue(CallSite, dPrime, fPrime.computeTarget(Val)); } } } @@ -675,11 +677,9 @@ class IDESolver { CachedFlowEdgeFunctions.getCallFlowFunction(Stmt, Callee); INC_COUNTER("FF Queries", 1, PAMM_SEVERITY_LEVEL::Full); for (const d_t dPrime : CallFlowFunction->computeTargets(Fact)) { - EdgeFunctionPtrType EdgeFn = - CachedFlowEdgeFunctions.getCallEdgeFunction(Stmt, Fact, Callee, - dPrime); - PHASAR_LOG_LEVEL(DEBUG, - "Queried Call Edge Function: " << EdgeFn->str()); + EdgeFunction EdgeFn = CachedFlowEdgeFunctions.getCallEdgeFunction( + Stmt, Fact, Callee, dPrime); + PHASAR_LOG_LEVEL(DEBUG, "Queried Call Edge Function: " << EdgeFn); if (SolverConfig.emitESG()) { for (const auto SP : ICF->getStartPointsOf(Callee)) { IntermediateEdgeFunctions[std::make_tuple(Stmt, Fact, SP, dPrime)] @@ -690,7 +690,7 @@ class IDESolver { for (const n_t StartPoint : ICF->getStartPointsOf(Callee)) { INC_COUNTER("Value Propagation", 1, PAMM_SEVERITY_LEVEL::Full); propagateValue(StartPoint, dPrime, - EdgeFn->computeTarget(val(Stmt, Fact))); + EdgeFn.computeTarget(val(Stmt, Fact))); } } } @@ -731,7 +731,7 @@ class IDESolver { // } } - EdgeFunctionPtrType jumpFunction(const PathEdge Edge) { + EdgeFunction jumpFunction(const PathEdge Edge) { IF_LOG_ENABLED( PHASAR_LOG_LEVEL(DEBUG, "JumpFunctions Forward-Lookup:"); PHASAR_LOG_LEVEL(DEBUG, " Source D: " << IDEProblem.DtoString( @@ -750,16 +750,16 @@ class IDESolver { return Edge.factAtTarget() == Pair.first; }); Find != Ref.end()) { - PHASAR_LOG_LEVEL(DEBUG, " => EdgeFn: " << Find->second->str()); + PHASAR_LOG_LEVEL(DEBUG, " => EdgeFn: " << Find->second); return Find->second; } } - PHASAR_LOG_LEVEL(DEBUG, " => EdgeFn: " << AllTop->str()); + PHASAR_LOG_LEVEL(DEBUG, " => EdgeFn: " << AllTop); // JumpFn initialized to all-top, see line [2] in SRH96 paper return AllTop; } - void addEndSummary(n_t SP, d_t d1, n_t eP, d_t d2, EdgeFunctionPtrType f) { + void addEndSummary(n_t SP, d_t d1, n_t eP, d_t d2, EdgeFunction f) { // note: at this point we don't need to join with a potential previous f // because f is a jump function, which is already properly joined // within propagate(..) @@ -824,18 +824,18 @@ class IDESolver { PAMM_GET_INSTANCE; for (n_t n : Values) { for (n_t SP : ICF->getStartPointsOf(ICF->getFunctionOf(n))) { - using TableCell = typename Table::Cell; - Table &LookupByTarget = + using TableCell = typename Table>::Cell; + Table> &LookupByTarget = JumpFn->lookupByTarget(n); for (const TableCell &SourceValTargetValAndFunction : LookupByTarget.cellSet()) { d_t dPrime = SourceValTargetValAndFunction.getRowKey(); d_t d = SourceValTargetValAndFunction.getColumnKey(); - EdgeFunctionPtrType fPrime = SourceValTargetValAndFunction.getValue(); + EdgeFunction fPrime = SourceValTargetValAndFunction.getValue(); l_t TargetVal = val(SP, dPrime); setVal(n, d, IDEProblem.join(val(n, d), - fPrime->computeTarget(std::move(TargetVal)))); + fPrime.computeTarget(std::move(TargetVal)))); INC_COUNTER("Value Computation", 1, PAMM_SEVERITY_LEVEL::Full); } } @@ -925,10 +925,8 @@ class IDESolver { if (!IDEProblem.isZeroValue(Fact)) { INC_COUNTER("Gen facts", 1, PAMM_SEVERITY_LEVEL::Core); } - propagate(Fact, StartPoint, Fact, EdgeIdentity::getInstance(), - nullptr, false); - JumpFn->addFunction(Fact, StartPoint, Fact, - EdgeIdentity::getInstance()); + propagate(Fact, StartPoint, Fact, EdgeIdentity{}, nullptr, false); + JumpFn->addFunction(Fact, StartPoint, Fact, EdgeIdentity{}); } } } @@ -947,7 +945,7 @@ class IDESolver { PHASAR_LOG_LEVEL(DEBUG, "Process exit at target: " << IDEProblem.NtoString(Edge.getTarget())); n_t n = Edge.getTarget(); // an exit node; line 21... - EdgeFunctionPtrType f = jumpFunction(Edge); + EdgeFunction f = jumpFunction(Edge); f_t FunctionThatNeedsSummary = ICF->getFunctionOf(n); d_t d1 = Edge.factAtSource(); d_t d2 = Edge.factAtTarget(); @@ -988,17 +986,14 @@ class IDESolver { for (d_t d5 : Targets) { // compute composed function // get call edge function - EdgeFunctionPtrType f4 = - CachedFlowEdgeFunctions.getCallEdgeFunction( - c, d4, ICF->getFunctionOf(n), d1); - PHASAR_LOG_LEVEL(DEBUG, - "Queried Call Edge Function: " << f4->str()); + EdgeFunction f4 = CachedFlowEdgeFunctions.getCallEdgeFunction( + c, d4, ICF->getFunctionOf(n), d1); + PHASAR_LOG_LEVEL(DEBUG, "Queried Call Edge Function: " << f4); // get return edge function - EdgeFunctionPtrType f5 = + EdgeFunction f5 = CachedFlowEdgeFunctions.getReturnEdgeFunction( c, ICF->getFunctionOf(n), n, d2, RetSiteC, d5); - PHASAR_LOG_LEVEL(DEBUG, - "Queried Return Edge Function: " << f5->str()); + PHASAR_LOG_LEVEL(DEBUG, "Queried Return Edge Function: " << f5); if (SolverConfig.emitESG()) { for (auto SP : ICF->getStartPointsOf(ICF->getFunctionOf(n))) { IntermediateEdgeFunctions[std::make_tuple(c, d4, SP, d1)] @@ -1009,26 +1004,24 @@ class IDESolver { } INC_COUNTER("EF Queries", 2, PAMM_SEVERITY_LEVEL::Full); // compose call function * function * return function - PHASAR_LOG_LEVEL(DEBUG, "Compose: " << f5->str() << " * " - << f->str() << " * " - << f4->str()); + PHASAR_LOG_LEVEL(DEBUG, + "Compose: " << f5 << " * " << f << " * " << f4); PHASAR_LOG_LEVEL(DEBUG, " (return * function * call)"); - EdgeFunctionPtrType fPrime = f4->composeWith(f)->composeWith(f5); - PHASAR_LOG_LEVEL(DEBUG, " = " << fPrime->str()); + EdgeFunction fPrime = f4.composeWith(f).composeWith(f5); + PHASAR_LOG_LEVEL(DEBUG, " = " << fPrime); // for each jump function coming into the call, propagate to // return site using the composed function auto RevLookupResult = JumpFn->reverseLookup(c, d4); if (RevLookupResult) { for (size_t I = 0; I < RevLookupResult->get().size(); ++I) { auto ValAndFunc = RevLookupResult->get()[I]; - EdgeFunctionPtrType f3 = ValAndFunc.second; - if (!f3->equal_to(AllTop)) { + EdgeFunction f3 = ValAndFunc.second; + if (f3 != AllTop) { d_t d3 = ValAndFunc.first; d_t d5_restoredCtx = restoreContextOnReturnedFact(c, d4, d5); - PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime->str() << " * " - << f3->str()); + PHASAR_LOG_LEVEL(DEBUG, "Compose: " << fPrime << " * " << f3); propagate(d3, RetSiteC, d5_restoredCtx, - f3->composeWith(fPrime), c, false); + f3.composeWith(fPrime), c, false); } } } @@ -1057,19 +1050,17 @@ class IDESolver { PAMM_SEVERITY_LEVEL::Full); saveEdges(n, RetSiteC, d2, Targets, true); for (d_t d5 : Targets) { - EdgeFunctionPtrType f5 = + EdgeFunction f5 = CachedFlowEdgeFunctions.getReturnEdgeFunction( Caller, ICF->getFunctionOf(n), n, d2, RetSiteC, d5); - PHASAR_LOG_LEVEL(DEBUG, - "Queried Return Edge Function: " << f5->str()); + PHASAR_LOG_LEVEL(DEBUG, "Queried Return Edge Function: " << f5); if (SolverConfig.emitESG()) { IntermediateEdgeFunctions[std::make_tuple(n, d2, RetSiteC, d5)] .push_back(f5); } INC_COUNTER("EF Queries", 1, PAMM_SEVERITY_LEVEL::Full); - PHASAR_LOG_LEVEL(DEBUG, - "Compose: " << f5->str() << " * " << f->str()); - propagteUnbalancedReturnFlow(RetSiteC, d5, f->composeWith(f5), + PHASAR_LOG_LEVEL(DEBUG, "Compose: " << f5 << " * " << f); + propagteUnbalancedReturnFlow(RetSiteC, d5, f.composeWith(f5), Caller); // register for value processing (2nd IDE phase) UnbalancedRetSites.insert(RetSiteC); @@ -1091,7 +1082,7 @@ class IDESolver { } void propagteUnbalancedReturnFlow(n_t RetSiteC, d_t TargetVal, - EdgeFunctionPtrType EdgeFunc, + EdgeFunction EdgeFunc, n_t RelatedCallSite) { propagate(ZeroValue, RetSiteC, TargetVal, std::move(EdgeFunc), RelatedCallSite, true); @@ -1197,7 +1188,7 @@ class IDESolver { /// but may be useful for subclasses of {@link IDESolver}) /// void propagate(d_t SourceVal, n_t Target, d_t TargetVal, - const EdgeFunctionPtrType &f, + const EdgeFunction &f, /* deliberately exposed to clients */ n_t /*RelatedCallSite*/, /* deliberately exposed to clients */ @@ -1208,11 +1199,10 @@ class IDESolver { PHASAR_LOG_LEVEL(DEBUG, "Target : " << IDEProblem.NtoString(Target)); PHASAR_LOG_LEVEL(DEBUG, "Target value : " << IDEProblem.DtoString(TargetVal)); - PHASAR_LOG_LEVEL(DEBUG, - "Edge function : " << f.get()->str() - << " (result of previous compose)"); + PHASAR_LOG_LEVEL( + DEBUG, "Edge function : " << f << " (result of previous compose)"); - EdgeFunctionPtrType JumpFnE = [&]() { + EdgeFunction JumpFnE = [&]() { const auto RevLookupResult = JumpFn->reverseLookup(Target, TargetVal); if (RevLookupResult) { const auto &JumpFnContainer = RevLookupResult->get(); @@ -1227,16 +1217,15 @@ class IDESolver { // was found return AllTop; }(); - EdgeFunctionPtrType fPrime = JumpFnE->joinWith(f); - bool NewFunction = !(fPrime->equal_to(JumpFnE)); + EdgeFunction fPrime = JumpFnE.joinWith(f); + bool NewFunction = fPrime != JumpFnE; IF_LOG_ENABLED( PHASAR_LOG_LEVEL( - DEBUG, - "Join: " << JumpFnE->str() << " & " << f.get()->str() - << (JumpFnE->equal_to(f) ? " (EF's are equal)" : " ")); + DEBUG, "Join: " << JumpFnE << " & " << f + << (JumpFnE == f ? " (EF's are equal)" : " ")); PHASAR_LOG_LEVEL(DEBUG, - " = " << fPrime->str() + " = " << fPrime << (NewFunction ? " (new jump func)" : " ")); PHASAR_LOG_LEVEL(DEBUG, ' ')); if (NewFunction) { @@ -1253,7 +1242,7 @@ class IDESolver { " ---> str() << '>'); + PHASAR_LOG_LEVEL(DEBUG, " EF: " << fPrime << '>'); PHASAR_LOG_LEVEL(DEBUG, ' '); }); } else { @@ -1265,7 +1254,7 @@ class IDESolver { return IDEProblem.join(std::move(Curr), std::move(NewVal)); } - std::set::Cell> + std::set>::Cell> endSummary(n_t SP, d_t d3) { if constexpr (PAMM_CURR_SEV_LEVEL >= PAMM_SEVERITY_LEVEL::Core) { auto Key = std::make_pair(SP, d3); @@ -1324,7 +1313,7 @@ class IDESolver { DEBUG, " eP: " << IDEProblem.NtoString(InnerCell.getRowKey())); PHASAR_LOG_LEVEL(DEBUG, " d2: " << IDEProblem.DtoString( InnerCell.getColumnKey())); - PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerCell.getValue()->str()); + PHASAR_LOG_LEVEL(DEBUG, " EF: " << InnerCell.getValue()); } PHASAR_LOG_LEVEL(DEBUG, "---------------"); } PHASAR_LOG_LEVEL(DEBUG, "End of endsummarytab entry");) @@ -1588,12 +1577,12 @@ class IDESolver { void emitESGAsDot(llvm::raw_ostream &OS = llvm::outs(), - std::string DotConfigDir = PhasarConfig::PhasarDirectory()) { + llvm::StringRef DotConfigDir = PhasarConfig::PhasarDirectory()) { PHASAR_LOG_LEVEL(DEBUG, "Emit Exploded super-graph (ESG) as DOT graph"); PHASAR_LOG_LEVEL(DEBUG, "Process intra-procedural path egdes"); PHASAR_LOG_LEVEL(DEBUG, "============================================="); DOTGraph G; - DOTConfig::importDOTConfig(std::move(DotConfigDir)); + DOTConfig::importDOTConfig(DotConfigDir); DOTFunctionSubGraph *FG = nullptr; // Sort intra-procedural path edges @@ -1667,7 +1656,7 @@ class IDESolver { auto EFVec = IntermediateEdgeFunctions[std::make_tuple( Edge.first, D1Fact, Edge.second, D2Fact)]; for (const auto &EF : EFVec) { - EFLabel += EF->str() + ", "; + EFLabel += to_string(EF) + ", "; } PHASAR_LOG_LEVEL(DEBUG, "EF LABEL: " << EFLabel); if (D1FactId == D2FactId && !IDEProblem.isZeroValue(D1Fact)) { @@ -1787,8 +1776,8 @@ class IDESolver { auto EFVec = IntermediateEdgeFunctions[std::make_tuple( Edge.first, D1Fact, Edge.second, D2Fact)]; for (const auto &EF : EFVec) { - PHASAR_LOG_LEVEL(DEBUG, "Partial EF Label: " << EF->str()); - EFLabel.append(EF->str() + ", "); + PHASAR_LOG_LEVEL(DEBUG, "Partial EF Label: " << EF); + EFLabel.append(to_string(EF) + ", "); } PHASAR_LOG_LEVEL(DEBUG, "EF LABEL: " << EFLabel); G.InterFactEdges.emplace(D1, D2, true, EFLabel); diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSSolver.h b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h similarity index 91% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSSolver.h rename to include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h index 12bb215f2..f9ed15d76 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IFDSSolver.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h @@ -17,9 +17,9 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IFDSSOLVER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_IFDSSOLVER_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" -#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/Domain/BinaryDomain.h" #include #include @@ -30,9 +30,6 @@ namespace psr { template class IFDSSolver : public IDESolver> { - static_assert(std::is_same_v, - "Expect an IFDS analysis domain"); - public: using ProblemTy = IFDSTabulationProblem; using d_t = typename AnalysisDomainTy::d_t; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JumpFunctions.h b/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JumpFunctions.h rename to include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h index 0bf0b2ec7..dc3dbac3c 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/JumpFunctions.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/JumpFunctions.h @@ -17,6 +17,12 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_JUMPFUNCTIONS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_JUMPFUNCTIONS_H +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/Utils/Logger.h" +#include "phasar/Utils/Table.h" + +#include "llvm/ADT/SmallVector.h" + #include #include #include @@ -24,13 +30,6 @@ #include #include -#include "llvm/ADT/SmallVector.h" - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" -#include "phasar/Utils/Logger.h" -#include "phasar/Utils/Table.h" - namespace psr { // Forward declare the IDETabulationProblem as we require its toString @@ -44,35 +43,30 @@ template class JumpFunctions { using d_t = typename AnalysisDomainTy::d_t; using n_t = typename AnalysisDomainTy::n_t; - using EdgeFunctionType = EdgeFunction; - using EdgeFunctionPtrType = std::shared_ptr; - private: - EdgeFunctionPtrType Alltop; const IDETabulationProblem &Problem; protected: // mapping from target node and value to a list of all source values and // associated functions where the list is implemented as a mapping from // the source value to the function we exclude empty default functions - Table, 1>> + Table>, 1>> NonEmptyReverseLookup; // mapping from source value and target node to a list of all target values // and associated functions where the list is implemented as a mapping from // the source value to the function we exclude empty default functions - Table, 1>> + Table>, 1>> NonEmptyForwardLookup; // a mapping from target node to a list of triples consisting of source value, // target value and associated function; the triple is implemented by a table // we exclude empty default functions - std::unordered_map> + std::unordered_map>> NonEmptyLookupByTargetNode; public: JumpFunctions( - EdgeFunctionPtrType Alltop, const IDETabulationProblem &Problem) - : Alltop(std::move(Alltop)), Problem(Problem) {} + : Problem(Problem) {} ~JumpFunctions() = default; @@ -86,23 +80,23 @@ template class JumpFunctions { * @see PathEdge */ void addFunction(d_t SourceVal, n_t Target, d_t TargetVal, - EdgeFunctionPtrType EdgeFunc) { + EdgeFunction EdgeFunc) { PHASAR_LOG_LEVEL(DEBUG, "Start adding new jump function"); PHASAR_LOG_LEVEL(DEBUG, "Fact at source : " << Problem.DtoString(SourceVal)); PHASAR_LOG_LEVEL(DEBUG, "Fact at target : " << Problem.DtoString(TargetVal)); PHASAR_LOG_LEVEL(DEBUG, "Destination : " << Problem.NtoString(Target)); - PHASAR_LOG_LEVEL(DEBUG, "Edge Function : " << EdgeFunc->str()); + PHASAR_LOG_LEVEL(DEBUG, "Edge Function : " << EdgeFunc); // we do not store the default function (all-top) - if (EdgeFunc->equal_to(Alltop)) { + if (llvm::isa>(EdgeFunc)) { return; } auto &SourceValToFunc = NonEmptyReverseLookup.get(Target, TargetVal); if (auto Find = std::find_if( SourceValToFunc.begin(), SourceValToFunc.end(), - [SourceVal](const std::pair &Entry) { + [SourceVal](const std::pair> &Entry) { return SourceVal == Entry.first; }); Find != SourceValToFunc.end()) { @@ -116,7 +110,7 @@ template class JumpFunctions { auto &TargetValToFunc = NonEmptyForwardLookup.get(SourceVal, Target); if (auto Find = std::find_if( TargetValToFunc.begin(), TargetValToFunc.end(), - [TargetVal](const std::pair &Entry) { + [TargetVal](const std::pair> &Entry) { return TargetVal == Entry.first; }); Find != TargetValToFunc.end()) { @@ -139,7 +133,7 @@ template class JumpFunctions { * The return value is a mapping from source value to function. */ std::optional>>> + llvm::SmallVectorImpl>>>> reverseLookup(n_t Target, d_t TargetVal) { if (!NonEmptyReverseLookup.contains(Target, TargetVal)) { return std::nullopt; @@ -153,7 +147,7 @@ template class JumpFunctions { * The return value is a mapping from target value to function. */ std::optional>>> + llvm::SmallVectorImpl>>>> forwardLookup(d_t SourceVal, n_t Target) { if (!NonEmptyForwardLookup.contains(SourceVal, Target)) { return std::nullopt; @@ -167,7 +161,7 @@ template class JumpFunctions { * The return value is a set of records of the form * (sourceVal,targetVal,edgeFunction). */ - Table &lookupByTarget(n_t Target) { + Table> &lookupByTarget(n_t Target) { return NonEmptyLookupByTargetNode[Target]; } @@ -181,7 +175,7 @@ template class JumpFunctions { auto &SourceValToFunc = NonEmptyReverseLookup.get(Target, TargetVal); if (auto Find = std::find_if( SourceValToFunc.begin(), SourceValToFunc.end(), - [SourceVal](const std::pair &Entry) { + [SourceVal](const std::pair> &Entry) { return SourceVal == Entry.first; }); Find != SourceValToFunc.end()) { @@ -190,7 +184,7 @@ template class JumpFunctions { auto &TargetValToFunc = NonEmptyForwardLookup.get(SourceVal, Target); if (auto Find = std::find_if( TargetValToFunc.begin(), TargetValToFunc.end(), - [TargetVal](const std::pair &Entry) { + [TargetVal](const std::pair> &Entry) { return TargetVal == Entry.first; }); Find != TargetValToFunc.end()) { @@ -219,7 +213,7 @@ template class JumpFunctions { for (auto Cell : Entry.second.cellSet()) { OS << "D1: " << Problem.DtoString(Cell.r) << '\n' << "\tD2: " << Problem.DtoString(Cell.c) << '\n' - << "\tEF: " << Cell.v->str() << "\n\n"; + << "\tEF: " << Cell.v << "\n\n"; } } } @@ -233,7 +227,7 @@ template class JumpFunctions { << "\nD1: " << Problem.DtoString(Cell.c) << '\n'; for (auto D2ToEF : Cell.v) { OS << "D2: " << Problem.DtoString(D2ToEF.first) - << "\nEF: " << D2ToEF.second->str() << '\n'; + << "\nEF: " << D2ToEF.second << '\n'; } OS << '\n'; } @@ -248,7 +242,7 @@ template class JumpFunctions { << "\nN : " << Problem.NtoString(Cell.c) << '\n'; for (auto D2ToEF : Cell.v) { OS << "D2: " << Problem.DtoString(D2ToEF.first) - << "\nEF: " << D2ToEF.second->str() << '\n'; + << "\nEF: " << D2ToEF.second << '\n'; } OS << '\n'; } @@ -263,7 +257,7 @@ template class JumpFunctions { auto CellVec = Table.cellVec(); for (auto Cell : CellVec) { OS << "D1: " << Problem.DtoString(Cell.r) - << "\nD2: " << Problem.DtoString(Cell.c) << "\nEF: " << Cell.v->str() + << "\nD2: " << Problem.DtoString(Cell.c) << "\nEF: " << Cell.v << '\n'; } OS << '\n'; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathEdge.h b/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h similarity index 57% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathEdge.h rename to include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h index 1ab42af3c..d5bfffb60 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/PathEdge.h +++ b/include/phasar/DataFlow/IfdsIde/Solver/PathEdge.h @@ -7,51 +7,42 @@ * Philipp Schubert and others *****************************************************************************/ -/* - * PathEdge.h - * - * Created on: 16.08.2016 - * Author: pdschbrt - */ - #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHEDGE_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_PATHEDGE_H -#include +#include "phasar/Utils/ByRef.h" + +#include "llvm/Support/raw_ostream.h" + +#include namespace psr { template class PathEdge { -private: - const N Target; - const D DSource; - const D DTarget; public: - PathEdge(D DSource, N Target, D DTarget) - : Target(Target), DSource(DSource), DTarget(DTarget) {} - - ~PathEdge() = default; + PathEdge(D DSource, N Target, + D DTarget) noexcept(std::is_nothrow_move_constructible_v + &&std::is_nothrow_move_constructible_v) + : Target(std::move(Target)), DSource(std::move(DSource)), + DTarget(std::move(DTarget)) {} - PathEdge(const PathEdge &) = default; + [[nodiscard]] ByConstRef getTarget() const noexcept { return Target; } - PathEdge &operator=(const PathEdge &) = default; + [[nodiscard]] ByConstRef factAtSource() const noexcept { return DSource; } - PathEdge(PathEdge &&) noexcept = default; - - PathEdge &operator=(PathEdge &&) noexcept = default; - - [[nodiscard]] N getTarget() const { return Target; } - - [[nodiscard]] D factAtSource() const { return DSource; } - - [[nodiscard]] D factAtTarget() const { return DTarget; } + [[nodiscard]] ByConstRef factAtTarget() const noexcept { return DTarget; } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const PathEdge &Edge) { return OS << "<" << Edge.DSource << "> -> <" << Edge.Target << "," << Edge.DTarget << ">"; } + +private: + N Target; + D DSource; + D DTarget; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h b/include/phasar/DataFlow/IfdsIde/SolverResults.h similarity index 83% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h rename to include/phasar/DataFlow/IfdsIde/SolverResults.h index 506134490..85f9aade7 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/SolverResults.h +++ b/include/phasar/DataFlow/IfdsIde/SolverResults.h @@ -17,14 +17,15 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_SOLVERRESULTS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SOLVER_SOLVERRESULTS_H +#include "phasar/Domain/BinaryDomain.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/Table.h" + #include #include #include #include -#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" -#include "phasar/Utils/Table.h" - namespace psr { template class SolverResults { @@ -35,9 +36,12 @@ template class SolverResults { public: SolverResults(Table &ResTab, D ZV) : Results(ResTab), ZV(ZV) {} - L resultAt(N Stmt, D Node) const { return Results.get(Stmt, Node); } + ByConstRef resultAt(ByConstRef Stmt, ByConstRef Node) const { + return Results.get(Stmt, Node); + } - std::unordered_map resultsAt(N Stmt, bool StripZero = false) const { + std::unordered_map resultsAt(ByConstRef Stmt, + bool StripZero = false) const { std::unordered_map Result = Results.row(Stmt); if (StripZero) { for (auto It = Result.begin(); It != Result.end();) { @@ -56,7 +60,7 @@ template class SolverResults { template >> - std::set ifdsResultsAt(N Stmt) const { + std::set ifdsResultsAt(ByConstRef Stmt) const { std::set KeySet; std::unordered_map ResultMap = this->resultsAt(Stmt); for (auto FlowFact : ResultMap) { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/SpecialSummaries.h b/include/phasar/DataFlow/IfdsIde/SpecialSummaries.h similarity index 91% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/SpecialSummaries.h rename to include/phasar/DataFlow/IfdsIde/SpecialSummaries.h index 6612ef74c..d02851edf 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/SpecialSummaries.h +++ b/include/phasar/DataFlow/IfdsIde/SpecialSummaries.h @@ -17,20 +17,21 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SPECIALSUMMARIES_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_SPECIALSUMMARIES_H +#include "phasar/Config/Configuration.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/Domain/BinaryDomain.h" +#include "phasar/Utils/IO.h" // readFile + +#include "llvm/IR/Function.h" + #include #include #include #include #include -#include "phasar/Config/Configuration.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" -#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" -#include "phasar/Utils/IO.h" // readFile - -#include "llvm/IR/Function.h" - namespace psr { template class SpecialSummaries { @@ -39,7 +40,7 @@ template class SpecialSummaries { private: std::map SpecialFlowFunctions; - std::map>> SpecialEdgeFunctions; + std::map> SpecialEdgeFunctions; std::vector SpecialFunctionNames; // Constructs the SpecialSummaryMap such that it contains all glibc, @@ -52,7 +53,7 @@ template class SpecialSummaries { SpecialFlowFunctions.insert( std::make_pair(FunctionName, Identity::getInstance())); SpecialEdgeFunctions.insert( - std::make_pair(FunctionName, EdgeIdentity::getInstance())); + std::make_pair(FunctionName, EdgeIdentity{})); } } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Contexts/CallStringCTX.h b/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/Contexts/CallStringCTX.h rename to include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h index 134eb16ff..07a7693c7 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Contexts/CallStringCTX.h +++ b/include/phasar/DataFlow/Mono/Contexts/CallStringCTX.h @@ -1,19 +1,22 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_CONTEXTS_CALLSTRINGCTX_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_CONTEXTS_CALLSTRINGCTX_H +#include "phasar/Utils/Printer.h" + +#include "llvm/Support/raw_ostream.h" + +#include "boost/functional/hash.hpp" + #include #include #include -#include "boost/functional/hash.hpp" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" - namespace psr { template class CallStringCTX { protected: std::deque CallString; - static const unsigned KLimit = K; + static constexpr unsigned KLimit = K; friend struct std::hash>; public: @@ -65,21 +68,16 @@ template class CallStringCTX { return Lhs.cs < Rhs.cs; } - void print(llvm::raw_ostream &OS) const { + llvm::raw_ostream &print(llvm::raw_ostream &OS, + const NodePrinterBase &NP) const { OS << "Call string: [ "; for (auto C : CallString) { - OS << llvmIRToString(C); + NP.printNode(OS, C); if (C != CallString.back()) { OS << " * "; } } - OS << " ]"; - } - - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const CallStringCTX &C) { - C.print(OS); - return OS; + return OS << " ]"; } [[nodiscard]] bool empty() const { return CallString.empty(); } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h b/include/phasar/DataFlow/Mono/InterMonoProblem.h similarity index 85% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h rename to include/phasar/DataFlow/Mono/InterMonoProblem.h index 9efebee1c..5d119ac64 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h +++ b/include/phasar/DataFlow/Mono/InterMonoProblem.h @@ -17,8 +17,9 @@ #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/ControlFlow/ICFGBase.h" +#include "phasar/DataFlow/Mono/IntraMonoProblem.h" +#include "phasar/Pointer/AliasInfo.h" #include "phasar/Utils/BitVectorSet.h" #include @@ -28,7 +29,6 @@ namespace psr { template class TypeHierarchy; -template class PointsToInfo; template class ICFG; template @@ -47,15 +47,14 @@ class InterMonoProblem : public IntraMonoProblem { const i_t *ICF; public: - InterMonoProblem(const db_t *IRDB, const TypeHierarchy *TH, - const i_t *ICF, const PointsToInfo *PT, + InterMonoProblem(const ProjectIRDBBase *IRDB, + const TypeHierarchy *TH, const i_t *ICF, + AliasInfoRef PT, std::vector EntryPoints = {}) : IntraMonoProblem(IRDB, TH, ICF, PT, EntryPoints), 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; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h b/include/phasar/DataFlow/Mono/IntraMonoProblem.h similarity index 75% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h rename to include/phasar/DataFlow/Mono/IntraMonoProblem.h index 77f8beb26..4f5927d81 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h +++ b/include/phasar/DataFlow/Mono/IntraMonoProblem.h @@ -17,10 +17,10 @@ #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/ControlFlow/CFGBase.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/Pointer/AliasInfo.h" +#include "phasar/Utils/Printer.h" #include "phasar/Utils/Soundness.h" #include @@ -33,7 +33,6 @@ namespace psr { struct HasNoConfigurationType; template class TypeHierarchy; -template class PointsToInfo; template class CFG; template @@ -54,10 +53,10 @@ class IntraMonoProblem : public NodePrinter, using ProblemAnalysisDomain = AnalysisDomainTy; protected: - const db_t *IRDB; + const ProjectIRDBBase *IRDB; const TypeHierarchy *TH; - const c_t *CF; - const PointsToInfo *PT; + const CFGBase *CF; + AliasInfoRef PT; std::vector EntryPoints; [[maybe_unused]] Soundness S = Soundness::Soundy; @@ -66,16 +65,12 @@ class IntraMonoProblem : public NodePrinter, // a user problem can override the type of configuration to be used, if any using ConfigurationTy = HasNoConfigurationType; - IntraMonoProblem(const db_t *IRDB, const TypeHierarchy *TH, - const c_t *CF, const PointsToInfo *PT, + IntraMonoProblem(const ProjectIRDBBase *IRDB, + const TypeHierarchy *TH, const CFGBase *CF, + AliasInfoRef PT, std::vector EntryPoints = {}) : IRDB(IRDB), TH(TH), CF(CF), PT(PT), - 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!"); - } + EntryPoints(std::move(EntryPoints)) {} ~IntraMonoProblem() override = default; @@ -95,17 +90,17 @@ class IntraMonoProblem : public NodePrinter, return EntryPoints; } - [[nodiscard]] const db_t *getProjectIRDB() const { return IRDB; } + [[nodiscard]] const ProjectIRDBBase *getProjectIRDB() const { + return IRDB; + } [[nodiscard]] const TypeHierarchy *getTypeHierarchy() const { return TH; } - [[nodiscard]] const c_t *getCFG() const { return CF; } + [[nodiscard]] const CFGBase *getCFG() const { return CF; } - [[nodiscard]] const PointsToInfo *getPointstoInfo() const { - return PT; - } + [[nodiscard]] AliasInfoRef getPointstoInfo() const { return PT; } virtual bool setSoundness(Soundness /*S*/) { return false; } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h b/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h similarity index 93% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h rename to include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h index 254ee7eec..c1a7285b6 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/InterMonoSolver.h +++ b/include/phasar/DataFlow/Mono/Solver/InterMonoSolver.h @@ -17,16 +17,15 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_SOLVER_INTERMONOSOLVER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_SOLVER_INTERMONOSOLVER_H +#include "phasar/DataFlow/Mono/Contexts/CallStringCTX.h" +#include "phasar/DataFlow/Mono/InterMonoProblem.h" + #include #include #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/Contexts/CallStringCTX.h" -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" - namespace psr { template class InterMonoSolver { @@ -86,8 +85,8 @@ template class InterMonoSolver { void printWorkList() { llvm::outs() << "CURRENT WORKLIST:\n"; for (auto &[Src, Dst] : Worklist) { - llvm::outs() << llvmIRToString(Src) << " --> " << llvmIRToString(Dst) - << '\n'; + llvm::outs() << IMProblem.NtoString(Src) << " --> " + << IMProblem.NtoString(Dst) << '\n'; } llvm::outs() << "-----------------\n"; } @@ -179,8 +178,8 @@ template class InterMonoSolver { llvm::outs() << "Handle normal flow\n"; auto Src = Edge.first; auto Dst = Edge.second; - llvm::outs() << "Src: " << llvmIRToString(Src) << '\n'; - llvm::outs() << "Dst: " << llvmIRToString(Dst) << '\n'; + llvm::outs() << "Src: " << IMProblem.NtoString(Src) << '\n'; + llvm::outs() << "Dst: " << IMProblem.NtoString(Dst) << '\n'; std::unordered_map, mono_container_t> Out; for (auto &[Ctx, Facts] : Analysis[Src]) { Out[Ctx] = IMProblem.normalFlow(Src, Analysis[Src][Ctx]); @@ -225,8 +224,8 @@ template class InterMonoSolver { std::unordered_map, mono_container_t> Out; if (!isIntraEdge(Edge)) { llvm::outs() << "Handle call flow\n"; - llvm::outs() << "Src: " << llvmIRToString(Src) << '\n'; - llvm::outs() << "Dst: " << llvmIRToString(Dst) << '\n'; + llvm::outs() << "Src: " << IMProblem.NtoString(Src) << '\n'; + llvm::outs() << "Dst: " << IMProblem.NtoString(Dst) << '\n'; for (auto &[Ctx, Facts] : Analysis[Src]) { auto CTXAdd(Ctx); CTXAdd.push_back(Src); @@ -254,8 +253,8 @@ template class InterMonoSolver { } else { // Handle call-to-ret flow llvm::outs() << "Handle call to ret flow\n"; - llvm::outs() << "Src: " << llvmIRToString(Src) << '\n'; - llvm::outs() << "Dst: " << llvmIRToString(Dst) << '\n'; + llvm::outs() << "Src: " << IMProblem.NtoString(Src) << '\n'; + llvm::outs() << "Dst: " << IMProblem.NtoString(Dst) << '\n'; for (auto &[Ctx, Facts] : Analysis[Src]) { // call-to-ret flow does not modify contexts Out[Ctx] = IMProblem.callToRetFlow( @@ -289,11 +288,11 @@ template class InterMonoSolver { std::unordered_map, mono_container_t> Out; llvm::outs() << "\nHandle ret flow in: " << ICF->getFunctionName(ICF->getFunctionOf(Src)) << '\n'; - llvm::outs() << "Src: " << llvmIRToString(Src) << '\n'; - llvm::outs() << "Dst: " << llvmIRToString(Dst) << '\n'; + llvm::outs() << "Src: " << IMProblem.NtoString(Src) << '\n'; + llvm::outs() << "Dst: " << IMProblem.NtoString(Dst) << '\n'; for (auto &[Ctx, Facts] : Analysis[Src]) { auto CTXRm(Ctx); - llvm::outs() << "CTXRm: " << CTXRm << '\n'; + CTXRm.print(llvm::outs() << "CTXRm: ", IMProblem) << '\n'; // we need to use several call- and retsites if the context is empty llvm::SmallVector CallSites; @@ -320,7 +319,7 @@ template class InterMonoSolver { // TODO! llvm::outs() << "ResSites.size(): " << RetSites.size() << '\n'; for (auto RetSite : RetSites) { - llvm::outs() << "RetSite: " << llvmIRToString(RetSite) << '\n'; + llvm::outs() << "RetSite: " << IMProblem.NtoString(RetSite) << '\n'; llvm::outs() << "Return facts: "; IMProblem.printContainer(llvm::outs(), Out[CTXRm]); llvm::outs() << '\n'; @@ -403,18 +402,18 @@ template class InterMonoSolver { virtual void dumpResults(llvm::raw_ostream &OS = llvm::outs()) { OS << "======= DUMP LLVM-INTER-MONOTONE-SOLVER RESULTS =======\n"; for (auto &[Node, ContextMap] : this->Analysis) { - OS << "Instruction:\n" << this->IMProblem.NtoString(Node); + OS << "Instruction:\n" << IMProblem.NtoString(Node); OS << "\nFacts:\n"; if (ContextMap.empty()) { OS << "\tEMPTY\n"; } else { for (auto &[Context, FlowFacts] : ContextMap) { - OS << Context << '\n'; + Context.print(OS, IMProblem) << '\n'; if (FlowFacts.empty()) { OS << "\tEMPTY\n"; } else { for (auto FlowFact : FlowFacts) { - OS << this->IMProblem.DtoString(FlowFact); + OS << IMProblem.DtoString(FlowFact); } } } diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/IntraMonoSolver.h b/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h similarity index 98% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/IntraMonoSolver.h rename to include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h index 32d397914..0283ce9d4 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Solver/IntraMonoSolver.h +++ b/include/phasar/DataFlow/Mono/Solver/IntraMonoSolver.h @@ -17,14 +17,14 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_SOLVER_INTRAMONOSOLVER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_SOLVER_INTRAMONOSOLVER_H +#include "phasar/DataFlow/Mono/IntraMonoProblem.h" +#include "phasar/Utils/BitVectorSet.h" + #include #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/IntraMonoProblem.h" -#include "phasar/Utils/BitVectorSet.h" - namespace psr { template class IntraMonoSolver { @@ -43,7 +43,7 @@ template class IntraMonoSolver { ProblemTy &IMProblem; std::deque> Worklist; std::unordered_map Analysis; - const c_t *CFG; + const CFGBase *CFG; void initialize() { const auto &EntryPoints = IMProblem.getEntryPoints(); diff --git a/include/phasar/PhasarLLVM/Domain/AnalysisDomain.h b/include/phasar/Domain/AnalysisDomain.h similarity index 100% rename from include/phasar/PhasarLLVM/Domain/AnalysisDomain.h rename to include/phasar/Domain/AnalysisDomain.h diff --git a/include/phasar/PhasarLLVM/Utils/BinaryDomain.h b/include/phasar/Domain/BinaryDomain.h similarity index 61% rename from include/phasar/PhasarLLVM/Utils/BinaryDomain.h rename to include/phasar/Domain/BinaryDomain.h index 8e159062a..80fe3d8ed 100644 --- a/include/phasar/PhasarLLVM/Utils/BinaryDomain.h +++ b/include/phasar/Domain/BinaryDomain.h @@ -17,6 +17,8 @@ #ifndef PHASAR_PHASARLLVM_UTILS_BINARYDOMAIN_H_ #define PHASAR_PHASARLLVM_UTILS_BINARYDOMAIN_H_ +#include "phasar/Utils/JoinLattice.h" + #include namespace llvm { @@ -27,8 +29,21 @@ namespace psr { enum class BinaryDomain { BOTTOM = 0, TOP = 1 }; +[[nodiscard]] std::string to_string(BinaryDomain B); + llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, BinaryDomain B); +template <> struct JoinLatticeTraits { + static constexpr BinaryDomain top() noexcept { return BinaryDomain::TOP; } + static constexpr BinaryDomain bottom() noexcept { + return BinaryDomain::BOTTOM; + } + static constexpr BinaryDomain join(BinaryDomain LHS, + BinaryDomain RHS) noexcept { + return LHS == RHS ? LHS : BinaryDomain::BOTTOM; + } +}; + } // namespace psr #endif diff --git a/include/phasar/Domain/LatticeDomain.h b/include/phasar/Domain/LatticeDomain.h new file mode 100644 index 000000000..76dd845bc --- /dev/null +++ b/include/phasar/Domain/LatticeDomain.h @@ -0,0 +1,283 @@ +/****************************************************************************** + * Copyright (c) 2020 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_UTILS_LATTICEDOMAIN_H +#define PHASAR_PHASARLLVM_UTILS_LATTICEDOMAIN_H + +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/JoinLattice.h" +#include "phasar/Utils/TypeTraits.h" + +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_os_ostream.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +namespace psr { + +/// Represents the infimum of the lattice: +/// Top is the greatest element that is less than or equal to all elements of +/// the lattice. +struct Top { + friend constexpr bool operator==(Top /*unused*/, Top /*unused*/) noexcept { + return true; + } + friend constexpr bool operator!=(Top /*unused*/, Top /*unused*/) noexcept { + return false; + } + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Top /*unused*/) { + return OS << "Top"; + } +}; + +/// Represents the supremum of the lattice: +/// Bottom is the least element that is greater than or equal to all elements +/// of the lattice. +struct Bottom { + friend constexpr bool operator==(Bottom /*unused*/, + Bottom /*unused*/) noexcept { + return true; + } + friend constexpr bool operator!=(Bottom /*unused*/, + Bottom /*unused*/) noexcept { + return false; + } + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + Bottom /*unused*/) { + return OS << "Bottom"; + } +}; + +/// A easy shorthand to construct a complete lattice of L. +template +struct LatticeDomain : public std::variant { + using std::variant::variant; + + [[nodiscard]] inline bool isBottom() const noexcept { + return std::holds_alternative(*this); + } + [[nodiscard]] inline bool isTop() const noexcept { + return std::holds_alternative(*this); + } + + [[nodiscard]] inline L *getValueOrNull() noexcept { + return std::get_if(this); + } + [[nodiscard]] inline const L *getValueOrNull() const noexcept { + return std::get_if(this); + } + template >> + friend llvm::hash_code + hash_value(const LatticeDomain &LD) noexcept { // NOLINT + if (LD.isBottom()) { + return llvm::hash_value(INTPTR_MAX); + } + if (LD.isTop()) { + return llvm::hash_value(INTPTR_MIN); + } + return hash_value(std::get(LD)); + } + + [[nodiscard]] inline L &assertGetValue() noexcept { + assert(std::holds_alternative(*this)); + return std::get(*this); + } + [[nodiscard]] inline const L &assertGetValue() const noexcept { + assert(std::holds_alternative(*this)); + return std::get(*this); + } +}; + +template () + << std::declval())>> +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const LatticeDomain &LD) { + if (LD.isBottom()) { + return OS << "Bottom"; + } + if (LD.isTop()) { + return OS << "Top"; + } + + const auto *Val = LD.getValueOrNull(); + assert(Val && "Only alternative remaining is L"); + return OS << *Val; +} + +template +inline std::ostream &operator<<(std::ostream &OS, const LatticeDomain &LD) { + llvm::raw_os_ostream ROS(OS); + ROS << LD; + return OS; +} + +template +inline bool operator==(const LatticeDomain &Lhs, + const LatticeDomain &Rhs) { + if (Lhs.index() != Rhs.index()) { + return false; + } + if (auto LhsPtr = Lhs.getValueOrNull()) { + /// No need to check whether Lhs is an L; the indices are already the same + return *LhsPtr == *Rhs.getValueOrNull(); + } + return true; +} + +template < + typename L, typename LL, + typename = std::void_t() == std::declval())>> +inline bool operator==(const LL &Lhs, const LatticeDomain &Rhs) { + if (auto RVal = Rhs.getValueOrNull()) { + return Lhs == *RVal; + } + return false; +} + +template < + typename L, typename LL, + typename = std::void_t() == std::declval())>> +inline bool operator==(const LatticeDomain &Lhs, const LL &Rhs) { + return Rhs == Lhs; +} + +template +inline bool operator==(const LatticeDomain &Lhs, Bottom /*Rhs*/) noexcept { + return Lhs.isBottom(); +} + +template +inline bool operator==(const LatticeDomain &Lhs, Top /*Rhs*/) noexcept { + return Lhs.isTop(); +} + +template +inline bool operator==(Bottom /*Lhs*/, const LatticeDomain &Rhs) noexcept { + return Rhs.isBottom(); +} + +template +inline bool operator==(Top /*Lhs*/, const LatticeDomain &Rhs) noexcept { + return Rhs.isTop(); +} + +#if __cplusplus < 202002L + +// With C++20 inequality is defaulted if equality is provided + +template +inline bool operator!=(const LatticeDomain &Lhs, + const LatticeDomain &Rhs) { + return !(Lhs == Rhs); +} + +template < + typename L, typename LL, + typename = std::void_t() == std::declval())>> +inline bool operator!=(const LL &Lhs, const LatticeDomain Rhs) { + return !(Lhs == Rhs); +} + +template < + typename L, typename LL, + typename = std::void_t() == std::declval())>> +inline bool operator!=(const LatticeDomain Lhs, const LL &Rhs) { + return !(Rhs == Lhs); +} + +template +inline bool operator!=(const LatticeDomain &Lhs, Bottom /*Rhs*/) noexcept { + return !(Lhs == Bottom{}); +} + +template +inline bool operator!=(const LatticeDomain &Lhs, Top /*Rhs*/) noexcept { + return !(Lhs == Top{}); +} + +template +inline bool operator!=(Bottom /*Lhs*/, const LatticeDomain &Rhs) noexcept { + return !(Bottom{} == Rhs); +} + +template +inline bool operator!=(Top /*Lhs*/, const LatticeDomain &Rhs) noexcept { + return !(Top{} == Rhs); +} + +#endif + +template +inline bool operator<(const LatticeDomain &Lhs, + const LatticeDomain &Rhs) { + /// Top < (Lhs::L < Rhs::L) < Bottom + if (Rhs.isTop()) { + return false; + } + if (Lhs.isTop()) { + return true; + } + if (auto LhsPtr = Lhs.getValueOrNull()) { + if (auto RhsPtr = Rhs.getValueOrNull()) { + return *LhsPtr < *RhsPtr; + } + } else if (Lhs.isBottom()) { + return false; + } + if (Rhs.isBottom()) { + return true; + } + llvm_unreachable("All comparison cases should be handled above."); +} + +template struct JoinLatticeTraits> { + using l_t = L; + static constexpr Bottom bottom() noexcept { return {}; } + static constexpr Top top() noexcept { return {}; } + static LatticeDomain join(ByConstRef> LHS, + ByConstRef> RHS) { + // Top < (Lhs::l_t < Rhs::l_t) < Bottom + if (LHS.isTop() || LHS == RHS) { + return RHS; + } + + if (RHS.isTop()) { + return LHS; + } + + return Bottom{}; + } +}; + +/// If we know that a stored L value is never Top or Bottom, we don't need to +/// store the discriminator of the std::variant. +template +struct NonTopBotValue< + LatticeDomain, + std::enable_if_t< + std::is_nothrow_constructible_v, const L &> || + !std::is_nothrow_copy_constructible_v>>> { + using type = L; + + static L unwrap(LatticeDomain Value) noexcept( + std::is_nothrow_move_constructible_v) { + return std::get(std::move(Value)); + } +}; + +} // namespace psr + +#endif diff --git a/include/phasar/PhasarClang/RandomChangeASTConsumer.h b/include/phasar/PhasarClang/RandomChangeASTConsumer.h index b2851a6ec..996c960b5 100644 --- a/include/phasar/PhasarClang/RandomChangeASTConsumer.h +++ b/include/phasar/PhasarClang/RandomChangeASTConsumer.h @@ -17,10 +17,10 @@ #ifndef PHASAR_PHASARCLANG_RANDOMCHANGEASTCONSUMER_H_ #define PHASAR_PHASARCLANG_RANDOMCHANGEASTCONSUMER_H_ -#include "clang/AST/ASTConsumer.h" - #include "phasar/PhasarClang/RandomChangeVisitor.h" +#include "clang/AST/ASTConsumer.h" + namespace clang { class ASTContext; class Rewriter; diff --git a/include/phasar/PhasarClang/RandomChangeFrontendAction.h b/include/phasar/PhasarClang/RandomChangeFrontendAction.h index 7ea874751..add91715c 100644 --- a/include/phasar/PhasarClang/RandomChangeFrontendAction.h +++ b/include/phasar/PhasarClang/RandomChangeFrontendAction.h @@ -17,13 +17,12 @@ #ifndef PHASAR_PHASARCLANG_RANDOMCHANGEFRONTENDACTION_H_ #define PHASAR_PHASARCLANG_RANDOMCHANGEFRONTENDACTION_H_ -#include - -#include "llvm/ADT/StringRef.h" - #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Rewrite/Core/Rewriter.h" +#include "llvm/ADT/StringRef.h" + +#include namespace clang { class CompilerInstance; diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h index 9792fca22..a488e9b46 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h @@ -10,7 +10,6 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDCFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDCFG_H_ -#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" namespace llvm { diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h index 61571a8d1..10a342488 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardICFG.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDICFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDBACKWARDICFG_H_ -#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" +#include "phasar/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedBackwardCFG.h" #include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h index d1d195433..2c7ac54cf 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h @@ -10,9 +10,7 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDCFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDCFG_H_ -#include "phasar/PhasarLLVM/ControlFlow/CFGBase.h" - -#include "nlohmann/json.hpp" +#include "phasar/ControlFlow/CFGBase.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" @@ -20,6 +18,8 @@ #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" +#include "nlohmann/json.hpp" + namespace llvm { class Function; } // namespace llvm @@ -49,10 +49,11 @@ template class LLVMBasedCFGImpl : public CFGBase { } protected: - LLVMBasedCFGImpl(bool IgnoreDbgInstructions = true) noexcept + LLVMBasedCFGImpl() noexcept = default; + LLVMBasedCFGImpl(bool IgnoreDbgInstructions) noexcept : IgnoreDbgInstructions(IgnoreDbgInstructions) {} - bool IgnoreDbgInstructions = false; + bool IgnoreDbgInstructions = true; [[nodiscard]] f_t getFunctionOfImpl(n_t Inst) const noexcept; [[nodiscard]] llvm::SmallVector getPredsOfImpl(n_t Inst) const; @@ -99,7 +100,8 @@ class LLVMBasedCFG : public detail::LLVMBasedCFGImpl { friend class LLVMBasedBackwardCFG; public: - LLVMBasedCFG(bool IgnoreDbgInstructions = true) noexcept + LLVMBasedCFG() noexcept = default; + LLVMBasedCFG(bool IgnoreDbgInstructions) noexcept : detail::LLVMBasedCFGImpl(IgnoreDbgInstructions) {} [[nodiscard]] nlohmann::json exportCFGAsJson(const llvm::Function *F) const; diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index 3c7182f86..3878aa155 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -17,15 +17,15 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDICFG_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMBASEDICFG_H_ -#include "phasar/PhasarLLVM/ControlFlow/ICFGBase.h" +#include "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" -#include "phasar/PhasarLLVM/ControlFlow/Resolver/CallGraphAnalysisType.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" #include "phasar/Utils/MaybeUniquePtr.h" +#include "phasar/Utils/MemoryResource.h" #include "phasar/Utils/Soundness.h" -#include "nlohmann/json.hpp" - #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -33,21 +33,18 @@ #include "llvm/IR/Value.h" #include "llvm/Support/raw_ostream.h" -#include +#include "nlohmann/json.hpp" -#include "phasar/Utils/MemoryResource.h" +#include /// On some MAC systems, is still not fully implemented, so do /// a workaround here -#if HAS_MEMORY_RESOURCE -#include -#else +#if !HAS_MEMORY_RESOURCE #include "llvm/Support/Allocator.h" #endif namespace psr { -class LLVMPointsToInfo; class LLVMTypeHierarchy; class LLVMPointsToInfo; class LLVMProjectIRDB; @@ -88,7 +85,7 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB, CallGraphAnalysisType CGType, llvm::ArrayRef EntryPoints = {}, LLVMTypeHierarchy *TH = nullptr, - LLVMPointsToInfo *PT = nullptr, + LLVMAliasInfoRef PT = nullptr, Soundness S = Soundness::Soundy, bool IncludeGlobals = true); diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h index 6bc00e735..5755c5207 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h @@ -18,7 +18,7 @@ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_OTFRESOLVER_H_ #include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include #include @@ -41,11 +41,11 @@ class LLVMTypeHierarchy; class OTFResolver : public Resolver { protected: LLVMBasedICFG &ICF; - LLVMPointsToInfo &PT; + LLVMAliasInfoRef PT; public: OTFResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH, LLVMBasedICFG &ICF, - LLVMPointsToInfo &PT); + LLVMAliasInfoRef PT); ~OTFResolver() override = default; @@ -61,7 +61,7 @@ class OTFResolver : public Resolver { FunctionSetTy resolveFunctionPointer(const llvm::CallBase *CallSite) override; static std::set - getReachableTypes(const LLVMPointsToInfo::PointsToSetTy &Values); + getReachableTypes(const LLVMAliasInfo::AliasSetTy &Values); static std::vector> getActualFormalPointerPairs(const llvm::CallBase *CallSite, diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h index 36cc24162..5b67a4c92 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h @@ -19,6 +19,8 @@ #include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" +#include + namespace llvm { class CallBase; class StructType; diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h index d14382efc..58671342f 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h @@ -17,6 +17,8 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_RESOLVER_H_ +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" + #include "llvm/ADT/DenseSet.h" #include @@ -33,15 +35,20 @@ class StructType; namespace psr { class LLVMProjectIRDB; class LLVMTypeHierarchy; -class LLVMPointsToInfo; enum class CallGraphAnalysisType; class LLVMBasedICFG; +class LLVMPointsToInfo; + +[[nodiscard]] std::optional +getVFTIndex(const llvm::CallBase *CallSite); -std::optional getVFTIndex(const llvm::CallBase *CallSite); +[[nodiscard]] const llvm::StructType * +getReceiverType(const llvm::CallBase *CallSite); -const llvm::StructType *getReceiverType(const llvm::CallBase *CallSite); +[[nodiscard]] std::string getReceiverTypeName(const llvm::CallBase *CallSite); -std::string getReceiverTypeName(const llvm::CallBase &CallSite); +[[nodiscard]] bool isConsistentCall(const llvm::CallBase *CallSite, + const llvm::Function *DestFun); class Resolver { protected: @@ -78,7 +85,7 @@ class Resolver { static std::unique_ptr create(CallGraphAnalysisType Ty, LLVMProjectIRDB *IRDB, LLVMTypeHierarchy *TH, - LLVMBasedICFG *ICF = nullptr, LLVMPointsToInfo *PT = nullptr); + LLVMBasedICFG *ICF = nullptr, LLVMAliasInfoRef PT = nullptr); }; } // namespace psr diff --git a/include/phasar/DB/LLVMProjectIRDB.h b/include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h similarity index 100% rename from include/phasar/DB/LLVMProjectIRDB.h rename to include/phasar/PhasarLLVM/DB/LLVMProjectIRDB.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h similarity index 87% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h index 8744d6a97..75129176f 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/BranchSwitchInstFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_BRANCHSWITCHINSTFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_BRANCHSWITCHINSTFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h index e8dd07049..efa2f22b9 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CallToRetFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CALLTORETFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CALLTORETFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h index 4dee3bb83..2a9f2f5bf 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/CheckOperandsFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CHECKOPERANDSFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_CHECKOPERANDSFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h similarity index 78% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h index 5eff99559..0117e364b 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h @@ -5,16 +5,11 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_FLOWFUNCTIONBASE_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_FLOWFUNCTIONBASE_H -#include "../Stats/TraceStats.h" - -#include "../Utils/DataFlowUtils.h" -#include "../Utils/Log.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde//IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h" #include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" -#include "phasar/PhasarLLVM/Domain/ExtendedValue.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h index 85000b4fe..4ebf27b65 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GEPInstFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GEPINSTFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GEPINSTFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h index 077cf95b9..969e7dd73 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/GenerateFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GENERATEFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_GENERATEFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h index b10b7c732..0aa541206 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/IdentityFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_IDENTITYFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_IDENTITYFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h similarity index 77% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h index a24075417..fcca65bf6 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCallee.h @@ -5,15 +5,14 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLEE_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLEE_H -#include "../Stats/TraceStats.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde//IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" #include "llvm/IR/AbstractCallSite.h" #include "llvm/IR/Instruction.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h" -#include "phasar/PhasarLLVM/Domain/ExtendedValue.h" - namespace psr { class MapTaintedValuesToCallee : public FlowFunction { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h similarity index 74% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h index 34d0aaf48..57477a0ad 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MapTaintedValuesToCaller.h @@ -5,14 +5,13 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MAPTAINTEDVALUESTOCALLER_H -#include "../Stats/TraceStats.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde//IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" #include "llvm/IR/Instructions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h" -#include "phasar/PhasarLLVM/Domain/ExtendedValue.h" - namespace psr { class MapTaintedValuesToCaller : public FlowFunction { @@ -28,7 +27,7 @@ class MapTaintedValuesToCaller : public FlowFunction { private: const llvm::CallInst *CallInst; const llvm::ReturnInst *RetInst; - ::psr::TraceStats &TraceStats; + TraceStats &TraceStats; ExtendedValue ZV; }; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h index c96ebf6f3..9c12e828b 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemSetInstFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMSETINSTFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMSETINSTFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h similarity index 87% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h index 80df2e5dd..7d52a7458 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/MemTransferInstFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMTRANSFERINSTFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_MEMTRANSFERINSTFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h index d6499dada..1aa55b8eb 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/PHINodeFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_PHINODEFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_PHINODEFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h index 80172d59d..700699152 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/ReturnInstFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_RETURNINSTFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_RETURNINSTFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h index a54302f01..c2e121de1 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/StoreInstFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_STOREINSTFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_STOREINSTFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h index 0f71e7f07..04949dae2 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAEndInstFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VAENDINSTFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VAENDINSTFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h similarity index 86% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h index 470c06e90..3b7980bc5 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/VAStartInstFlowFunction.h @@ -5,7 +5,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VASTARTINSTFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_FLOWFUNCTIONS_VASTARTINSTFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/FlowFunctions/FlowFunctionBase.h" namespace psr { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovRetValWriter.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovRetValWriter.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovRetValWriter.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovRetValWriter.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovWriter.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovWriter.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovWriter.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LcovWriter.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberEntry.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberEntry.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberEntry.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberEntry.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberWriter.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberWriter.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberWriter.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/LineNumberWriter.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h index 7a3367431..5ba0fcd25 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h @@ -5,13 +5,13 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATS_H +#include "llvm/IR/Instruction.h" + #include "LineNumberEntry.h" #include #include -#include "llvm/IR/Instruction.h" - namespace psr { class TraceStats { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h similarity index 99% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h index c249a1527..d4d5f599d 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStatsWriter.h @@ -5,9 +5,8 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATSWRITER_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_STATS_TRACESTATSWRITER_H -#include "TraceStats.h" - #include "../Utils/Log.h" +#include "TraceStats.h" #include #include diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h similarity index 97% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h index bcd301051..cb936e237 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/DataFlowUtils.h @@ -5,15 +5,15 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_DATAFLOWUTILS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSFIELDSENSTAINTANALYSIS_UTILS_DATAFLOWUTILS_H +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" + +#include "llvm/IR/Instructions.h" + #include #include #include #include -#include "llvm/IR/Instructions.h" - -#include "phasar/PhasarLLVM/Domain/ExtendedValue.h" - namespace psr { class DataFlowUtils { diff --git a/include/phasar/PhasarLLVM/Domain/ExtendedValue.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h similarity index 100% rename from include/phasar/PhasarLLVM/Domain/ExtendedValue.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/Log.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/Log.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/Log.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Utils/Log.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h similarity index 72% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h index f20549334..ef3dd2c83 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMFlowFunctions.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h @@ -10,13 +10,10 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMFLOWFUNCTIONS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMFLOWFUNCTIONS_H -#include -#include -#include -#include -#include -#include -#include +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/TypeTraits.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/IR/Constant.h" @@ -26,9 +23,14 @@ #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" +#include +#include +#include +#include +#include +#include +#include +#include namespace psr { @@ -52,20 +54,23 @@ namespace psr { /// 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>> +template , + typename Fn = TrueFn, typename DCtor = DefaultConstruct, + typename = std::enable_if_t< + std::is_invocable_r_v>> auto mapFactsAlongsideCallSite(const llvm::CallBase *CallSite, Fn &&PropagateArgs = {}, - bool PropagateGlobals = true) { - struct Mapper : public FlowFunction { + bool PropagateGlobals = true, + DCtor &&FactConstructor = {}) { + struct Mapper : public FlowFunction { - Mapper(const llvm::CallBase *CS, bool PropagateGlobals, Fn &&PropArgs) + Mapper(const llvm::CallBase *CS, bool PropagateGlobals, Fn &&PropArgs, + DCtor &&FactConstructor) : CSAndPropGlob(CS, PropagateGlobals), - PropArgs(std::forward(PropArgs)) {} + PropArgs(std::forward(PropArgs)), + FactConstructor(std::forward(FactConstructor)) {} - Container computeTargets(const llvm::Value *Source) override { + Container computeTargets(D Source) override { // Pass ZeroValue as is if (LLVMZeroValue::isLLVMZeroValue(Source)) { return {Source}; @@ -83,7 +88,7 @@ auto mapFactsAlongsideCallSite(const llvm::CallBase *CallSite, for (const auto &Arg : CSAndPropGlob.getPointer()->args()) { if (Arg.get() == Source) { if (std::invoke(PropArgs, Arg.get())) { - return {Arg.get()}; + return {std::invoke(FactConstructor, Arg.get())}; } return {}; } @@ -94,10 +99,12 @@ auto mapFactsAlongsideCallSite(const llvm::CallBase *CallSite, llvm::PointerIntPair CSAndPropGlob; [[no_unique_address]] std::decay_t PropArgs; + [[no_unique_address]] std::decay_t FactConstructor; }; return std::make_shared(CallSite, PropagateGlobals, - std::forward(PropagateArgs)); + std::forward(PropagateArgs), + std::forward(FactConstructor)); } /// A flow function that serves as default implementation of the @@ -122,24 +129,26 @@ auto mapFactsAlongsideCallSite(const llvm::CallBase *CallSite, /// 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 +template , + typename Fn = std::equal_to, typename DCtor = DefaultConstruct, + typename = std::enable_if_t< + std::is_invocable_r_v>> +FlowFunctionPtrType mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, Fn &&PropagateArgumentWithSource = {}, - bool PropagateGlobals = true, + DCtor &&FactConstructor = {}, bool PropagateGlobals = true, bool PropagateZeroToCallee = true) { - struct Mapper : public FlowFunction { + struct Mapper : public FlowFunction { Mapper(const llvm::CallBase *CS, const llvm::Function *DestFun, - bool PropagateGlobals, bool PropagateZeroToCallee, Fn &&PropArg) + bool PropagateGlobals, bool PropagateZeroToCallee, Fn &&PropArg, + DCtor &&FactConstructor) : CSAndPropGlob(CS, PropagateGlobals), DestFunAndPropZero(DestFun, PropagateZeroToCallee), - PropArg(std::forward(PropArg)) {} + PropArg(std::forward(PropArg)), + FactConstructor(std::forward(FactConstructor)) {} - Container computeTargets(const llvm::Value *Source) override { + Container computeTargets(D Source) override { // If DestFun is a declaration we cannot follow this call, we thus need to // kill everything if (DestFunAndPropZero.getPointer()->isDeclaration()) { @@ -149,7 +158,7 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, Container Res; if (DestFunAndPropZero.getInt() && LLVMZeroValue::isLLVMZeroValue(Source)) { - Res.insert(Source); + Res.insert(std::move(Source)); } else if (CSAndPropGlob.getInt() && !LLVMZeroValue::isLLVMZeroValue(Source) && llvm::isa(Source)) { @@ -157,7 +166,7 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, // 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); + Res.insert(std::move(Source)); } const auto *CS = CSAndPropGlob.getPointer(); @@ -172,7 +181,7 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, for (; ParamIt != ParamEnd; ++ParamIt, ++ArgIt) { if (std::invoke(PropArg, ArgIt->get(), Source)) { - Res.insert(&*ParamIt); + Res.insert(std::invoke(FactConstructor, &*ParamIt)); } } @@ -196,7 +205,7 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, Alloc->getAllocatedType() ->getArrayElementType() ->getStructName() == "struct.__va_list_tag") { - Res.insert(Alloc); + Res.insert(std::invoke(FactConstructor, Alloc)); } } } @@ -209,11 +218,13 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, llvm::PointerIntPair CSAndPropGlob; llvm::PointerIntPair DestFunAndPropZero; [[no_unique_address]] std::decay_t PropArg; + [[no_unique_address]] std::decay_t FactConstructor; }; - return std::make_shared( - CallSite, DestFun, PropagateGlobals, PropagateZeroToCallee, - std::forward(PropagateArgumentWithSource)); + return std::make_shared(CallSite, DestFun, PropagateGlobals, + PropagateZeroToCallee, + std::forward(PropagateArgumentWithSource), + std::forward(FactConstructor)); } /// A flow function that serves as default-implementation of the return flow @@ -235,28 +246,32 @@ mapFactsToCallee(const llvm::CallBase *CallSite, const llvm::Function *DestFun, /// 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, +template , + typename FnParam = std::equal_to, + typename FnRet = std::equal_to, + typename DCtor = DefaultConstruct, 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 { + std::is_invocable_r_v && + std::is_invocable_r_v>> +FlowFunctionPtrType +mapFactsToCaller(const llvm::CallBase *CallSite, + const llvm::Instruction *ExitInst, + FnParam &&PropagateParameter = {}, FnRet &&PropagateRet = {}, + DCtor &&FactConstructor = {}, 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) + FnRet &&PropagateRet, DCtor &&FactConstructor, + bool PropagateZeroToCaller) : CSAndPropGlob(CallSite, PropagateGlobals), ExitInstAndPropZero(ExitInst, PropagateZeroToCaller), PropArg(std::forward(PropagateParameter)), - PropRet(std::forward(PropagateRet)) {} + PropRet(std::forward(PropagateRet)), + FactConstructor(std::forward(FactConstructor)) {} - Container computeTargets(const llvm::Value *Source) override { + Container computeTargets(D Source) override { Container Res; if (ExitInstAndPropZero.getInt() && LLVMZeroValue::isLLVMZeroValue(Source)) { @@ -281,7 +296,7 @@ FlowFunctionPtrType mapFactsToCaller( for (; ParamIt != ParamEnd; ++ParamIt, ++ArgIt) { if (std::invoke(PropArg, &*ParamIt, Source)) { - Res.insert(ArgIt->get()); + Res.insert(std::invoke(FactConstructor, ArgIt->get())); } } @@ -299,7 +314,8 @@ FlowFunctionPtrType mapFactsToCaller( AllocTy->getArrayElementType()->getStructName() == "struct.__va_list_tag") { if (std::invoke(PropArg, Alloc, Source)) { - Res.insert(ArgIt, ArgEnd); + std::transform(ArgIt, ArgEnd, std::inserter(Res, Res.end()), + FactConstructor); break; } } @@ -311,7 +327,7 @@ FlowFunctionPtrType mapFactsToCaller( ExitInstAndPropZero.getPointer()); RetInst && RetInst->getReturnValue()) { if (std::invoke(PropRet, RetInst->getReturnValue(), Source)) { - Res.insert(CS); + Res.insert(std::invoke(FactConstructor, CS)); } } @@ -323,11 +339,13 @@ FlowFunctionPtrType mapFactsToCaller( ExitInstAndPropZero; [[no_unique_address]] std::decay_t PropArg; [[no_unique_address]] std::decay_t PropRet; + [[no_unique_address]] std::decay_t FactConstructor; }; return std::make_shared(CallSite, ExitInst, PropagateGlobals, std::forward(PropagateParameter), std::forward(PropagateRet), + std::forward(FactConstructor), PropagateZeroToCaller); } @@ -368,6 +386,38 @@ template , std::is_invocable_r_v>> FlowFunctionPtrType strongUpdateStore(const llvm::StoreInst *Store, Fn &&GeneratePointerOpIf) { + // Here we cheat a bit and "look through" the GetElementPtrInst to the + // targeted memory location. + const auto *BasePtrOp = Store->getPointerOperand()->stripPointerCasts(); + if (BasePtrOp != Store->getPointerOperand()) { + struct StrongUpdateFlow + : public FlowFunction { + + StrongUpdateFlow(const llvm::Value *PointerOp, + const llvm::Value *BasePtrOp, Fn &&GeneratePointerOpIf) + : PointerOp(PointerOp), BasePtrOp(BasePtrOp), + Pred(std::forward(GeneratePointerOpIf)) {} + + Container computeTargets(const llvm::Value *Source) override { + if (Source == PointerOp || Source == BasePtrOp) { + return {}; + } + if (std::invoke(Pred, Source)) { + return {Source, PointerOp, BasePtrOp}; + } + return {Source}; + } + + const llvm::Value *PointerOp; + const llvm::Value *BasePtrOp; + [[no_unique_address]] std::decay_t Pred; + }; + + return std::make_shared( + Store->getPointerOperand(), BasePtrOp, + std::forward(GeneratePointerOpIf)); + } + struct StrongUpdateFlow : public FlowFunction { @@ -413,10 +463,38 @@ strongUpdateStore(const llvm::StoreInst *Store, Fn &&GeneratePointerOpIf) { template > FlowFunctionPtrType strongUpdateStore(const llvm::StoreInst *Store) { + // Here we cheat a bit and "look through" the GetElementPtrInst to the + // targeted memory location. + const auto *BasePtrOp = Store->getPointerOperand()->stripPointerCasts(); + if (BasePtrOp != Store->getPointerOperand()) { + struct StrongUpdateFlow + : public FlowFunction { + + StrongUpdateFlow(const llvm::StoreInst *Store, + const llvm::Value *BasePtrOp) noexcept + : Store(Store), BasePtrOp(BasePtrOp) {} + + Container computeTargets(const llvm::Value *Source) override { + if (Source == Store->getPointerOperand() || Source == BasePtrOp) { + return {}; + } + if (Source == Store->getValueOperand()) { + return {Source, Store->getPointerOperand(), BasePtrOp}; + } + return {Source}; + } + + const llvm::StoreInst *Store; + const llvm::Value *BasePtrOp; + }; + + return std::make_shared(Store, BasePtrOp); + } + struct StrongUpdateFlow : public FlowFunction { - StrongUpdateFlow(const llvm::StoreInst *Store) : Store(Store) {} + StrongUpdateFlow(const llvm::StoreInst *Store) noexcept : Store(Store) {} Container computeTargets(const llvm::Value *Source) override { if (Source == Store->getPointerOperand()) { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h similarity index 82% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h index 9e6511597..c57bfd088 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h @@ -17,11 +17,11 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMZEROVALUE_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_LLVMZEROVALUE_H -#include - #include "llvm/ADT/StringRef.h" #include "llvm/IR/GlobalVariable.h" +#include + namespace llvm { class Value; } // namespace llvm @@ -34,9 +34,9 @@ namespace psr { */ class LLVMZeroValue : public llvm::GlobalVariable { private: - LLVMZeroValue(llvm::Module &Mod); // NOLINT(modernize-use-equals-delete) + LLVMZeroValue(llvm::Module &Mod); - static constexpr auto LLVMZeroValueInternalName = "zero_value"; + static constexpr llvm::StringLiteral LLVMZeroValueInternalName = "zero_value"; public: LLVMZeroValue(const LLVMZeroValue &Z) = delete; @@ -45,16 +45,17 @@ class LLVMZeroValue : public llvm::GlobalVariable { LLVMZeroValue &operator=(LLVMZeroValue &&Z) = delete; ~LLVMZeroValue() = default; - [[nodiscard]] llvm::StringRef getName() const { + [[nodiscard]] llvm::StringRef getName() const noexcept { return LLVMZeroValueInternalName; } - static bool isLLVMZeroValue(const llvm::Value *V) { - return V == getInstance(); - } - // Do not specify a destructor (at all)! static const LLVMZeroValue *getInstance(); + + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr auto isLLVMZeroValue = [](const llvm::Value *V) { + return V == getInstance(); + }; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h similarity index 95% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h index 5ab15978c..5f7dbf727 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h @@ -10,10 +10,9 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATION_H -#include -#include -#include -#include +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMapInfo.h" @@ -26,9 +25,10 @@ #include "llvm/Support/TrailingObjects.h" #include "llvm/Support/raw_ostream.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include +#include +#include +#include namespace psr { @@ -113,9 +113,8 @@ class AbstractMemoryLocationImpl final /// implement the GEP-FF [[nodiscard]] bool isProperPrefixOf(const AbstractMemoryLocationImpl &Larger) const; - [[nodiscard]] bool isProperPrefixOf( - const AbstractMemoryLocationImpl &Larger, - PointsToInfo &PT) const; + [[nodiscard]] bool isProperPrefixOf(const AbstractMemoryLocationImpl &Larger, + LLVMAliasInfoRef PT) const; /// Are *this and TV equivalent? [[nodiscard]] bool equivalent(const AbstractMemoryLocationImpl &TV) const; @@ -125,9 +124,8 @@ class AbstractMemoryLocationImpl final unsigned PALevel = 1) const; /// Are *this and TV equivalent wrt aliasing? - bool mustAlias( - const AbstractMemoryLocationImpl &TV, - PointsToInfo &PT) const; + [[nodiscard]] bool mustAlias(const AbstractMemoryLocationImpl &TV, + LLVMAliasInfoRef PT) const; /// Provide an arbitrary partial order for being able to store TaintedValues /// in std::set or as key in std::map diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h similarity index 98% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h index 435afccb4..aa27ef024 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h @@ -10,8 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATIONFACTORY_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ABSTRACTMEMORYLOCATIONFACTORY_H -#include -#include +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -19,7 +18,8 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/TrailingObjects.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h" +#include +#include namespace llvm { class DataLayout; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AllSanitized.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AllSanitized.h new file mode 100644 index 000000000..2288416f4 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AllSanitized.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ALLSANITIZED_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ALLSANITIZED_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" +#include "phasar/Utils/ByRef.h" + +namespace psr::XTaint { +struct AllSanitized { + using l_t = EdgeDomain; + + [[nodiscard]] l_t + computeTarget([[maybe_unused]] ByConstRef Source) const noexcept { + return Sanitized{}; + } + + [[nodiscard]] bool isConstant() const noexcept { return true; } + + static EdgeFunction compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction); + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction); +}; +} // namespace psr::XTaint + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_ALLSANITIZED_H diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h new file mode 100644 index 000000000..981461c48 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_COMPOSEEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_COMPOSEEDGEFUNCTION_H + +#include "phasar//DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" + +#include "llvm/Support/raw_ostream.h" + +namespace psr::XTaint { +struct ComposeEdgeFunction : EdgeFunctionComposer { + using typename EdgeFunctionComposer::l_t; + + static EdgeFunction + join(EdgeFunctionRef This, + const EdgeFunction &Other); + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const ComposeEdgeFunction &CEF); +}; +} // namespace psr::XTaint + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h similarity index 81% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h index 55594e770..ad3d9404e 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h @@ -10,7 +10,9 @@ #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 "phasar/Domain/LatticeDomain.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/JoinLattice.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/IR/Instruction.h" // Need a complete type llvm::Instruction for llvm::PointerIntPair @@ -91,4 +93,24 @@ class EdgeDomain final { }; } // namespace psr::XTaint +namespace psr { +template <> struct NonTopBotValue { + using type = const llvm::Instruction *; + + static type unwrap(XTaint::EdgeDomain Value) noexcept { + return Value.getSanitizer(); + } +}; + +template <> struct JoinLatticeTraits { + static constexpr auto bottom() noexcept { return Bottom{}; } + static constexpr auto top() noexcept { return Top{}; } + + static XTaint::EdgeDomain join(ByConstRef LHS, + ByConstRef RHS) noexcept { + return LHS.join(RHS); + } +}; +} // namespace psr + #endif diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h new file mode 100644 index 000000000..4376f40eb --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_GENEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_GENEDGEFUNCTION_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" + +namespace psr::XTaint { +using GenEdgeFunction = ConstantEdgeFunction; +} // namespace psr::XTaint + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h similarity index 60% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h index e11a1d302..a4bd479ca 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h @@ -10,20 +10,19 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_HELPERS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_HELPERS_H -#include -#include -#include -#include +#include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" +#include "phasar/Domain/LatticeDomain.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" -#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" -#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" +#include +#include +#include +#include namespace llvm { class Instruction; @@ -37,30 +36,12 @@ namespace psr::XTaint { using LeakMap_t = std::unordered_map>; -EdgeFunction::EdgeFunctionPtrType -getGenEdgeFunction(BasicBlockOrdering &BBO); - -EdgeFunction::EdgeFunctionPtrType -getEdgeIdentity(const llvm::Instruction *Inst); -bool isEdgeIdentity(EdgeFunction *EF); - -llvm::hash_code -getHashCode(const EdgeFunction::EdgeFunctionPtrType &EF); - -EdgeFunction::EdgeFunctionPtrType getAllTop(); -EdgeFunction::EdgeFunctionPtrType getAllBot(); -EdgeFunction::EdgeFunctionPtrType getAllSanitized(); - /// Have an own function for creating a flow/edge-function instance to allow /// fast migration to memory-management schemes other than std::shared_ptr template inline std::shared_ptr makeFF(Args &&...Arguments) { return std::make_shared(std::forward(Arguments)...); } -template -inline std::shared_ptr makeEF(Args &&...Arguments) { - return std::make_shared(std::forward(Arguments)...); -} } // namespace psr::XTaint diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h new file mode 100644 index 000000000..181a9190f --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_KILLIFSANITIZEDEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_KILLIFSANITIZEDEDGEFUNCTION_H + +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" +#include "phasar/Utils/ByRef.h" + +namespace psr::XTaint { + +struct KillIfSanitizedEdgeFunction + : EdgeFunctionBase { + BasicBlockOrdering *BBO{}; + const llvm::Instruction *Load{}; + + using l_t = EdgeDomain; + + [[nodiscard]] l_t computeTarget(ByConstRef Source) const; + + [[nodiscard]] inline const llvm::Instruction *getLoad() const { return Load; } +}; + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + ByConstRef KEF); + +[[nodiscard]] bool +operator==(ByConstRef LHS, + ByConstRef RHS) noexcept; + +} // namespace psr::XTaint + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h new file mode 100644 index 000000000..450a8519e --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_TRANSFEREDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_TRANSFEREDGEFUNCTION_H + +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" +#include "phasar/Utils/ByRef.h" + +namespace psr::XTaint { +struct TransferEdgeFunction : EdgeFunctionBase { + using l_t = EdgeDomain; + + BasicBlockOrdering *BBO{}; + const llvm::Instruction *Load{}; + const llvm::Instruction *To{}; + + [[nodiscard]] l_t computeTarget(ByConstRef Source) const; + + friend bool operator==(const TransferEdgeFunction &LHS, + const TransferEdgeFunction &RHS) noexcept; + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const TransferEdgeFunction &TRE); +}; +} // namespace psr::XTaint + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h similarity index 93% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h index 4dda271b1..5263343fb 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h @@ -19,15 +19,15 @@ class Function; } // namespace llvm namespace psr { -class TaintConfig; +class LLVMTaintConfig; } // namespace psr namespace psr::XTaint { class AnalysisBase { protected: - const TaintConfig *TSF; + const LLVMTaintConfig *TSF; - explicit AnalysisBase(const TaintConfig *TSF) noexcept; + explicit AnalysisBase(const LLVMTaintConfig *TSF) noexcept; using SourceConfigTy = llvm::SmallPtrSet; using SinkConfigTy = llvm::SmallPtrSet; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h new file mode 100644 index 000000000..339fa2f81 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTEDGEFUNCTIONBASE_H_ +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTEDGEFUNCTIONBASE_H_ + +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AllSanitized.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" + +#include "llvm/ADT/Hashing.h" + +#include + +namespace psr::XTaint { + +static constexpr size_t JoinThreshold = 2; + +EdgeFunction makeComposeEF(const EdgeFunction &F, + const EdgeFunction &G); + +template struct EdgeFunctionBase { + static EdgeFunction + compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + return makeComposeEF(This, SecondFunction); + } + + static EdgeFunction + join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + if (auto Default = + defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + if (llvm::isa(OtherFunction)) { + return This; + } + + return JoinEdgeFunction::create(This, + OtherFunction); + } +}; + +} // namespace psr::XTaint +#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h similarity index 82% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h index b2dda23ea..cb13c7344 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEExtendedTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEExtendedTaintAnalysis.h @@ -10,18 +10,20 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEEXTENDEDTAINTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEEXTENDEDTAINTANALYSIS_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" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h" -#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/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/Domain/LatticeDomain.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocationFactory.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintAnalysisBase.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" +#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/BasicBlockOrdering.h" -#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" @@ -40,7 +42,6 @@ namespace psr { class LLVMBasedICFG; -class LLVMPointsToInfo; template class SolverResults; struct IDEExtendedTaintAnalysisDomain : public LLVMAnalysisDomainDefault { @@ -63,10 +64,9 @@ class IDEExtendedTaintAnalysis using typename IDETabulationProblem::l_t; using typename IDETabulationProblem< IDEExtendedTaintAnalysisDomain>::FlowFunctionPtrType; - using typename IDETabulationProblem< - IDEExtendedTaintAnalysisDomain>::EdgeFunctionPtrType; + using EdgeFunctionType = EdgeFunction; - using config_callback_t = TaintConfig::TaintDescriptionCallBackTy; + using config_callback_t = LLVMTaintConfig::TaintDescriptionCallBackTy; private: struct SourceSinkInfo { @@ -116,7 +116,7 @@ class IDEExtendedTaintAnalysis const llvm::Value *ValueOp, const llvm::Instruction *Store, unsigned PALevel = 1); - std::set propagateAtStore(PointsToInfo::PointsToSetPtrTy PTS, + std::set propagateAtStore(AliasInfoRef::AliasSetPtrTy PTS, d_t Source, d_t Val, d_t Mem, const llvm::Value *PointerOp, const llvm::Value *ValueOp, @@ -124,9 +124,9 @@ class IDEExtendedTaintAnalysis template >> - void forEachAliasOf(PointsToInfo::PointsToSetPtrTy PTS, + void forEachAliasOf(AliasInfoRef::AliasSetPtrTy PTS, const llvm::Value *Of, CallBack &&CB) { - if (!HasPrecisePointsToInfo) { + if (!HasPreciseAliasInfo) { auto OfFF = makeFlowFact(Of); for (const auto *Alias : *PTS) { if (const auto *AliasGlob = llvm::dyn_cast(Alias); @@ -155,7 +155,7 @@ class IDEExtendedTaintAnalysis static const llvm::Value *getVAListTagOrNull(const llvm::Function *DestFun); - void populateWithMayAliases(SourceConfigTy &Facts) const; + void populateWithMayAliases(SourceConfigTy &Facts); bool isMustAlias(const SanitizerConfigTy &Facts, d_t CurrNod); @@ -179,8 +179,8 @@ class IDEExtendedTaintAnalysis /// analysis or the results from a LLVM pass computing dominator trees template IDEExtendedTaintAnalysis(const LLVMProjectIRDB *IRDB, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - const TaintConfig *TSF, + const LLVMBasedICFG *ICF, LLVMAliasInfoRef PT, + const LLVMTaintConfig *TSF, std::vector EntryPoints, unsigned Bound, bool DisableStrongUpdates, GetDomTree &&GDT = DefaultDominatorTreeAnalysis{}) @@ -190,7 +190,7 @@ class IDEExtendedTaintAnalysis DL(IRDB->getModule()->getDataLayout()), Bound(Bound), PostProcessed(DisableStrongUpdates), DisableStrongUpdates(DisableStrongUpdates) { - assert(PT != nullptr); + assert(PT); assert(ICF != nullptr); initializeZeroValue(createZeroValue()); @@ -198,8 +198,8 @@ class IDEExtendedTaintAnalysis this->getIFDSIDESolverConfig().setAutoAddZero(false); - /// TODO: Once we have better PointsToInfo, do a dynamic_cast over PT and - /// set HasPrecisePointsToInfo accordingly + /// TODO: Once we have better AliasInfo, do a dynamic_cast over PT and + /// set HasPreciseAliasInfo accordingly } ~IDEExtendedTaintAnalysis() override = default; @@ -222,23 +222,23 @@ class IDEExtendedTaintAnalysis // Edge functions - EdgeFunctionPtrType getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, - d_t SuccNode) override; + EdgeFunctionType getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, + d_t SuccNode) override; - EdgeFunctionPtrType getCallEdgeFunction(n_t CallInst, d_t SrcNode, - f_t CalleeFun, d_t DestNode) override; + EdgeFunctionType getCallEdgeFunction(n_t CallInst, d_t SrcNode, f_t CalleeFun, + d_t DestNode) override; - EdgeFunctionPtrType getReturnEdgeFunction(n_t CallSite, f_t CalleeFun, - n_t ExitInst, d_t ExitNode, - n_t RetSite, d_t RetNode) override; + EdgeFunctionType getReturnEdgeFunction(n_t CallSite, f_t CalleeFun, + n_t ExitInst, d_t ExitNode, + n_t RetSite, d_t RetNode) override; - EdgeFunctionPtrType + EdgeFunctionType 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; + EdgeFunctionType getSummaryEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, + d_t SuccNode) override; // Misc @@ -248,7 +248,7 @@ class IDEExtendedTaintAnalysis [[nodiscard]] bool isZeroValue(d_t Fact) const override; - EdgeFunctionPtrType allTopFunction() override; + EdgeFunctionType allTopFunction() override; // JoinLattice @@ -272,7 +272,7 @@ class IDEExtendedTaintAnalysis llvm::raw_ostream &OS = llvm::outs()) override; private: - LLVMPointsToInfo *PT{}; + LLVMAliasInfoRef PT{}; const LLVMBasedICFG *ICF{}; /// Save all leaks here that were found using the IFDS part if the analysis. @@ -298,7 +298,7 @@ class IDEExtendedTaintAnalysis bool DisableStrongUpdates = false; - bool HasPrecisePointsToInfo = false; + bool HasPreciseAliasInfo = false; public: BasicBlockOrdering &getBasicBlockOrdering() { return BBO; } @@ -341,15 +341,15 @@ class IDEExtendedTaintAnalysis : public XTaint::IDEExtendedTaintAnalysis { public: template IDEExtendedTaintAnalysis(const LLVMProjectIRDB *IRDB, - const LLVMBasedICFG *ICF, LLVMPointsToInfo *PT, - const TaintConfig &TSF, + const LLVMBasedICFG *ICF, LLVMAliasInfoRef PT, + const LLVMTaintConfig &TSF, std::vector EntryPoints = {}, GetDomTree &&GDT = DefaultDominatorTreeAnalysis{}) : XTaint::IDEExtendedTaintAnalysis( IRDB, ICF, PT, &TSF, std::move(EntryPoints), BOUND, !USE_STRONG_UPDATES, std::forward(GDT)) {} - using ConfigurationTy = TaintConfig; + using ConfigurationTy = LLVMTaintConfig; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h new file mode 100644 index 000000000..0dd0789a4 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_ALLBOT_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_ALLBOT_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" + +namespace psr::glca { + +// struct AllBot { +// using type = AllBottom; +// static std::shared_ptr getInstance(); +// static bool isBot(const EdgeFunction *EdgeFn, +// bool NonRec = false); +// static bool +// isBot(const std::shared_ptr> &EdgeFn, +// bool NonRec = false); +// }; + +} // namespace psr::glca + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h new file mode 100644 index 000000000..d65f87f55 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_BINARYEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_BINARYEDGEFUNCTION_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h" + +namespace psr::glca { + +struct BinaryEdgeFunction { + using l_t = IDEGeneralizedLCADomain::l_t; + + llvm::BinaryOperator::BinaryOps Op{}; + l_t Const{}; + bool LeftConst{}; + + l_t computeTarget(ByConstRef Source) const; + + static EdgeFunction compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction); + + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction); + + bool operator==(const BinaryEdgeFunction &Other) const noexcept; + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const BinaryEdgeFunction &EF); +}; + +} // namespace psr::glca + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/ConstantHelper.h diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h similarity index 87% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h index ff69dc5ae..1fa752cb9 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h @@ -10,14 +10,14 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUE_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUE_H -#include -#include -#include - #include "llvm/ADT/APSInt.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Instructions.h" +#include "llvm/Support/raw_os_ostream.h" +#include "llvm/Support/raw_ostream.h" + +#include namespace psr::glca { @@ -46,7 +46,7 @@ class EdgeValue { EdgeValue(std::nullptr_t); ~EdgeValue(); const static EdgeValue TopValue; - [[nodiscard]] bool tryGetInt(uint64_t &Res) const; + [[nodiscard]] bool tryGetInt(int64_t &Res) const; [[nodiscard]] bool tryGetFP(double &Res) const; [[nodiscard]] bool tryGetString(std::string &Res) const; [[nodiscard]] bool isTop() const; @@ -82,6 +82,13 @@ class EdgeValue { friend llvm::raw_ostream &operator<<(llvm::raw_ostream &Os, const EdgeValue &EV); static std::string typeToString(Type Ty); + + friend std::string to_string(const EdgeValue &EV) { + std::string Ret; + llvm::raw_string_ostream ROS(Ret); + ROS << EV; + return Ret; + } }; class EdgeValueSet; using ev_t = EdgeValueSet; @@ -95,6 +102,11 @@ ev_t join(const ev_t &Lhs, const ev_t &Rhs, size_t MaxSize); 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); +inline std::ostream &operator<<(std::ostream &Os, const ev_t &Val) { + llvm::raw_os_ostream ROS(Os); + ROS << Val; + return Os; +} } // namespace psr::glca @@ -104,11 +116,11 @@ template <> struct hash { hash() = default; size_t operator()(const psr::glca::EdgeValue &Val) const { auto Hash = hash()(Val.getKind()); - uint64_t AsInt; + int64_t AsInt; double AsFloat; string AsString; if (Val.tryGetInt(AsInt)) { - return hash()(AsInt) * 31 + Hash; + return hash()(AsInt) * 31 + Hash; } if (Val.tryGetFP(AsFloat)) { return hash()(round(AsFloat)) * 31 + Hash; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h similarity index 75% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h index 495432972..8526c3474 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h @@ -10,11 +10,12 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUESET_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_EDGEVALUESET_H +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h" +#include "phasar/Utils/JoinLattice.h" + #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h" - namespace psr::glca { class EdgeValueSet { @@ -43,4 +44,16 @@ class EdgeValueSet { } // namespace psr::glca +namespace psr { +template <> struct JoinLatticeTraits { + using l_t = glca::EdgeValueSet; + + static l_t bottom() { return l_t({glca::EdgeValue::TopValue}); } + static l_t top() { return l_t({}); } + static l_t join(const l_t &LHS, const l_t &RHS) { + return glca::join(LHS, RHS, 2); + } +}; +} // namespace psr + #endif diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h new file mode 100644 index 000000000..50b14da39 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_GENCONSTANT_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_GENCONSTANT_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValue.h" + +namespace psr::glca { + +using GenConstant = ConstantEdgeFunction; + +} // namespace psr::glca + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h similarity index 75% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h index 49285fcea..63949390d 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h @@ -10,11 +10,12 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCA_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCA_H +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #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/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" -#include "phasar/PhasarLLVM/Utils/Printer.h" +#include "phasar/Utils/Printer.h" #include #include @@ -27,12 +28,7 @@ namespace psr { /// domain. Instead of using single Values, we use a bounded set of cadidates to /// increase precision. -struct IDEGeneralizedLCADomain : LLVMAnalysisDomainDefault { - using l_t = glca::EdgeValueSet; -}; - class IDEGeneralizedLCA : public IDETabulationProblem { - public: using d_t = typename IDEGeneralizedLCADomain::d_t; using f_t = typename IDEGeneralizedLCADomain::f_t; @@ -82,27 +78,25 @@ class IDEGeneralizedLCA : public IDETabulationProblem { // 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; + EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, + d_t SuccNode) override; - std::shared_ptr> getCallEdgeFunction(n_t CallStmt, - d_t SrcNode, - f_t DestinationMethod, - d_t DestNode) override; + EdgeFunction getCallEdgeFunction(n_t CallStmt, d_t SrcNode, + f_t DestinationMethod, + d_t DestNode) override; - std::shared_ptr> - getReturnEdgeFunction(n_t CallSite, f_t CalleeMethod, n_t ExitStmt, - d_t ExitNode, n_t RetSite, d_t RetNode) override; + EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeMethod, + n_t ExitStmt, d_t ExitNode, + n_t RetSite, d_t RetNode) override; - std::shared_ptr> + EdgeFunction getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode, llvm::ArrayRef Callees) override; - std::shared_ptr> - getSummaryEdgeFunction(n_t CallStmt, d_t CallNode, n_t RetSite, - d_t RetSiteNode) override; + EdgeFunction getSummaryEdgeFunction(n_t CallStmt, d_t CallNode, + n_t RetSite, + d_t RetSiteNode) override; l_t topElement() override; @@ -110,7 +104,7 @@ class IDEGeneralizedLCA : public IDETabulationProblem { l_t join(l_t Lhs, l_t Rhs) override; - std::shared_ptr> allTopFunction() override; + EdgeFunction allTopFunction() override; void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h new file mode 100644 index 000000000..c4b07728a --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCADOMAIN_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCADOMAIN_H + +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" + +namespace psr { + +struct IDEGeneralizedLCADomain : LLVMAnalysisDomainDefault { + using l_t = glca::EdgeValueSet; + static constexpr size_t JoinThreshold = 2; + static constexpr size_t MaxSetSize = 2; +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_IDEGENERALIZEDLCADOMAIN_H diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h new file mode 100644 index 000000000..a0bac57af --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_LCAEDGEFUNCTIONCOMPOSER_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_LCAEDGEFUNCTIONCOMPOSER_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCADomain.h" + +namespace psr::glca { + +struct LCAEdgeFunctionComposer + : public EdgeFunctionComposer { + + static EdgeFunction + join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction); +}; + +} // namespace psr::glca + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h similarity index 91% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h index b69c86621..f6a11eb95 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCalleeFlowFunction.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLEEFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLEEFLOWFUNCTION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" namespace llvm { class CallBase; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h similarity index 89% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h index 936b4833f..50acbe5c6 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/MapFactsToCallerFlowFunction.h @@ -10,8 +10,9 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLERFLOWFUNCTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_MAPFACTSTOCALLERFLOWFUNCTION_H -#include -#include +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" @@ -19,9 +20,8 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/Value.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/LLVMZeroValue.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include +#include namespace llvm { class CallBase; diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h new file mode 100644 index 000000000..426b4d0b1 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 2020 Fabian Schiebel. + * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_TYPECASTEDGEFUNCTION_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_TYPECASTEDGEFUNCTION_H + +#include "phasar/DataFlow/IfdsIde/EdgeFunction.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" + +#include "llvm/Support/raw_ostream.h" + +namespace psr::glca { + +struct TypecastEdgeFunction { + using l_t = IDEGeneralizedLCADomain::l_t; + + unsigned Bits{}; + EdgeValue::Type Dest{}; + + [[nodiscard]] l_t computeTarget(ByConstRef Source) const; + + static EdgeFunction compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction); + + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction); +}; + +[[nodiscard]] bool operator==(ByConstRef LHS, + ByConstRef RHS) noexcept; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + ByConstRef EF); + +} // namespace psr::glca + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h new file mode 100644 index 000000000..c39808640 --- /dev/null +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEInstInteractionAnalysis.h @@ -0,0 +1,1321 @@ +/****************************************************************************** + * Copyright (c) 2019 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 and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_IFDSIDE_PROBLEMS_IDEINSTINTERACTIONALYSIS_H +#define PHASAR_PHASARLLVM_IFDSIDE_PROBLEMS_IDEINSTINTERACTIONALYSIS_H + +#include "phasar/DataFlow/IfdsIde/DefaultEdgeFunctionSingletonCache.h" +#include "phasar/DataFlow/IfdsIde/EdgeFunctionUtils.h" +#include "phasar/DataFlow/IfdsIde/FlowFunctions.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/SolverResults.h" +#include "phasar/Domain/LatticeDomain.h" +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMFlowFunctions.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" +#include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" +#include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" +#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" +#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" +#include "phasar/Utils/BitVectorSet.h" +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/Logger.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_os_ostream.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Have some handy helper functionalities + +namespace vara { +class Taint; +} // namespace vara + +namespace psr { + +// [[nodiscard]] static inline const llvm::AllocaInst * +// getAllocaInstruction(const llvm::GetElementPtrInst *GEP) { +// if (!GEP) { +// return nullptr; +// } +// const auto *Alloca = GEP->getPointerOperand(); +// while (const auto *NestedGEP = +// llvm::dyn_cast(Alloca)) { +// Alloca = NestedGEP->getPointerOperand(); +// } +// return llvm::dyn_cast(Alloca); +// } + +template static BitVectorSet bvSetFrom(const std::set &Set) { + BitVectorSet Ret; + Ret.reserve(Set.size()); + Ret.insert(Set.begin(), Set.end()); + return Ret; +} + +template +static std::invoke_result_t, ArgTys...> +invoke_or_default(Callable &&Fn, ArgTys &&...Args) { + if (!Fn) { + return {}; + } + + return std::invoke(Fn, std::forward(Args)...); +} + +class IDEIIAFlowFact { + +public: + constexpr static unsigned KLimit = 2; + +private: + const llvm::Value *BaseVal = nullptr; + llvm::SmallVector FieldDesc; + +public: + ~IDEIIAFlowFact() = default; + IDEIIAFlowFact() = default; + /// Constructs a data-flow fact from the base value. Fields are ignored. Use + /// the factory function(s) to construct field-sensitive data-flow facts. + IDEIIAFlowFact(const llvm::Value *BaseVal); + /// Construct a data-flow fact from the base value and field specification. + IDEIIAFlowFact( + const llvm::Value *BaseVal, + llvm::SmallVector FieldDesc); + + /// Creates a new data-flow fact of the base value that respects fields. Field + /// accesses that exceed the specified depth will be collapsed and not further + /// distinguished. + static IDEIIAFlowFact create(const llvm::Value *BaseVal); + + /// Returns whether this data-flow fact describes the same abstract memory + /// location than the other one. + [[nodiscard]] bool flowFactEqual(const IDEIIAFlowFact &Other) const; + + [[nodiscard]] inline const llvm::Value *getBase() const { return BaseVal; } + [[nodiscard]] inline llvm::SmallVector + getField() const { + return FieldDesc; + } + [[nodiscard]] inline constexpr unsigned getKLimit() const { return KLimit; } + + void print(llvm::raw_ostream &OS, bool IsForDebug = false) const; + + bool operator==(const IDEIIAFlowFact &Other) const; + bool operator!=(const IDEIIAFlowFact &Other) const; + bool operator<(const IDEIIAFlowFact &Other) const; + + bool operator==(const llvm::Value *V) const; + + inline operator const llvm::Value *() { return BaseVal; } + + [[nodiscard]] std::string str() const { + std::string Ret; + llvm::raw_string_ostream OS(Ret); + print(OS); + return Ret; + } +}; + +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const IDEIIAFlowFact &FlowFact) { + FlowFact.print(OS); + return OS; +} + +inline std::ostream &operator<<(std::ostream &OS, + const IDEIIAFlowFact &FlowFact) { + llvm::raw_os_ostream Rso(OS); + FlowFact.print(Rso); + return OS; +} + +} // namespace psr + +// Implementations of STL traits. +namespace std { +template <> struct hash { + size_t operator()(const psr::IDEIIAFlowFact &FlowFact) const { + return std::hash()(FlowFact.getBase()); + } +}; +} // namespace std + +// Compatibility with LLVM Casting +namespace llvm { +template <> struct simplify_type { + using SimpleType = const llvm::Value *; + + static SimpleType getSimplifiedValue(const psr::IDEIIAFlowFact &FF) noexcept { + return FF.getBase(); + } +}; +} // namespace llvm + +namespace psr { + +template +struct IDEInstInteractionAnalysisDomain : public LLVMAnalysisDomainDefault { + // type of the element contained in the sets of edge functions + using d_t = IDEIIAFlowFact; + using e_t = EdgeFactType; + using l_t = LatticeDomain>; +}; + +/// +/// SyntacticAnalysisOnly: Can be set if a syntactic-only analysis is desired +/// (without using points-to information) +/// +/// IndirectTaints: Can be set to ensure non-interference +/// +template +class IDEInstInteractionAnalysisT + : public IDETabulationProblem< + IDEInstInteractionAnalysisDomain> { + using IDETabulationProblem< + IDEInstInteractionAnalysisDomain>::generateFromZero; + +public: + using AnalysisDomainTy = IDEInstInteractionAnalysisDomain; + + using IDETabProblemType = IDETabulationProblem; + using typename IDETabProblemType::container_type; + using typename IDETabProblemType::FlowFunctionPtrType; + + 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; + // type of the element contained in the sets of edge functions + using e_t = typename AnalysisDomainTy::e_t; + using l_t = typename AnalysisDomainTy::l_t; + using i_t = typename AnalysisDomainTy::i_t; + using EdgeFunctionType = EdgeFunction; + + using EdgeFactGeneratorTy = std::set( + std::variant InstOrGlobal); + + IDEInstInteractionAnalysisT( + const LLVMProjectIRDB *IRDB, const LLVMBasedICFG *ICF, + LLVMAliasInfoRef PT, std::vector EntryPoints = {"main"}, + std::function EdgeFactGenerator = nullptr) + : IDETabulationProblem( + IRDB, std::move(EntryPoints), createZeroValue()), + ICF(ICF), PT(PT), EdgeFactGen(std::move(EdgeFactGenerator)) { + assert(ICF != nullptr); + assert(PT); + // IIAAAddLabelsEF::initEdgeFunctionCleaner(); + // IIAAKillOrReplaceEF::initEdgeFunctionCleaner(); + } + + ~IDEInstInteractionAnalysisT() override = default; + + /// Offer a special hook to the user that allows to generate additional + /// edge facts on-the-fly. Above the generator function, the ordinary + /// edge facts are generated according to the usual edge functions. + inline void registerEdgeFactGenerator( + std::function EdgeFactGenerator) { + EdgeFactGen = std::move(EdgeFactGenerator); + } + + // start formulating our analysis by specifying the parts required for IFDS + + FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t /* Succ */) override { + // Generate all local variables + // + // Flow function: + // + // 0 + // |\ + // x = alloca y | \ + // v v + // 0 x + // + if (const auto *Alloca = llvm::dyn_cast(Curr)) { + PHASAR_LOG_LEVEL(DFADEBUG, "AllocaInst"); + return generateFromZero(Alloca); + } + + // Handle indirect taints, i. e., propagate values that depend on branch + // conditions whose operands are tainted. + if constexpr (EnableIndirectTaints) { + if (const auto *Br = llvm::dyn_cast(Curr); + Br && Br->isConditional()) { + // If the branch is conditional and its condition is tainted, then we + // need to propagates the instructions that are depending on this + // branch, too. + // + // Flow function: + // + // Let I be the set of instructions of the branch instruction's + // successors. + // + // 0 c x + // | |\ + // x = br C, label if.then, label if.else | | \--\ + // v v v v + // 0 c x I + // + return lambdaFlow([Br](d_t Src) { + container_type Facts; + Facts.insert(Src); + if (Src == Br->getCondition()) { + Facts.insert(Br); + for (const auto *Succs : Br->successors()) { + for (const auto &Inst : Succs->instructionsWithoutDebug()) { + Facts.insert(&Inst); + } + } + } + return Facts; + }); + } + } + + // Handle points-to information if the user wishes to conduct a + // non-syntax-only inst-interaction analysis. + if constexpr (!SyntacticAnalysisOnly) { + + // (ii) Handle semantic propagation (pointers) for load instructions. + + if (const auto *Load = llvm::dyn_cast(Curr)) { + // If one of the potentially many loaded values holds, the load itself + // (dereferenced value) must also be generated and populated. + // + // Flow function: + // + // Let Y = pts(y), be the points-to set of y. + // + // 0 Y x + // | |\ + // x = load y | | \ + // v v v + // 0 Y x + // + return generateFlowIf( + Load, [PointerOp = Load->getPointerOperand(), + PTS = PT.getReachableAllocationSites( + Load->getPointerOperand(), OnlyConsiderLocalAliases)]( + d_t Src) { return Src == PointerOp || PTS->count(Src); }); + } + + // (ii) Handle semantic propagation (pointers) for store instructions. + if (const auto *Store = llvm::dyn_cast(Curr)) { + // If the value to be stored holds, the potential memory location(s) + // that it is stored to must be generated and populated, too. + // + // Flow function: + // + // Let X be + // - pts(x), the points-to set of x, if x is an intersting pointer. + // - a singleton set containing x, otherwise. + // + // Let Y be pts(y), the points-to set of y. + // + // 0 X y + // | |\ | + // store x y | | \| + // v v v + // 0 x Y + // + return lambdaFlow( + [Store, PointerPTS = PT.getReachableAllocationSites( + Store->getPointerOperand(), OnlyConsiderLocalAliases, + Store)](d_t Src) -> container_type { + if (Store->getPointerOperand() == Src || PointerPTS->count(Src)) { + // Here, we are unsound! + return {}; + } + container_type Facts; + Facts.insert(Src); + // y/Y now obtains its new value(s) from x/X + // If a value is stored that holds we must generate all potential + // memory locations the store might write to. + if (Store->getValueOperand() == Src) { + Facts.insert(Store->getPointerOperand()); + Facts.insert(PointerPTS->begin(), PointerPTS->end()); + } + // ... or from zero, if a constant literal is stored to y + if (llvm::isa(Store->getValueOperand()) && + IDEInstInteractionAnalysisT::isZeroValueImpl(Src)) { + Facts.insert(Store->getPointerOperand()); + Facts.insert(PointerPTS->begin(), PointerPTS->end()); + } + return Facts; + }); + } + } + + // (i) Handle syntactic propagation + + // Handle load instruction + // + // Flow function: + // + // 0 y x + // | |\ + // x = load y | | \ + // v v v + // 0 y x + // + if (const auto *Load = llvm::dyn_cast(Curr)) { + return generateFlow(Load, Load->getPointerOperand()); + } + // Handle store instructions + // + // Flow function: + // + // 0 x y + // | |\ | + // store x y | | \| + // v v v + // 0 x y + // + if (const auto *Store = llvm::dyn_cast(Curr)) { + return lambdaFlow([Store](d_t Src) -> container_type { + // Override old value, i.e., kill value that is written to and + // generate from value that is stored. + if (Store->getPointerOperand() == Src) { + return {}; + } + container_type Facts = {Src}; + // y now obtains its new value from x + if (Store->getValueOperand() == Src) { + Facts.insert(Store->getPointerOperand()); + } + // ... or from zero, if a constant literal is stored to y + if (llvm::isa(Store->getValueOperand()) && + IDEInstInteractionAnalysisT::isZeroValueImpl(Src)) { + Facts.insert(Store->getPointerOperand()); + } + IF_LOG_ENABLED({ + for (const auto Fact : Facts) { + PHASAR_LOG_LEVEL(DFADEBUG, "Create edge: " + << llvmIRToShortString(Src) << " --" + << llvmIRToShortString(Store) + << "--> " << Fact); + } + }); + return Facts; + }); + } + // At last, we can handle all other (unary/binary) instructions. + // + // Flow function: + // + // 0 x o p + // | | /| /| + // x = instruction o p | |/ |/ | + // | | /| | + // | |/ | | + // v v v v + // 0 x o p + // + return lambdaFlow([Inst = Curr](d_t Src) { + container_type Facts; + if (IDEInstInteractionAnalysisT::isZeroValueImpl(Src)) { + // keep the zero flow fact + Facts.insert(Src); + return Facts; + } + + // continue syntactic propagation: populate and propagate other existing + // facts + for (auto &Op : Inst->operands()) { + // if one of the operands holds, also generate the instruction using + // it + if (Op == Src) { + Facts.insert(Inst); + } + } + // pass everything that already holds as identity + Facts.insert(Src); + IF_LOG_ENABLED({ + for (const auto Fact : Facts) { + PHASAR_LOG_LEVEL(DFADEBUG, + "Create edge: " << llvmIRToShortString(Src) << " --" + << llvmIRToShortString(Inst) + << "--> " << Fact); + } + }); + return Facts; + }); + } + + inline FlowFunctionPtrType getCallFlowFunction(n_t CallSite, + f_t DestFun) override { + if (this->ICF->isHeapAllocatingFunction(DestFun)) { + // Kill add facts and model the effects in getCallToRetFlowFunction(). + return killAllFlows(); + } + if (DestFun->isDeclaration()) { + // We don't have anything that we could analyze, kill all facts. + return killAllFlows(); + } + const auto *CS = llvm::cast(CallSite); + + // Map actual to formal parameters. + auto MapFactsToCalleeFF = mapFactsToCallee( + CS, DestFun, [CS](const llvm::Value *ActualArg, ByConstRef Src) { + if (d_t(ActualArg) != Src) { + return false; + } + + if (CS->hasStructRetAttr() && ActualArg == CS->getArgOperand(0)) { + return false; + } + + return true; + }); + + // Generate the artificially introduced RVO parameters from zero value. + auto SRetFormal = CS->hasStructRetAttr() ? DestFun->getArg(0) : nullptr; + + if (SRetFormal) { + return unionFlows( + std::move(MapFactsToCalleeFF), + generateFlowAndKillAllOthers(SRetFormal, this->getZeroValue())); + } + + return MapFactsToCalleeFF; + } + + inline FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t /*CalleeFun*/, + n_t ExitInst, + n_t /* RetSite */) override { + // Map return value back to the caller. If pointer parameters hold at the + // end of a callee function generate all of those in the caller context. + + auto MapFactsToCallerFF = + mapFactsToCaller(llvm::cast(CallSite), ExitInst, + {}, [](const llvm::Value *RetVal, d_t Src) { + if (Src == RetVal) { + return true; + } + if (isZeroValueImpl(Src)) { + if (llvm::isa(RetVal)) { + return true; + } + } + return false; + }); + + return MapFactsToCallerFF; + } + + inline FlowFunctionPtrType + getCallToRetFlowFunction(n_t CallSite, n_t /* RetSite */, + llvm::ArrayRef Callees) override { + // Model call to heap allocating functions (new, new[], malloc, etc.) -- + // only model direct calls, though. + if (Callees.size() == 1) { + const auto *Callee = Callees.front(); + if (this->ICF->isHeapAllocatingFunction(Callee)) { + // In case a heap allocating function is called, generate the pointer + // that is returned. + // + // Flow function: + // + // Let H be a heap allocating function. + // + // 0 + // |\ + // x = call H | \ + // v v + // 0 x + // + return generateFromZero(CallSite); + } + } + // Just use the auto mapping for values; pointer parameters and global + // variables are killed and handled by getCallFlowfunction() and + // getRetFlowFunction(). + // However, if only declarations are available as callee targets we would + // lose the data-flow facts involved in the call which is usually not the + // 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; + } + } + + return lambdaFlow([CallSite = llvm::cast(CallSite), + OnlyDecls, + AllVoidRetTys](d_t Source) -> container_type { + // There are a few things to consider, in case only declarations of + // callee targets are available. + if (OnlyDecls) { + if (!AllVoidRetTys) { + // If one or more of the declaration-only targets return a value, it + // must be generated from zero! + if (isZeroValueImpl(Source)) { + return {Source, CallSite}; + } + } + // If all declaration-only callee targets return void, just pass + // everything as identity. + return {Source}; + } + // 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 {}; + } + // Pass everything else as identity. In particular, also do not kill + // pointer or reference parameters since this then also captures usages + // oft the parameters, which we wish to compute using this analysis. + return {Source}; + }); + } + + inline FlowFunctionPtrType + getSummaryFlowFunction(n_t /* CallSite */, f_t /* DestFun */) override { + // Do not use user-crafted summaries. + return nullptr; + } + + inline InitialSeeds initialSeeds() override { + InitialSeeds Seeds; + + forallStartingPoints(this->EntryPoints, ICF, [this, &Seeds](n_t SP) { + // Set initial seeds at the required entry points and generate the global + // variables using generalized initial seeds + + // Generate zero value at the entry points + Seeds.addSeed(SP, this->getZeroValue(), bottomElement()); + // Generate formal parameters of entry points, e.g. main(). Formal + // parameters will otherwise cause trouble by overriding alloca + // instructions without being valid data-flow facts themselves. + for (const auto &Arg : SP->getFunction()->args()) { + Seeds.addSeed(SP, &Arg, Bottom{}); + } + // Generate all global variables using generalized initial seeds + + 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(SP, GV, InitialValues); + } + } + }); + + return Seeds; + } + + [[nodiscard]] inline d_t createZeroValue() const { + // Create a special value to represent the zero value! + return LLVMZeroValue::getInstance(); + } + + inline bool isZeroValue(d_t d) const override { return isZeroValueImpl(d); } + + // In addition provide specifications for the IDE parts. + + inline EdgeFunctionType getStrongUpdateStoreEF(const llvm::StoreInst *Store, + d_t CurrNode, d_t SuccNode, + l_t UserEdgeFacts) { + + // Overriding edge: obtain labels from value to be stored (and may add + // UserEdgeFacts, if any). + // + // x --> y + // + // Edge function: + // + // x + // \ + // store x y \ \x.x \cup { commit of('store x y') } + // v + // y + // + + if (CurrNode == Store->getValueOperand() || + (isZeroValue(CurrNode) && + llvm::isa(Store->getValueOperand()))) { + if (SuccNode == Store->getPointerOperand() || + PT.isInReachableAllocationSites(Store->getPointerOperand(), SuccNode, + true, Store)) { + return IIAAAddLabelsEFCache.createEdgeFunction(UserEdgeFacts); + } + } + + if (SyntacticAnalysisOnly) { + // Kill all labels that are propagated along the edge of the value that + // is overridden. + // + // y --> y + // + // Edge function: + // + // y + // | + // store x y | \x.{ commit of('store x y') } + // v + // y + // + if ((CurrNode == SuccNode) && CurrNode == Store->getPointerOperand()) { + // y obtains its value(s) from its original allocation and the store + // instruction under analysis. + IF_LOG_ENABLED({ + PHASAR_LOG_LEVEL(DFADEBUG, + "Const-Replace at '" << llvmIRToString(Store)); + PHASAR_LOG_LEVEL(DFADEBUG, "Replacement label(s): "); + for (const auto &Item : UserEdgeFacts.assertGetValue()) { + PHASAR_LOG_LEVEL(DFADEBUG, Item << ", "); + } + PHASAR_LOG_LEVEL(DFADEBUG, '\n'); + }); + // obtain label from the original allocation + return IIAAKillOrReplaceEFCache.createEdgeFunction(UserEdgeFacts); + } + + } else { + // Use points-to information to find all possible overriding edges. + + // Kill all labels that are propagated along the edge of the + // value/values that is/are overridden. + // + // y --> y + // + // Edge function: + // + // y + // | + // store x y | \x.{} + // v + // y + // + if (CurrNode == SuccNode && (Store->getPointerOperand() == CurrNode || + this->PT.isInReachableAllocationSites( + Store->getPointerOperand(), CurrNode, + OnlyConsiderLocalAliases))) { + return IIAAKillOrReplaceEFCache.createEdgeFunction(BitVectorSet()); + } + } + + if (CurrNode == SuccNode) { + // Everything unrelated to the store + return EdgeIdentity{}; + } + + llvm::report_fatal_error( + llvm::Twine("Unhandled edge: \n> Store: ") + llvmIRToString(Store) + + "\n> CurrNode: " + CurrNode.str() + "\n> SuccNode: " + SuccNode.str()); + } + + inline EdgeFunctionType getNormalEdgeFunction(n_t Curr, d_t CurrNode, + n_t /* Succ */, + d_t SuccNode) override { + PHASAR_LOG_LEVEL(DFADEBUG, + "Process edge: " << llvmIRToShortString(CurrNode) << " --" + << llvmIRToString(Curr) << "--> " + << llvmIRToShortString(SuccNode)); + + if (isZeroValue(SuccNode)) { + // We don't want to propagate any facts on zero + return EdgeIdentity{}; + } + + // Overrides at store instructions + if (const auto *Store = llvm::dyn_cast(Curr)) { + return getStrongUpdateStoreEF( + Store, CurrNode, SuccNode, + bvSetFrom(invoke_or_default(EdgeFactGen, Curr))); + } + + // + // Identity edges + // + // Edge function: + // + // 0 + // | + // %i = instruction | \x.x + // v + // 0 + // + if (CurrNode == SuccNode) { + return EdgeIdentity{}; + } + + if (Curr != CurrNode && Curr == SuccNode) { + // check if the user has registered a fact generator function + l_t UserEdgeFacts = bvSetFrom(invoke_or_default(EdgeFactGen, Curr)); + + // We generate Curr in this instruction, so we have to annotate it with + // edge labels + return IIAAAddLabelsEFCache.createEdgeFunction(UserEdgeFacts); + } + + // Otherwise stick to identity. + return EdgeIdentity{}; + } + + inline EdgeFunctionType getCallEdgeFunction(n_t CallSite, d_t SrcNode, + f_t /* DestinationMethod */, + d_t DestNode) override { + // Handle the case in which a parameter that has been artificially + // introduced by the compiler is passed. Such a value must be generated from + // the zero value, to reflact the fact that the data flows from the callee + // to the caller (at least) according to the source code. + // + // Let a_i be an argument that is annotated by the sret attribute. + // + // 0 --> a_i + // + // Edge function: + // + // 0 + // \ + // call/invoke f(a_i) \ \x.{} + // v + // a_i + // + std::set SRetParams; + const auto *CS = llvm::cast(CallSite); + for (unsigned Idx = 0; Idx < CS->arg_size(); ++Idx) { + if (CS->paramHasAttr(Idx, llvm::Attribute::StructRet)) { + SRetParams.insert(CS->getArgOperand(Idx)); + } + } + if (isZeroValue(SrcNode) && SRetParams.count(DestNode)) { + return IIAAAddLabelsEFCache.createEdgeFunction(); + } + // Everything else can be passed as identity. + return EdgeIdentity{}; + } + + inline EdgeFunctionType + getReturnEdgeFunction(n_t CallSite, f_t /* CalleeMethod */, n_t ExitInst, + d_t ExitNode, n_t /* RetSite */, d_t RetNode) override { + // Handle the case in which constant data is returned, e.g. ret i32 42. + // + // Let c be the return instruction's corresponding call site. + // + // 0 --> c + // + // Edge function: + // + // 0 + // \ + // ret x \ \x.x \cup { commit of('ret x') } + // v + // c + // + if (isZeroValue(ExitNode) && RetNode == CallSite) { + const auto *Ret = llvm::dyn_cast(ExitInst); + if (const auto *CD = + llvm::dyn_cast(Ret->getReturnValue())) { + // Check if the user has registered a fact generator function + l_t UserEdgeFacts = BitVectorSet(); + std::set EdgeFacts; + if (EdgeFactGen) { + EdgeFacts = EdgeFactGen(ExitInst); + // fill BitVectorSet + UserEdgeFacts = BitVectorSet(EdgeFacts.begin(), EdgeFacts.end()); + } + return IIAAAddLabelsEFCache.createEdgeFunction( + std::move(UserEdgeFacts)); + } + } + // Everything else can be passed as identity. + return EdgeIdentity{}; + } + + inline EdgeFunctionType + getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t /* RetSite */, + d_t RetSiteNode, + llvm::ArrayRef Callees) override { + // Check if the user has registered a fact generator function + l_t UserEdgeFacts = BitVectorSet(); + std::set EdgeFacts; + if (EdgeFactGen) { + EdgeFacts = EdgeFactGen(CallSite); + // fill BitVectorSet + UserEdgeFacts = BitVectorSet(EdgeFacts.begin(), EdgeFacts.end()); + } + // Model call to heap allocating functions (new, new[], malloc, etc.) -- + // only model direct calls, though. + if (Callees.size() == 1) { + for (const auto *Callee : Callees) { + if (this->ICF->isHeapAllocatingFunction(Callee)) { + // Let H be a heap allocating function. + // + // 0 --> x + // + // Edge function: + // + // 0 + // \ + // %i = call H \ \x.x \cup { commit of('%i = call H') } + // v + // i + // + if (isZeroValue(CallNode) && RetSiteNode == CallSite) { + return IIAAAddLabelsEFCache.createEdgeFunction( + std::move(UserEdgeFacts)); + } + } + } + } + // Capture interactions of the call instruction and its arguments. + const auto *CS = llvm::dyn_cast(CallSite); + for (const auto &Arg : CS->args()) { + // + // o_i --> o_i + // + // Edge function: + // + // o_i + // | + // %i = call o_i | \ \x.x \cup { commit of('%i = call H') } + // v + // o_i + // + if (CallNode == Arg && CallNode == RetSiteNode) { + return IIAAAddLabelsEFCache.createEdgeFunction( + std::move(UserEdgeFacts)); + } + } + // Otherwise stick to identity + return EdgeIdentity{}; + } + + inline EdgeFunctionType + getSummaryEdgeFunction(n_t /* CallSite */, d_t /* CallNode */, + n_t /* RetSite */, d_t /* RetSiteNode */) override { + // Do not use user-crafted summaries. + return nullptr; + } + + inline l_t topElement() override { return Top{}; } + + inline l_t bottomElement() override { return Bottom{}; } + + inline l_t join(l_t Lhs, l_t Rhs) override { return joinImpl(Lhs, Rhs); } + + inline EdgeFunctionType allTopFunction() override { return AllTop(); } + + // Provide some handy helper edge functions to improve reuse. + + // Edge function that kills all labels in a set (and may replaces them with + // others). + struct IIAAKillOrReplaceEF { + using l_t = typename AnalysisDomainTy::l_t; + l_t Replacement{}; + + l_t computeTarget(ByConstRef /* Src */) const { return Replacement; } + + static EdgeFunction compose(EdgeFunctionRef This, + const EdgeFunction SecondFunction) { + + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + + auto Cache = This.getCacheOrNull(); + assert(Cache != nullptr && "We expect a cache, because " + "IIAAKillOrReplaceEF is too large for SOO"); + + if (auto *AD = llvm::dyn_cast(SecondFunction)) { + auto ADCache = + SecondFunction.template getCacheOrNull(); + assert(ADCache != nullptr); + if (This->isKillAll()) { + return ADCache->createEdgeFunction(*AD); + } + auto Union = + IDEInstInteractionAnalysisT::joinImpl(This->Replacement, AD->Data); + return ADCache->createEdgeFunction(std::move(Union)); + } + + if (auto *KR = llvm::dyn_cast(SecondFunction)) { + if (This->isKillAll()) { + return Cache->createEdgeFunction(*KR); + } + if (KR->isKillAll()) { + return SecondFunction; + } + auto Union = IDEInstInteractionAnalysisT::joinImpl(This->Replacement, + KR->Replacement); + return Cache->createEdgeFunction(std::move(Union)); + } + llvm::report_fatal_error( + "found unexpected edge function in 'IIAAKillOrReplaceEF'"); + } + + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + /// XXX: Here, we underapproximate joins with EdgeIdentity + if (llvm::isa>(OtherFunction)) { + return This; + } + + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + + auto Cache = This.getCacheOrNull(); + assert(Cache != nullptr && "We expect a cache, because " + "IIAAKillOrReplaceEF is too large for SOO"); + + if (auto *AD = llvm::dyn_cast(OtherFunction)) { + auto ADCache = OtherFunction.template getCacheOrNull(); + assert(ADCache); + auto Union = + IDEInstInteractionAnalysisT::joinImpl(This->Replacement, AD->Data); + return ADCache->createEdgeFunction(std::move(Union)); + } + if (auto *KR = llvm::dyn_cast(OtherFunction)) { + auto Union = IDEInstInteractionAnalysisT::joinImpl(This->Replacement, + KR->Replacement); + return Cache->createEdgeFunction(std::move(Union)); + } + llvm::report_fatal_error( + "found unexpected edge function in 'IIAAKillOrReplaceEF'"); + } + + bool operator==(const IIAAKillOrReplaceEF &Other) const noexcept { + return Replacement == Other.Replacement; + } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const IIAAKillOrReplaceEF &EF) { + OS << "EF: (IIAAKillOrReplaceEF)<->"; + if (EF.isKillAll()) { + OS << "(KillAll"; + } else { + IDEInstInteractionAnalysisT::printEdgeFactImpl(OS, EF.Replacement); + } + return OS << ")"; + } + + [[nodiscard]] bool isKillAll() const noexcept { + if (auto *RSet = std::get_if>(&Replacement)) { + return RSet->empty(); + } + return false; + } + + // NOLINTNEXTLINE(readability-identifier-naming) -- needed for ADL + friend llvm::hash_code hash_value(const IIAAKillOrReplaceEF &EF) { + return hash_value(EF.Replacement); + } + }; + + // Edge function that adds the given labels to existing labels + // add all labels provided by Data. + struct IIAAAddLabelsEF { + using l_t = typename AnalysisDomainTy::l_t; + l_t Data{}; + + l_t computeTarget(ByConstRef Src) const { + return IDEInstInteractionAnalysisT::joinImpl(Src, Data); + } + + static EdgeFunction compose(EdgeFunctionRef This, + const EdgeFunction &SecondFunction) { + if (auto Default = defaultComposeOrNull(This, SecondFunction)) { + return Default; + } + + auto Cache = This.getCacheOrNull(); + assert(Cache != nullptr && "We expect a cache, because " + "IIAAAddLabelsEF is too large for SOO"); + + if (auto *AD = llvm::dyn_cast(SecondFunction)) { + auto Union = + IDEInstInteractionAnalysisT::joinImpl(This->Data, AD->Data); + return Cache->createEdgeFunction(std::move(Union)); + } + if (auto *KR = llvm::dyn_cast(SecondFunction)) { + return Cache->createEdgeFunction(KR->Replacement); + } + llvm::report_fatal_error( + "found unexpected edge function in 'IIAAAddLabelsEF'"); + } + + static EdgeFunction join(EdgeFunctionRef This, + const EdgeFunction &OtherFunction) { + /// XXX: Here, we underapproximate joins with EdgeIdentity + if (llvm::isa>(OtherFunction)) { + return This; + } + + if (auto Default = defaultJoinOrNull(This, OtherFunction)) { + return Default; + } + + auto Cache = This.getCacheOrNull(); + assert(Cache != nullptr && "We expect a cache, because " + "IIAAAddLabelsEF is too large for SOO"); + + if (auto *AD = llvm::dyn_cast(OtherFunction)) { + auto Union = + IDEInstInteractionAnalysisT::joinImpl(This->Data, AD->Data); + return Cache->createEdgeFunction(std::move(Union)); + } + if (auto *KR = llvm::dyn_cast(OtherFunction)) { + auto Union = + IDEInstInteractionAnalysisT::joinImpl(This->Data, KR->Replacement); + return Cache->createEdgeFunction(std::move(Union)); + } + llvm::report_fatal_error( + "found unexpected edge function in 'IIAAAddLabelsEF'"); + } + + bool operator==(const IIAAAddLabelsEF &Other) const noexcept { + return Data == Other.Data; + } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const IIAAAddLabelsEF &EF) { + OS << "EF: (IIAAAddLabelsEF: "; + IDEInstInteractionAnalysisT::printEdgeFactImpl(OS, EF.Data); + return OS << ")"; + } + + // NOLINTNEXTLINE(readability-identifier-naming) -- needed for ADL + friend llvm::hash_code hash_value(const IIAAAddLabelsEF &EF) { + return hash_value(EF.Data); + } + }; + + // Provide functionalities for printing things and emitting text reports. + + void printNode(llvm::raw_ostream &OS, n_t n) const override { + OS << llvmIRToString(n); + } + + void printDataFlowFact(llvm::raw_ostream &OS, d_t FlowFact) const override { + OS << llvmIRToString(FlowFact); + } + + void printFunction(llvm::raw_ostream &OS, f_t Fun) const override { + OS << Fun->getName(); + } + + inline void printEdgeFact(llvm::raw_ostream &OS, + l_t EdgeFact) const override { + printEdgeFactImpl(OS, EdgeFact); + } + + static void stripBottomResults(std::unordered_map &Res) { + for (auto It = Res.begin(); It != Res.end();) { + if (It->second.isBottom()) { + It = Res.erase(It); + } else { + ++It; + } + } + } + + void emitTextReport(const SolverResults &SR, + llvm::raw_ostream &OS = llvm::outs()) override { + OS << "\n====================== IDE-Inst-Interaction-Analysis Report " + "======================\n"; + // if (!IRDB->debugInfoAvailable()) { + // // Emit only IR code, function name and module info + // OS << "\nWARNING: No Debug Info available - emiting results without " + // "source code mapping!\n"; + for (const auto *f : this->ICF->getAllFunctions()) { + std::string FunName = getFunctionNameFromIR(f); + OS << "\nFunction: " << FunName << "\n----------" + << std::string(FunName.size(), '-') << '\n'; + for (const auto *Inst : this->ICF->getAllInstructionsOf(f)) { + auto Results = SR.resultsAt(Inst, true); + stripBottomResults(Results); + if (!Results.empty()) { + OS << "At IR statement: " << this->NtoString(Inst) << '\n'; + for (auto Result : Results) { + if (!Result.second.isBottom()) { + OS << " Fact: " << this->DtoString(Result.first) + << "\n Value: " << this->LtoString(Result.second) << '\n'; + } + } + OS << '\n'; + } + } + OS << '\n'; + } + // } else { + // TODO: implement better report in case debug information are available + // } + } + + /// Computes all variables where a result set has been computed using the + /// edge functions (and respective value domain). + inline std::unordered_set + getAllVariables(const SolverResults & /* Solution */) const { + std::unordered_set Variables; + // collect all variables that are available + const llvm::Module *M = this->IRDB->getModule(); + for (const auto &G : M->globals()) { + Variables.insert(&G); + } + for (const auto *I : this->IRDB->getAllInstructions()) { + if (const auto *A = llvm::dyn_cast(I)) { + Variables.insert(A); + } + if (const auto *H = llvm::dyn_cast(I)) { + if (!H->isIndirectCall() && H->getCalledFunction() && + this->ICF->isHeapAllocatingFunction(H->getCalledFunction())) { + Variables.insert(H); + } + } + } + + return Variables; + } + + /// Computes all variables for which an empty set has been computed using the + /// edge functions (and respective value domain). + inline std::unordered_set getAllVariablesWithEmptySetValue( + const SolverResults &Solution) const { + return removeVariablesWithoutEmptySetValue(Solution, + getAllVariables(Solution)); + } + +protected: + static inline bool isZeroValueImpl(d_t d) { + return LLVMZeroValue::isLLVMZeroValue(d); + } + + static void printEdgeFactImpl(llvm::raw_ostream &OS, + ByConstRef EdgeFact) { + if (std::holds_alternative(EdgeFact)) { + OS << std::get(EdgeFact); + } else if (std::holds_alternative(EdgeFact)) { + OS << std::get(EdgeFact); + } else { + auto LSet = std::get>(EdgeFact); + OS << "(set size: " << LSet.size() << ") values: "; + if constexpr (std::is_same_v) { + for (const auto &LElem : LSet) { + std::string IRBuffer; + llvm::raw_string_ostream RSO(IRBuffer); + LElem->print(RSO); + RSO.flush(); + OS << IRBuffer << ", "; + } + } else { + for (const auto &LElem : LSet) { + OS << LElem << ", "; + } + } + } + } + + static inline l_t joinImpl(ByConstRef Lhs, ByConstRef Rhs) { + if (Lhs.isTop() || Lhs.isBottom()) { + return Rhs; + } + if (Rhs.isTop() || Rhs.isBottom()) { + return Lhs; + } + const auto &LhsSet = std::get>(Lhs); + const auto &RhsSet = std::get>(Rhs); + return LhsSet.setUnion(RhsSet); + } + +private: + /// Filters out all variables that had a non-empty set during edge functions + /// computations. + inline std::unordered_set removeVariablesWithoutEmptySetValue( + const SolverResults &Solution, + std::unordered_set Variables) const { + // Check the solver results and remove all variables for which a + // non-empty set has been computed + auto Results = Solution.getAllResultEntries(); + for (const auto &Result : Results) { + // We do not care for the concrete instruction at which data-flow facts + // hold, instead we just wish to find out if a variable has been generated + // 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 &Value = Result.getValue(); + // skip result entry if variable is not in the set of all variables + if (Variables.find(Variable) == Variables.end()) { + continue; + } + // skip result entry if the computed value is not of type BitVectorSet + if (!std::holds_alternative>(Value)) { + continue; + } + // remove variable from result set if a non-empty that has been computed + auto &Values = std::get>(Value); + if (!Values.empty()) { + Variables.erase(Variable); + } + } + return Variables; + } + + DefaultEdgeFunctionSingletonCache IIAAAddLabelsEFCache; + DefaultEdgeFunctionSingletonCache + IIAAKillOrReplaceEFCache; + + const LLVMBasedICFG *ICF{}; + LLVMAliasInfoRef PT{}; + std::function EdgeFactGen; + static inline const bool OnlyConsiderLocalAliases = true; + +}; // namespace psr + +using IDEInstInteractionAnalysis = IDEInstInteractionAnalysisT<>; + +} // namespace psr + +#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h similarity index 72% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h index e71dc1deb..ec1b4beea 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDELinearConstantAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis.h @@ -10,10 +10,9 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDELINEARCONSTANTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDELINEARCONSTANTANALYSIS_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" +#include "phasar/Domain/LatticeDomain.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" -#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" #include "llvm/Support/raw_ostream.h" @@ -38,11 +37,10 @@ struct IDELinearConstantAnalysisDomain : public LLVMAnalysisDomainDefault { class LLVMBasedICFG; class LLVMTypeHierarchy; -class LLVMPointsToInfo; +// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) class IDELinearConstantAnalysis : public IDETabulationProblem { - public: using IDETabProblemType = IDETabulationProblem; @@ -60,23 +58,17 @@ class IDELinearConstantAnalysis ~IDELinearConstantAnalysis() override; - IDELinearConstantAnalysis(const IDELinearConstantAnalysis &) = delete; - IDELinearConstantAnalysis & - operator=(const IDELinearConstantAnalysis &) = delete; - struct LCAResult { LCAResult() = default; unsigned LineNr = 0; std::string SrcNode; std::map VariableToValue; std::vector IRTrace; - void print(llvm::raw_ostream &OS); + void print(llvm::raw_ostream &OS) const; inline bool operator==(const LCAResult &Rhs) const { return SrcNode == Rhs.SrcNode && VariableToValue == Rhs.VariableToValue && IRTrace == Rhs.IRTrace; } - - operator std::string() const; }; using lca_results_t = std::map>; @@ -96,8 +88,7 @@ class IDELinearConstantAnalysis getCallToRetFlowFunction(n_t CallSite, n_t RetSite, llvm::ArrayRef Callees) override; - FlowFunctionPtrType getSummaryFlowFunction(n_t CallSite, - f_t DestFun) override; + FlowFunctionPtrType getSummaryFlowFunction(n_t Curr, f_t CalleeFun) override; [[nodiscard]] InitialSeeds initialSeeds() override; @@ -107,34 +98,26 @@ class IDELinearConstantAnalysis // 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; + EdgeFunction 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; + EdgeFunction 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 ExitStmt, - d_t ExitNode, n_t RetSite, d_t RetNode) override; + EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, + n_t ExitStmt, d_t ExitNode, + n_t RetSite, d_t RetNode) override; - std::shared_ptr> + EdgeFunction getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode, llvm::ArrayRef 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; + EdgeFunction getSummaryEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, + d_t SuccNode) override; - std::shared_ptr> allTopFunction() override; + EdgeFunction allTopFunction() override; // Helper functions diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h similarity index 69% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h index dd0996fdc..fffad0dd6 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDEProtoAnalysis.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEPROTOANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEPROTOANALYSIS_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include @@ -70,26 +70,25 @@ class IDEProtoAnalysis : public IDETabulationProblem { // 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; + EdgeFunction 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; + EdgeFunction 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; + EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, + n_t ExitInst, d_t ExitNode, + n_t RetSite, d_t RetNode) override; - std::shared_ptr> + EdgeFunction getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode, llvm::ArrayRef Callees) override; - std::shared_ptr> - getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode) override; + EdgeFunction getSummaryEdgeFunction(n_t CallSite, d_t CallNode, + n_t RetSite, + d_t RetSiteNode) override; l_t topElement() override; @@ -97,21 +96,7 @@ class IDEProtoAnalysis : public IDETabulationProblem { l_t join(l_t Lhs, l_t Rhs) override; - std::shared_ptr> allTopFunction() override; - - class IDEProtoAnalysisAllTop - : 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; - }; + EdgeFunction allTopFunction() override; void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h similarity index 67% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h index 9bca773a6..7bc28bbdf 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESECUREHEAPPROPAGATION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESECUREHEAPPROPAGATION_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include "llvm/ADT/StringRef.h" @@ -19,6 +19,21 @@ namespace psr { enum class SecureHeapFact { ZERO, INITIALIZED }; enum class SecureHeapValue { TOP, INITIALIZED, BOT }; +template <> struct JoinLatticeTraits { + static constexpr auto bottom() noexcept { return SecureHeapValue::BOT; } + static constexpr auto top() noexcept { return SecureHeapValue::TOP; } + static constexpr auto join(SecureHeapValue LHS, + SecureHeapValue RHS) noexcept { + if (LHS == RHS || RHS == top()) { + return LHS; + } + if (LHS == top()) { + return RHS; + } + return bottom(); + } +}; + struct IDESecureHeapPropagationAnalysisDomain : LLVMAnalysisDomainDefault { using d_t = SecureHeapFact; using l_t = SecureHeapValue; @@ -27,8 +42,9 @@ struct IDESecureHeapPropagationAnalysisDomain : LLVMAnalysisDomainDefault { class IDESecureHeapPropagation : public IDETabulationProblem { - const llvm::StringLiteral InitializerFn = "CRYPTO_secure_malloc_init"; - const llvm::StringLiteral ShutdownFn = "CRYPTO_secure_malloc_done"; + static constexpr llvm::StringLiteral InitializerFn = + "CRYPTO_secure_malloc_init"; + static constexpr llvm::StringLiteral ShutdownFn = "CRYPTO_secure_malloc_done"; public: using IDETabProblemType = @@ -74,27 +90,25 @@ class IDESecureHeapPropagation // 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; + EdgeFunction 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 DestinationMethod, - d_t DestNode) override; + EdgeFunction getCallEdgeFunction(n_t CallSite, d_t SrcNode, + f_t DestinationMethod, + d_t DestNode) override; - std::shared_ptr> - getReturnEdgeFunction(n_t CallSite, f_t CalleeMethod, n_t ExitInst, - d_t ExitNode, n_t RetSite, d_t RetNode) override; + EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeMethod, + n_t ExitInst, d_t ExitNode, + n_t RetSite, d_t RetNode) override; - std::shared_ptr> + EdgeFunction getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode, llvm::ArrayRef Callees) override; - std::shared_ptr> - getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode) override; + EdgeFunction getSummaryEdgeFunction(n_t CallSite, d_t CallNode, + n_t RetSite, + d_t RetSiteNode) override; l_t topElement() override; @@ -102,7 +116,7 @@ class IDESecureHeapPropagation l_t join(l_t Lhs, l_t Rhs) override; - std::shared_ptr> allTopFunction() override; + EdgeFunction allTopFunction() override; void printEdgeFact(llvm::raw_ostream &OS, l_t L) const override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h similarity index 69% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h index a40697cde..6ae2e387a 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESolverTest.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESOLVERTEST_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDESOLVERTEST_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include @@ -71,26 +71,25 @@ class IDESolverTest : public IDETabulationProblem { // 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; + EdgeFunction 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; + EdgeFunction 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 ExitStmt, - d_t ExitNode, n_t RetSite, d_t RetNode) override; + EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, + n_t ExitStmt, d_t ExitNode, + n_t RetSite, d_t RetNode) override; - std::shared_ptr> + EdgeFunction getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode, llvm::ArrayRef Callees) override; - std::shared_ptr> - getSummaryEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode) override; + EdgeFunction getSummaryEdgeFunction(n_t CallSite, d_t CallNode, + n_t RetSite, + d_t RetSiteNode) override; l_t topElement() override; @@ -98,21 +97,7 @@ class IDESolverTest : public IDETabulationProblem { l_t join(l_t Lhs, l_t Rhs) override; - std::shared_ptr> allTopFunction() override; - - class IDESolverTestAllTop - : 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; - }; + EdgeFunction allTopFunction() override; void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h similarity index 78% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h index efd535d73..2d46060ed 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h @@ -10,9 +10,9 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDETYPESTATEANALYSIS_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IDETabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "llvm/IR/InstrTypes.h" @@ -30,7 +30,8 @@ class Value; namespace psr { -class LLVMPointsToInfo; +class LLVMBasedICFG; +class LLVMTypeHierarchy; struct TypeStateDescription; struct IDETypeStateAnalysisDomain : public LLVMAnalysisDomainDefault { @@ -51,10 +52,7 @@ class IDETypeStateAnalysis using ConfigurationTy = TypeStateDescription; - const l_t TOP; - const l_t BOTTOM; - - IDETypeStateAnalysis(const LLVMProjectIRDB *IRDB, LLVMPointsToInfo *PT, + IDETypeStateAnalysis(const LLVMProjectIRDB *IRDB, LLVMAliasInfoRef PT, const TypeStateDescription *TSD, std::vector EntryPoints = {"main"}); @@ -84,25 +82,25 @@ class IDETypeStateAnalysis // in addition provide specifications for the IDE parts - EdgeFunctionPtrType getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, - d_t SuccNode) override; + EdgeFunction getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, + d_t SuccNode) override; - EdgeFunctionPtrType getCallEdgeFunction(n_t CallSite, d_t SrcNode, - f_t DestinationFunction, - d_t DestNode) override; + EdgeFunction getCallEdgeFunction(n_t CallSite, d_t SrcNode, + f_t DestinationFunction, + d_t DestNode) override; - EdgeFunctionPtrType getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, - n_t ExitInst, d_t ExitNode, - n_t RetSite, d_t RetNode) override; + EdgeFunction getReturnEdgeFunction(n_t CallSite, f_t CalleeFunction, + n_t ExitInst, d_t ExitNode, + n_t RetSite, d_t RetNode) override; - EdgeFunctionPtrType + EdgeFunction getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, d_t RetSiteNode, llvm::ArrayRef Callees) override; - EdgeFunctionPtrType getSummaryEdgeFunction(n_t CallSite, d_t CallNode, - n_t RetSite, - d_t RetSiteNode) override; + EdgeFunction getSummaryEdgeFunction(n_t CallSite, d_t CallNode, + n_t RetSite, + d_t RetSiteNode) override; l_t topElement() override; @@ -118,7 +116,7 @@ class IDETypeStateAnalysis */ l_t join(l_t Lhs, l_t Rhs) override; - EdgeFunctionPtrType allTopFunction() override; + EdgeFunction allTopFunction() override; void printNode(llvm::raw_ostream &OS, n_t Stmt) const override; @@ -133,8 +131,8 @@ class IDETypeStateAnalysis private: const TypeStateDescription *TSD{}; - LLVMPointsToInfo *PT{}; - std::map PointsToCache; + std::map AliasCache; + LLVMAliasInfoRef PT{}; std::map> RelevantAllocaCache; @@ -155,10 +153,10 @@ class IDETypeStateAnalysis * 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 + * might become unnecessary once PhASAR's AliasGraph starts using a cache * itself. */ - std::set getWMPointsToSet(d_t V); + std::set getWMAliasSet(d_t V); /** * @brief Provides whole module aliases and relevant alloca's of V. diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h similarity index 93% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h index 7c3e4bae7..85ca53443 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSConstAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSConstAnalysis.h @@ -10,9 +10,11 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSCONSTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSCONSTANALYSIS_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" +#include #include #include #include @@ -27,7 +29,9 @@ class Value; } // namespace llvm namespace psr { -class LLVMPointsToInfo; + +class LLVMBasedICFG; +class LLVMTypeHierarchy; /** * This IFDS analysis will compute possibly mutable memory @@ -42,7 +46,7 @@ class IFDSConstAnalysis : public IFDSTabulationProblem { public: - IFDSConstAnalysis(const LLVMProjectIRDB *IRDB, LLVMPointsToInfo *PT, + IFDSConstAnalysis(const LLVMProjectIRDB *IRDB, LLVMAliasInfoRef PT, std::vector EntryPoints = {"main"}); ~IFDSConstAnalysis() override = default; @@ -53,7 +57,7 @@ class IFDSConstAnalysis * initialized, i.e. at least one write access occurred, the * pointer operand is generated as a data-flow fact. Also all aliases that * meet the 'context-relevant' requirements (see {@link - * getContextRelevantPointsToSet}) will be generated! + * getContextRelevantAliasSet}) will be generated! * * Otherwise, the memory location (i.e. memory location's pointer operand) is * marked as initialized. @@ -199,14 +203,14 @@ class IFDSConstAnalysis * new data-flow facts will be generated. * @brief Refines the given points-to information to only context-relevant * points-to information. - * @param PointsToSet that is refined. + * @param AliasSet that is refined. * @param Context dictates which points-to information is relevant. */ // clang-format on - static std::set getContextRelevantPointsToSet(std::set &PointsToSet, - f_t Context); + static std::set getContextRelevantAliasSet(std::set &AliasSet, + f_t Context); private: - LLVMPointsToInfo *PT{}; + LLVMAliasInfoRef PT{}; // Holds all allocated memory locations, including global variables std::set AllMemLocs; // FIXME: initialize within the constructor body! // Holds all initialized variables and objects. diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h similarity index 87% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h index 1c892bc39..d64c3993f 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSFieldSensTaintAnalysis.h @@ -5,18 +5,19 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSFIELDSENSTAINTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSFIELDSENSTAINTANALYSIS_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/ExtendedValue.h" +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde//IFDSFieldSensTaintAnalysis/Utils/ExtendedValue.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/IFDSFieldSensTaintAnalysis/Stats/TraceStats.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMZeroValue.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" -#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" +#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.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 #include @@ -36,10 +37,10 @@ struct IFDSFieldSensTaintAnalysisDomain : public LLVMIFDSAnalysisDomainDefault { class IFDSFieldSensTaintAnalysis : public IFDSTabulationProblem { public: - using ConfigurationTy = TaintConfig; + using ConfigurationTy = LLVMTaintConfig; IFDSFieldSensTaintAnalysis(const LLVMProjectIRDB *IRDB, - const TaintConfig *TaintConfig, + const LLVMTaintConfig *TaintConfig, std::vector EntryPoints = {"main"}); ~IFDSFieldSensTaintAnalysis() override = default; @@ -114,7 +115,7 @@ class IFDSFieldSensTaintAnalysis } private: - const TaintConfig *Config{}; + const LLVMTaintConfig *Config{}; TraceStats Stats{}; }; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h similarity index 94% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h index a12032852..ee628992c 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSProtoAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSProtoAnalysis.h @@ -10,7 +10,7 @@ #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/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include @@ -34,8 +34,6 @@ class IFDSProtoAnalysis IFDSProtoAnalysis(const LLVMProjectIRDB *IRDB, std::vector EntryPoints = {"main"}); - ~IFDSProtoAnalysis() override = default; - FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t Succ) override; FlowFunctionPtrType getCallFlowFunction(n_t CallSite, f_t DestFun) override; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h similarity index 96% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h index 7f059e250..a97e4a9c9 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSignAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSignAnalysis.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSIGNANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSIGNANALYSIS_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h similarity index 96% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h index 286cbbf47..69c0ea3eb 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSSolverTest.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSOLVERTEST_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSSOLVERTEST_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h similarity index 89% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h index 63864b19b..7054f4165 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.h @@ -10,8 +10,9 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTAINTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTAINTANALYSIS_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include #include @@ -25,8 +26,7 @@ class CallBase; } // namespace llvm namespace psr { -class LLVMPointsToInfo; -class TaintConfig; +class LLVMTaintConfig; /** * This analysis tracks data-flows through a program. Data flows from @@ -42,7 +42,7 @@ class IFDSTaintAnalysis public: // Setup the configuration type - using ConfigurationTy = TaintConfig; + using ConfigurationTy = LLVMTaintConfig; /// Holds all leaks found during the analysis std::map> Leaks; @@ -53,8 +53,8 @@ class IFDSTaintAnalysis * @param TSF * @param EntryPoints */ - IFDSTaintAnalysis(const LLVMProjectIRDB *IRDB, LLVMPointsToInfo *PT, - const TaintConfig *Config, + IFDSTaintAnalysis(const LLVMProjectIRDB *IRDB, LLVMAliasInfoRef PT, + const LLVMTaintConfig *Config, std::vector EntryPoints = {"main"}); ~IFDSTaintAnalysis() override = default; @@ -89,8 +89,8 @@ class IFDSTaintAnalysis llvm::raw_ostream &OS = llvm::outs()) override; private: - const TaintConfig *Config{}; - LLVMPointsToInfo *PT{}; + const LLVMTaintConfig *Config{}; + LLVMAliasInfoRef PT{}; bool isSourceCall(const llvm::CallBase *CB, const llvm::Function *Callee) const; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h similarity index 96% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h index 6009ba3ce..b8b4e060c 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSTypeAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTypeAnalysis.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTYPEANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IFDSTYPEANALYSIS_H -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h" +#include "phasar/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h similarity index 97% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h index 691549168..46db4b631 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IFDSUninitializedVariables.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h @@ -10,7 +10,7 @@ #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/DataFlow/IfdsIde/IFDSTabulationProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" #include diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h similarity index 96% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h index 581ebb0ec..88e29ef1a 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/CSTDFILEIOTypeStateDescription.h @@ -10,12 +10,12 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_CSTDFILEIOTYPESTATEDESCRIPTION_H +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" + #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" - namespace psr { /** diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h similarity index 93% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h index 88bd82fb3..580a4011a 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFCTXDescription.h @@ -10,16 +10,16 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFCTXDESCRIPTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFCTXDESCRIPTION_H +#include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/Domain/AnalysisDomain.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDETypeStateAnalysis.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" + #include #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDETypeStateAnalysis.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - namespace llvm { class Instruction; class Value; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h similarity index 96% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h index cc068328d..96bd98864 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLEVPKDFDescription.h @@ -10,12 +10,12 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFDESCRIPTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLEVPKDFDESCRIPTION_H +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" + #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" - namespace psr { class OpenSSLEVPKDFDescription : public TypeStateDescription { public: diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h similarity index 89% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h index 1f8bde2c2..ca1205856 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureHeapDescription.h @@ -10,15 +10,15 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREHEAPDESCRIPTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREHEAPDESCRIPTION_H +#include "phasar/DataFlow/IfdsIde/Solver/IDESolver.h" +#include "phasar/Domain/AnalysisDomain.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IDESecureHeapPropagation.h" +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" + #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDESecureHeapPropagation.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Solver/IDESolver.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" - namespace psr { class OpenSSLSecureHeapDescription : public TypeStateDescription { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h similarity index 95% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h index 9f370012a..9078d0321 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/OpenSSLSecureMemoryDescription.h @@ -10,12 +10,12 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREMEMORYDESCRIPTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_OPENSSLSECUREMEMORYDESCRIPTION_H +#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" + #include #include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h" - namespace psr { class OpenSSLSecureMemoryDescription : public TypeStateDescription { diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h similarity index 100% rename from include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h rename to include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h index 84e3ab52c..4302cb0a1 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h +++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/TypeStateDescriptions/TypeStateDescription.h @@ -10,11 +10,11 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_TYPESTATEDESCRIPTIONS_TYPESTATEDESCRIPTION_H +#include "llvm/IR/InstrTypes.h" + #include #include -#include "llvm/IR/InstrTypes.h" - namespace psr { /** diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h similarity index 91% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h rename to include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h index 046f5f0f4..c2ab701a7 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoFullConstantPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoFullConstantPropagation.h @@ -10,10 +10,11 @@ #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/DataFlow/Mono/InterMonoProblem.h" +#include "phasar/Domain/LatticeDomain.h" +#include "phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" -#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include #include @@ -32,7 +33,6 @@ namespace psr { class LLVMBasedICFG; class LLVMTypeHierarchy; -class LLVMPointsToInfo; class InterMonoFullConstantPropagation : public IntraMonoFullConstantPropagation, @@ -50,7 +50,7 @@ class InterMonoFullConstantPropagation InterMonoFullConstantPropagation(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, const LLVMBasedICFG *ICF, - const LLVMPointsToInfo *PT, + LLVMAliasInfoRef PT, std::vector EntryPoints = {}); ~InterMonoFullConstantPropagation() override = default; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h similarity index 94% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h rename to include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h index 7b8cadb5e..2c5446829 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoSolverTest.h @@ -17,8 +17,9 @@ #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/DataFlow/Mono/InterMonoProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/Utils/BitVectorSet.h" #include @@ -35,7 +36,6 @@ class StructType; namespace psr { -class LLVMPointsToInfo; class LLVMTypeHierarchy; struct InterMonoSolverTestDomain : LLVMAnalysisDomainDefault { @@ -53,7 +53,7 @@ class InterMonoSolverTest : public InterMonoProblem { using mono_container_t = InterMonoSolverTestDomain::mono_container_t; InterMonoSolverTest(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedICFG *ICF, const LLVMPointsToInfo *PT, + const LLVMBasedICFG *ICF, LLVMAliasInfoRef PT, std::vector EntryPoints = {}); ~InterMonoSolverTest() override = default; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h similarity index 90% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h rename to include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h index ed97f674b..36bcc8439 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/InterMonoTaintAnalysis.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/InterMonoTaintAnalysis.h @@ -17,10 +17,11 @@ #ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOTAINTANALYSIS_H #define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_PROBLEMS_INTERMONOTAINTANALYSIS_H +#include "phasar/DataFlow/Mono/InterMonoProblem.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h" -#include "phasar/PhasarLLVM/DataFlowSolver/Mono/InterMonoProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" -#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" +#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" #include "phasar/Utils/BitVectorSet.h" #include @@ -36,7 +37,6 @@ class StructType; namespace psr { -class LLVMPointsToInfo; class LLVMTypeHierarchy; struct InterMonoTaintAnalysisDomain : LLVMAnalysisDomainDefault { @@ -53,11 +53,11 @@ class InterMonoTaintAnalysis using v_t = InterMonoTaintAnalysisDomain::v_t; using i_t = InterMonoTaintAnalysisDomain::i_t; using mono_container_t = InterMonoTaintAnalysisDomain::mono_container_t; - using ConfigurationTy = TaintConfig; + using ConfigurationTy = LLVMTaintConfig; InterMonoTaintAnalysis(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, const LLVMBasedICFG *ICF, - const LLVMPointsToInfo *PT, const TaintConfig &Config, + LLVMAliasInfoRef PT, const LLVMTaintConfig &Config, std::vector EntryPoints = {}); ~InterMonoTaintAnalysis() override = default; @@ -91,7 +91,7 @@ class InterMonoTaintAnalysis [[nodiscard]] const std::map> &getAllLeaks() const; private: - [[maybe_unused]] const TaintConfig &Config; + [[maybe_unused]] const LLVMTaintConfig &Config; std::map> Leaks; }; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoFullConstantPropagation.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h similarity index 93% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoFullConstantPropagation.h rename to include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h index 08aff4aa4..d8b64028e 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoFullConstantPropagation.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoFullConstantPropagation.h @@ -17,9 +17,10 @@ #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/DataFlow/Mono/IntraMonoProblem.h" +#include "phasar/Domain/LatticeDomain.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" -#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/Utils/BitVectorSet.h" #include @@ -41,7 +42,6 @@ namespace psr { class LLVMBasedCFG; class LLVMBasedICFG; class LLVMTypeHierarchy; -class LLVMPointsToInfo; class InterMonoFullConstantPropagation; struct IntraMonoFullConstantPropagationAnalysisDomain @@ -76,8 +76,7 @@ class IntraMonoFullConstantPropagation public: IntraMonoFullConstantPropagation(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedCFG *CF, - const LLVMPointsToInfo *PT, + const LLVMBasedCFG *CF, LLVMAliasInfoRef PT, std::vector EntryPoints = {}); ~IntraMonoFullConstantPropagation() override = default; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoSolverTest.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h similarity index 93% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoSolverTest.h rename to include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h index d0e81b6b6..cae80de31 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoSolverTest.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoSolverTest.h @@ -17,8 +17,9 @@ #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/DataFlow/Mono/IntraMonoProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/Utils/BitVectorSet.h" #include @@ -37,7 +38,6 @@ namespace psr { class LLVMBasedCFG; class LLVMBasedICFG; class LLVMTypeHierarchy; -class LLVMPointsToInfo; struct IntraMonoSolverTestAnalysisDomain : public LLVMAnalysisDomainDefault { using mono_container_t = BitVectorSet; @@ -55,7 +55,7 @@ class IntraMonoSolverTest using mono_container_t = IntraMonoSolverTestAnalysisDomain::mono_container_t; IntraMonoSolverTest(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, - const LLVMBasedCFG *CF, const LLVMPointsToInfo *PT, + const LLVMBasedCFG *CF, LLVMAliasInfoRef PT, std::vector EntryPoints = {}); ~IntraMonoSolverTest() override = default; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoUninitVariables.h b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h similarity index 94% rename from include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoUninitVariables.h rename to include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h index 902a23df9..c3d4ac5a4 100644 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/Problems/IntraMonoUninitVariables.h +++ b/include/phasar/PhasarLLVM/DataFlow/Mono/Problems/IntraMonoUninitVariables.h @@ -10,8 +10,9 @@ #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/DataFlow/Mono/IntraMonoProblem.h" #include "phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include #include @@ -28,7 +29,6 @@ class StructType; namespace psr { class LLVMTypeHierarchy; -class LLVMPointsToInfo; class LLVMBasedCFG; class LLVMBasedICFG; @@ -49,7 +49,7 @@ class IntraMonoUninitVariables IntraMonoUninitVariables(const LLVMProjectIRDB *IRDB, const LLVMTypeHierarchy *TH, const LLVMBasedCFG *CF, - const LLVMPointsToInfo *PT, + LLVMAliasInfoRef PT, std::vector EntryPoints = {}); ~IntraMonoUninitVariables() override = default; diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h deleted file mode 100644 index 0318c6b2a..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h +++ /dev/null @@ -1,102 +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_EDGEFUNCTIONCOMPOSER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_EDGEFUNCTIONCOMPOSER_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" - -#include - -namespace psr { - -/** - * This abstract class models edge function composition. It holds two edge - * functions. The edge function computation order is implemented as - * F -> G -> otherFunction - * i.e. F is computed before G, G is computed before otherFunction. - * - * Note that an own implementation for the join function is required, since - * this varies between different analyses, and is not implemented by this - * class. - * It is also advised to provide a more precise compose function, which is able - * to reduce the result of the composition, rather than using the default - * implementation. By default, an explicit composition is used. Such a function - * definition can grow unduly large. - */ -template -class EdgeFunctionComposer - : public EdgeFunction, - public std::enable_shared_from_this> { -public: - using typename EdgeFunction::EdgeFunctionPtrType; - -private: - // For debug purpose only - const unsigned EFComposerId; - static inline unsigned CurrEFComposerId = 0; // NOLINT - -protected: - /// First edge function - EdgeFunctionPtrType F; - /// Second edge function - EdgeFunctionPtrType G; - -public: - EdgeFunctionComposer(EdgeFunctionPtrType &F, EdgeFunctionPtrType &G) - : EFComposerId(++CurrEFComposerId), F(F), G(G) {} - - ~EdgeFunctionComposer() override = default; - - /** - * Target value computation is implemented as - * G(F(source)) - */ - L computeTarget(L Source) override { - return G->computeTarget(F->computeTarget(Source)); - } - - /** - * Function composition is implemented as an explicit composition, i.e. - * (secondFunction * G) * F = EFC(F, EFC(G , otherFunction)) - * - * However, it is advised to immediately reduce the resulting edge function - * by providing an own implementation of this function. - */ - EdgeFunctionPtrType composeWith(EdgeFunctionPtrType SecondFunction) override { - if (auto *EI = dynamic_cast *>(SecondFunction.get())) { - return this->shared_from_this(); - } - if (auto *AB = dynamic_cast *>(SecondFunction.get())) { - return this->shared_from_this(); - } - return F->composeWith(G->composeWith(SecondFunction)); - } - - // virtual EdgeFunctionPtrType - // joinWith(EdgeFunctionPtrType otherFunction) = 0; - - bool equal_to // NOLINT - would break too many client analyses - (EdgeFunctionPtrType Other) const override { - if (auto EFC = dynamic_cast *>(Other.get())) { - return F->equal_to(EFC->F) && G->equal_to(EFC->G); - } - return false; - } - - void print(llvm::raw_ostream &OS, - bool /*IsForDebug = false*/) const override { - OS << "COMP[ " << F.get()->str() << " , " << G.get()->str() - << " ] (EF:" << EFComposerId << ')'; - } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h deleted file mode 100644 index 4fcc0a884..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h +++ /dev/null @@ -1,629 +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 - *****************************************************************************/ - -/* - * AbstractEdgeFunctions.h - * - * Created on: 04.08.2016 - * Author: pdschbrt - */ - -#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" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace psr { -namespace internal { -struct TestEdgeFunction; -} // namespace internal - -// -// This class models an edge function for distributive data-flow problems. -// -// An edge function describes a value computation problem along an exploded -// supergraph edge. -// -template class EdgeFunction { -public: - using EdgeFunctionPtrType = std::shared_ptr>; - - virtual ~EdgeFunction() = default; - - // - // This function describes the concrete value computation for its respective - // exploded supergraph edge. The function(s) will be evaluated once the - // exploded supergraph has been constructed and the concrete values of the - // various value computation problems along the supergraph edges are - // evaluated. - // - // Please also refer to the various edge function factories of the - // EdgeFunctions interface: EdgeFunctions::get*EdgeFunction() for more - // details. - // - [[nodiscard]] virtual L computeTarget(L Source) = 0; - - // - // This function composes the two edge functions this and SecondFunction. This - // function is used to extend an edge function in order to construct so-called - // jump functions that describe the effects of everlonger sequences of code. - // - [[nodiscard]] virtual EdgeFunctionPtrType - composeWith(EdgeFunctionPtrType SecondFunction) = 0; - - // - // This function describes the join of the two edge functions this and - // OtherFunction. The function is called whenever two edge functions need to - // be joined, for instance, when two branches lead to a common successor - // instruction. - // - [[nodiscard]] virtual EdgeFunctionPtrType - joinWith(EdgeFunctionPtrType OtherFunction) = 0; - - [[nodiscard]] virtual bool - equal_to // NOLINT - would break too many client analyses - (EdgeFunctionPtrType OtherFunction) const = 0; - - virtual void print(llvm::raw_ostream &OS, - [[maybe_unused]] bool IsForDebug = false) const { - OS << "EdgeFunction"; - } - - [[nodiscard]] std::string str() { - std::string Buffer; - llvm::raw_string_ostream OSS(Buffer); - print(OSS); - return OSS.str(); - } -}; - -template -static inline bool operator==(const EdgeFunction &F, - const EdgeFunction &G) { - return F.equal_to(G); -} - -template -static inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const EdgeFunction &F) { - F.print(OS); - return OS; -} - -template -class AllTop : public EdgeFunction, - public std::enable_shared_from_this> { -public: - using typename EdgeFunction::EdgeFunctionPtrType; - -private: - const L TopElement; - -public: - AllTop(L TopElement) : TopElement(std::move(TopElement)) {} - - ~AllTop() override = default; - - L computeTarget(L /*Source*/) override { return TopElement; } - - EdgeFunctionPtrType - composeWith(EdgeFunctionPtrType /*SecondFunction*/) override { - return this->shared_from_this(); - } - - EdgeFunctionPtrType joinWith(EdgeFunctionPtrType OtherFunction) override { - return OtherFunction; - } - - [[nodiscard]] bool equal_to // NOLINT - would break too many client analyses - (EdgeFunctionPtrType Other) const override { - if (auto *Alltop = dynamic_cast *>(Other.get())) { - return (Alltop->TopElement == TopElement); - } - return false; - } - - void print(llvm::raw_ostream &OS, - [[maybe_unused]] bool IsForDebug = false) const override { - OS << "AllTop"; - } -}; - -template class EdgeIdentity; - -template -class AllBottom : public EdgeFunction, - public std::enable_shared_from_this> { -public: - using typename EdgeFunction::EdgeFunctionPtrType; - -private: - const L BottomElement; - -public: - AllBottom(L BottomElement) : BottomElement(std::move(BottomElement)) {} - - ~AllBottom() override = default; - - L computeTarget(L /*Source*/) override { return BottomElement; } - - EdgeFunctionPtrType - composeWith(EdgeFunctionPtrType /*SecondFunction*/) override { - return this->shared_from_this(); - } - - EdgeFunctionPtrType joinWith(EdgeFunctionPtrType /*OtherFunction*/) override { - return this->shared_from_this(); - } - - [[nodiscard]] bool equal_to // NOLINT - would break too many client analyses - (EdgeFunctionPtrType Other) const override { - if (auto *AB = dynamic_cast *>(Other.get())) { - return (AB->BottomElement == BottomElement); - } - return false; - } - - void print(llvm::raw_ostream &OS, - bool /*IsForDebug = false*/) const override { - OS << "AllBottom"; - } -}; - -template -class EdgeIdentity : public EdgeFunction, - public std::enable_shared_from_this> { -public: - using typename EdgeFunction::EdgeFunctionPtrType; - -private: - EdgeIdentity() = default; - -public: - EdgeIdentity(const EdgeIdentity &EI) = delete; - - EdgeIdentity &operator=(const EdgeIdentity &EI) = delete; - - ~EdgeIdentity() override = default; - - L computeTarget(L Source) override { return Source; } - - EdgeFunctionPtrType composeWith(EdgeFunctionPtrType SecondFunction) override { - return SecondFunction; - } - - EdgeFunctionPtrType joinWith(EdgeFunctionPtrType OtherFunction) override { - if ((OtherFunction.get() == this) || - OtherFunction->equal_to(this->shared_from_this())) { - return this->shared_from_this(); - } - if (auto *AB = dynamic_cast *>(OtherFunction.get())) { - return OtherFunction; - } - if (auto *AT = dynamic_cast *>(OtherFunction.get())) { - return this->shared_from_this(); - } - // do not know how to join; hence ask other function to decide on this - return OtherFunction->joinWith(this->shared_from_this()); - } - - [[nodiscard]] bool equal_to // NOLINT - would break too many client analyses - (EdgeFunctionPtrType Other) const override { - return this == Other.get(); - } - - static EdgeFunctionPtrType getInstance() { - // implement singleton C++11 thread-safe (see Scott Meyers) - static EdgeFunctionPtrType Instance(new EdgeIdentity()); - return Instance; - } - - void print(llvm::raw_ostream &OS, - bool /*IsForDebug = false*/) const override { - OS << "EdgeIdentity"; - } -}; - -//===----------------------------------------------------------------------===// -// EdgeFunctions interface - -template class EdgeFunctions { -public: - using n_t = typename AnalysisDomainTy::n_t; - using d_t = typename AnalysisDomainTy::d_t; - using f_t = typename AnalysisDomainTy::f_t; - using l_t = typename AnalysisDomainTy::l_t; - - using EdgeFunctionType = EdgeFunction; - using EdgeFunctionPtrType = typename EdgeFunctionType::EdgeFunctionPtrType; - - virtual ~EdgeFunctions() = default; - - // - // Also refer to FlowFunctions::getNormalFlowFunction() - // - // Describes a value computation problem along a normal (non-call, non-return) - // intra-procedural exploded supergraph edge. A normal edge function - // implementation is queried for each edge that has been generated by appling - // the flow function returned by FlowFunctions::getNormalFlowFunction(). The - // supergraph edge whose computation is requested is defined by the supergraph - // nodes CurrNode and SuccNode. - // - // Let instruction_1 := Curr, instruction_2 := Succ, and 0 the tautological - // lambda fact. - // - // The concrete implementation of an edge function e is depending on the - // analysis problem. In the following, we present a brief, contrived example: - // - // Consider the following flow function implementation (cf. - // FlowFunctions::getNormalFlowfunction()): - // - // f(0) -> {0} // pass the lambda (or zero fact) as identity - // f(o) -> {o, x} // generate a new fact x from o - // f(.) -> {.} // pass all other facts that hold before instruction_1 - // // as identity - // - // The above flow-function implementation corresponds to the following edges - // in the exploded supergraph. - // - // 0 o ... - // | |\ ... - // Curr := x = instruction_1 o p | | \ ... - // | | | ... - // v v v ... - // 0 o x ... - // - // Succ := y = instruction_2 q r - // - // For each edge generated by the respective flow function a normal edge - // function is queried that describes a value computation. This results in the - // following queries: - // - // getNormalEdgeFunction(0, Curr, 0 Succ); - // getNormalEdgeFunction(o, Curr, o Succ); - // getNormalEdgeFunction(o, Curr, x Succ); - // - virtual EdgeFunctionPtrType getNormalEdgeFunction(n_t Curr, d_t CurrNode, - n_t Succ, d_t SuccNode) = 0; - - // - // Also refer to FlowFunctions::getCallFlowFunction() - // - // Describes a value computation problem along a call flow. A call edge - // function is queried for each edge that has been generated by applying the - // flow function that has been returned by FlowFunctions::getCallFlowFunction. - // The supergraph edge whose computation is requested is defined by the - // supergraph nodes SrcNode and DestNode. - // - // The concrete implementation of an edge function e is depending on the - // analysis problem. In the following, we present a brief, contrived example: - // - // Consider the following flow function implementation (cf. - // FlowFunctions::getCallFlowFunction()): - // - // f(0) -> {0} // pass as identity into the callee target - // f(o) -> {q} // map actual o into formal q - // f(p) -> {r} // map actual p into formal r - // f(.) -> {} // kill all other facts that are not visible to the - // // callee target - // - // The above implementation corresponds to the following edges in the exploded - // supergraph. - // - // 0 o p ... - // \ \ \ ... - // CallInst := x = CalleeFun(o, p, ...) \ \ +----------------+ - // \ +---------------- | - // +-------------+ + | - // ... | | | - // ... | | | - // 0 o p ... | | | - // | | | - // | | | - // | | | - // Ty CalleeFun(q, r, ...) | | | - // v v v - // 0 q r ... - // - // start point - // - // For each edge generated by the respective flow function a call edge - // function is queried that describes a value computation. This results in the - // following queries: - // - // getCallEdgeFunction(CallInst, 0, CalleeFun, 0); - // getCallEdgeFunction(CallInst, o, CalleeFun, q); - // getCallEdgeFunction(CallInst, p, CalleeFun, r); - // - virtual EdgeFunctionPtrType getCallEdgeFunction(n_t CallInst, d_t SrcNode, - f_t CalleeFun, - d_t DestNode) = 0; - - // - // Also refer to FlowFunction::getRetFlowFunction() - // - // Describes a value computation problem along a return flow. A return edge - // function implementation is queried for each edge that has been generated by - // applying the flow function that has been returned by - // FlowFunctions::getRetFlowFunction(). The supergraph edge whose computation - // is requested is defined by the supergraph nodes ExitNode and RetNode. - // - // The concrete implementation of an edge function e is depending on the - // analysis problem. In the following, we present a brief, contrived example: - // - // Consider the following flow function implementation (cf. - // FlowFunctions::getRetFlowFunction()): - // - // f(0) -> {0} // pass as identity into the callee target - // f(r) -> {x} // map return value to lhs variable at CallSite - // f(q) -> {o} // map pointer-typed formal q to actual o - // f(.) -> {} // kill all other facts that are not visible to the - // // caller - // - // The above implementation corresponds to the following edges in the exploded - // supergraph. - // - // 0 o ... - // - // CallSite = RetSite := x = CalleeFun(o, ...) - // +------------------+ - // +--|---------------+ | - // +--|--|------------+ | | - // v v v ... | | | - // 0 o x ... | | | - // | | | - // | | | - // | | | - // Ty CalleeFun(q, ...) | | | - // | | | - // 0 q r - // - // ExitInst := return r - // - // For each edge generated by the respective flow function a return edge - // function is queried that describes a value computation. This results in the - // following queries: - // - // getReturnEdgeFunction(CallSite, CalleeFun, ExitInst, 0, RetSite, 0); - // getReturnEdgeFunction(CallSite, CalleeFun, ExitInst, q, RetSite, o); - // getReturnEdgeFunction(CallSite, CalleeFun, ExitInst, r, RetSite, x); - // - virtual EdgeFunctionPtrType getReturnEdgeFunction(n_t CallSite, f_t CalleeFun, - n_t ExitInst, d_t ExitNode, - n_t RetSite, - d_t RetNode) = 0; - - // - // Also refer to FlowFunctions::getCallToRetFlowFunction() - // - // Describes a value computation problem along data-flows alongsite a - // CallSite. A return edge function implementation is queried for each edge - // that has been generated by applying the flow function that has been - // returned by FlowFunctions::getCallToRetFlowFunction(). The supergraph edge - // whose computation is requested is defined by the supergraph nodes CallNode - // and RetSiteNode. - // - // The concrete implementation of an edge function e is depending on the - // analysis problem. In the following, we present a brief, contrived example: - // - // Consider the following flow function implementation (cf. - // FlowFunctions::getCallToRetFlowFunction()): - // - // f(0) -> {0} // pass lambda as identity alongsite the CallSite - // f(o) -> {o} // assuming that o is passed by value, it is passed - // // alongsite the CallSite - // f(p) -> {} // assuming that p is a pointer-typed value, we need - // // to kill p, as it will be handled by the call- and - // // return-flow functions - // f(.) -> {.} // pass everything that is not involved in the call as - // // identity - // - // The above implementation corresponds to the following edges in the exploded - // supergraph. - // - // 0 o ... - // | | - // | +-------+ - // +--------+ | - // | | - // CallSite = RetSite := x = CalleeFun(o, p, ...) | | - // | | - // +--------+ | - // | +-------+ - // v v - // 0 o x ... - // - // For each edge generated by the respective flow function a call-to-return - // edge function is queried that describes a value computation. This results - // in the following queries: - // - // getCallToRetEdgeFunction(CallSite, 0, RetSite, 0, {CalleeFun}); - // getCallToRetEdgeFunction(CallSite, o, RetSite, o, {CalleeFun}); - // - virtual EdgeFunctionPtrType - getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t RetSite, - d_t RetSiteNode, llvm::ArrayRef Callees) = 0; - - // - // Also refer to FlowFunction::getSummaryFlowFunction() - // - // Describes a value computation problem along a summary data flow. A summary - // edge function implementation is queried for each edge that has been - // generated by FlowFunctions::getSummaryFlowFunction(). The supergraph edge - // whose computation is requested is defined by the supergraph nodes CurrNode - // and SuccNode. - // - // The default implementation returns a nullptr to indicate that the mechanism - // should not be used. - // - virtual EdgeFunctionPtrType - getSummaryEdgeFunction(n_t Curr, d_t CurrNode, n_t Succ, d_t SuccNode) = 0; -}; - -// This class can be used as a singleton factory for EdgeFunctions that only -// have constant data. -// -// EdgeFunction that have constant data only need to be allocated once and can -// be turned into a singleton, which save large amounts of memory. The -// automatic singleton creation can be enabled for a EdgeFunction class by -// inheriting from EdgeFunctionSingletonFactory and only allocating -// EdgeFunction throught the provided createEdgeFunction method. -// -// Old unused EdgeFunction that were deallocated need to/should be clean from -// the factory by either calling cleanExpiredEdgeFunctions or initializing the -// automatic cleaner thread with initEdgeFunctionCleaner. -template -class EdgeFunctionSingletonFactory { -public: - EdgeFunctionSingletonFactory() = default; - EdgeFunctionSingletonFactory(const EdgeFunctionSingletonFactory &) = default; - EdgeFunctionSingletonFactory & - operator=(const EdgeFunctionSingletonFactory &) = default; - EdgeFunctionSingletonFactory(EdgeFunctionSingletonFactory &&) noexcept = - default; - EdgeFunctionSingletonFactory & - operator=(EdgeFunctionSingletonFactory &&) noexcept = default; - - virtual ~EdgeFunctionSingletonFactory() { - std::lock_guard DataLock(getCacheData().DataMutex); - } - - // Creates a new EdgeFunction of type EdgeFunctionType, reusing the previous - // allocation if an EdgeFunction with the same values was already created. - static inline std::shared_ptr - createEdgeFunction(CtorArgT K) { - std::lock_guard DataLock(getCacheData().DataMutex); - - auto &Storage = getCacheData().Storage; - auto SearchVal = Storage.find(K); - if (SearchVal != Storage.end() && !SearchVal->second.expired()) { - return SearchVal->second.lock(); - } - auto NewEdgeFunc = std::make_shared(K); - Storage[K] = NewEdgeFunc; - return NewEdgeFunc; - } - - // Initialize a cleaner thread to automatically remove unused/expired - // EdgeFunctions. The thread is only started the first time this function is - // called. - static inline void initEdgeFunctionCleaner() { getCleaner(); } - - static inline void stopEdgeFunctionCleaner() { getCleaner().stop(); } - - // Clean all unused/expired EdgeFunctions from the internal storage. - static inline void cleanExpiredEdgeFunctions() { - cleanExpiredMapEntries(getCacheData()); - } - - LLVM_DUMP_METHOD - static void dump(bool PrintElements = false) { - std::lock_guard DataLock(getCacheData().DataMutex); - - llvm::outs() << "Elements in cache: " << getCacheData().Storage.size(); - - if (PrintElements) { - llvm::outs() << "\n"; - for (auto &KVPair : getCacheData().Storage) { - llvm::outs() << "(" << KVPair.first << ") -> " - << KVPair.second.expired() << '\n'; - } - } - llvm::outs() << '\n'; - } - -private: - struct EFStorageData { - std::map> Storage{}; - std::mutex DataMutex; - }; - - static inline EFStorageData &getCacheData() { - static EFStorageData StoredData{}; - return StoredData; - } - - static void cleanExpiredMapEntries(EFStorageData &CData) { - std::lock_guard DataLock(CData.DataMutex); - - auto &Storage = CData.Storage; - for (auto Iter = Storage.begin(); Iter != Storage.end();) { - if (Iter->second.expired()) { - Iter = Storage.erase(Iter); - } else { - ++Iter; - } - } - } - - class EdgeFactoryStorageCleaner { - public: - EdgeFactoryStorageCleaner() - : CleanerThread(&EdgeFactoryStorageCleaner::runCleaner, this, - std::reference_wrapper( - EdgeFunctionSingletonFactory::getCacheData())) { -#ifdef __linux__ - pthread_setname_np(CleanerThread.native_handle(), - "EdgeFactoryStorageCleanerThread"); -#endif - } - EdgeFactoryStorageCleaner(const EdgeFactoryStorageCleaner &) = delete; - EdgeFactoryStorageCleaner & - operator=(const EdgeFactoryStorageCleaner &) = delete; - EdgeFactoryStorageCleaner(EdgeFactoryStorageCleaner &&) = delete; - EdgeFactoryStorageCleaner &operator=(EdgeFactoryStorageCleaner &&) = delete; - ~EdgeFactoryStorageCleaner() { stop(); } - - // Stops the cleaning thread running in the background. - void stop() { - KeepRunning = false; - if (CleanerThread.joinable()) { - CleanerThread.join(); - } - } - - private: - void runCleaner(EFStorageData &CData) { - while (KeepRunning) { - std::this_thread::sleep_for(CleaningPauseTime); - cleanExpiredMapEntries(CData); - } - } - - static constexpr auto CleaningPauseTime = std::chrono::seconds(2); - - std::atomic_bool KeepRunning{true}; - std::thread CleanerThread; - }; - - static inline EdgeFactoryStorageCleaner &getCleaner() { - static EdgeFactoryStorageCleaner EdgeFunctionCleaner{}; - return EdgeFunctionCleaner; - } - - friend internal::TestEdgeFunction; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h deleted file mode 100644 index d0a5aa284..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSTabulationProblem.h +++ /dev/null @@ -1,103 +0,0 @@ -/****************************************************************************** - * 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_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_IFDSTABULATIONPROBLEM_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" -#include "phasar/PhasarLLVM/Utils/BinaryDomain.h" - -#include -#include - -namespace psr { - -template > -class IFDSTabulationProblem - : public IDETabulationProblem, - Container> { - using Base = - IDETabulationProblem, Container>; - -public: - 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; - - EdgeFunctionPtrType getNormalEdgeFunction(n_t /*Curr*/, d_t /*CurrNode*/, - n_t /*Succ*/, - d_t /*SuccNode*/) final { - return EdgeIdentity::getInstance(); - } - - EdgeFunctionPtrType getCallEdgeFunction(n_t /*CallInst*/, d_t /*SrcNode*/, - f_t /*CalleeFun*/, - d_t /*DestNode*/) final { - return EdgeIdentity::getInstance(); - } - - EdgeFunctionPtrType getReturnEdgeFunction(n_t /*CallSite*/, f_t /*CalleeFun*/, - n_t /*ExitInst*/, d_t /*ExitNode*/, - n_t /*RetSite*/, - d_t /*RetNode*/) final { - return EdgeIdentity::getInstance(); - } - - EdgeFunctionPtrType - getCallToRetEdgeFunction(n_t /*CallSite*/, d_t /*CallNode*/, n_t /*RetSite*/, - d_t /*RetSiteNode*/, - llvm::ArrayRef /*Callees*/) final { - return EdgeIdentity::getInstance(); - } - - EdgeFunctionPtrType getSummaryEdgeFunction(n_t /*Curr*/, d_t /*CurrNode*/, - n_t /*Succ*/, - d_t /*SuccNode*/) final { - return EdgeIdentity::getInstance(); - } - - BinaryDomain topElement() final { return BinaryDomain::TOP; } - - BinaryDomain bottomElement() final { return BinaryDomain::BOTTOM; } - - BinaryDomain join(BinaryDomain Lhs, BinaryDomain Rhs) final { - if (Lhs == BinaryDomain::TOP && Rhs == BinaryDomain::TOP) { - return BinaryDomain::TOP; - } - return BinaryDomain::BOTTOM; - } - - EdgeFunctionPtrType allTopFunction() final { - static EdgeFunctionPtrType AllTopFn = - std::make_shared>(BinaryDomain::TOP); - return AllTopFn; - } - - void printEdgeFact(llvm::raw_ostream &OS, BinaryDomain Val) const final { - OS << Val; - } -}; -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/JoinLattice.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/JoinLattice.h deleted file mode 100644 index 095422c9c..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/JoinLattice.h +++ /dev/null @@ -1,33 +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 - *****************************************************************************/ - -/* - * AbstractJoinLattice.h - * - * Created on: 04.08.2016 - * Author: pdschbrt - */ - -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_JOINLATTICE_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_JOINLATTICE_H - -namespace psr { - -template class JoinLattice { -public: - using l_t = typename AnalysisDomainTy::l_t; - - virtual ~JoinLattice() = default; - virtual l_t topElement() = 0; - virtual l_t bottomElement() = 0; - virtual l_t join(l_t Lhs, l_t Rhs) = 0; -}; -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h deleted file mode 100644 index 478f2a917..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/ComposeEdgeFunction.h +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_COMPOSEEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_COMPOSEEDGEFUNCTION_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" - -namespace psr::XTaint { -class ComposeEdgeFunction : public EdgeFunctionBase { - EdgeFunctionPtrType F, G; - -public: - ComposeEdgeFunction(BasicBlockOrdering &BBO, EdgeFunctionPtrType F, - EdgeFunctionPtrType G); - - l_t computeTarget(l_t Source) override; - - bool equal_to(EdgeFunctionPtrType Other) const override; - - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - - llvm::hash_code getHashCode() const override; - - static inline bool classof(const EdgeFunctionBase *EF) { - return EF->getKind() == EFKind::Compose; - } -}; -} // namespace psr::XTaint - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/DebugEdgeIdentity.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/DebugEdgeIdentity.h deleted file mode 100644 index 4c665e880..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/DebugEdgeIdentity.h +++ /dev/null @@ -1,42 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2021 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_DEBUGEDGEIDENTITY_H_ -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_DEBUGEDGEIDENTITY_H_ - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" - -namespace llvm { -class Instruction; -} // namespace llvm - -namespace psr::XTaint { -class DebugEdgeIdentity - : public EdgeFunction, - public std::enable_shared_from_this { - const llvm::Instruction *Inst; - -public: - using typename EdgeFunction::EdgeFunctionPtrType; - DebugEdgeIdentity(const llvm::Instruction *Inst); - - EdgeDomain computeTarget(EdgeDomain Source) override; - - EdgeFunctionPtrType composeWith(EdgeFunctionPtrType SecondFunction) override; - - EdgeFunctionPtrType joinWith(EdgeFunctionPtrType OtherFunction) override; - - bool equal_to(EdgeFunctionPtrType Other) const override; - - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; -}; -} // namespace psr::XTaint - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h deleted file mode 100644 index a90c858e5..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/GenEdgeFunction.h +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_GENEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_GENEDGEFUNCTION_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" - -namespace llvm { -class Instruction; -} // namespace llvm - -namespace psr::XTaint { -class GenEdgeFunction : public EdgeFunctionBase { - const llvm::Instruction *Sani; - -public: - GenEdgeFunction(BasicBlockOrdering &BBO, const llvm::Instruction *Sani); - - l_t computeTarget(l_t Source) override; - - EdgeFunctionPtrType composeWith(EdgeFunctionPtrType SecondFunction) override; - - EdgeFunctionPtrType joinWith(EdgeFunctionPtrType OtherFunction) override; - - bool equal_to(EdgeFunctionPtrType OtherFunction) const override; - - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - - inline const llvm::Instruction *getSanitizer() const { return Sani; } - - static inline bool classof(const EdgeFunctionBase *EF) { - return EF->getKind() == EFKind::Gen; - } - - llvm::hash_code getHashCode() const override; -}; -} // namespace psr::XTaint - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/JoinConstEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/JoinConstEdgeFunction.h deleted file mode 100644 index 4e7a025c7..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/JoinConstEdgeFunction.h +++ /dev/null @@ -1,44 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_JOINCONSTEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_JOINCONSTEDGEFUNCTION_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" - -namespace psr::XTaint { -class JoinConstEdgeFunction : public EdgeFunctionBase { - EdgeFunctionPtrType OtherFn; - const llvm::Instruction *OtherConst; - -public: - JoinConstEdgeFunction(BasicBlockOrdering &BBO, EdgeFunctionPtrType OtherFn, - const llvm::Instruction *OtherConst); - - l_t computeTarget(l_t Source) override; - - EdgeFunctionPtrType joinWith(EdgeFunctionPtrType OtherFunction) override; - - bool equal_to(EdgeFunctionPtrType OtherFunction) const override; - - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - - inline const llvm::Instruction *getConstant() const { return OtherConst; } - - inline const EdgeFunctionPtrType &getFunction() const { return OtherFn; } - - llvm::hash_code getHashCode() const override; - - inline static bool classof(const EdgeFunctionBase *EF) { - return EF->getKind() == EFKind::JoinConst; - } -}; -} // namespace psr::XTaint - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/JoinEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/JoinEdgeFunction.h deleted file mode 100644 index ecd2691a7..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/JoinEdgeFunction.h +++ /dev/null @@ -1,96 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_JOINEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_JOINEDGEFUNCTION_H - -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallVector.h" - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" - -namespace psr::XTaint { -class JoinEdgeFunction : public EdgeFunctionBase { - struct EFDenseSetInfo { - static inline EdgeFunctionPtrType getEmptyKey() { - static EdgeFunctionPtrType EmptyKey( - llvm::DenseMapInfo *>::getEmptyKey(), - [](const EdgeFunction * /*unused*/) {}); - - return EmptyKey; - } - static inline EdgeFunctionPtrType getTombstoneKey() { - static EdgeFunctionPtrType TombstoneKey( - llvm::DenseMapInfo *>::getTombstoneKey(), - [](const EdgeFunction * /*unused*/) {}); - - return TombstoneKey; - } - static unsigned getHashValue(const EdgeFunctionPtrType &EF) { - return XTaint::getHashCode(EF); - } - static bool isEqual(const EdgeFunctionPtrType &LHS, - const EdgeFunctionPtrType &RHS) { - if (&*LHS == &*RHS) { - return true; - } - - if (&*LHS == llvm::DenseMapInfo *>::getEmptyKey() || - &*LHS == llvm::DenseMapInfo *>::getTombstoneKey()) { - return false; - } - - if (&*RHS == llvm::DenseMapInfo *>::getEmptyKey() || - &*RHS == llvm::DenseMapInfo *>::getTombstoneKey()) { - return false; - } - - return LHS->equal_to(RHS); - } - }; - - using SubEdgeFuctionsTy = - llvm::SmallDenseSet; - // The set of joined edge-functions. Is not empty - SubEdgeFuctionsTy SubEF; - - // The joined edge-value of collected constants (GenEdgeFunction and - // JoinConstEdgeFunction) - EdgeDomain Seed; - - JoinEdgeFunction(BasicBlockOrdering &BBO, - std::initializer_list SubEF, - const EdgeDomain &Seed); - -public: - // FOR INTERNAL USE ONLY! USE JoiEdgeFunction::create INSTEAD - JoinEdgeFunction(BasicBlockOrdering &BBO, SubEdgeFuctionsTy &&SubEF, - const EdgeDomain &Seed); - // Replaces the constructor and aims to deduplicate the sub-edge-functions if - // one or more of {First, Second} are also JoinEdgeFunctions - static EdgeFunctionPtrType create(BasicBlockOrdering &BBO, - EdgeFunctionPtrType First, - EdgeFunctionPtrType Second); - - l_t computeTarget(l_t Source) override; - - bool equal_to(EdgeFunctionPtrType OtherFunction) const override; - - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - - llvm::hash_code getHashCode() const override; - - static inline bool classof(const EdgeFunctionBase *EF) { - return EF->getKind() == EFKind::Join; - } -}; -} // namespace psr::XTaint - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h deleted file mode 100644 index c2b873eef..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/KillIfSanitizedEdgeFunction.h +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_KILLIFSANITIZEDEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_KILLIFSANITIZEDEDGEFUNCTION_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/Helpers.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" - -namespace psr::XTaint { - -class KillIfSanitizedEdgeFunction : public EdgeFunctionBase { - const llvm::Instruction *Load; - -public: - KillIfSanitizedEdgeFunction(BasicBlockOrdering &BBO, - const llvm::Instruction *Load); - - l_t computeTarget(l_t Source) override; - - bool equal_to(EdgeFunctionPtrType OtherFunction) const override; - - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; - - inline const llvm::Instruction *getLoad() const { return Load; } - - llvm::hash_code getHashCode() const override; - - inline static bool classof(const EdgeFunctionBase *EF) { - return EF->getKind() == EFKind::KillIfSani; - } -}; - -inline EdgeFunctionBase::EdgeFunctionPtrType -makeKillIfSanitizedEdgeFunction(BasicBlockOrdering &BBO, - const llvm::Instruction *Load) { - return makeEF(BBO, Load); -} - -} // namespace psr::XTaint - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h deleted file mode 100644 index e2149fc4d..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/TransferEdgeFunction.h +++ /dev/null @@ -1,34 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_TRANSFEREDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_TRANSFEREDGEFUNCTION_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h" - -namespace psr::XTaint { -class TransferEdgeFunction : public EdgeFunctionBase { - const llvm::Instruction *Load; - const llvm::Instruction *To; - -public: - TransferEdgeFunction(BasicBlockOrdering &BBO, const llvm::Instruction *Load, - const llvm::Instruction *To); - - l_t computeTarget(l_t Source) override; - - llvm::hash_code getHashCode() const override; - - bool equal_to(EdgeFunctionPtrType Other) const override; - - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const override; -}; -} // namespace psr::XTaint - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h deleted file mode 100644 index 6f01032d5..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/XTaintEdgeFunctionBase.h +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTEDGEFUNCTIONBASE_H_ -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_EXTENDEDTAINTANALYSIS_XTAINTEDGEFUNCTIONBASE_H_ - -#include - -#include "llvm/ADT/Hashing.h" - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/ExtendedTaintAnalysis/EdgeDomain.h" - -namespace psr::XTaint { -/// A common baseclass for all EdgeFunctions used for the -/// IDEExtendedTaintAnalysis. Implements default overrides for composeWith and -/// joinWith and additionally provides LLVM-style RTTI allowing fast runtime -/// typechecks. -class EdgeFunctionBase : public EdgeFunction, - public std::enable_shared_from_this { -public: - enum class EFKind { Gen, Join, JoinConst, Compose, KillIfSani, Transfer }; - -protected: - BasicBlockOrdering &BBO; - -private: - const EFKind Kind; - -public: - using l_t = EdgeDomain; - - EdgeFunctionBase(EFKind Kind, BasicBlockOrdering &BBO); - ~EdgeFunctionBase() override = default; - - EdgeFunctionPtrType composeWith(EdgeFunctionPtrType SecondFunction) override; - EdgeFunctionPtrType joinWith(EdgeFunctionPtrType OtherFunction) override; - - /// The actualy kind of this edge function. Can be used in a type-switch. - [[nodiscard]] inline EFKind getKind() const { return Kind; } - - virtual llvm::hash_code getHashCode() const = 0; -}; -} // namespace psr::XTaint -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h deleted file mode 100644 index c6a07f32c..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/AllBot.h +++ /dev/null @@ -1,30 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_ALLBOT_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_ALLBOT_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" - -namespace psr::glca { - -struct AllBot { - using type = AllBottom; - static std::shared_ptr getInstance(); - static bool isBot(const EdgeFunction *EdgeFn, - bool NonRec = false); - static bool - isBot(const std::shared_ptr> &EdgeFn, - bool NonRec = false); -}; - -} // 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 deleted file mode 100644 index 2b3227fd3..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/BinaryEdgeFunction.h +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_BINARYEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_BINARYEDGEFUNCTION_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" - -namespace psr::glca { - -class BinaryEdgeFunction - : public EdgeFunction, - public std::enable_shared_from_this { - llvm::BinaryOperator::BinaryOps Op; - const IDEGeneralizedLCA::l_t Const; - bool LeftConst; - size_t MaxSize; - -public: - BinaryEdgeFunction(llvm::BinaryOperator::BinaryOps Op, - const IDEGeneralizedLCA::l_t &Const, bool LeftConst, - size_t MaxSize) - : Op(Op), Const(Const), LeftConst(LeftConst), MaxSize(MaxSize) {} - - IDEGeneralizedLCA::l_t computeTarget(IDEGeneralizedLCA::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; -}; - -} // 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 deleted file mode 100644 index f5efbc5fb..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/GenConstant.h +++ /dev/null @@ -1,42 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_GENCONSTANT_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_GENCONSTANT_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" - -namespace psr::glca { - -class GenConstant : public EdgeFunction, - public std::enable_shared_from_this { - IDEGeneralizedLCA::l_t Val; - size_t MaxSize; - -public: - GenConstant(const IDEGeneralizedLCA::l_t &Val, size_t MaxSize); - IDEGeneralizedLCA::l_t computeTarget(IDEGeneralizedLCA::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; -}; - -} // namespace psr::glca - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/JoinEdgeFunction.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/JoinEdgeFunction.h deleted file mode 100644 index 92f89a5d4..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/JoinEdgeFunction.h +++ /dev/null @@ -1,49 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_JOINEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_JOINEDGEFUNCTION_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" - -namespace psr::glca { - -class JoinEdgeFunction : public EdgeFunction, - public std::enable_shared_from_this { - std::shared_ptr> First; - std::shared_ptr> Second; - size_t MaxSize; - -public: - JoinEdgeFunction( - const std::shared_ptr> &First, - const std::shared_ptr> &Second, - size_t MaxSize); - IDEGeneralizedLCA::l_t computeTarget(IDEGeneralizedLCA::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; - const std::shared_ptr> &getFirst() const; - const std::shared_ptr> & - getSecond() const; -}; - -} // 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 deleted file mode 100644 index ffc64e127..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/LCAEdgeFunctionComposer.h +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_LCAEDGEFUNCTIONCOMPOSER_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_LCAEDGEFUNCTIONCOMPOSER_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" - -namespace psr::glca { - -class LCAEdgeFunctionComposer - : public EdgeFunctionComposer { - size_t MaxSize; - -public: - LCAEdgeFunctionComposer( - std::shared_ptr> F, - std::shared_ptr> G, size_t MaxSize); - // IDEGeneralizedLCA::l_t - // computeTarget(IDEGeneralizedLCA::l_t Source) override; - std::shared_ptr> composeWith( - std::shared_ptr> SecondFunction) - override; - - std::shared_ptr> - joinWith(std::shared_ptr> OtherFunction) - override; - const std::shared_ptr> &getFirst() const; - const std::shared_ptr> & - getSecond() const; -}; - -} // 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 deleted file mode 100644 index fc7bb20c0..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/TypecastEdgeFunction.h +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 Fabian Schiebel. - * 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_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_TYPECASTEDGEFUNCTION_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_PROBLEMS_IDEGENERALIZEDLCA_TYPECASTEDGEFUNCTION_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/EdgeValueSet.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEGeneralizedLCA/IDEGeneralizedLCA.h" - -namespace psr::glca { - -class TypecastEdgeFunction - : public EdgeFunction, - public std::enable_shared_from_this { - unsigned Bits; - EdgeValue::Type Dest; - size_t MaxSize; - -public: - TypecastEdgeFunction(unsigned Bits, EdgeValue::Type Dest, size_t MaxSize) - : Bits(Bits), Dest(Dest), MaxSize(MaxSize) {} - - IDEGeneralizedLCA::l_t computeTarget(IDEGeneralizedLCA::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; -}; - -} // namespace psr::glca - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h b/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h deleted file mode 100644 index 9a69a9eb5..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/IfdsIde/Problems/IDEInstInteractionAnalysis.h +++ /dev/null @@ -1,1797 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2019 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 and others - *****************************************************************************/ - -#ifndef PHASAR_PHASARLLVM_IFDSIDE_PROBLEMS_IDEINSTINTERACTIONALYSIS_H -#define PHASAR_PHASARLLVM_IFDSIDE_PROBLEMS_IDEINSTINTERACTIONALYSIS_H - -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctionComposer.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/EdgeFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/FlowFunctions.h" -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IDETabulationProblem.h" -#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/LLVMAnalysisDomain.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h" -#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h" -#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" -#include "phasar/PhasarLLVM/Utils/LatticeDomain.h" -#include "phasar/Utils/BitVectorSet.h" -#include "phasar/Utils/Logger.h" - -#include "llvm/ADT/SmallVector.h" -#include "llvm/IR/Attributes.h" -#include "llvm/IR/Constant.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Value.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Have some handy helper functionalities -namespace { - -[[maybe_unused]] inline const llvm::AllocaInst * -getAllocaInstruction(const llvm::GetElementPtrInst *GEP) { - if (!GEP) { - return nullptr; - } - const auto *Alloca = GEP->getPointerOperand(); - while (const auto *NestedGEP = - llvm::dyn_cast(Alloca)) { - Alloca = NestedGEP->getPointerOperand(); - } - return llvm::dyn_cast(Alloca); -} - -} // namespace - -namespace vara { -class Taint; -} // namespace vara - -namespace psr { -class IDEIIAFlowFact { -public: - constexpr static unsigned KLimit = 2; - -private: - const llvm::Value *BaseVal = nullptr; - llvm::SmallVector FieldDesc; - -public: - ~IDEIIAFlowFact() = default; - IDEIIAFlowFact() = default; - /// Constructs a data-flow fact from the base value. Fields are ignored. Use - /// the factory function(s) to construct field-sensitive data-flow facts. - IDEIIAFlowFact(const llvm::Value *BaseVal); - /// Construct a data-flow fact from the base value and field specification. - IDEIIAFlowFact( - const llvm::Value *BaseVal, - llvm::SmallVector FieldDesc); - - /// Creates a new data-flow fact of the base value that respects fields. Field - /// accesses that exceed the specified depth will be collapsed and not further - /// distinguished. - static IDEIIAFlowFact create(const llvm::Value *BaseVal); - - /// Returns whether this data-flow fact describes the same abstract memory - /// location than the other one. - [[nodiscard]] bool flowFactEqual(const IDEIIAFlowFact &Other) const; - - [[nodiscard]] inline const llvm::Value *getBase() const { return BaseVal; } - [[nodiscard]] inline llvm::SmallVector - getField() const { - return FieldDesc; - } - [[nodiscard]] inline constexpr unsigned getKLimit() const { return KLimit; } - - void print(llvm::raw_ostream &OS, bool IsForDebug = false) const; - - bool operator==(const IDEIIAFlowFact &Other) const; - bool operator!=(const IDEIIAFlowFact &Other) const; - bool operator<(const IDEIIAFlowFact &Other) const; - - bool operator==(const llvm::Value *V) const; - - inline operator const llvm::Value *() { return BaseVal; } -}; - -inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const IDEIIAFlowFact &FlowFact) { - FlowFact.print(OS); - return OS; -} - -inline std::ostream &operator<<(std::ostream &OS, - const IDEIIAFlowFact &FlowFact) { - std::string Buf; - llvm::raw_string_ostream Rso(Buf); - FlowFact.print(Rso); - return OS << Buf; -} - -} // namespace psr - -// Implementations of STL traits. -namespace std { -template <> struct hash { - size_t operator()(const psr::IDEIIAFlowFact &FlowFact) const { - return std::hash()(FlowFact.getBase()); - } -}; - -template <> struct less { - bool operator()(const psr::IDEIIAFlowFact &Lhs, - const psr::IDEIIAFlowFact &Rhs) const { - return Lhs < Rhs; - } -}; - -template <> struct equal_to { - bool operator()(const psr::IDEIIAFlowFact &Lhs, - const psr::IDEIIAFlowFact &Rhs) const { - return Lhs == Rhs; - } -}; -} // namespace std - -namespace psr { - -template -struct IDEInstInteractionAnalysisDomain : public LLVMAnalysisDomainDefault { - // type of the element contained in the sets of edge functions - using d_t = IDEIIAFlowFact; - using e_t = EdgeFactType; - using l_t = LatticeDomain>; -}; - -/// -/// SyntacticAnalysisOnly: Can be set if a syntactic-only analysis is desired -/// (without using points-to information) -/// -/// IndirectTaints: Can be set to ensure non-interference -/// -template -class IDEInstInteractionAnalysisT - : public IDETabulationProblem< - IDEInstInteractionAnalysisDomain> { - using IDETabulationProblem< - IDEInstInteractionAnalysisDomain>::generateFromZero; - -public: - using AnalysisDomainTy = IDEInstInteractionAnalysisDomain; - - using IDETabProblemType = IDETabulationProblem; - using typename IDETabProblemType::container_type; - using typename IDETabProblemType::FlowFunctionPtrType; - - 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; - // type of the element contained in the sets of edge functions - using e_t = typename AnalysisDomainTy::e_t; - using l_t = typename AnalysisDomainTy::l_t; - using i_t = typename AnalysisDomainTy::i_t; - - using EdgeFactGeneratorTy = std::set( - std::variant InstOrGlobal); - - IDEInstInteractionAnalysisT( - const LLVMProjectIRDB *IRDB, const LLVMBasedICFG *ICF, - LLVMPointsToInfo *PT, std::vector EntryPoints = {"main"}, - std::function EdgeFactGenerator = nullptr) - : IDETabulationProblem( - IRDB, std::move(EntryPoints), createZeroValue()), - ICF(ICF), PT(PT), EdgeFactGen(std::move(EdgeFactGenerator)) { - assert(ICF != nullptr); - assert(PT != nullptr); - IIAAAddLabelsEF::initEdgeFunctionCleaner(); - IIAAKillOrReplaceEF::initEdgeFunctionCleaner(); - } - - ~IDEInstInteractionAnalysisT() override = default; - - /// Offer a special hook to the user that allows to generate additional - /// edge facts on-the-fly. Above the generator function, the ordinary - /// edge facts are generated according to the usual edge functions. - inline void registerEdgeFactGenerator( - std::function EdgeFactGenerator) { - EdgeFactGen = std::move(EdgeFactGenerator); - } - - // start formulating our analysis by specifying the parts required for IFDS - - FlowFunctionPtrType getNormalFlowFunction(n_t Curr, n_t /* Succ */) override { - // Generate all local variables - // - // Flow function: - // - // 0 - // |\ - // x = alloca y | \ - // v v - // 0 x - // - if (const auto *Alloca = llvm::dyn_cast(Curr)) { - PHASAR_LOG_LEVEL(DFADEBUG, "AllocaInst"); - return generateFromZero(Alloca); - } - - // Handle indirect taints, i. e., propagate values that depend on branch - // conditions whose operands are tainted. - if constexpr (EnableIndirectTaints) { - if (const auto *Br = llvm::dyn_cast(Curr); - Br && Br->isConditional()) { - // If the branch is conditional and its condition is tainted, then we - // need to propagates the instructions that are depending on this - // branch, too. - // - // Flow function: - // - // Let I be the set of instructions of the branch instruction's - // successors. - // - // 0 c x - // | |\ - // x = br C, label if.then, label if.else | | \--\ - // v v v v - // 0 c x I - // - struct IIAFlowFunction : FlowFunction { - const llvm::BranchInst *Br; - - IIAFlowFunction(const llvm::BranchInst *Br) : Br(Br) {} - - container_type computeTargets(d_t Src) override { - container_type Facts; - Facts.insert(Src); - if (Src == Br->getCondition()) { - Facts.insert(Br); - for (const auto *Succs : Br->successors()) { - for (const auto &Inst : Succs->instructionsWithoutDebug()) { - Facts.insert(&Inst); - } - } - } - return Facts; - } - }; - return std::make_shared(Br); - } - } - - // Handle points-to information if the user wishes to conduct a - // non-syntax-only inst-interaction analysis. - if constexpr (!SyntacticAnalysisOnly) { - - // (ii) Handle semantic propagation (pointers) for load instructions. - - if (const auto *Load = llvm::dyn_cast(Curr)) { - // If one of the potentially many loaded values holds, the load itself - // (dereferenced value) must also be generated and populated. - // - // Flow function: - // - // Let Y = pts(y), be the points-to set of y. - // - // 0 Y x - // | |\ - // x = load y | | \ - // v v v - // 0 Y x - // - struct IIAFlowFunction : FlowFunction { - const llvm::LoadInst *Load; - LLVMPointsToInfo::AllocationSiteSetPtrTy PTS; - - IIAFlowFunction(IDEInstInteractionAnalysisT &Problem, - const llvm::LoadInst *Load) - : Load(Load), PTS(Problem.PT->getReachableAllocationSites( - Load->getPointerOperand(), - Problem.OnlyConsiderLocalAliases)) {} - - container_type computeTargets(d_t Src) override { - container_type Facts; - Facts.insert(Src); - - // Handle global variables which behave a bit special. - if (Src == Load->getPointerOperand() || PTS->count(Src)) { - Facts.insert(Load); - } - return Facts; - } - }; - return std::make_shared(*this, Load); - } - - // (ii) Handle semantic propagation (pointers) for store instructions. - if (const auto *Store = llvm::dyn_cast(Curr)) { - // If the value to be stored holds, the potential memory location(s) - // that it is stored to must be generated and populated, too. - // - // Flow function: - // - // Let X be - // - pts(x), the points-to set of x, if x is an intersting pointer. - // - a singleton set containing x, otherwise. - // - // Let Y be pts(y), the points-to set of y. - // - // 0 X y - // | |\ | - // store x y | | \| - // v v v - // 0 x Y - // - struct IIAFlowFunction : FlowFunction { - const llvm::StoreInst *Store; - LLVMPointsToInfo::AllocationSiteSetPtrTy ValuePTS; - LLVMPointsToInfo::AllocationSiteSetPtrTy PointerPTS; - - IIAFlowFunction(IDEInstInteractionAnalysisT &Problem, - const llvm::StoreInst *Store) - : Store(Store), ValuePTS([&]() { - if (isInterestingPointer(Store->getValueOperand())) { - return Problem.PT->getReachableAllocationSites( - Store->getValueOperand(), - Problem.OnlyConsiderLocalAliases); - } - return std::make_unique( - LLVMPointsToInfo::PointsToSetTy{ - Store->getValueOperand()}); - }()), - PointerPTS(Problem.PT->getReachableAllocationSites( - Store->getPointerOperand(), - Problem.OnlyConsiderLocalAliases)) {} - - container_type computeTargets(d_t Src) override { - // Override old value(s), i.e., kill value(s) that is written to and - // generate from value that is stored. - if (Store->getPointerOperand() == Src || PointerPTS->count(Src)) { - return {}; - } - container_type Facts; - Facts.insert(Src); - // y/Y now obtains its new value(s) from x/X - // If a value is stored that holds we must generate all potential - // memory locations the store might write to. - if (Store->getValueOperand() == Src || ValuePTS->count(Src)) { - Facts.insert(Store->getValueOperand()); - Facts.insert(Store->getPointerOperand()); - Facts.insert(PointerPTS->begin(), PointerPTS->end()); - } - // ... or from zero, if a constant literal is stored to y - if (llvm::isa(Store->getValueOperand()) && - IDEInstInteractionAnalysisT::isZeroValueImpl(Src)) { - Facts.insert(Store->getPointerOperand()); - Facts.insert(PointerPTS->begin(), PointerPTS->end()); - } - return Facts; - } - }; - return std::make_shared(*this, Store); - } - } - - // (i) Handle syntactic propagation - - // Handle load instruction - // - // Flow function: - // - // 0 y x - // | |\ - // x = load y | | \ - // v v v - // 0 y x - // - if (const auto *Load = llvm::dyn_cast(Curr)) { - return generateFlow(Load, Load->getPointerOperand()); - } - // Handle store instructions - // - // Flow function: - // - // 0 x y - // | |\ | - // store x y | | \| - // v v v - // 0 x y - // - if (const auto *Store = llvm::dyn_cast(Curr)) { - // Case x is a load instruction - if (const auto *Load = - llvm::dyn_cast(Store->getValueOperand())) { - struct IIAAFlowFunction : FlowFunction { - const llvm::StoreInst *Store; - const llvm::LoadInst *Load; - - IIAAFlowFunction(const llvm::StoreInst *S, const llvm::LoadInst *L) - : Store(S), Load(L) {} - ~IIAAFlowFunction() override = default; - - container_type computeTargets(d_t Src) override { - // Override old value, i.e., kill value that is written to and - // generate from value that is stored. - if (Store->getPointerOperand() == Src) { - return {}; - } - container_type Facts; - // y now obtains its new value from x - if (Load == Src || Load->getPointerOperand() == Src) { - Facts.insert(Src); - Facts.insert(Load->getPointerOperand()); - Facts.insert(Store->getPointerOperand()); - } else { - Facts.insert(Src); - } - IF_LOG_ENABLED({ - for (const auto Fact : Facts) { - PHASAR_LOG_LEVEL(DFADEBUG, - "Create edge: " << llvmIRToShortString(Src) - << " --" - << llvmIRToShortString(Store) - << "--> " << Fact); - } - }); - return Facts; - } - }; - return std::make_shared(Store, Load); - } - // Otherwise - struct IIAAFlowFunction : FlowFunction { - const llvm::StoreInst *Store; - - IIAAFlowFunction(const llvm::StoreInst *S) : Store(S) {} - ~IIAAFlowFunction() override = default; - - container_type computeTargets(d_t Src) override { - // Override old value, i.e., kill value that is written to and - // generate from value that is stored. - if (Store->getPointerOperand() == Src) { - return {}; - } - container_type Facts; - Facts.insert(Src); - // y now obtains its new value from x - if (Store->getValueOperand() == Src) { - Facts.insert(Store->getPointerOperand()); - } - // ... or from zero, if a constant literal is stored to y - if (llvm::isa(Store->getValueOperand()) && - IDEInstInteractionAnalysisT::isZeroValueImpl(Src)) { - Facts.insert(Store->getPointerOperand()); - } - IF_LOG_ENABLED({ - for (const auto Fact : Facts) { - PHASAR_LOG_LEVEL( - DFADEBUG, "Create edge: " << llvmIRToShortString(Src) << " --" - << llvmIRToShortString(Store) - << "--> " << Fact); - } - }); - return Facts; - } - }; - return std::make_shared(Store); - } - // At last, we can handle all other (unary/binary) instructions. - // - // Flow function: - // - // 0 x o p - // | | /| /| - // x = instruction o p | |/ |/ | - // | | /| | - // | |/ | | - // v v v v - // 0 x o p - // - struct IIAFlowFunction : FlowFunction { - n_t Inst; - - IIAFlowFunction(n_t Inst) : Inst(Inst) {} - - ~IIAFlowFunction() override = default; - - container_type computeTargets(d_t Src) override { - container_type Facts; - if (IDEInstInteractionAnalysisT::isZeroValueImpl(Src)) { - // keep the zero flow fact - Facts.insert(Src); - return Facts; - } - // (i) syntactic propagation - if (Inst == Src) { - Facts.insert(Inst); - } - // continue syntactic propagation: populate and propagate other existing - // facts - for (auto &Op : Inst->operands()) { - // if one of the operands holds, also generate the instruction using - // it - if (Op == Src) { - Facts.insert(Inst); - Facts.insert(Src); - } - } - // pass everything that already holds as identity - Facts.insert(Src); - IF_LOG_ENABLED({ - for (const auto Fact : Facts) { - PHASAR_LOG_LEVEL(DFADEBUG, "Create edge: " - << llvmIRToShortString(Src) << " --" - << llvmIRToShortString(Inst) - << "--> " << Fact); - } - }); - return Facts; - } - }; - return std::make_shared(Curr); - } - - inline FlowFunctionPtrType getCallFlowFunction(n_t CallSite, - f_t DestFun) override { - if (this->ICF->isHeapAllocatingFunction(DestFun)) { - // Kill add facts and model the effects in getCallToRetFlowFunction(). - return killAllFlows(); - } - if (DestFun->isDeclaration()) { - // We don't have anything that we could analyze, kill all facts. - return killAllFlows(); - } - const auto *CS = llvm::cast(CallSite); - // Map actual to formal parameters. - struct MapFactsToCallee : public FlowFunction { - const llvm::CallBase *CallSite; - const llvm::Function *DestFun; - std::vector Actuals; - std::vector Formals; - // Predicate for handling actual parameters - std::function - ActualPredicate = [](const llvm::CallBase *CS, const llvm::Value *V) { - bool PassParameter = true; - for (unsigned Idx = 0; Idx < CS->arg_size(); ++Idx) { - if (V == CS->getArgOperand(Idx)) { - return !CS->paramHasAttr(Idx, llvm::Attribute::StructRet); - } - } - return PassParameter; - }; - - MapFactsToCallee(const llvm::CallBase *CallSite, - const llvm::Function *DestFun) - : CallSite(CallSite), DestFun(DestFun) { - // 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); - } - } - - std::set computeTargets(IDEIIAFlowFact Source) override { - // If DestFun is a declaration we cannot follow this call, we thus need - // to kill everything - if (DestFun->isDeclaration()) { - return {}; - } - // Pass ZeroValue as is, if desired - if (LLVMZeroValue::isLLVMZeroValue(Source)) { - return {Source}; - } - 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 (llvm::isa(Source.getBase())) { - 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(CallSite, 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() - ->getArrayElementType() - ->isStructTy() && - Alloc->getAllocatedType() - ->getArrayElementType() - ->getStructName() == "struct.__va_list_tag") { - Res.insert(Alloc); - } - } - } - } - } else { - assert(Idx < Formals.size() && - "Out of bound access to formal parameters!"); - Res.insert(Formals[Idx]); // corresponding formal - } - } - } - } - // 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(CallSite, Actuals[Idx])) { - assert(Idx < Formals.size() && - "Out of bound access to formal parameters!"); - Res.insert(Formals[Idx]); // corresponding formal - } - } - return Res; - } - }; - auto MapFactsToCalleeFF = std::make_shared(CS, DestFun); - // Generate the artificially introduced RVO parameters from zero value. - std::set SRetFormals; - for (unsigned Idx = 0; Idx < CS->arg_size(); ++Idx) { - if (CS->paramHasAttr(Idx, llvm::Attribute::StructRet)) { - SRetFormals.insert(DestFun->getArg(Idx)); - } - } - - return unionFlows(std::move(MapFactsToCalleeFF), - generateManyFlowsAndKillAllOthers(std::move(SRetFormals), - this->getZeroValue())); - } - - inline FlowFunctionPtrType getRetFlowFunction(n_t CallSite, f_t CalleeFun, - n_t ExitInst, - n_t /* RetSite */) override { - // Map return value back to the caller. If pointer parameters hold at the - // end of a callee function generate all of those in the caller context. - struct MapFactsToCaller : public FlowFunction { - const llvm::CallBase *CallSite; - const llvm::Function *CalleeFun; - const llvm::ReturnInst *ExitInst; - std::vector Actuals; - std::vector Formals; - - MapFactsToCaller(const llvm::CallBase *CallSite, - const llvm::Function *CalleeFun, - const llvm::ReturnInst *ExitInst) - : CallSite(CallSite), CalleeFun(CalleeFun), ExitInst(ExitInst) { - // 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); - } - } - - std::set computeTargets(IDEIIAFlowFact Source) override { - // Pass ZeroValue as is, if desired - if (LLVMZeroValue::isLLVMZeroValue(Source.getBase())) { - return {Source}; - } - // Pass global variables as is, if desired - // Need llvm::Constant here to cover also ConstantExpr and - // ConstantAggregate - if (llvm::isa(Source.getBase())) { - 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 (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 ;-) - } - } - } - } - // 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]); - } - } - } - // Handle ordinary case - // Map formal parameter into corresponding actual parameter. - for (unsigned Idx = 0; Idx < Formals.size(); ++Idx) { - if (Source == Formals[Idx]) { - Res.insert(Actuals[Idx]); // corresponding actual - } - } - // Collect return value facts - if (ExitInst != nullptr && Source == ExitInst->getReturnValue()) { - Res.insert(CallSite); - } - return Res; - } - }; - auto MapFactsToCallerFF = std::make_shared( - llvm::dyn_cast(CallSite), CalleeFun, - llvm::dyn_cast(ExitInst)); - // We must also handle the special case if the returned value is a constant - // literal, e.g. ret i32 42. - if (ExitInst) { - if (const auto *Ret = llvm::dyn_cast(ExitInst)) { - const auto *RetVal = Ret->getReturnValue(); - if (RetVal) { - if (const auto *CD = llvm::dyn_cast(RetVal)) { - // Generate the respective callsite. The callsite will receive its - // value from this very return instruction cf. - // getReturnEdgeFunction(). - return unionFlows(std::move(MapFactsToCallerFF), - generateFlowAndKillAllOthers( - CallSite, this->getZeroValue())); - } - } - } - } - return MapFactsToCallerFF; - } - - inline FlowFunctionPtrType - getCallToRetFlowFunction(n_t CallSite, n_t /* RetSite */, - llvm::ArrayRef Callees) override { - // Model call to heap allocating functions (new, new[], malloc, etc.) -- - // only model direct calls, though. - if (Callees.size() == 1) { - for (const auto *Callee : Callees) { - if (this->ICF->isHeapAllocatingFunction(Callee)) { - // In case a heap allocating function is called, generate the pointer - // that is returned. - // - // Flow function: - // - // Let H be a heap allocating function. - // - // 0 - // |\ - // x = call H | \ - // v v - // 0 x - // - return generateFromZero(CallSite); - } - } - } - // Just use the auto mapping for values; pointer parameters and global - // variables are killed and handled by getCallFlowfunction() and - // getRetFlowFunction(). - // However, if only declarations are available as callee targets we would - // lose the data-flow facts involved in the call which is usually not the - // 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, bool AllVoidRetTys, - const llvm::CallBase *CallSite, d_t ZeroValue) - : OnlyDecls(OnlyDecls), AllVoidRetTys(AllVoidRetTys), - CallSite(CallSite), ZeroValue(ZeroValue) {} - - std::set computeTargets(IDEIIAFlowFact Source) override { - // There are a few things to consider, in case only declarations of - // callee targets are available. - if (OnlyDecls) { - - 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 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 {}; - } - // Pass everything else as identity. In particular, also do not kill - // pointer or reference parameters since this then also captures usages - // oft he parameters, which we wish to compute using this analysis. - return {Source}; - } - }; - return std::make_shared( - OnlyDecls, AllVoidRetTys, llvm::dyn_cast(CallSite), - this->getZeroValue()); - } - - inline FlowFunctionPtrType - getSummaryFlowFunction(n_t /* CallSite */, f_t /* DestFun */) override { - // Do not use user-crafted summaries. - return nullptr; - } - - inline InitialSeeds initialSeeds() override { - InitialSeeds Seeds; - std::set EntryPointFuns; - for (const auto &EntryPoint : this->EntryPoints) { - EntryPointFuns.insert(this->IRDB->getFunctionDefinition(EntryPoint)); - } - // Set initial seeds at the required entry points and generate the global - // variables using generalized initial seeds - for (const auto *EntryPointFun : EntryPointFuns) { - // Generate zero value at the entry points - Seeds.addSeed(&EntryPointFun->front().front(), this->getZeroValue(), - bottomElement()); - // Generate formal parameters of entry points, e.g. main(). Formal - // parameters will otherwise cause trouble by overriding alloca - // instructions without being valid data-flow facts themselves. - for (const auto &Arg : EntryPointFun->args()) { - Seeds.addSeed(&EntryPointFun->front().front(), &Arg, BottomElement); - } - // Generate all global variables using generalized initial seeds - - 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 { - // Create a special value to represent the zero value! - return LLVMZeroValue::getInstance(); - } - - inline bool isZeroValue(d_t d) const override { return isZeroValueImpl(d); } - - // In addition provide specifications for the IDE parts. - - inline std::shared_ptr> - getNormalEdgeFunction(n_t Curr, d_t CurrNode, n_t /* Succ */, - d_t SuccNode) override { - PHASAR_LOG_LEVEL(DFADEBUG, - "Process edge: " << llvmIRToShortString(CurrNode) << " --" - << llvmIRToString(Curr) << "--> " - << llvmIRToShortString(SuccNode)); - // - // Zero --> Zero edges - // - // Edge function: - // - // 0 - // | - // %i = instruction | \x.BOT - // v - // 0 - // - if (isZeroValue(CurrNode) && isZeroValue(SuccNode)) { - return EdgeIdentity::getInstance(); - } - // check if the user has registered a fact generator function - l_t UserEdgeFacts = BitVectorSet(); - std::set EdgeFacts; - if (EdgeFactGen) { - EdgeFacts = EdgeFactGen(Curr); - // fill BitVectorSet - UserEdgeFacts = BitVectorSet(EdgeFacts.begin(), EdgeFacts.end()); - } - // - // Zero --> Alloca edges - // - // Edge function: - // - // 0 - // \ - // %a = alloca \ \x.x \cup { commit of('%a = alloca') } - // v - // a - // - if (isZeroValue(CurrNode) && Curr == SuccNode) { - if (llvm::isa(Curr)) { - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - } - // - // i --> i edges - // - // Edge function: - // - // i - // | - // %i = instruction | \x.x \cup { commit of('%i = instruction') } - // v - // i - // - if (Curr == CurrNode && CurrNode == SuccNode) { - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - // Handle loads in non-syntax only analysis - if constexpr (!SyntacticAnalysisOnly) { - if (const auto *Load = llvm::dyn_cast(Curr)) { - // - // y --> x - // - // Edge function: - // - // y - // \ - // x = load y \ \x.{ commit of('x = load y') } \cup { commits of y } - // v - // x - // - if ((CurrNode == Load->getPointerOperand() || - this->PT->isInReachableAllocationSites( - Load->getPointerOperand(), CurrNode, - OnlyConsiderLocalAliases)) && - Load == SuccNode) { - IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } else { - // - // y --> y - // - // Edge function: - // - // y - // | - // x = load y | \x.x (loads do not modify the value that is loaded - // from) - // v - // y - // - return EdgeIdentity::getInstance(); - } - } - } - // Overrides at store instructions - if (const auto *Store = llvm::dyn_cast(Curr)) { - if (SyntacticAnalysisOnly) { - // Kill all labels that are propagated along the edge of the value that - // is overridden. - // - // y --> y - // - // Edge function: - // - // y - // | - // store x y | \x.{ commit of('store x y') } - // v - // y - // - if ((CurrNode == SuccNode) && CurrNode == Store->getPointerOperand()) { - // y obtains its value(s) from its original allocation and the store - // instruction under analysis. - IF_LOG_ENABLED({ - PHASAR_LOG_LEVEL(DFADEBUG, - "Const-Replace at '" << llvmIRToString(Curr)); - PHASAR_LOG_LEVEL(DFADEBUG, "Replacement label(s): "); - for (const auto &Item : EdgeFacts) { - PHASAR_LOG_LEVEL(DFADEBUG, Item << ", "); - } - PHASAR_LOG_LEVEL(DFADEBUG, '\n'); - }); - // obtain label from the original allocation - const llvm::AllocaInst *OrigAlloca = nullptr; - if (const auto *Alloca = llvm::dyn_cast( - Store->getPointerOperand())) { - OrigAlloca = Alloca; - } - if (const auto *GEP = llvm::dyn_cast( - Store->getPointerOperand())) { - OrigAlloca = getAllocaInstruction(GEP); - } - // obtain the label - if (OrigAlloca) { - if (auto *UEF = std::get_if>(&UserEdgeFacts)) { - UEF->insert(edgeFactGenForInstToBitVectorSet(OrigAlloca)); - } - } - return IIAAKillOrReplaceEF::createEdgeFunction(UserEdgeFacts); - } - // - // x --> y - // - // Edge function: - // - // x - // \ - // store x y \ \x.{ commit of('store x y') } - // v - // y - // - if (CurrNode == Store->getValueOperand() && - SuccNode == Store->getPointerOperand()) { - IF_LOG_ENABLED({ - PHASAR_LOG_LEVEL(DFADEBUG, "Var-Override: "); - for (const auto &EF : EdgeFacts) { - PHASAR_LOG_LEVEL(DFADEBUG, EF << ", "); - } - PHASAR_LOG_LEVEL(DFADEBUG, "at '" << llvmIRToString(Curr) << "'\n"); - }); - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - } else { - // Use points-to information to find all possible overriding edges. - - // Overriding edge with literal: kill all labels that are propagated - // along the edge of the value that is overridden. - // - // x --> y - // - // Edge function: - // - // Let x be a literal. - // - // y - // | - // store x y | \x.{} \cup { commit of('store x y') } - // v - // y - // - if (llvm::isa(Store->getValueOperand()) && - CurrNode == SuccNode && - (this->PT->isInReachableAllocationSites(Store->getPointerOperand(), - CurrNode, - OnlyConsiderLocalAliases) || - Store->getPointerOperand() == CurrNode)) { - // Add the original variable, i.e., memory location. - return IIAAKillOrReplaceEF::createEdgeFunction(UserEdgeFacts); - } - // Kill all labels that are propagated along the edge of the - // value/values that is/are overridden. - // - // y --> y - // - // Edge function: - // - // y - // | - // store x y | \x.{} - // v - // y - // - if (CurrNode == SuccNode && this->PT->isInReachableAllocationSites( - Store->getPointerOperand(), CurrNode, - OnlyConsiderLocalAliases)) { - return IIAAKillOrReplaceEF::createEdgeFunction(BitVectorSet()); - } - // Overriding edge: obtain labels from value to be stored (and may add - // UserEdgeFacts, if any). - // - // x --> y - // - // Edge function: - // - // x - // \ - // store x y \ \x.x \cup { commit of('store x y') } - // v - // y - // - bool StoreValOpIsPointerTy = - Store->getValueOperand()->getType()->isPointerTy(); - if ((CurrNode == Store->getValueOperand() || - (StoreValOpIsPointerTy && - this->PT->isInReachableAllocationSites( - Store->getValueOperand(), Store->getValueOperand(), - OnlyConsiderLocalAliases))) && - this->PT->isInReachableAllocationSites(Store->getPointerOperand(), - Store->getPointerOperand(), - OnlyConsiderLocalAliases)) { - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - } - } - // Handle edge functions for general instructions. - for (const auto &Op : Curr->operands()) { - // - // 0 --> o_i - // - // Edge function: - // - // 0 - // \ - // %i = instruction o_i \ \x.x \cup { commit of('%i = instruction') } - // v - // o_i - // - if (isZeroValue(CurrNode) && Op == SuccNode) { - // Constant variables should retain their own label - if (llvm::isa(SuccNode.getBase())) { - if (llvm::isa_and_nonnull(SuccNode.getBase())) { - if (auto *UEF = std::get_if>(&UserEdgeFacts)) { - UEF->insert(edgeFactGenForGlobalVarToBitVectorSet( - llvm::dyn_cast(SuccNode.getBase()))); - } - } - } - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - // - // o_i --> o_i - // - // Edge function: - // - // o_i - // | - // %i = instruction o_i | \x.x \cup { commit of('%i = instruction') } - // v - // o_i - // - if (Op == CurrNode && CurrNode == SuccNode) { - IF_LOG_ENABLED({ - PHASAR_LOG_LEVEL(DFADEBUG, "this is 'i'\n"); - for (auto &EdgeFact : EdgeFacts) { - PHASAR_LOG_LEVEL(DFADEBUG, EdgeFact << ", "); - } - PHASAR_LOG_LEVEL(DFADEBUG, '\n'); - }); - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - // - // o_i --> i - // - // Edge function: - // - // o_i - // \ - // %i = instruction o_i \ \x.x \cup { commit of('%i = instruction') } - // v - // i - // - if (Op == CurrNode && Curr == SuccNode) { - IF_LOG_ENABLED({ - PHASAR_LOG_LEVEL(DFADEBUG, "this is '0'\n"); - for (auto &EdgeFact : EdgeFacts) { - PHASAR_LOG_LEVEL(DFADEBUG, EdgeFact << ", "); - } - PHASAR_LOG_LEVEL(DFADEBUG, '\n'); - }); - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - } - // Otherwise stick to identity. - return EdgeIdentity::getInstance(); - } - - inline std::shared_ptr> - getCallEdgeFunction(n_t CallSite, d_t SrcNode, f_t /* DestinationMethod */, - d_t DestNode) override { - // Handle the case in which a parameter that has been artificially - // introduced by the compiler is passed. Such a value must be generated from - // the zero value, to reflact the fact that the data flows from the callee - // to the caller (at least) according to the source code. - // - // Let a_i be an argument that is annotated by the sret attribute. - // - // 0 --> a_i - // - // Edge function: - // - // 0 - // \ - // call/invoke f(a_i) \ \x.{} - // v - // a_i - // - std::set SRetParams; - const auto *CS = llvm::cast(CallSite); - for (unsigned Idx = 0; Idx < CS->arg_size(); ++Idx) { - if (CS->paramHasAttr(Idx, llvm::Attribute::StructRet)) { - SRetParams.insert(CS->getArgOperand(Idx)); - } - } - if (isZeroValue(SrcNode) && SRetParams.count(DestNode)) { - return IIAAAddLabelsEF::createEdgeFunction(BitVectorSet()); - } - // Everything else can be passed as identity. - return EdgeIdentity::getInstance(); - } - - inline std::shared_ptr> - getReturnEdgeFunction(n_t CallSite, f_t /* CalleeMethod */, n_t ExitInst, - d_t ExitNode, n_t /* RetSite */, d_t RetNode) override { - // Handle the case in which constant data is returned, e.g. ret i32 42. - // - // Let c be the return instruction's corresponding call site. - // - // 0 --> c - // - // Edge function: - // - // 0 - // \ - // ret x \ \x.x \cup { commit of('ret x') } - // v - // c - // - if (isZeroValue(ExitNode) && RetNode == CallSite) { - const auto *Ret = llvm::dyn_cast(ExitInst); - if (const auto *CD = - llvm::dyn_cast(Ret->getReturnValue())) { - // Check if the user has registered a fact generator function - l_t UserEdgeFacts = BitVectorSet(); - std::set EdgeFacts; - if (EdgeFactGen) { - EdgeFacts = EdgeFactGen(ExitInst); - // fill BitVectorSet - UserEdgeFacts = BitVectorSet(EdgeFacts.begin(), EdgeFacts.end()); - } - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - } - // Everything else can be passed as identity. - return EdgeIdentity::getInstance(); - } - - inline std::shared_ptr> - getCallToRetEdgeFunction(n_t CallSite, d_t CallNode, n_t /* RetSite */, - d_t RetSiteNode, - llvm::ArrayRef Callees) override { - // Check if the user has registered a fact generator function - l_t UserEdgeFacts = BitVectorSet(); - std::set EdgeFacts; - if (EdgeFactGen) { - EdgeFacts = EdgeFactGen(CallSite); - // fill BitVectorSet - UserEdgeFacts = BitVectorSet(EdgeFacts.begin(), EdgeFacts.end()); - } - // Model call to heap allocating functions (new, new[], malloc, etc.) -- - // only model direct calls, though. - if (Callees.size() == 1) { - for (const auto *Callee : Callees) { - if (this->ICF->isHeapAllocatingFunction(Callee)) { - // Let H be a heap allocating function. - // - // 0 --> x - // - // Edge function: - // - // 0 - // \ - // %i = call H \ \x.x \cup { commit of('%i = call H') } - // v - // i - // - if (isZeroValue(CallNode) && RetSiteNode == CallSite) { - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - } - } - } - // Capture interactions of the call instruction and its arguments. - const auto *CS = llvm::dyn_cast(CallSite); - for (const auto &Arg : CS->args()) { - // - // o_i --> o_i - // - // Edge function: - // - // o_i - // | - // %i = call o_i | \ \x.x \cup { commit of('%i = call H') } - // v - // o_i - // - if (CallNode == Arg && CallNode == RetSiteNode) { - return IIAAAddLabelsEF::createEdgeFunction(UserEdgeFacts); - } - } - // Otherwise stick to identity - return EdgeIdentity::getInstance(); - } - - inline std::shared_ptr> - getSummaryEdgeFunction(n_t /* CallSite */, d_t /* CallNode */, - n_t /* RetSite */, d_t /* RetSiteNode */) override { - // Do not use user-crafted summaries. - return nullptr; - } - - inline l_t topElement() override { return TopElement; } - - inline l_t bottomElement() override { return BottomElement; } - - inline l_t join(l_t Lhs, l_t Rhs) override { return joinImpl(Lhs, Rhs); } - - inline std::shared_ptr> allTopFunction() override { - return std::make_shared>(topElement()); - } - - // Provide some handy helper edge functions to improve reuse. - - // Edge function that kills all labels in a set (and may replaces them with - // others). - class IIAAKillOrReplaceEF - : public EdgeFunction, - public std::enable_shared_from_this, - public EdgeFunctionSingletonFactory { - public: - l_t Replacement; - - explicit IIAAKillOrReplaceEF() : Replacement(BitVectorSet()) { - // PHASAR_LOG_LEVEL(DFADEBUG, - // << "IIAAKillOrReplaceEF"); - } - - explicit IIAAKillOrReplaceEF(l_t Replacement) : Replacement(Replacement) { - // PHASAR_LOG_LEVEL(DFADEBUG, - // << "IIAAKillOrReplaceEF"); - } - - ~IIAAKillOrReplaceEF() override = default; - - l_t computeTarget(l_t /* Src */) override { return Replacement; } - - std::shared_ptr> - composeWith(std::shared_ptr> SecondFunction) override { - // PHASAR_LOG_LEVEL(DFADEBUG, - // << "IIAAKillOrReplaceEF::composeWith(): " << this->str() - // << " * " << SecondFunction->str()); - if (auto *AT = dynamic_cast *>(SecondFunction.get())) { - return this->shared_from_this(); - } - if (auto *AB = dynamic_cast *>(SecondFunction.get())) { - return this->shared_from_this(); - } - if (auto *EI = dynamic_cast *>(SecondFunction.get())) { - return this->shared_from_this(); - } - if (auto *AD = dynamic_cast(SecondFunction.get())) { - if (isKillAll()) { - return IIAAAddLabelsEF::createEdgeFunction(AD->Data); - } - auto Union = - IDEInstInteractionAnalysisT::joinImpl(Replacement, AD->Data); - return IIAAAddLabelsEF::createEdgeFunction(Union); - } - if (auto *KR = - dynamic_cast(SecondFunction.get())) { - if (isKillAll()) { - return IIAAKillOrReplaceEF::createEdgeFunction(KR->Replacement); - } - if (KR->isKillAll()) { - return SecondFunction; - } - auto Union = - IDEInstInteractionAnalysisT::joinImpl(Replacement, KR->Replacement); - return IIAAKillOrReplaceEF::createEdgeFunction(Union); - } - llvm::report_fatal_error( - "found unexpected edge function in 'IIAAKillOrReplaceEF'"); - } - - std::shared_ptr> - joinWith(std::shared_ptr> OtherFunction) override { - // PHASAR_LOG_LEVEL(DFADEBUG, << - // "IIAAKillOrReplaceEF::joinWith"); - if (auto *AT = dynamic_cast *>(OtherFunction.get())) { - return this->shared_from_this(); - } - if (auto *AB = dynamic_cast *>(OtherFunction.get())) { - return this->shared_from_this(); - } - if (auto *ID = dynamic_cast *>(OtherFunction.get())) { - return this->shared_from_this(); - } - if (auto *AD = dynamic_cast(OtherFunction.get())) { - auto Union = - IDEInstInteractionAnalysisT::joinImpl(Replacement, AD->Data); - return IIAAAddLabelsEF::createEdgeFunction(Union); - } - if (auto *KR = dynamic_cast(OtherFunction.get())) { - auto Union = - IDEInstInteractionAnalysisT::joinImpl(Replacement, KR->Replacement); - return IIAAKillOrReplaceEF::createEdgeFunction(Union); - } - llvm::report_fatal_error( - "found unexpected edge function in 'IIAAKillOrReplaceEF'"); - } - - bool equal_to(std::shared_ptr> Other) const override { - if (auto *KR = dynamic_cast(Other.get())) { - return Replacement == KR->Replacement; - } - return this == Other.get(); - } - - void print(llvm::raw_ostream &OS, - bool /* IsForDebug */ = false) const override { - OS << "EF: (IIAAKillOrReplaceEF)<->"; - if (isKillAll()) { - OS << "(KillAll"; - } else { - IDEInstInteractionAnalysisT::printEdgeFactImpl(OS, Replacement); - } - OS << ")"; - } - - [[nodiscard]] bool isKillAll() const { - if (auto *RSet = std::get_if>(&Replacement)) { - return RSet->empty(); - } - return false; - } - }; - - // Edge function that adds the given labels to existing labels - // add all labels provided by Data. - class IIAAAddLabelsEF - : public EdgeFunction, - public std::enable_shared_from_this, - public EdgeFunctionSingletonFactory { - public: - const l_t Data; - - explicit IIAAAddLabelsEF(l_t Data) : Data(Data) { - // PHASAR_LOG_LEVEL(DFADEBUG, << "IIAAAddLabelsEF"); - } - - ~IIAAAddLabelsEF() override = default; - - l_t computeTarget(l_t Src) override { - return IDEInstInteractionAnalysisT::joinImpl(Src, Data); - } - - std::shared_ptr> - composeWith(std::shared_ptr> SecondFunction) override { - // PHASAR_LOG_LEVEL(DFADEBUG, - // << "IIAAAddLabelEF::composeWith(): " << this->str() << " - // * " - // << SecondFunction->str()); - if (auto *AT = dynamic_cast *>(SecondFunction.get())) { - return this->shared_from_this(); - } - if (auto *AB = dynamic_cast *>(SecondFunction.get())) { - return this->shared_from_this(); - } - if (auto *EI = dynamic_cast *>(SecondFunction.get())) { - return this->shared_from_this(); - } - if (auto *AD = dynamic_cast(SecondFunction.get())) { - auto Union = IDEInstInteractionAnalysisT::joinImpl(Data, AD->Data); - return IIAAAddLabelsEF::createEdgeFunction(Union); - } - if (auto *KR = - dynamic_cast(SecondFunction.get())) { - return IIAAAddLabelsEF::createEdgeFunction(KR->Replacement); - } - llvm::report_fatal_error( - "found unexpected edge function in 'IIAAAddLabelsEF'"); - } - - std::shared_ptr> - joinWith(std::shared_ptr> OtherFunction) override { - // PHASAR_LOG_LEVEL(DFADEBUG, << - // "IIAAAddLabelsEF::joinWith"); - if (auto *AT = dynamic_cast *>(OtherFunction.get())) { - return this->shared_from_this(); - } - if (auto *AB = dynamic_cast *>(OtherFunction.get())) { - return this->shared_from_this(); - } - if (auto *ID = dynamic_cast *>(OtherFunction.get())) { - return this->shared_from_this(); - } - if (auto *AD = dynamic_cast(OtherFunction.get())) { - auto Union = IDEInstInteractionAnalysisT::joinImpl(Data, AD->Data); - return IIAAAddLabelsEF::createEdgeFunction(Union); - } - if (auto *KR = dynamic_cast(OtherFunction.get())) { - auto Union = - IDEInstInteractionAnalysisT::joinImpl(Data, KR->Replacement); - return IIAAAddLabelsEF::createEdgeFunction(Union); - } - llvm::report_fatal_error( - "found unexpected edge function in 'IIAAAddLabelsEF'"); - } - - [[nodiscard]] bool - equal_to(std::shared_ptr> Other) const override { - if (auto *AS = dynamic_cast(Other.get())) { - return (Data == AS->Data); - } - return this == Other.get(); - } - - void print(llvm::raw_ostream &OS, - bool /* IsForDebug */ = false) const override { - OS << "EF: (IIAAAddLabelsEF: "; - IDEInstInteractionAnalysisT::printEdgeFactImpl(OS, Data); - OS << ")"; - } - }; - - // Provide functionalities for printing things and emitting text reports. - - void printNode(llvm::raw_ostream &OS, n_t n) const override { - OS << llvmIRToString(n); - } - - void printDataFlowFact(llvm::raw_ostream &OS, d_t FlowFact) const override { - OS << llvmIRToString(FlowFact); - } - - void printFunction(llvm::raw_ostream &OS, f_t Fun) const override { - OS << Fun->getName(); - } - - inline void printEdgeFact(llvm::raw_ostream &OS, - l_t EdgeFact) const override { - printEdgeFactImpl(OS, EdgeFact); - } - - void stripBottomResults(std::unordered_map &Res) { - for (auto It = Res.begin(); It != Res.end();) { - if (It->second == BottomElement) { - It = Res.erase(It); - } else { - ++It; - } - } - } - - void emitTextReport(const SolverResults &SR, - llvm::raw_ostream &OS = llvm::outs()) override { - OS << "\n====================== IDE-Inst-Interaction-Analysis Report " - "======================\n"; - // if (!IRDB->debugInfoAvailable()) { - // // Emit only IR code, function name and module info - // OS << "\nWARNING: No Debug Info available - emiting results without " - // "source code mapping!\n"; - for (const auto *f : this->ICF->getAllFunctions()) { - std::string FunName = getFunctionNameFromIR(f); - OS << "\nFunction: " << FunName << "\n----------" - << std::string(FunName.size(), '-') << '\n'; - for (const auto *Inst : this->ICF->getAllInstructionsOf(f)) { - auto Results = SR.resultsAt(Inst, true); - stripBottomResults(Results); - if (!Results.empty()) { - OS << "At IR statement: " << this->NtoString(Inst) << '\n'; - for (auto Result : Results) { - if (Result.second != BottomElement) { - OS << " Fact: " << this->DtoString(Result.first) - << "\n Value: " << this->LtoString(Result.second) << '\n'; - } - } - OS << '\n'; - } - } - OS << '\n'; - } - // } else { - // TODO: implement better report in case debug information are available - // } - } - - /// Computes all variables where a result set has been computed using the - /// edge functions (and respective value domain). - inline std::unordered_set - getAllVariables(const SolverResults & /* Solution */) const { - std::unordered_set Variables; - // collect all variables that are available - for (const auto *M : this->IRDB->getAllModules()) { - for (const auto &G : M->globals()) { - Variables.insert(&G); - } - for (const auto &F : *M) { - for (const auto &BB : F) { - for (const auto &I : BB) { - if (const auto *A = llvm::dyn_cast(&I)) { - Variables.insert(A); - } - if (const auto *H = llvm::dyn_cast(&I)) { - if (!H->isIndirectCall() && H->getCalledFunction() && - this->ICF->isHeapAllocatingFunction(H->getCalledFunction())) { - Variables.insert(H); - } - } - } - } - } - } - - return Variables; - } - - /// Computes all variables for which an empty set has been computed using the - /// edge functions (and respective value domain). - inline std::unordered_set getAllVariablesWithEmptySetValue( - const SolverResults &Solution) const { - return removeVariablesWithoutEmptySetValue(Solution, - getAllVariables(Solution)); - } - -protected: - static inline bool isZeroValueImpl(d_t d) { - return LLVMZeroValue::isLLVMZeroValue(d); - } - - static void printEdgeFactImpl(llvm::raw_ostream &OS, l_t EdgeFact) { - if (std::holds_alternative(EdgeFact)) { - OS << std::get(EdgeFact); - } else if (std::holds_alternative(EdgeFact)) { - OS << std::get(EdgeFact); - } else { - auto LSet = std::get>(EdgeFact); - OS << "(set size: " << LSet.size() << ") values: "; - if constexpr (std::is_same_v) { - for (const auto &LElem : LSet) { - std::string IRBuffer; - llvm::raw_string_ostream RSO(IRBuffer); - LElem->print(RSO); - RSO.flush(); - OS << IRBuffer << ", "; - } - } else { - for (const auto &LElem : LSet) { - OS << LElem << ", "; - } - } - } - } - - static inline l_t joinImpl(l_t Lhs, l_t Rhs) { - if (Lhs == TopElement || Lhs == BottomElement) { - return Rhs; - } - if (Rhs == TopElement || Rhs == BottomElement) { - return Lhs; - } - auto LhsSet = std::get>(Lhs); - auto RhsSet = std::get>(Rhs); - return LhsSet.setUnion(RhsSet); - } - -private: - /// Filters out all variables that had a non-empty set during edge functions - /// computations. - inline std::unordered_set removeVariablesWithoutEmptySetValue( - const SolverResults &Solution, - std::unordered_set Variables) const { - // Check the solver results and remove all variables for which a - // non-empty set has been computed - auto Results = Solution.getAllResultEntries(); - for (const auto &Result : Results) { - // We do not care for the concrete instruction at which data-flow facts - // hold, instead we just wish to find out if a variable has been generated - // 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 &Value = Result.getValue(); - // skip result entry if variable is not in the set of all variables - if (Variables.find(Variable) == Variables.end()) { - continue; - } - // skip result entry if the computed value is not of type BitVectorSet - if (!std::holds_alternative>(Value)) { - continue; - } - // remove variable from result set if a non-empty that has been computed - auto &Values = std::get>(Value); - if (!Values.empty()) { - Variables.erase(Variable); - } - } - return Variables; - } - - const LLVMBasedICFG *ICF{}; - LLVMPointsToInfo *PT{}; - std::function EdgeFactGen; - static inline const l_t BottomElement = Bottom{}; - static inline const l_t TopElement = Top{}; - const bool OnlyConsiderLocalAliases = true; - - inline BitVectorSet edgeFactGenForInstToBitVectorSet(n_t CurrInst) { - if (EdgeFactGen) { - auto Results = EdgeFactGen(CurrInst); - BitVectorSet BVS(Results.begin(), Results.end()); - return BVS; - } - return {}; - } - - inline BitVectorSet - edgeFactGenForGlobalVarToBitVectorSet(const llvm::GlobalVariable *GlobalVar) { - if (EdgeFactGen) { - auto Results = EdgeFactGen(GlobalVar); - BitVectorSet BVS(Results.begin(), Results.end()); - return BVS; - } - return {}; - } -}; // namespace psr - -using IDEInstInteractionAnalysis = IDEInstInteractionAnalysisT<>; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/CallString.h b/include/phasar/PhasarLLVM/DataFlowSolver/Mono/CallString.h deleted file mode 100644 index 10d2687ce..000000000 --- a/include/phasar/PhasarLLVM/DataFlowSolver/Mono/CallString.h +++ /dev/null @@ -1,90 +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 - *****************************************************************************/ - -/* - * CallString.h - * - * Created on: 06.06.2017 - * Author: philipp - */ - -#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_CALLSTRING_H -#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_MONO_CALLSTRING_H - -#include -#include -#include -#include -#include - -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/raw_ostream.h" - -namespace psr { - -template class CallString { -private: - std::deque CS; - static const unsigned KLimit = K; - -public: - CallString() = default; - CallString(std::initializer_list IList) : CS(IList) { - if (IList.size() > KLimit) { - throw std::runtime_error( - "initial call string length exceeds maximal length K"); - } - } - - void push(T S) { - if (CS.size() > KLimit - 1) { - CS.pop_front(); - } - CS.push_back(S); - } - - T returnSite() { - if (!CS.empty()) { - return CS.back(); - } - return {}; - } - - void pop() { - if (!CS.empty()) { - CS.pop_back(); - } - } - - size_t size() { return CS.size(); } - - std::deque getInternalCS() const { return CS; } - - friend bool operator==(const CallString &Lhs, const CallString &Rhs) { - return Lhs.cs == Rhs.cs; - } - - friend bool operator!=(const CallString &Lhs, const CallString &Rhs) { - return !(Lhs == Rhs); - } - - friend bool operator<(const CallString &Lhs, const CallString &Rhs) { - return Lhs.cs < Rhs.cs; - } - - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const CallString &C) { - llvm::interleave(C.CS, OS, " * "); - return OS; - } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h b/include/phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h index 68ec9fda9..11490fe20 100644 --- a/include/phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h +++ b/include/phasar/PhasarLLVM/Domain/LLVMAnalysisDomain.h @@ -10,7 +10,7 @@ #ifndef PHASAR_PHASARLLVM_DOMAIN_LLVMANALYSISDOMAIN_H #define PHASAR_PHASARLLVM_DOMAIN_LLVMANALYSISDOMAIN_H -#include "phasar/PhasarLLVM/Domain/AnalysisDomain.h" +#include "phasar/Domain/AnalysisDomain.h" namespace llvm { class Value; diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalyses.h b/include/phasar/PhasarLLVM/HelperAnalyses.h similarity index 62% rename from include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalyses.h rename to include/phasar/PhasarLLVM/HelperAnalyses.h index 98abb315c..07b09878d 100644 --- a/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalyses.h +++ b/include/phasar/PhasarLLVM/HelperAnalyses.h @@ -10,7 +10,8 @@ #ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSES_H_ #define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_HELPERANALYSES_H_ -#include "phasar/PhasarLLVM/AnalysisStrategy/HelperAnalysisConfig.h" +#include "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/PhasarLLVM/HelperAnalysisConfig.h" #include "nlohmann/json.hpp" @@ -23,39 +24,48 @@ namespace psr { class LLVMProjectIRDB; class LLVMTypeHierarchy; class LLVMBasedICFG; -class LLVMPointsToInfo; +class LLVMBasedCFG; +class LLVMAliasSet; class HelperAnalyses { // NOLINT(cppcoreguidelines-special-member-functions) public: explicit HelperAnalyses(std::string IRFile, std::optional PrecomputedPTS, - PointerAnalysisType PTATy, bool AllowLazyPTS, + AliasAnalysisType PTATy, bool AllowLazyPTS, std::vector EntryPoints, CallGraphAnalysisType CGTy, Soundness SoundnessLevel, - bool AutoGlobalSupport); + bool AutoGlobalSupport) noexcept; explicit HelperAnalyses(std::string IRFile, + std::vector EntryPoints, + HelperAnalysisConfig Config = {}) noexcept; + explicit HelperAnalyses(const llvm::Twine &IRFile, + std::vector EntryPoints, + HelperAnalysisConfig Config = {}); + explicit HelperAnalyses(const char *IRFile, std::vector EntryPoints, HelperAnalysisConfig Config = {}); - ~HelperAnalyses(); + ~HelperAnalyses() noexcept; - LLVMProjectIRDB &getProjectIRDB(); - LLVMPointsToInfo &getPointsToInfo(); - LLVMTypeHierarchy &getTypeHierarchy(); - LLVMBasedICFG &getICFG(); + [[nodiscard]] LLVMProjectIRDB &getProjectIRDB(); + [[nodiscard]] LLVMAliasSet &getAliasInfo(); + [[nodiscard]] LLVMTypeHierarchy &getTypeHierarchy(); + [[nodiscard]] LLVMBasedICFG &getICFG(); + [[nodiscard]] LLVMBasedCFG &getCFG(); private: std::unique_ptr IRDB; - std::unique_ptr PT; + std::unique_ptr PT; std::unique_ptr TH; std::unique_ptr ICF; + std::unique_ptr CFG; // IRDB std::string IRFile; // PTS std::optional PrecomputedPTS; - PointerAnalysisType PTATy{}; + AliasAnalysisType PTATy{}; bool AllowLazyPTS{}; // ICF diff --git a/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalysisConfig.h b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h similarity index 76% rename from include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalysisConfig.h rename to include/phasar/PhasarLLVM/HelperAnalysisConfig.h index c2492c1bb..d35195e76 100644 --- a/include/phasar/PhasarLLVM/AnalysisStrategy/HelperAnalysisConfig.h +++ b/include/phasar/PhasarLLVM/HelperAnalysisConfig.h @@ -10,22 +10,27 @@ #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 "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/Pointer/AliasAnalysisType.h" +#include "phasar/Utils/Soundness.h" #include "nlohmann/json.hpp" -#include "phasar/Utils/Soundness.h" #include namespace psr { struct HelperAnalysisConfig { std::optional PrecomputedPTS = std::nullopt; - PointerAnalysisType PTATy = PointerAnalysisType::CFLAnders; + AliasAnalysisType PTATy = AliasAnalysisType::CFLAnders; CallGraphAnalysisType CGTy = CallGraphAnalysisType::OTF; Soundness SoundnessLevel = Soundness::Soundy; bool AutoGlobalSupport = true; bool AllowLazyPTS = true; + + HelperAnalysisConfig &&withCGType(CallGraphAnalysisType CGTy) &&noexcept { + this->CGTy = CGTy; + return std::move(*this); + } }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h b/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h index 0891893cc..ca6767a3a 100644 --- a/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h +++ b/include/phasar/PhasarLLVM/Passes/GeneralStatisticsAnalysis.h @@ -17,10 +17,11 @@ #ifndef PHASAR_PHASARLLVM_PASSES_GENERALSTATISTICSANALYSIS_H_ #define PHASAR_PHASARLLVM_PASSES_GENERALSTATISTICSANALYSIS_H_ -#include +#include "llvm/IR/PassManager.h" #include "nlohmann/json.hpp" -#include "llvm/IR/PassManager.h" + +#include namespace llvm { class Type; @@ -48,6 +49,7 @@ class GeneralStatistics { size_t Branches = 0; size_t GetElementPtrs = 0; size_t PhiNodes = 0; + size_t GlobalConsts = 0; std::set AllocatedTypes; std::set AllocaInstructions; std::set RetResInstructions; @@ -89,6 +91,11 @@ class GeneralStatistics { */ [[nodiscard]] size_t getGlobals() const; + /** + * @brief Returns the number of constant globals. + */ + [[nodiscard]] size_t getGlobalConsts() const; + /** * @brief Returns the number of memory intrinsics. */ diff --git a/include/phasar/PhasarLLVM/Pointer/DynamicPointsToSetPtr.h b/include/phasar/PhasarLLVM/Pointer/DynamicPointsToSetPtr.h deleted file mode 100644 index e10922cde..000000000 --- a/include/phasar/PhasarLLVM/Pointer/DynamicPointsToSetPtr.h +++ /dev/null @@ -1,230 +0,0 @@ -/****************************************************************************** - * 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_POINTER_DYNAMICPOINTSTOSET_H -#define PHASAR_PHASARLLVM_POINTER_DYNAMICPOINTSTOSET_H - -#include - -#include "llvm/ADT/DenseMapInfo.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/Hashing.h" - -namespace llvm { -class Value; -} // namespace llvm - -namespace psr { - -template > -class DynamicPointsToSetConstPtr; -/// A Container** that behaves like a Container* -template > -class DynamicPointsToSetPtr { -public: - using container_type = Container; - - constexpr DynamicPointsToSetPtr() noexcept = default; - constexpr DynamicPointsToSetPtr(std::nullptr_t) noexcept {} - constexpr DynamicPointsToSetPtr(container_type **Value) noexcept - : Value(Value) { - assert(Value != nullptr); - } - constexpr DynamicPointsToSetPtr(const DynamicPointsToSetPtr &) noexcept = - default; - constexpr DynamicPointsToSetPtr & - operator=(const DynamicPointsToSetPtr &) noexcept = default; - ~DynamicPointsToSetPtr() noexcept = default; - - [[nodiscard]] constexpr container_type *get() noexcept { return *Value; } - [[nodiscard]] constexpr const container_type *get() const noexcept { - return *Value; - } - - constexpr container_type *operator->() noexcept { return get(); } - constexpr const container_type *operator->() const noexcept { return get(); } - - constexpr container_type &operator*() noexcept { return **Value; } - constexpr const container_type &operator*() const noexcept { return **Value; } - - constexpr operator bool() const noexcept { - return Value && *Value != nullptr; - } - - [[nodiscard]] constexpr container_type **value() noexcept { return Value; } - [[nodiscard]] constexpr container_type const *const *value() const noexcept { - return Value; - } - - [[nodiscard]] friend constexpr llvm::hash_code - hash_value(DynamicPointsToSetPtr // NOLINT(readability-identifier-naming) - Ptr) noexcept { - return llvm::hash_value(Ptr.Value); - } - - [[nodiscard]] friend constexpr bool - operator==(DynamicPointsToSetPtr LHS, DynamicPointsToSetPtr RHS) noexcept { - return LHS.Value == RHS.Value; - } - [[nodiscard]] friend constexpr bool - operator!=(DynamicPointsToSetPtr LHS, DynamicPointsToSetPtr RHS) noexcept { - return !(LHS == RHS); - } - - [[nodiscard]] friend constexpr bool - operator<(DynamicPointsToSetPtr LHS, DynamicPointsToSetPtr RHS) noexcept { - return LHS.Value < RHS.Value; - } - [[nodiscard]] friend constexpr bool - operator>(DynamicPointsToSetPtr LHS, DynamicPointsToSetPtr RHS) noexcept { - return LHS.Value > RHS.Value; - } - - [[nodiscard]] friend constexpr bool - operator<=(DynamicPointsToSetPtr LHS, DynamicPointsToSetPtr RHS) noexcept { - return LHS.Value <= RHS.Value; - } - [[nodiscard]] friend constexpr bool - operator>=(DynamicPointsToSetPtr LHS, DynamicPointsToSetPtr RHS) noexcept { - return LHS.Value >= RHS.Value; - } - -private: - friend class DynamicPointsToSetConstPtr; - - container_type **Value = nullptr; -}; - -/// A Container const** that behaves like a const Container*. -/// NOTE: This is different to const DynamicPointsToSetPtr which -/// propagates the const through all known layers of indirection -template -class DynamicPointsToSetConstPtr : private DynamicPointsToSetPtr { -public: - using DynamicPointsToSetPtr::DynamicPointsToSetPtr; - using DynamicPointsToSetPtr::operator bool; - using typename DynamicPointsToSetPtr::container_type; - - constexpr DynamicPointsToSetConstPtr( - DynamicPointsToSetPtr Other) noexcept - : DynamicPointsToSetPtr(Other) {} - - [[nodiscard]] constexpr const container_type *get() const noexcept { - return DynamicPointsToSetPtr::get(); - } - - constexpr const container_type *operator->() const noexcept { return get(); } - - constexpr const container_type &operator*() const noexcept { - return *DynamicPointsToSetPtr::get(); - } - - [[nodiscard]] constexpr container_type const *const *value() const noexcept { - return DynamicPointsToSetPtr::value(); - } - - [[nodiscard]] friend constexpr llvm::hash_code - hash_value(DynamicPointsToSetConstPtr // NOLINT(readability-identifier-naming) - Ptr) noexcept { - return llvm::hash_value(Ptr.value()); - } - - [[nodiscard]] friend constexpr bool - operator==(DynamicPointsToSetConstPtr LHS, - DynamicPointsToSetConstPtr RHS) noexcept { - return LHS.value() == RHS.value(); - } - [[nodiscard]] friend constexpr bool - operator!=(DynamicPointsToSetConstPtr LHS, - DynamicPointsToSetConstPtr RHS) noexcept { - return !(LHS == RHS); - } - - [[nodiscard]] friend constexpr bool - operator<(DynamicPointsToSetConstPtr LHS, - DynamicPointsToSetConstPtr RHS) noexcept { - return LHS.value() < RHS.value(); - } - [[nodiscard]] friend constexpr bool - operator>(DynamicPointsToSetConstPtr LHS, - DynamicPointsToSetConstPtr RHS) noexcept { - return LHS.value() > RHS.value(); - } - - [[nodiscard]] friend constexpr bool - operator<=(DynamicPointsToSetConstPtr LHS, - DynamicPointsToSetConstPtr RHS) noexcept { - return LHS.value() <= RHS.value(); - } - [[nodiscard]] friend constexpr bool - operator>=(DynamicPointsToSetConstPtr LHS, - DynamicPointsToSetConstPtr RHS) noexcept { - return LHS.value() >= RHS.value(); - } -}; - -extern template class DynamicPointsToSetPtr<>; -extern template class DynamicPointsToSetConstPtr<>; -} // namespace psr - -namespace std { -template struct hash> { - constexpr size_t - operator()(psr::DynamicPointsToSetPtr Ptr) const noexcept { - return std::hash{}(Ptr.value()); - } -}; -template struct hash> { - constexpr size_t - operator()(psr::DynamicPointsToSetConstPtr Ptr) const noexcept { - return std::hash{}(Ptr.value()); - } -}; -} // namespace std - -namespace llvm { -template struct DenseMapInfo> { - inline static psr::DynamicPointsToSetPtr getEmptyKey() noexcept { - return DenseMapInfo::getEmptyKey(); - } - inline static psr::DynamicPointsToSetPtr getTombstoneKey() noexcept { - return DenseMapInfo::getTombstoneKey(); - } - - inline static bool isEqual(psr::DynamicPointsToSetPtr LHS, - psr::DynamicPointsToSetPtr RHS) noexcept { - return LHS == RHS; - } - - inline static unsigned - getHashValue(psr::DynamicPointsToSetPtr Ptr) noexcept { - return hash_value(Ptr); - } -}; -template struct DenseMapInfo> { - inline static psr::DynamicPointsToSetConstPtr getEmptyKey() noexcept { - return DenseMapInfo::getEmptyKey(); - } - inline static psr::DynamicPointsToSetConstPtr getTombstoneKey() noexcept { - return DenseMapInfo::getTombstoneKey(); - } - - inline static bool isEqual(psr::DynamicPointsToSetConstPtr LHS, - psr::DynamicPointsToSetConstPtr RHS) noexcept { - return LHS == RHS; - } - - inline static unsigned - getHashValue(psr::DynamicPointsToSetConstPtr Ptr) noexcept { - return hash_value(Ptr); - } -}; -} // namespace llvm - -#endif // PHASAR_PHASARLLVM_POINTER_DYNAMICPOINTSTOSET_H diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToGraph.h b/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h similarity index 71% rename from include/phasar/PhasarLLVM/Pointer/LLVMPointsToGraph.h rename to include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h index d7d8ff281..c266980b1 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToGraph.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMAliasGraph.h @@ -7,24 +7,25 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_LLVMPOINTSTOGRAPH_H_ -#define PHASAR_PHASARLLVM_POINTER_LLVMPOINTSTOGRAPH_H_ +#ifndef PHASAR_PHASARLLVM_POINTER_LLVMALIASGRAPH_H_ +#define PHASAR_PHASARLLVM_POINTER_LLVMALIASGRAPH_H_ -#include -#include -#include -#include - -#include "boost/graph/adjacency_list.hpp" +#include "phasar/Config/Configuration.h" +#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" +#include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h" +#include "phasar/Pointer/AliasInfoBase.h" +#include "phasar/Pointer/AliasInfoTraits.h" +#include "phasar/Pointer/AliasSetOwner.h" +#include "phasar/Utils/AnalysisProperties.h" #include "llvm/IR/AbstractCallSite.h" +#include "boost/graph/adjacency_list.hpp" #include "nlohmann/json.hpp" -#include "phasar/Config/Configuration.h" -#include "phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" -#include "phasar/PhasarLLVM/Pointer/PointsToSetOwner.h" +#include +#include +#include namespace llvm { class Value; @@ -36,8 +37,18 @@ class Type; } // namespace llvm namespace psr { +extern template class BoxedPtr; +extern template class BoxedConstPtr; +extern template class AliasSetOwner; + +class LLVMAliasGraph; +template <> +struct AliasInfoTraits + : DefaultAATraits {}; /** + * TODO: Is this impl legacy code? Can it be removed? + * * This class is a representation of a points-to graph. It is possible to * construct a points-to graph for a single function using the results of * the llvm alias analysis or merge several points-to graphs into a single @@ -47,9 +58,18 @@ namespace psr { * * @brief Represents the points-to graph of a function. */ -class LLVMPointsToGraph : public LLVMPointsToInfo { +class LLVMAliasGraph : public AnalysisPropertiesMixin, + AliasInfoBaseUtils { + using traits_t = AliasInfoTraits; + public: - // Call-graph firends + using n_t = traits_t::n_t; + using v_t = traits_t::v_t; + using AliasSetTy = traits_t::AliasSetTy; + using AliasSetPtrTy = traits_t::AliasSetPtrTy; + using AllocationSiteSetPtrTy = traits_t::AllocationSiteSetPtrTy; + + // Call-graph friends friend class LLVMBasedICFG; /** * @brief Holds the information of a vertex in the points-to graph. @@ -96,30 +116,6 @@ class LLVMPointsToGraph : public LLVMPointsToInfo { using out_edge_iterator = boost::graph_traits::out_edge_iterator; using in_edge_iterator = boost::graph_traits::in_edge_iterator; -private: - struct AllocationSiteDFSVisitor; - struct ReachabilityDFSVisitor; - - /// The points to graph. - graph_t PAG; - using ValueVertexMapT = std::unordered_map; - ValueVertexMapT ValueVertexMap; - /// Keep track of what has already been merged into this points-to graph. - std::unordered_set AnalyzedFunctions; - LLVMBasedPointsToAnalysis PTA; - - PointsToSetOwner::memory_resource_type MRes; - PointsToSetOwner Owner{&MRes}; - std::unordered_map> - Cache; - - // void mergeGraph(const LLVMPointsToGraph &Other); - - void computePointsToGraph(const llvm::Value *V); - - void computePointsToGraph(llvm::Function *F); - -public: /** * Creates a points-to graph based on the computed Alias results. * @@ -130,44 +126,9 @@ class LLVMPointsToGraph : public LLVMPointsToInfo { * considered. False, if May and Must Aliases should be * considered. */ - LLVMPointsToGraph(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, - PointerAnalysisType PATy = PointerAnalysisType::CFLAnders); - - ~LLVMPointsToGraph() override = default; - - bool isInterProcedural() const override; - - PointerAnalysisType getPointerAnalysistype() const override; - - AliasResult alias(const llvm::Value *V1, const llvm::Value *V2, - const llvm::Instruction *I = nullptr) override; - - PointsToSetPtrTy - getPointsToSet(const llvm::Value *V, - const llvm::Instruction *I = nullptr) override; - - AllocationSiteSetPtrTy - getReachableAllocationSites(const llvm::Value *V, bool IntraProcOnly = false, - const llvm::Instruction *I = nullptr) override; - - [[nodiscard]] bool - isInReachableAllocationSites(const llvm::Value *V, - const llvm::Value *PotentialValue, - bool IntraProcOnly = false, - const llvm::Instruction *I = nullptr) override; - - void mergeWith(const PointsToInfo &PTI) override; - - void introduceAlias(const llvm::Value *V1, const llvm::Value *V2, - const llvm::Instruction *I = nullptr, - AliasResult Kind = AliasResult::MustAlias) override; - - void print(llvm::raw_ostream &OS = llvm::outs()) const override; - - nlohmann::json getAsJson() const override; - - void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const override; + explicit LLVMAliasGraph( + LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, + AliasAnalysisType PATy = AliasAnalysisType::CFLAnders); /** * @brief Returns true if graph contains 0 nodes. @@ -246,6 +207,66 @@ class LLVMPointsToGraph : public LLVMPointsToInfo { size_t getNumVertices() const; size_t getNumEdges() const; + + // --- IsAliasInfo impl + + [[nodiscard]] bool isInterProcedural() const noexcept; + + [[nodiscard]] AliasAnalysisType getAliasAnalysisType() const noexcept; + + AliasResult alias(const llvm::Value *V1, const llvm::Value *V2, + const llvm::Instruction *I = nullptr); + + AliasSetPtrTy getAliasSet(const llvm::Value *V, + const llvm::Instruction *I = nullptr); + + AllocationSiteSetPtrTy + getReachableAllocationSites(const llvm::Value *V, bool IntraProcOnly = false, + const llvm::Instruction *I = nullptr); + + [[nodiscard]] bool isInReachableAllocationSites( + const llvm::Value *V, const llvm::Value *PotentialValue, + bool IntraProcOnly = false, const llvm::Instruction *I = nullptr); + + void mergeWith(const LLVMAliasGraph &OtherPTI); + + void introduceAlias(const llvm::Value *V1, const llvm::Value *V2, + const llvm::Instruction *I = nullptr, + AliasResult Kind = AliasResult::MustAlias); + + void print(llvm::raw_ostream &OS = llvm::outs()) const; + + [[nodiscard]] nlohmann::json getAsJson() const; + + void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; + + [[nodiscard]] AnalysisProperties getAnalysisProperties() const noexcept { + return AnalysisProperties::None; + } + +private: + // --- + + // void mergeGraph(const LLVMAliasGraph &Other); + + void computeAliasGraph(const llvm::Value *V); + + void computeAliasGraph(llvm::Function *F); + + struct AllocationSiteDFSVisitor; + struct ReachabilityDFSVisitor; + + /// The points to graph. + graph_t PAG; + using ValueVertexMapT = std::unordered_map; + ValueVertexMapT ValueVertexMap; + /// Keep track of what has already been merged into this points-to graph. + std::unordered_set AnalyzedFunctions; + LLVMBasedAliasAnalysis PTA; + + AliasSetOwner::memory_resource_type MRes; + AliasSetOwner Owner{&MRes}; + std::unordered_map> Cache; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/Utils/IOFormat.h b/include/phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h similarity index 51% rename from include/phasar/PhasarLLVM/Utils/IOFormat.h rename to include/phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h index 32e8d022b..43d83a1f6 100644 --- a/include/phasar/PhasarLLVM/Utils/IOFormat.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h @@ -7,27 +7,23 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_UTILS_IOFORMAT_H_ -#define PHASAR_PHASARLLVM_UTILS_IOFORMAT_H_ +#ifndef PHASAR_PHASARLLVM_POINTER_LLVMALIASINFO_H_ +#define PHASAR_PHASARLLVM_POINTER_LLVMALIASINFO_H_ -namespace llvm { -class raw_ostream; -} +#include "phasar/Pointer/AliasInfo.h" -#include +namespace llvm { +class Function; +class Instruction; +class Value; +} // namespace llvm namespace psr { -enum class IOFormat { -#define IO_FORMAT_TYPES(NAME, CMDFLAG, TYPE) TYPE, -#include "phasar/PhasarLLVM/Utils/IOFormat.def" -}; - -std::string toString(const IOFormat &D); - -IOFormat toIOFormat(const std::string &S); +using LLVMAliasInfoRef = + AliasInfoRef; -llvm::raw_ostream &operator<<(llvm::raw_ostream &Os, const IOFormat &D); +using LLVMAliasInfo = AliasInfo; } // namespace psr diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h b/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h new file mode 100644 index 000000000..0775e98d2 --- /dev/null +++ b/include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h @@ -0,0 +1,164 @@ +/****************************************************************************** + * Copyright (c) 2020 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_LLVMALIASSET_H +#define PHASAR_PHASARLLVM_POINTER_LLVMALIASSET_H + +#include "phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h" +#include "phasar/Pointer/AliasInfoBase.h" +#include "phasar/Pointer/AliasInfoTraits.h" +#include "phasar/Pointer/AliasResult.h" +#include "phasar/Pointer/AliasSetOwner.h" +#include "phasar/Utils/AnalysisProperties.h" +#include "phasar/Utils/StableVector.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" + +#include "nlohmann/json.hpp" + +#include + +namespace llvm { +class Value; +class Instruction; +class GlobalVariable; +class Function; +} // namespace llvm + +namespace psr { + +class LLVMAliasSet; +class LLVMProjectIRDB; + +template <> +struct AliasInfoTraits + : DefaultAATraits {}; + +class LLVMAliasSet : public AnalysisPropertiesMixin, + public AliasInfoBaseUtils { + +public: + using traits_t = AliasInfoTraits; + using n_t = traits_t::n_t; + using v_t = traits_t::v_t; + using AliasSetTy = traits_t::AliasSetTy; + using AliasSetPtrTy = traits_t::AliasSetPtrTy; + using AllocationSiteSetPtrTy = traits_t::AllocationSiteSetPtrTy; + using AliasSetMap = llvm::DenseMap>; + + /** + * Creates points-to set(s) for all functions in the IRDB. If + * UseLazyEvaluation is true, computes points-to-sets for functions that do + * not use global variables on the fly + */ + explicit LLVMAliasSet(LLVMProjectIRDB *IRDB, bool UseLazyEvaluation = true, + AliasAnalysisType PATy = AliasAnalysisType::CFLAnders); + + explicit LLVMAliasSet(LLVMProjectIRDB *IRDB, + const nlohmann::json &SerializedPTS); + + [[nodiscard]] inline bool isInterProcedural() const noexcept { + return false; + }; + + [[nodiscard]] inline AliasAnalysisType getAliasAnalysisType() const noexcept { + return PTA.getPointerAnalysisType(); + }; + + [[nodiscard]] AliasResult alias(const llvm::Value *V1, const llvm::Value *V2, + const llvm::Instruction *I = nullptr); + + [[nodiscard]] AliasSetPtrTy getAliasSet(const llvm::Value *V, + const llvm::Instruction *I = nullptr); + + [[nodiscard]] AllocationSiteSetPtrTy + getReachableAllocationSites(const llvm::Value *V, bool IntraProcOnly = false, + const llvm::Instruction *I = nullptr); + + // Checks if PotentialValue is in the reachable allocation sites of V. + [[nodiscard]] bool isInReachableAllocationSites( + const llvm::Value *V, const llvm::Value *PotentialValue, + bool IntraProcOnly = false, const llvm::Instruction *I = nullptr); + + void mergeWith(const LLVMAliasSet &OtherPTI); + + void introduceAlias(const llvm::Value *V1, const llvm::Value *V2, + const llvm::Instruction *I = nullptr, + AliasResult Kind = AliasResult::MustAlias); + + void print(llvm::raw_ostream &OS = llvm::outs()) const; + + [[nodiscard]] nlohmann::json getAsJson() const; + + void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const; + + [[nodiscard]] AnalysisProperties getAnalysisProperties() const noexcept { + return AnalysisProperties::None; + } + + /** + * Shows a parts of an alias set. Good for debugging when one wants to peak + * into a points to set. + * + * @param ValueSetPair a pair on an Value* and the corresponding points to set + * @param Peak the amount of instrutions shown from the points to set + */ + static void peakIntoAliasSet(const AliasSetMap::value_type &ValueSetPair, + int Peak); + + /** + * Prints out the size distribution for all points to sets. + * + * @param Peak the amount of instrutions shown from one of the biggest points + * to sets, use 0 show nothing. + */ + void drawAliasSetsDistribution(int Peak = 10) const; + + [[nodiscard]] inline bool empty() const { return AnalyzedFunctions.empty(); } + +private: + void computeValuesAliasSet(const llvm::Value *V); + + void computeFunctionsAliasSet(llvm::Function *F); + + void addSingletonAliasSet(const llvm::Value *V); + + void mergeAliasSets(const llvm::Value *V1, const llvm::Value *V2); + + void mergeAliasSets(BoxedPtr PTS1, BoxedPtr PTS2); + + bool interIsReachableAllocationSiteTy(const llvm::Value *V, + const llvm::Value *P) const; + + bool intraIsReachableAllocationSiteTy(const llvm::Value *V, + const llvm::Value *P, + const llvm::Function *VFun, + const llvm::GlobalObject *VG) const; + + /// Utility function used by computeFunctionsAliasSet(...) + void addPointer(llvm::AAResults &AA, const llvm::DataLayout &DL, + const llvm::Value *V, std::vector &Reps); + + [[nodiscard]] static BoxedPtr getEmptyAliasSet(); + + LLVMBasedAliasAnalysis PTA; + llvm::DenseSet AnalyzedFunctions; + + AliasSetOwner::memory_resource_type MRes; + AliasSetOwner Owner{&MRes}; + + AliasSetMap AliasSets; +}; + +static_assert(IsAliasInfo); + +} // namespace psr + +#endif diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h b/include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h similarity index 55% rename from include/phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h rename to include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h index 899b2cb87..e724a0c4d 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.h @@ -7,17 +7,15 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_LLVMBASEDPOINTSTOANALYSIS_H_ -#define PHASAR_PHASARLLVM_POINTER_LLVMBASEDPOINTSTOANALYSIS_H_ +#ifndef PHASAR_PHASARLLVM_POINTER_LLVMBASEDALIASANALYSIS_H_ +#define PHASAR_PHASARLLVM_POINTER_LLVMBASEDALIASANALYSIS_H_ -#include +#include "phasar/Pointer/AliasAnalysisType.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/IR/PassManager.h" #include "llvm/Passes/PassBuilder.h" -#include "phasar/PhasarLLVM/Pointer/PointsToInfo.h" - namespace llvm { class Value; class Function; @@ -28,40 +26,39 @@ namespace psr { class LLVMProjectIRDB; -class LLVMBasedPointsToAnalysis { +class LLVMBasedAliasAnalysis { private: llvm::PassBuilder PB; llvm::AAManager AA; llvm::FunctionAnalysisManager FAM; llvm::FunctionPassManager FPM; - mutable std::unordered_map AAInfos; - PointerAnalysisType PATy; + llvm::DenseMap AAInfos; + AliasAnalysisType PATy; - bool hasPointsToInfo(const llvm::Function &Fun) const; + [[nodiscard]] bool hasAliasInfo(const llvm::Function &Fun) const; - void computePointsToInfo(llvm::Function &Fun); + void computeAliasInfo(llvm::Function &Fun); public: - LLVMBasedPointsToAnalysis( - LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, - PointerAnalysisType PATy = PointerAnalysisType::CFLAnders); + LLVMBasedAliasAnalysis(LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, + AliasAnalysisType PATy = AliasAnalysisType::CFLAnders); - ~LLVMBasedPointsToAnalysis() = default; + ~LLVMBasedAliasAnalysis() = default; void print(llvm::raw_ostream &OS = llvm::outs()) const; [[nodiscard]] inline llvm::AAResults *getAAResults(llvm::Function *F) { - if (!hasPointsToInfo(*F)) { - computePointsToInfo(*F); + if (!hasAliasInfo(*F)) { + computeAliasInfo(*F); } - return AAInfos.at(F); + return AAInfos.lookup(F); }; void erase(llvm::Function *F); void clear(); - [[nodiscard]] inline PointerAnalysisType getPointerAnalysisType() const { + [[nodiscard]] inline AliasAnalysisType getPointerAnalysisType() const { return PATy; }; }; diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h b/include/phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h deleted file mode 100644 index 0017cebf0..000000000 --- a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 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_LLVMPOINTSTOINFO_H_ -#define PHASAR_PHASARLLVM_POINTER_LLVMPOINTSTOINFO_H_ - -#include "phasar/PhasarLLVM/Pointer/PointsToInfo.h" - -namespace llvm { -class Function; -class Instruction; -class Value; -} // namespace llvm - -namespace psr { - -class LLVMPointsToInfo - : public PointsToInfo { -public: - using PointsToInfo::AllocationSiteSetPtrTy; - using PointsToInfo::PointsToSetPtrTy; - using PointsToInfo::PointsToSetTy; - - ~LLVMPointsToInfo() override = default; - - static const llvm::Function *retrieveFunction(const llvm::Value *V); -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h b/include/phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h deleted file mode 100644 index d860c6e45..000000000 --- a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToSet.h +++ /dev/null @@ -1,155 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 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_LLVMPOINTSTOSET_H -#define PHASAR_PHASARLLVM_POINTER_LLVMPOINTSTOSET_H - -#include "phasar/PhasarLLVM/Pointer/DynamicPointsToSetPtr.h" -#include "phasar/PhasarLLVM/Pointer/LLVMBasedPointsToAnalysis.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" -#include "phasar/PhasarLLVM/Pointer/PointsToSetOwner.h" -#include "phasar/Utils/StableVector.h" - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" - -#include "nlohmann/json.hpp" - -namespace llvm { -class Value; -class Module; -class Instruction; -class AAResults; -class GlobalVariable; -class Function; -class Type; -} // namespace llvm - -namespace psr { - -class LLVMProjectIRDB; - -class LLVMPointsToSet : public LLVMPointsToInfo { -private: - using PointsToSetMap = - llvm::DenseMap>; - - LLVMBasedPointsToAnalysis PTA; - llvm::DenseSet AnalyzedFunctions; - - PointsToSetOwner::memory_resource_type MRes; - PointsToSetOwner Owner{&MRes}; - - PointsToSetMap PointsToSets; - - void computeValuesPointsToSet(const llvm::Value *V); - - void computeFunctionsPointsToSet(llvm::Function *F); - - void addSingletonPointsToSet(const llvm::Value *V); - - void mergePointsToSets(const llvm::Value *V1, const llvm::Value *V2); - - void mergePointsToSets(DynamicPointsToSetPtr PTS1, - DynamicPointsToSetPtr PTS2); - - bool interIsReachableAllocationSiteTy(const llvm::Value *V, - const llvm::Value *P); - - bool intraIsReachableAllocationSiteTy(const llvm::Value *V, - const llvm::Value *P, - const llvm::Function *VFun, - const llvm::GlobalObject *VG); - - /// Utility function used by computeFunctionsPointsToSet(...) - void addPointer(llvm::AAResults &AA, const llvm::DataLayout &DL, - const llvm::Value *V, std::vector &Reps); - - [[nodiscard]] static DynamicPointsToSetPtr - getEmptyPointsToSet(); - -public: - /** - * Creates points-to set(s) for all functions in the IRDB. If - * UseLazyEvaluation is true, computes points-to-sets for functions that do - * not use global variables on the fly - */ - explicit LLVMPointsToSet( - LLVMProjectIRDB &IRDB, bool UseLazyEvaluation = true, - PointerAnalysisType PATy = PointerAnalysisType::CFLAnders); - - explicit LLVMPointsToSet(LLVMProjectIRDB &IRDB, - const nlohmann::json &SerializedPTS); - - ~LLVMPointsToSet() override = default; - - [[nodiscard]] inline bool isInterProcedural() const override { - return false; - }; - - [[nodiscard]] inline PointerAnalysisType - getPointerAnalysistype() const override { - return PTA.getPointerAnalysisType(); - }; - - [[nodiscard]] AliasResult - alias(const llvm::Value *V1, const llvm::Value *V2, - const llvm::Instruction *I = nullptr) override; - - [[nodiscard]] PointsToSetPtrTy - getPointsToSet(const llvm::Value *V, - const llvm::Instruction *I = nullptr) override; - - [[nodiscard]] AllocationSiteSetPtrTy - getReachableAllocationSites(const llvm::Value *V, bool IntraProcOnly = false, - const llvm::Instruction *I = nullptr) override; - - // Checks if PotentialValue is in the reachable allocation sites of V. - [[nodiscard]] bool - isInReachableAllocationSites(const llvm::Value *V, - const llvm::Value *PotentialValue, - bool IntraProcOnly = false, - const llvm::Instruction *I = nullptr) override; - - void mergeWith(const PointsToInfo &PTI) override; - - void introduceAlias(const llvm::Value *V1, const llvm::Value *V2, - const llvm::Instruction *I = nullptr, - AliasResult Kind = AliasResult::MustAlias) override; - - [[nodiscard]] inline bool empty() const { return AnalyzedFunctions.empty(); } - - void print(llvm::raw_ostream &OS = llvm::outs()) const override; - - [[nodiscard]] nlohmann::json getAsJson() const override; - - void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const override; - - /** - * Shows a parts of an alias set. Good for debugging when one wants to peak - * into a points to set. - * - * @param ValueSetPair a pair on an Value* and the corresponding points to set - * @param Peak the amount of instrutions shown from the points to set - */ - static void - peakIntoPointsToSet(const PointsToSetMap::value_type &ValueSetPair, int Peak); - - /** - * Prints out the size distribution for all points to sets. - * - * @param Peak the amount of instrutions shown from one of the biggest points - * to sets, use 0 show nothing. - */ - void drawPointsToSetsDistribution(int Peak = 10) const; -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h b/include/phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h index 99778d08b..6ac25f29f 100644 --- a/include/phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h +++ b/include/phasar/PhasarLLVM/Pointer/LLVMPointsToUtils.h @@ -10,15 +10,12 @@ #ifndef PHASAR_PHASARLLVM_POINTER_LLVMPOINTSTOUTILS_H_ #define PHASAR_PHASARLLVM_POINTER_LLVMPOINTSTOUTILS_H_ -#include - #include "llvm/ADT/StringRef.h" #include "llvm/IR/Constants.h" -#include "llvm/IR/Type.h" #include "llvm/IR/Value.h" namespace llvm { -class Value; +class Function; } // namespace llvm namespace psr { @@ -27,12 +24,12 @@ namespace psr { * @brief Returns true if the given pointer is an interesting pointer, * i.e. not a constant null pointer. */ -inline bool isInterestingPointer(const llvm::Value *V) { +[[nodiscard]] inline bool isInterestingPointer(const llvm::Value *V) { return V->getType()->isPointerTy() && !llvm::isa(V); } -extern const std::set HeapAllocatingFunctions; +[[nodiscard]] bool isHeapAllocatingFunction(const llvm::Function *Fun); } // namespace psr diff --git a/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.def b/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.def deleted file mode 100644 index 76c75b779..000000000 --- a/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.def +++ /dev/null @@ -1,17 +0,0 @@ -/****************************************************************************** - * 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 POINTER_ANALYSIS_TYPE -#define POINTER_ANALYSIS_TYPE(NAME, CMDFLAG, DESC) -#endif - -POINTER_ANALYSIS_TYPE(CFLSteens, "cflsteens", "Steensgaard-style alias analysis (equality-based)") -POINTER_ANALYSIS_TYPE(CFLAnders, "cflanders", "Andersen-style alias analysis (subset-based)") - -#undef POINTER_ANALYSIS_TYPE diff --git a/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.h b/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.h deleted file mode 100644 index 771d43a85..000000000 --- a/include/phasar/PhasarLLVM/Pointer/PointerAnalysisType.h +++ /dev/null @@ -1,44 +0,0 @@ - -/****************************************************************************** - * 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 deleted file mode 100644 index a969b0e8a..000000000 --- a/include/phasar/PhasarLLVM/Pointer/PointsToInfo.h +++ /dev/null @@ -1,72 +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_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" - -namespace psr { - -template class PointsToInfo { -public: - using PointsToSetTy = llvm::DenseSet; - using PointsToSetPtrTy = DynamicPointsToSetConstPtr; - using AllocationSiteSetPtrTy = std::unique_ptr; - - virtual ~PointsToInfo() = default; - - [[nodiscard]] virtual bool isInterProcedural() const = 0; - - [[nodiscard]] virtual PointerAnalysisType getPointerAnalysistype() const = 0; - - [[nodiscard]] virtual AliasResult alias(V V1, V V2, N I = N{}) = 0; - - [[nodiscard]] virtual PointsToSetPtrTy getPointsToSet(V V1, N I = N{}) = 0; - - [[nodiscard]] virtual AllocationSiteSetPtrTy - getReachableAllocationSites(V V1, bool IntraProcOnly = false, N I = N{}) = 0; - - // Checks if V2 is a reachable allocation in the points to set of V1. - [[nodiscard]] virtual bool - isInReachableAllocationSites(V V1, V V2, bool IntraProcOnly = false, - N I = N{}) = 0; - - virtual void print(llvm::raw_ostream &OS = llvm::outs()) const = 0; - - [[nodiscard]] virtual nlohmann::json getAsJson() const = 0; - - virtual void printAsJson(llvm::raw_ostream &OS) const = 0; - - // The following functions are relevent when combining points-to with other - // pieces of information. For instance, during a call-graph construction (or - // a data-flow analysis) points-to information may be altered to incorporate - // novel information. - virtual void mergeWith(const PointsToInfo &PTI) = 0; - - virtual void introduceAlias(V V1, V V2, N I = N{}, - AliasResult Kind = AliasResult::MustAlias) = 0; -}; - -template -static inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const PointsToInfo &PTI) { - PTI.print(OS); - return OS; -} - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h b/include/phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h index d90eef39f..1931705cf 100644 --- a/include/phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h +++ b/include/phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h @@ -17,17 +17,16 @@ #ifndef PHASAR_PHASARLLVM_POINTER_TYPEGRAPHS_CACHEDTYPEGRAPH_H_ #define PHASAR_PHASARLLVM_POINTER_TYPEGRAPHS_CACHEDTYPEGRAPH_H_ -#include -#include -#include - -#include "gtest/gtest_prod.h" +#include "phasar/PhasarLLVM/Pointer/TypeGraphs/TypeGraph.h" #include "boost/graph/adjacency_list.hpp" #include "boost/graph/graph_traits.hpp" #include "boost/graph/reverse_graph.hpp" +#include "gtest/gtest_prod.h" -#include "phasar/PhasarLLVM/Pointer/TypeGraphs/TypeGraph.h" +#include +#include +#include namespace llvm { class StructType; diff --git a/include/phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h b/include/phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h index e16bbf413..025a4ffd6 100644 --- a/include/phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h +++ b/include/phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h @@ -17,17 +17,16 @@ #ifndef PHASAR_PHASARLLVM_POINTER_TYPEGRAPHS_LAZYTYPEGRAPH_H #define PHASAR_PHASARLLVM_POINTER_TYPEGRAPHS_LAZYTYPEGRAPH_H -#include -#include -#include - -#include "gtest/gtest_prod.h" +#include "phasar/PhasarLLVM/Pointer/TypeGraphs/TypeGraph.h" #include "boost/graph/adjacency_list.hpp" #include "boost/graph/graph_traits.hpp" #include "boost/graph/reverse_graph.hpp" +#include "gtest/gtest_prod.h" -#include "phasar/PhasarLLVM/Pointer/TypeGraphs/TypeGraph.h" +#include +#include +#include namespace llvm { class StructType; diff --git a/include/phasar/PhasarLLVM/SimpleAnalysisConstructor.h b/include/phasar/PhasarLLVM/SimpleAnalysisConstructor.h new file mode 100644 index 000000000..7976a42ac --- /dev/null +++ b/include/phasar/PhasarLLVM/SimpleAnalysisConstructor.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, and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_ANALYSISSTRATEGY_SIMPLEANALYSISCONSTRUCTOR_H_ +#define PHASAR_PHASARLLVM_ANALYSISSTRATEGY_SIMPLEANALYSISCONSTRUCTOR_H_ + +#include "phasar/PhasarLLVM/HelperAnalyses.h" + +#include +#include + +namespace psr { +class LLVMProjectIRDB; +class LLVMAliasSet; +class LLVMBasedICFG; +class LLVMTypeHierarchy; + +template +ProblemTy createAnalysisProblem(HelperAnalyses &HA, ArgTys &&...Args) { + if constexpr (std::is_constructible_v) { + return ProblemTy(HA, std::forward(Args)...); + } else if constexpr (std::is_constructible_v< + ProblemTy, const LLVMProjectIRDB *, ArgTys...>) { + return ProblemTy(&HA.getProjectIRDB(), std::forward(Args)...); + } else if constexpr (std::is_constructible_v< + ProblemTy, const LLVMProjectIRDB *, + const LLVMBasedICFG *, ArgTys...>) { + return ProblemTy(&HA.getProjectIRDB(), &HA.getICFG(), + std::forward(Args)...); + } else if constexpr (std::is_constructible_v) { + return ProblemTy(&HA.getProjectIRDB(), &HA.getAliasInfo(), + std::forward(Args)...); + } else if constexpr (std::is_constructible_v< + ProblemTy, const LLVMProjectIRDB *, + const LLVMBasedICFG *, LLVMAliasSet *, ArgTys...>) { + return ProblemTy(&HA.getProjectIRDB(), &HA.getICFG(), &HA.getAliasInfo(), + std::forward(Args)...); + } else if constexpr (std::is_constructible_v< + ProblemTy, const LLVMProjectIRDB *, + const LLVMTypeHierarchy *, const LLVMBasedCFG *, + LLVMAliasSet *, ArgTys...>) { + return ProblemTy(&HA.getProjectIRDB(), &HA.getTypeHierarchy(), &HA.getCFG(), + &HA.getAliasInfo(), std::forward(Args)...); + } else if constexpr (std::is_constructible_v< + ProblemTy, const LLVMProjectIRDB *, + const LLVMTypeHierarchy *, const LLVMBasedICFG *, + LLVMAliasSet *, ArgTys...>) { + return ProblemTy(&HA.getProjectIRDB(), &HA.getTypeHierarchy(), + &HA.getICFG(), &HA.getAliasInfo(), + std::forward(Args)...); + } else { + static_assert( + std::is_constructible_v, + "Cannot construct analysis problem from HelperAnalyses"); + } +} + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_ANALYSISSTRATEGY_SIMPLEANALYSISCONSTRUCTOR_H_ diff --git a/include/phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h b/include/phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h new file mode 100644 index 000000000..04c11650f --- /dev/null +++ b/include/phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h @@ -0,0 +1,109 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_TAINTCONFIG_LLVMTAINTCONFIG_H +#define PHASAR_PHASARLLVM_TAINTCONFIG_LLVMTAINTCONFIG_H + +#include "phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h" + +#include "llvm/IR/Instruction.h" + +#include + +namespace psr { +class LLVMTaintConfig; +class LLVMProjectIRDB; + +template <> struct TaintConfigTraits { + using n_t = const llvm::Instruction *; + using v_t = const llvm::Value *; + using f_t = const llvm::Function *; +}; + +class LLVMTaintConfig : public TaintConfigBase { + friend TaintConfigBase; + +public: + explicit LLVMTaintConfig(const psr::LLVMProjectIRDB &Code, + const nlohmann::json &Config); + explicit LLVMTaintConfig(const psr::LLVMProjectIRDB &AnnotatedCode); + explicit LLVMTaintConfig( + TaintDescriptionCallBackTy SourceCB, TaintDescriptionCallBackTy SinkCB, + TaintDescriptionCallBackTy SanitizerCB = {}) noexcept; + + void addSourceValue(const llvm::Value *V); + void addSinkValue(const llvm::Value *V); + void addSanitizerValue(const llvm::Value *V); + void addTaintCategory(const llvm::Value *Val, llvm::StringRef AnnotationStr); + void addTaintCategory(const llvm::Value *Val, TaintCategory Annotation); + +private: + [[nodiscard]] bool isSourceImpl(const llvm::Value *V) const; + [[nodiscard]] bool isSinkImpl(const llvm::Value *V) const; + [[nodiscard]] bool isSanitizerImpl(const llvm::Value *V) const; + + /// \brief Calls Handler for all operands of Inst (maybe including Inst + /// itself) that are generated unconditionally as tainted. + /// + /// If Inst is a function-call, the Callee function should be specified + /// explicitly. + void forAllGeneratedValuesAtImpl( + const llvm::Instruction *Inst, const llvm::Function *Callee, + llvm::function_ref Handler) const; + + /// \brief Calls Handler for all operands of Inst that may generate a leak + /// when they are tainted. + /// + /// If Inst is a function-call, the Callee function should be specified + /// explicitly. + void forAllLeakCandidatesAtImpl( + const llvm::Instruction *Inst, const llvm::Function *Callee, + llvm::function_ref Handler) const; + + /// \brief Calls Handler for all operands of Inst that become sanitized after + /// the instruction is completed. + /// + /// If Inst is a function-call, the Callee function should be specified + /// explicitly. + void forAllSanitizedValuesAtImpl( + const llvm::Instruction *Inst, const llvm::Function *Callee, + llvm::function_ref Handler) const; + + [[nodiscard]] bool generatesValuesAtImpl(const llvm::Instruction *Inst, + const llvm::Function *Callee) const; + [[nodiscard]] bool mayLeakValuesAtImpl(const llvm::Instruction *Inst, + const llvm::Function *Callee) const; + [[nodiscard]] bool sanitizesValuesAtImpl(const llvm::Instruction *Inst, + const llvm::Function *Callee) const; + + [[nodiscard]] TaintCategory getCategoryImpl(const llvm::Value *V) const; + + [[nodiscard]] std::map> + makeInitialSeedsImpl() const; + + void printImpl(llvm::raw_ostream &OS) const; + + // --- utilities + + void addAllFunctions(const LLVMProjectIRDB &IRDB, + const nlohmann::json &Config); + + // --- data members + + std::unordered_set SourceValues; + std::unordered_set SinkValues; + std::unordered_set SanitizerValues; +}; + +extern template class TaintConfigBase; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_TAINTCONFIG_LLVMTAINTCONFIG_H diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfig.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfig.h deleted file mode 100644 index b0bcbe586..000000000 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfig.h +++ /dev/null @@ -1,145 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2021 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_TAINTCONFIG_TAINTCONFIG_H -#define PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIG_H - -#include -#include -#include -#include -#include - -#include "nlohmann/json.hpp" - -#include "llvm/ADT/STLExtras.h" // function_ref -#include "llvm/ADT/StringRef.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Value.h" - -namespace psr { -class LLVMProjectIRDB; - -enum class TaintCategory { Source, Sink, Sanitizer, None }; - -constexpr inline llvm::StringRef toString(TaintCategory Cat) noexcept { - switch (Cat) { - case TaintCategory::Source: - return "Source"; - case TaintCategory::Sink: - return "Sink"; - case TaintCategory::Sanitizer: - return "Sanitizer"; - case TaintCategory::None: - return "None"; - } -} - -TaintCategory toTaintCategory(llvm::StringRef Str); - -//===----------------------------------------------------------------------===// -// TaintConfig Class -//===----------------------------------------------------------------------===// - -// This class models a taint configuration to be used to parameterize a taint -// analysis. -class TaintConfig { - - void addAllFunctions(const LLVMProjectIRDB &IRDB, - const nlohmann::json &Config); - -public: - using TaintDescriptionCallBackTy = - std::function(const llvm::Instruction *)>; - - TaintConfig(const psr::LLVMProjectIRDB &Code, const nlohmann::json &Config); - TaintConfig(const psr::LLVMProjectIRDB &AnnotatedCode); - TaintConfig( - TaintDescriptionCallBackTy SourceCB, TaintDescriptionCallBackTy SinkCB, - TaintDescriptionCallBackTy SanitizerCB = TaintDescriptionCallBackTy{}); - - void registerSourceCallBack(TaintDescriptionCallBackTy CB); - void registerSinkCallBack(TaintDescriptionCallBackTy CB); - void registerSanitizerCallBack(TaintDescriptionCallBackTy CB); - - [[nodiscard]] const TaintDescriptionCallBackTy & - getRegisteredSourceCallBack() const; - [[nodiscard]] const TaintDescriptionCallBackTy & - getRegisteredSinkCallBack() const; - - [[nodiscard]] bool isSource(const llvm::Value *V) const; - [[nodiscard]] bool isSink(const llvm::Value *V) const; - [[nodiscard]] bool isSanitizer(const llvm::Value *V) const; - - /// \brief Calls Handler for all operands of Inst (maybe including Inst - /// itself) that are generated unconditionally as tainted. - /// - /// If Inst is a function-call, the Callee function should be specified - /// explicitly. - void forAllGeneratedValuesAt( - const llvm::Instruction *Inst, const llvm::Function *Callee, - llvm::function_ref Handler) const; - - /// \brief Calls Handler for all operands of Inst that may generate a leak - /// when they are tainted. - /// - /// If Inst is a function-call, the Callee function should be specified - /// explicitly. - void forAllLeakCandidatesAt( - const llvm::Instruction *Inst, const llvm::Function *Callee, - llvm::function_ref Handler) const; - - /// \brief Calls Handler for all operands of Inst that become sanitized after - /// the instruction is completed. - /// - /// If Inst is a function-call, the Callee function should be specified - /// explicitly. - void forAllSanitizedValuesAt( - const llvm::Instruction *Inst, const llvm::Function *Callee, - llvm::function_ref Handler) const; - - [[nodiscard]] bool generatesValuesAt(const llvm::Instruction *Inst, - const llvm::Function *Callee) const; - [[nodiscard]] bool mayLeakValuesAt(const llvm::Instruction *Inst, - const llvm::Function *Callee) const; - [[nodiscard]] bool sanitizesValuesAt(const llvm::Instruction *Inst, - const llvm::Function *Callee) const; - - [[nodiscard]] TaintCategory getCategory(const llvm::Value *V) const; - - void addSourceValue(const llvm::Value *V); - void addSinkValue(const llvm::Value *V); - void addSanitizerValue(const llvm::Value *V); - void addTaintCategory(const llvm::Value *Val, llvm::StringRef AnnotationStr); - void addTaintCategory(const llvm::Value *Val, TaintCategory Annotation); - - [[nodiscard]] std::map> - makeInitialSeeds() const; - - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const TaintConfig &TC); - -private: - std::unordered_set SourceValues; - std::unordered_set SinkValues; - std::unordered_set SanitizerValues; - TaintDescriptionCallBackTy SourceCallBack; - TaintDescriptionCallBackTy SinkCallBack; - TaintDescriptionCallBackTy SanitizerCallBack; -}; - -//===----------------------------------------------------------------------===// -// Miscellaneous helper functions - -nlohmann::json parseTaintConfig(const std::filesystem::path &Path); - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h new file mode 100644 index 000000000..94979d2af --- /dev/null +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h @@ -0,0 +1,167 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_TAINTCONFIG_TAINTCONFIGBASE_H +#define PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGBASE_H + +#include "phasar/Utils/Nullable.h" + +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" + +#include "nlohmann/json.hpp" + +#include +#include +#include +#include + +namespace psr { + +enum class TaintCategory { Source, Sink, Sanitizer, None }; + +[[nodiscard]] llvm::StringRef to_string(TaintCategory Cat) noexcept; +[[nodiscard]] TaintCategory toTaintCategory(llvm::StringRef Str) noexcept; + +template struct TaintConfigTraits {}; + +template class TaintConfigBase { +public: + using n_t = typename TaintConfigTraits::n_t; + using v_t = typename TaintConfigTraits::v_t; + using f_t = typename TaintConfigTraits::f_t; + + using TaintDescriptionCallBackTy = + llvm::unique_function(n_t) const>; + + void registerSourceCallBack(TaintDescriptionCallBackTy CB) noexcept { + SourceCallBack = std::move(CB); + } + void registerSinkCallBack(TaintDescriptionCallBackTy CB) noexcept { + SinkCallBack = std::move(CB); + } + void registerSanitizerCallBack(TaintDescriptionCallBackTy CB) noexcept { + SanitizerCallBack = std::move(CB); + } + + [[nodiscard]] const TaintDescriptionCallBackTy & + getRegisteredSourceCallBack() const noexcept { + return SourceCallBack; + } + [[nodiscard]] const TaintDescriptionCallBackTy & + getRegisteredSinkCallBack() const noexcept { + return SinkCallBack; + } + [[nodiscard]] const TaintDescriptionCallBackTy & + getRegisteredSanitizerCallBack() const noexcept { + return SanitizerCallBack; + } + + [[nodiscard]] bool isSource(v_t Val) const { + return self().isSourceImpl(std::move(Val)); + } + [[nodiscard]] bool isSink(v_t Val) const { + return self().isSinkImpl(std::move(Val)); + } + [[nodiscard]] bool isSanitizer(v_t Val) const { + return self().isSanitizerImpl(std::move(Val)); + } + + /// \brief Calls Handler for all operands of Inst (maybe including Inst + /// itself) that are generated unconditionally as tainted. + /// + /// If Inst is a function-call, the Callee function should be specified + /// explicitly. + template + void forAllGeneratedValuesAt(n_t Inst, Nullable Callee, + HandlerFn &&Handler) const { + self().forAllGeneratedValuesAtImpl(std::move(Inst), std::move(Callee), + std::forward(Handler)); + } + + /// \brief Calls Handler for all operands of Inst that may generate a leak + /// when they are tainted. + /// + /// If Inst is a function-call, the Callee function should be specified + /// explicitly. + template + void forAllLeakCandidatesAt(n_t Inst, Nullable Callee, + HandlerFn &&Handler) const { + self().forAllLeakCandidatesAtImpl(std::move(Inst), std::move(Callee), + std::forward(Handler)); + } + + /// \brief Calls Handler for all operands of Inst that become sanitized after + /// the instruction is completed. + /// + /// If Inst is a function-call, the Callee function should be specified + /// explicitly. + template + void forAllSanitizedValuesAt(n_t Inst, Nullable Callee, + HandlerFn &&Handler) const { + self().forAllSanitizedValuesAtImpl(std::move(Inst), std::move(Callee), + std::forward(Handler)); + } + + [[nodiscard]] bool generatesValuesAt(n_t Inst, Nullable Callee) const { + return self().generatesValuesAtImpl(std::move(Inst), std::move(Callee)); + } + [[nodiscard]] bool mayLeakValuesAt(n_t Inst, Nullable Callee) const { + return self().mayLeakValuesAtImpl(std::move(Inst), std::move(Callee)); + } + [[nodiscard]] bool sanitizesValuesAt(n_t Inst, Nullable Callee) const { + return self().sanitizesValuesAtImpl(std::move(Inst), std::move(Callee)); + } + + [[nodiscard]] TaintCategory getCategory(v_t Val) const { + return self().getCategoryImpl(std::move(Val)); + } + + [[nodiscard]] std::map> makeInitialSeeds() const { + return self().makeInitialSeedsImpl(); + } + + void print(llvm::raw_ostream &OS = llvm::outs()) const { + self().printImpl(OS); + } + + LLVM_DUMP_METHOD void dump() const { print(); } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const TaintConfigBase &TC) { + TC.print(OS); + return OS; + } + +private: + [[nodiscard]] const Derived &self() const noexcept { + static_assert(std::is_base_of_v, + "Invalid CRTP instantiation!"); + return *static_cast(this); + } + +protected: + // --- data members + + TaintDescriptionCallBackTy SourceCallBack{}; + TaintDescriptionCallBackTy SinkCallBack{}; + TaintDescriptionCallBackTy SanitizerCallBack{}; +}; + +//===----------------------------------------------------------------------===// +// Miscellaneous helper functions + +nlohmann::json parseTaintConfig(const llvm::Twine &Path); +std::optional parseTaintConfigOrNull(const llvm::Twine &Path); + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGBASE_H diff --git a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h index fba7497e4..502b55989 100644 --- a/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h +++ b/include/phasar/PhasarLLVM/TaintConfig/TaintConfigUtilities.h @@ -7,10 +7,10 @@ * Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGUTILITIES_H -#define PHASAR_PHASARLLVM_TAINTCONFIG_TAINTCONFIGUTILITIES_H +#ifndef PHASAR_PHASARLLVM_TAINTCONFIG_LLVMTAINTCONFIGUTILITIES_H +#define PHASAR_PHASARLLVM_TAINTCONFIG_LLVMTAINTCONFIGUTILITIES_H -#include "phasar/PhasarLLVM/TaintConfig/TaintConfig.h" +#include "phasar/PhasarLLVM/TaintConfig/LLVMTaintConfig.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "llvm/IR/Function.h" @@ -24,10 +24,10 @@ namespace psr { template >> -void collectGeneratedFacts(ContainerTy &Dest, const TaintConfig &Config, +void collectGeneratedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { - auto Callback = Config.getRegisteredSourceCallBack(); + const auto &Callback = Config.getRegisteredSourceCallBack(); if (Callback) { auto CBFacts = Callback(CB); Dest.insert(CBFacts.begin(), CBFacts.end()); @@ -47,11 +47,11 @@ void collectGeneratedFacts(ContainerTy &Dest, const TaintConfig &Config, template >> -void collectLeakedFacts(ContainerTy &Dest, const TaintConfig &Config, +void collectLeakedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee, Pred &&LeakIf) { - auto Callback = Config.getRegisteredSinkCallBack(); + const auto &Callback = Config.getRegisteredSinkCallBack(); if (Callback) { auto CBLeaks = Callback(CB); std::copy_if(CBLeaks.begin(), CBLeaks.end(), @@ -66,7 +66,7 @@ void collectLeakedFacts(ContainerTy &Dest, const TaintConfig &Config, } template -inline void collectLeakedFacts(ContainerTy &Dest, const TaintConfig &Config, +inline void collectLeakedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { collectLeakedFacts(Dest, Config, CB, Callee, @@ -76,7 +76,7 @@ inline void collectLeakedFacts(ContainerTy &Dest, const TaintConfig &Config, template >> -void collectSanitizedFacts(ContainerTy &Dest, const TaintConfig &Config, +void collectSanitizedFacts(ContainerTy &Dest, const LLVMTaintConfig &Config, const llvm::CallBase *CB, const llvm::Function *Callee) { for (unsigned I = 0, End = Callee->arg_size(); I < End; ++I) { @@ -87,4 +87,4 @@ void collectSanitizedFacts(ContainerTy &Dest, const TaintConfig &Config, } } // namespace psr -#endif +#endif // PHASAR_PHASARLLVM_TAINTCONFIG_LLVMTAINTCONFIGUTILITIES_H diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h index 0152f5583..6024792d8 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h @@ -18,15 +18,13 @@ #define PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMTYPEHIERARCHY_H_ #include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" -#include "phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h" - -#include "boost/graph/adjacency_list.hpp" -#include "boost/graph/graph_traits.hpp" +#include "phasar/TypeHierarchy/TypeHierarchy.h" #include "llvm/ADT/StringRef.h" +#include "boost/graph/adjacency_list.hpp" +#include "boost/graph/graph_traits.hpp" #include "gtest/gtest_prod.h" - #include "nlohmann/json.hpp" #include diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h index 7396b1ca3..2feb38f3a 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h @@ -10,11 +10,11 @@ #ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMVFTABLE_H_ #define PHASAR_PHASARLLVM_TYPEHIERARCHY_LLVMVFTABLE_H_ -#include +#include "phasar/TypeHierarchy/VFTable.h" #include "nlohmann/json.hpp" -#include "phasar/PhasarLLVM/TypeHierarchy/VFTable.h" +#include namespace llvm { class Function; diff --git a/include/phasar/PhasarLLVM/Utils/Annotation.h b/include/phasar/PhasarLLVM/Utils/Annotation.h index 343580fc5..31d9c42ba 100644 --- a/include/phasar/PhasarLLVM/Utils/Annotation.h +++ b/include/phasar/PhasarLLVM/Utils/Annotation.h @@ -1,13 +1,13 @@ #ifndef PHASAR_PHASARLLVM_UTILS_ANNOTATION_H #define PHASAR_PHASARLLVM_UTILS_ANNOTATION_H -#include - #include "llvm/ADT/StringRef.h" #include "llvm/IR/Constants.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Value.h" +#include + namespace psr { //===----------------------------------------------------------------------===// diff --git a/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h b/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h index f6797fcb1..664f28304 100644 --- a/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h +++ b/include/phasar/PhasarLLVM/Utils/BasicBlockOrdering.h @@ -10,12 +10,12 @@ #ifndef PHASAR_PHASARLLVM_UTILS_BASICBLOCKORDERING_H_ #define PHASAR_PHASARLLVM_UTILS_BASICBLOCKORDERING_H_ -#include -#include - #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FunctionExtras.h" +#include +#include + namespace llvm { class Function; class BasicBlock; diff --git a/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.def b/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.def index 3f3e28788..5d9b001e2 100644 --- a/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.def +++ b/include/phasar/PhasarLLVM/Utils/DataFlowAnalysisType.def @@ -14,13 +14,11 @@ 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") diff --git a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h index 316535fb4..1c6013f61 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMIRToSrc.h @@ -17,10 +17,10 @@ #ifndef PHASAR_UTILS_LLVMIRTOSRC_H_ #define PHASAR_UTILS_LLVMIRTOSRC_H_ -#include - #include "nlohmann/json.hpp" +#include + // Forward declaration of types for which we only use its pointer or ref type namespace llvm { class Argument; diff --git a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h index 18599565e..5639c7a17 100644 --- a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h +++ b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h @@ -48,6 +48,14 @@ class LLVMProjectIRDB; */ bool isFunctionPointer(const llvm::Value *V) noexcept; +/** + * @brief Checks if the given LLVM Type is a integer like struct. + * @param V LLVM Type. + * @return True, if given LLVM Type is a struct like this %TSi = type <{ i64 }>. + * False, otherwise. + */ +bool isIntegerLikeType(const llvm::Type *T) noexcept; + /** * @brief Checks if the given LLVM Value is either a alloca instruction or a * heap allocation function, e.g. new, new[], malloc, realloc or calloc. @@ -67,14 +75,14 @@ llvm::ModuleSlotTracker &getModuleSlotTrackerFor(const llvm::Value *V); /** * @brief Returns a string representation of a LLVM Value. */ -std::string llvmIRToString(const llvm::Value *V); +[[nodiscard]] std::string llvmIRToString(const llvm::Value *V); /** * @brief Similar to llvmIRToString, but removes the metadata from the output as * they are not always stable. Prefer this function over llvmIRToString, if you * are comparing the string representations of LLVM iR instructions. */ -std::string llvmIRToStableString(const llvm::Value *V); +[[nodiscard]] std::string llvmIRToStableString(const llvm::Value *V); /** * @brief Same as @link(llvmIRToString) but tries to shorten the @@ -82,6 +90,14 @@ std::string llvmIRToStableString(const llvm::Value *V); */ std::string llvmIRToShortString(const llvm::Value *V); +/** + * @brief Returns a string-representation of a LLVM type. + * + * @param Shorten Tries to shorten the output + */ +[[nodiscard]] std::string llvmTypeToString(const llvm::Type *Ty, + bool Shorten = false); + LLVM_DUMP_METHOD void dumpIRValue(const llvm::Value *V); LLVM_DUMP_METHOD void dumpIRValue(const llvm::Instruction *V); @@ -113,8 +129,6 @@ std::string getMetaDataID(const llvm::Value *V); * underlying types for their ID's, size_t and string respectively. */ struct LLVMValueIDLess { - StringIDLess Sless; - LLVMValueIDLess() : Sless(StringIDLess()) {} bool operator()(const llvm::Value *Lhs, const llvm::Value *Rhs) const; }; diff --git a/include/phasar/PhasarLLVM/Utils/LatticeDomain.h b/include/phasar/PhasarLLVM/Utils/LatticeDomain.h deleted file mode 100644 index b04b83089..000000000 --- a/include/phasar/PhasarLLVM/Utils/LatticeDomain.h +++ /dev/null @@ -1,139 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2020 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_UTILS_LATTICEDOMAIN_H -#define PHASAR_PHASARLLVM_UTILS_LATTICEDOMAIN_H - -#include -#include - -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" - -#include "phasar/Utils/TypeTraits.h" - -namespace psr { - -/// Represents the infimum of the lattice: -/// Top is the greatest element that is less than or equal to all elements of -/// the lattice. -struct Top {}; - -inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Top /*unused*/) { - return OS << "Top"; -} - -/// Represents the supremum of the lattice: -/// Bottom is the least element that is greater than or equal to all elements -/// of the lattice. -struct Bottom {}; - -inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Bottom /*unused*/) { - return OS << "Bottom"; -} - -/// A easy shorthand to construct a complete lattice of L. -template -struct LatticeDomain : public std::variant { - using std::variant::variant; - - [[nodiscard]] inline bool isBottom() const noexcept { - return std::holds_alternative(*this); - } - [[nodiscard]] inline bool isTop() const noexcept { - return std::holds_alternative(*this); - } - [[nodiscard]] inline L *getValueOrNull() noexcept { - return std::get_if(this); - } - [[nodiscard]] inline const L *getValueOrNull() const noexcept { - return std::get_if(this); - } -}; - -template () - << std::declval())>> -inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const LatticeDomain &LD) { - if (LD.isBottom()) { - return OS << "Bottom"; - } - if (LD.isTop()) { - return OS << "Top"; - } - - const auto *Val = LD.getValueOrNull(); - assert(Val && "Only alternative remaining is L"); - return OS << *Val; -} - -template -inline bool operator==(const LatticeDomain &Lhs, - const LatticeDomain &Rhs) { - if (Lhs.index() != Rhs.index()) { - return false; - } - if (auto LhsPtr = Lhs.getValueOrNull()) { - /// No need to check whether Lhs is an L; the indices are already the same - return *LhsPtr == *Rhs.getValueOrNull(); - } - return true; -} - -template < - typename L, typename LL, - typename = std::void_t() == std::declval())>> -inline bool operator==(const LL &Lhs, const LatticeDomain Rhs) { - if (auto RVal = Rhs.getValueOrNull()) { - return Lhs == *RVal; - } - return false; -} - -template < - typename L, typename LL, - typename = std::void_t() == std::declval())>> -inline bool operator==(const LatticeDomain Lhs, const LL &Rhs) { - return Rhs == Lhs; -} - -template -inline bool operator!=(const LatticeDomain &Lhs, - const LatticeDomain &Rhs) { - return !(Lhs == Rhs); -} - -template -inline bool operator<(const LatticeDomain &Lhs, - const LatticeDomain &Rhs) { - /// Top < (Lhs::L < Rhs::L) < Bottom - if (Rhs.isTop()) { - return false; - } - if (Lhs.isTop()) { - return true; - } - if (auto LhsPtr = Lhs.getValueOrNull()) { - if (auto RhsPtr = Rhs.getValueOrNull()) { - return *LhsPtr < *RhsPtr; - } - } - if (Lhs.isBottom()) { - return false; - } - if (Rhs.isBottom()) { - return true; - } - llvm_unreachable("All comparision cases should be handled above."); -} - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/Utils/Printer.h b/include/phasar/PhasarLLVM/Utils/Printer.h deleted file mode 100644 index ca0c596f3..000000000 --- a/include/phasar/PhasarLLVM/Utils/Printer.h +++ /dev/null @@ -1,163 +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 - *****************************************************************************/ - -/* - * Printer.h - * - * Created on: 07.09.2018 - * Author: rleer - */ - -#ifndef PHASAR_PHASARLLVM_UTILS_PRINTER_H -#define PHASAR_PHASARLLVM_UTILS_PRINTER_H - -#include "llvm/Support/raw_ostream.h" - -#include - -namespace psr { - -template struct NodePrinter { - using N = typename AnalysisDomainTy::n_t; - - NodePrinter() = default; - NodePrinter(const NodePrinter &) = delete; - NodePrinter &operator=(const NodePrinter &) = delete; - NodePrinter(NodePrinter &&) = delete; - NodePrinter &operator=(NodePrinter &&) = delete; - virtual ~NodePrinter() = default; - - virtual void printNode(llvm::raw_ostream &OS, N Stmt) const = 0; - - virtual std::string NtoString(N Stmt) const { // NOLINT - std::string Buffer; - llvm::raw_string_ostream StrS(Buffer); - printNode(StrS, Stmt); - return StrS.str(); - } -}; - -template struct DataFlowFactPrinter { - using D = typename AnalysisDomainTy::d_t; - - DataFlowFactPrinter() = default; - DataFlowFactPrinter(const DataFlowFactPrinter &) = delete; - DataFlowFactPrinter &operator=(const DataFlowFactPrinter &) = delete; - DataFlowFactPrinter(DataFlowFactPrinter &&) = delete; - DataFlowFactPrinter &operator=(DataFlowFactPrinter &&) = delete; - virtual ~DataFlowFactPrinter() = default; - - virtual void printDataFlowFact(llvm::raw_ostream &OS, D Fact) const = 0; - - [[nodiscard]] virtual std::string DtoString(D Fact) const { // NOLINT - std::string Buffer; - llvm::raw_string_ostream StrS(Buffer); - printDataFlowFact(StrS, Fact); - return StrS.str(); - } -}; - -template struct ValuePrinter { - ValuePrinter() = default; - ValuePrinter(const ValuePrinter &) = delete; - ValuePrinter &operator=(const ValuePrinter &) = delete; - ValuePrinter(ValuePrinter &&) = delete; - ValuePrinter &operator=(ValuePrinter &&) = delete; - virtual ~ValuePrinter() = default; - - virtual void printValue(llvm::raw_ostream &OS, V Val) const = 0; - - virtual std::string VtoString(V Val) const { // NOLINT - std::string Buffer; - llvm::raw_string_ostream StrS(Buffer); - printValue(StrS, Val); - return StrS.str(); - } -}; - -template struct TypePrinter { - TypePrinter() = default; - TypePrinter(const TypePrinter &) = delete; - TypePrinter &operator=(const TypePrinter &) = delete; - TypePrinter(TypePrinter &&) = delete; - TypePrinter &operator=(TypePrinter &&) = delete; - virtual ~TypePrinter() = default; - - virtual void printType(llvm::raw_ostream &OS, T Ty) const = 0; - - virtual std::string TtoString(T Ty) const { // NOLINT - std::string Buffer; - llvm::raw_string_ostream StrS(Buffer); - printType(StrS, Ty); - return StrS.str(); - } -}; - -template struct EdgeFactPrinter { - using l_t = typename AnalysisDomainTy::l_t; - - EdgeFactPrinter() = default; - EdgeFactPrinter(const EdgeFactPrinter &) = delete; - EdgeFactPrinter &operator=(const EdgeFactPrinter &) = delete; - EdgeFactPrinter(EdgeFactPrinter &&) = delete; - EdgeFactPrinter &operator=(EdgeFactPrinter &&) = delete; - virtual ~EdgeFactPrinter() = default; - - virtual void printEdgeFact(llvm::raw_ostream &OS, l_t L) const = 0; - - [[nodiscard]] virtual std::string LtoString(l_t L) const { // NOLINT - std::string Buffer; - llvm::raw_string_ostream StrS(Buffer); - printEdgeFact(StrS, L); - return StrS.str(); - } -}; - -template struct FunctionPrinter { - using F = typename AnalysisDomainTy::f_t; - - FunctionPrinter() = default; - FunctionPrinter(const FunctionPrinter &) = delete; - FunctionPrinter &operator=(const FunctionPrinter &) = delete; - FunctionPrinter(FunctionPrinter &&) = delete; - FunctionPrinter &operator=(FunctionPrinter &&) = delete; - virtual ~FunctionPrinter() = default; - - virtual void printFunction(llvm::raw_ostream &OS, F Func) const = 0; - - virtual std::string FtoString(F Func) const { // NOLINT - std::string Buffer; - llvm::raw_string_ostream StrS(Buffer); - printFunction(StrS, Func); - return StrS.str(); - } -}; - -template struct ContainerPrinter { - ContainerPrinter() = default; - ContainerPrinter(const ContainerPrinter &) = delete; - ContainerPrinter &operator=(const ContainerPrinter &) = delete; - ContainerPrinter(ContainerPrinter &&) = delete; - ContainerPrinter &operator=(ContainerPrinter &&) = delete; - virtual ~ContainerPrinter() = default; - - virtual void printContainer(llvm::raw_ostream &OS, - ContainerTy Container) const = 0; - - virtual std::string ContainertoString(ContainerTy Container) const { // NOLINT - std::string Buffer; - llvm::raw_string_ostream StrS(Buffer); - printContainer(StrS, Container); - return StrS.str(); - } -}; - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/Utils/Scopes.h b/include/phasar/PhasarLLVM/Utils/Scopes.h deleted file mode 100644 index b43d7e9bf..000000000 --- a/include/phasar/PhasarLLVM/Utils/Scopes.h +++ /dev/null @@ -1,28 +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_UTILS_SCOPES_H_ -#define PHASAR_PHASARLLVM_UTILS_SCOPES_H_ - -#include -#include - -namespace llvm { -class raw_ostream; -} // namespace llvm - -namespace psr { - -enum class Scope { function, module, project }; - -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Scope S); - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarLLVM/Utils/SummaryStrategy.h b/include/phasar/PhasarLLVM/Utils/SummaryStrategy.h deleted file mode 100644 index f4cb78d0b..000000000 --- a/include/phasar/PhasarLLVM/Utils/SummaryStrategy.h +++ /dev/null @@ -1,41 +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_UTILS_SUMMARYSTRATEGY_H_ -#define PHASAR_PHASARLLVM_UTILS_SUMMARYSTRATEGY_H_ - -#include -#include - -namespace llvm { -class raw_ostream; -} - -namespace psr { - -enum class SummaryGenerationStrategy { - always_all = 0, - powerset, - all_and_none, - all_observed, - always_none -}; - -extern const std::map - SummaryGenerationStrategyToString; - -extern const std::map - StringToSummaryGenerationStrategy; - -llvm::raw_ostream &operator<<(llvm::raw_ostream &Os, - const SummaryGenerationStrategy &S); - -} // namespace psr - -#endif diff --git a/include/phasar/PhasarPass/Options.h b/include/phasar/PhasarPass/Options.h index 44723092a..2c9672a05 100644 --- a/include/phasar/PhasarPass/Options.h +++ b/include/phasar/PhasarPass/Options.h @@ -10,11 +10,11 @@ #ifndef PHASAR_PHASARPASS_OPTIONS_H_ #define PHASAR_PHASARPASS_OPTIONS_H_ +#include "llvm/Support/CommandLine.h" + #include #include -#include "llvm/Support/CommandLine.h" - extern llvm::cl::OptionCategory PhASARCategory; namespace psr { diff --git a/include/phasar/Pointer/AliasAnalysisType.def b/include/phasar/Pointer/AliasAnalysisType.def new file mode 100644 index 000000000..23fbe08c7 --- /dev/null +++ b/include/phasar/Pointer/AliasAnalysisType.def @@ -0,0 +1,18 @@ +/****************************************************************************** + * 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 ALIAS_ANALYSIS_TYPE +#define ALIAS_ANALYSIS_TYPE(NAME, CMDFLAG, DESC) +#endif + +ALIAS_ANALYSIS_TYPE(CFLSteens, "cflsteens", "Steensgaard-style alias analysis (equality-based)") +ALIAS_ANALYSIS_TYPE(CFLAnders, "cflanders", "Andersen-style alias analysis (subset-based)") +ALIAS_ANALYSIS_TYPE(PointsTo, "points-to", "Alias-information based on (external) points-to information") + +#undef ALIAS_ANALYSIS_TYPE diff --git a/include/phasar/Pointer/AliasAnalysisType.h b/include/phasar/Pointer/AliasAnalysisType.h new file mode 100644 index 000000000..c05177920 --- /dev/null +++ b/include/phasar/Pointer/AliasAnalysisType.h @@ -0,0 +1,23 @@ +#ifndef PHASAR_PHASARLLVM_POINTER_ALIASANALYSISTYPE_H_ +#define PHASAR_PHASARLLVM_POINTER_ALIASANALYSISTYPE_H_ + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { +enum class AliasAnalysisType { +#define ALIAS_ANALYSIS_TYPE(NAME, CMDFLAG, TYPE) NAME, +#include "phasar/Pointer/AliasAnalysisType.def" + Invalid +}; + +std::string toString(AliasAnalysisType PA); + +AliasAnalysisType toAliasAnalysisType(llvm::StringRef S); + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, AliasAnalysisType PA); +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_ALIASANALYSISTYPE_H_ diff --git a/include/phasar/Pointer/AliasInfo.h b/include/phasar/Pointer/AliasInfo.h new file mode 100644 index 000000000..eee1eca61 --- /dev/null +++ b/include/phasar/Pointer/AliasInfo.h @@ -0,0 +1,342 @@ +/****************************************************************************** + * 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_POINTER_ALIASINFO_H_ +#define PHASAR_PHASARLLVM_POINTER_ALIASINFO_H_ + +#include "phasar/Pointer/AliasInfoTraits.h" +#include "phasar/Pointer/AliasResult.h" +#include "phasar/Utils/AnalysisProperties.h" +#include "phasar/Utils/ByRef.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TypeName.h" +#include "llvm/Support/raw_ostream.h" + +#include "nlohmann/json.hpp" + +#include +#include + +namespace llvm { +class Value; +class Instruction; +} // namespace llvm + +namespace psr { +enum class AliasAnalysisType; + +template class AliasInfoRef; +template class AliasInfo; + +template +struct AliasInfoTraits> : DefaultAATraits {}; +template +struct AliasInfoTraits> : DefaultAATraits {}; + +/// A type-erased reference to any object implementing the IsAliasInfo +/// interface. Use this, if your analysis is not tied to a specific alias info +/// implementation. +/// +/// This is a *non-owning* reference similar to std::string_view and +/// llvm::ArrayRef. Pass values of this type by value. +/// +/// Example: +/// \code +/// LLVMAliasSet ASet(...); +/// AliasInfoRef AA = &ASet; +/// \endcode +/// +/// NOTE: AliasInfoRef::mergeWith() only works if supplied with a compatible +/// other AliasInfo. Otherwise, it asserts out +template +class AliasInfoRef : public AnalysisPropertiesMixin> { + friend class AliasInfo; + using traits_t = AliasInfoTraits>; + +public: + using AliasSetPtrTy = typename traits_t::AliasSetPtrTy; + using AliasSetTy = typename traits_t::AliasSetTy; + using AllocationSiteSetPtrTy = typename traits_t::AllocationSiteSetPtrTy; + using n_t = typename traits_t::n_t; + using v_t = typename traits_t::v_t; + + AliasInfoRef() noexcept = default; + AliasInfoRef(std::nullptr_t) noexcept : AliasInfoRef() {} + template && + std::is_same_v && + std::is_same_v>> + AliasInfoRef(ConcreteAA *AA) noexcept + : AA(AA), VT((std::is_empty_v || AA) ? &VTableFor + : nullptr) {} + + /// Prevent dangling references by disallowing implicit conversion of a + /// temporary AliasInfo to AliasInfoRef. + AliasInfoRef(AliasInfo &&) = delete; + AliasInfoRef &operator=(AliasInfo &&) = delete; + + AliasInfoRef(const AliasInfoRef &) noexcept = default; + AliasInfoRef &operator=(const AliasInfoRef &) noexcept = default; + ~AliasInfoRef() noexcept = default; + + explicit operator bool() const noexcept { return VT != nullptr; } + + // -- Impl for IsAliasInfo: + + [[nodiscard]] bool isInterProcedural() const noexcept { + assert(VT != nullptr); + return VT->IsInterProcedural(AA); + } + [[nodiscard]] AliasAnalysisType getAliasAnalysisType() const noexcept { + assert(VT != nullptr); + return VT->GetAliasAnalysisType(AA); + } + + [[nodiscard]] AliasResult alias(ByConstRef Pointer1, + ByConstRef Pointer2, + ByConstRef AtInstruction = {}) const { + assert(VT != nullptr); + return VT->Alias(AA, Pointer1, Pointer2, AtInstruction); + } + + [[nodiscard]] AliasSetPtrTy + getAliasSet(ByConstRef Pointer, + ByConstRef AtInstruction = {}) const { + assert(VT != nullptr); + return VT->GetAliasSet(AA, Pointer, AtInstruction); + } + + [[nodiscard]] AllocationSiteSetPtrTy + getReachableAllocationSites(ByConstRef Pointer, + bool IntraProcOnly = false, + ByConstRef AtInstruction = {}) const { + assert(VT != nullptr); + return VT->GetReachableAllocationSites(AA, Pointer, IntraProcOnly, + AtInstruction); + } + + // Checks if Pointer2 is a reachable allocation in the alias set of + // Pointer1. + [[nodiscard]] bool isInReachableAllocationSites( + ByConstRef Pointer1, ByConstRef Pointer2, + bool IntraProcOnly = false, ByConstRef AtInstruction = {}) const { + assert(VT != nullptr); + return VT->IsInReachableAllocationSites(AA, Pointer1, Pointer2, + IntraProcOnly, AtInstruction); + } + + void print(llvm::raw_ostream &OS = llvm::outs()) const { + assert(VT != nullptr); + VT->Print(AA, OS); + } + + [[nodiscard]] nlohmann::json getAsJson() const { + assert(VT != nullptr); + return VT->GetAsJson(AA); + } + + void printAsJson(llvm::raw_ostream &OS) const { + assert(VT != nullptr); + VT->PrintAsJson(AA, OS); + } + + void mergeWith(AliasInfoRef Other) { + assert(VT != nullptr); + assert(Other.VT != nullptr); + if (VT != Other.VT) { + llvm::report_fatal_error( + "Can only merge AliasInfos with same concrete type: " + + VT->TypeName() + " vs " + Other.VT->TypeName()); + } + VT->MergeWith(AA, Other.AA); + } + + void introduceAlias(ByConstRef Pointer1, ByConstRef Pointer2, + ByConstRef AtInstruction = {}, + AliasResult Kind = AliasResult::MustAlias) { + assert(VT != nullptr); + VT->IntroduceAlias(AA, Pointer1, Pointer2, AtInstruction, Kind); + } + + [[nodiscard]] AnalysisProperties getAnalysisProperties() const noexcept { + assert(VT != nullptr); + return VT->GetAnalysisProperties(AA); + } + + template [[nodiscard]] bool isa() const noexcept { + return VT == &VTableFor; + } + // NOLINTNEXTLINE(readability-identifier-naming) + template [[nodiscard]] T *dyn_cast() const noexcept { + return isa() ? static_cast(AA) : nullptr; + } + + template [[nodiscard]] T *cast() const noexcept { + assert(isa() && "Invalid AliasInfo cast!"); + return static_cast(AA); + } + +private: + struct VTable { + bool (*IsInterProcedural)(const void *) noexcept; + AliasAnalysisType (*GetAliasAnalysisType)(const void *) noexcept; + AliasResult (*Alias)(void *, ByConstRef, ByConstRef, + ByConstRef); + AliasSetPtrTy (*GetAliasSet)(void *, ByConstRef, ByConstRef); + AllocationSiteSetPtrTy (*GetReachableAllocationSites)(void *, + ByConstRef, bool, + ByConstRef); + bool (*IsInReachableAllocationSites)(void *, ByConstRef, + ByConstRef, bool, + ByConstRef); + void (*Print)(const void *, llvm::raw_ostream &); + nlohmann::json (*GetAsJson)(const void *); + void (*PrintAsJson)(const void *, llvm::raw_ostream &); + void (*MergeWith)(void *, void *); + void (*IntroduceAlias)(void *, ByConstRef, ByConstRef, + ByConstRef, AliasResult); + AnalysisProperties (*GetAnalysisProperties)(const void *) noexcept; + llvm::StringRef (*TypeName)() noexcept; + void (*Destroy)(const void *) noexcept; + }; + + template + static constexpr VTable VTableFor = { + [](const void *AA) noexcept { + return static_cast(AA)->isInterProcedural(); + }, + [](const void *AA) noexcept { + return static_cast(AA)->getAliasAnalysisType(); + }, + [](void *AA, ByConstRef Pointer1, ByConstRef Pointer2, + ByConstRef AtInstruction) { + return static_cast(AA)->alias(Pointer1, Pointer2, + AtInstruction); + }, + [](void *AA, ByConstRef Pointer, ByConstRef AtInstruction) { + return static_cast(AA)->getAliasSet(Pointer, + AtInstruction); + }, + [](void *AA, ByConstRef Pointer, bool IntraProcOnly, + ByConstRef AtInstruction) { + return static_cast(AA)->getReachableAllocationSites( + Pointer, IntraProcOnly, AtInstruction); + }, + [](void *AA, ByConstRef Pointer1, ByConstRef Pointer2, + bool IntraProcOnly, ByConstRef AtInstruction) { + return static_cast(AA)->isInReachableAllocationSites( + Pointer1, Pointer2, IntraProcOnly, AtInstruction); + }, + [](const void *AA, llvm::raw_ostream &OS) { + static_cast(AA)->print(OS); + }, + [](const void *AA) { + return static_cast(AA)->getAsJson(); + }, + [](const void *AA, llvm::raw_ostream &OS) { + static_cast(AA)->printAsJson(OS); + }, + [](void *AA, void *Other) { + static_cast(AA)->mergeWith( + *static_cast(Other)); + }, + [](void *AA, ByConstRef Pointer1, ByConstRef Pointer2, + ByConstRef AtInstruction, AliasResult Kind) { + static_cast(AA)->introduceAlias(Pointer1, Pointer2, + AtInstruction, Kind); + }, + [](const void *AA) noexcept { + return static_cast(AA)->getAnalysisProperties(); + }, + []() noexcept { return llvm::getTypeName(); }, + [](const void *AA) noexcept { + delete static_cast(AA); + }, + }; + + // -- + + void *AA{}; + const VTable *VT{}; +}; + +/// Similar to AliasInfoRef, but exclusively owns the held reference. Use this, +/// if you need to decide dynamically, which alias info implementation to use. +/// +/// Implicitly convertible to AliasInfoRef. +/// +/// Example: +/// \code +/// AliasInfo AA = std::make_unique(...); +/// \endcode +/// +template +class [[clang::trivial_abi]] AliasInfo final : public AliasInfoRef { + using base_t = AliasInfoRef; + +public: + using typename base_t::AliasSetPtrTy; + using typename base_t::AliasSetTy; + using typename base_t::AllocationSiteSetPtrTy; + using typename base_t::n_t; + using typename base_t::v_t; + + AliasInfo() noexcept = default; + AliasInfo(std::nullptr_t) noexcept {}; + AliasInfo(const AliasInfo &) = delete; + AliasInfo &operator=(const AliasInfo &) = delete; + AliasInfo(AliasInfo &&Other) noexcept { swap(Other); } + AliasInfo &operator=(AliasInfo &&Other) noexcept { + auto Cpy{std::move(Other)}; + swap(Cpy); + return *this; + } + + void swap(AliasInfo &Other) noexcept { + std::swap(this->AA, Other.AA); + std::swap(this->VT, Other.VT); + } + friend void swap(AliasInfo &LHS, AliasInfo &RHS) noexcept { LHS.swap(RHS); } + + template + explicit AliasInfo(std::in_place_type_t /*unused*/, + ArgTys &&...Args) + : base_t(new ConcretePTA(std::forward(Args)...)) {} + + template + AliasInfo(std::unique_ptr AA) : base_t(AA.release()) {} + + ~AliasInfo() noexcept { + if (*this) { + this->VT->Destroy(this->AA); + this->VT = nullptr; + this->AA = nullptr; + } + } + + [[nodiscard]] base_t asRef() &noexcept { return *this; } + [[nodiscard]] AliasInfoRef asRef() const &noexcept { return *this; } + [[nodiscard]] AliasInfoRef asRef() && = delete; + + /// For better interoperability with unique_ptr + [[nodiscard]] base_t get() &noexcept { return asRef(); } + [[nodiscard]] AliasInfoRef get() const &noexcept { return asRef(); } + [[nodiscard]] AliasInfoRef get() && = delete; +}; + +extern template class AliasInfoRef; +extern template class AliasInfo; +} // namespace psr + +#endif diff --git a/include/phasar/Pointer/AliasInfoBase.h b/include/phasar/Pointer/AliasInfoBase.h new file mode 100644 index 000000000..ae0488651 --- /dev/null +++ b/include/phasar/Pointer/AliasInfoBase.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * 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_POINTER_ALIASINFOBASE_H +#define PHASAR_PHASARLLVM_POINTER_ALIASINFOBASE_H + +#include "phasar/Pointer/AliasInfoTraits.h" + +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/raw_ostream.h" + +#include "nlohmann/json.hpp" + +#include +#include +#include + +namespace llvm { +class Function; +class Value; +} // namespace llvm + +namespace psr { + +enum class AliasAnalysisType; +enum class AnalysisProperties; +enum class AliasResult; + +class AliasInfoBaseUtils { +public: + static const llvm::Function *retrieveFunction(const llvm::Value *V); +}; + +namespace detail { + +template +auto testAliasInfo( + T &AI, const T &CAI, + const std::optional::n_t> &NT = {}, + const std::optional::v_t> &VT = {}) + -> decltype(std::make_tuple( + CAI.isInterProcedural(), CAI.getAliasAnalysisType(), + AI.alias(*VT, *VT, *NT), AI.getAliasSet(*VT, *NT), + AI.getReachableAllocationSites(*VT, true, *NT), + AI.isInReachableAllocationSites(*VT, *VT, true, *NT), CAI.getAsJson(), + CAI.getAnalysisProperties(), CAI.isContextSensitive(), + CAI.isFieldSensitive(), CAI.isFlowSensitive())); +template +struct IsAliasInfo : std::false_type {}; +template +struct IsAliasInfo< + T, + std::void_t().print(llvm::outs())), + decltype(std::declval().printAsJson(llvm::outs())), + decltype(std::declval().mergeWith(std::declval())), + decltype(std::declval().introduceAlias( + std::declval::v_t>(), + std::declval::v_t>(), + std::declval::n_t>(), + AliasResult{}))>, + std::enable_if_t::AliasSetPtrTy, + typename AliasInfoTraits::AllocationSiteSetPtrTy, bool, + nlohmann::json, AnalysisProperties, bool, bool, bool>, + decltype(testAliasInfo(std::declval(), + std::declval()))>>> : std::true_type { +}; +} // namespace detail + +template +static constexpr bool IsAliasInfo = detail::IsAliasInfo::value; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_ALIASINFOBASE_H diff --git a/include/phasar/Pointer/AliasInfoTraits.h b/include/phasar/Pointer/AliasInfoTraits.h new file mode 100644 index 000000000..ad25d1141 --- /dev/null +++ b/include/phasar/Pointer/AliasInfoTraits.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * 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_POINTER_ALIASINFOTRAITS_H +#define PHASAR_PHASARLLVM_POINTER_ALIASINFOTRAITS_H + +#include "phasar/Utils/BoxedPointer.h" + +#include "llvm/ADT/DenseSet.h" + +#include + +namespace psr { + +template struct AliasInfoTraits { + // using n_t; + // using v_t; + // using AliasSetTy; + // using AliasSetPtrTy; + // using AllocationSiteSetPtrTy; +}; + +template struct DefaultAATraits { + using n_t = N; + using v_t = V; + using AliasSetTy = llvm::DenseSet; + using AliasSetPtrTy = BoxedConstPtr; + using AllocationSiteSetPtrTy = std::unique_ptr; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_ALIASINFOTRAITS_H diff --git a/include/phasar/PhasarLLVM/Utils/IOFormat.def b/include/phasar/Pointer/AliasResult.def similarity index 52% rename from include/phasar/PhasarLLVM/Utils/IOFormat.def rename to include/phasar/Pointer/AliasResult.def index 1c353935a..6fd2294d9 100644 --- a/include/phasar/PhasarLLVM/Utils/IOFormat.def +++ b/include/phasar/Pointer/AliasResult.def @@ -1,18 +1,19 @@ /****************************************************************************** - * Copyright (c) 2020 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 + * Fabian Schiebel and others *****************************************************************************/ -#ifndef IO_FORMAT_TYPES -#define IO_FORMAT_TYPES(NAME, CMDFLAG, TYPE) +#ifndef ALIAS_RESULT_TYPE +#define ALIAS_RESULT_TYPE(NAME) #endif -IO_FORMAT_TYPES("JSON", "json", JSON) -IO_FORMAT_TYPES("SARIF", "sarif", SARIF) -IO_FORMAT_TYPES("None", "none", None) +ALIAS_RESULT_TYPE(NoAlias) +ALIAS_RESULT_TYPE(MayAlias) +ALIAS_RESULT_TYPE(PartialAlias) +ALIAS_RESULT_TYPE(MustAlias) -#undef IO_FORMAT_TYPES +#undef ALIAS_RESULT_TYPE diff --git a/include/phasar/Pointer/AliasResult.h b/include/phasar/Pointer/AliasResult.h new file mode 100644 index 000000000..29e62fff7 --- /dev/null +++ b/include/phasar/Pointer/AliasResult.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * 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_ALIASRESULT_H_ +#define PHASAR_PHASARLLVM_POINTER_ALIASRESULT_H_ + +#include "llvm/Support/raw_ostream.h" + +#include + +namespace psr { +enum class AliasResult { +#define ALIAS_RESULT_TYPE(NAME) NAME, +#include "phasar/Pointer/AliasResult.def" +}; + +std::string toString(AliasResult AR); + +AliasResult toAliasResult(llvm::StringRef S); + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, AliasResult AR); +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_ALIASRESULT_H_ diff --git a/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h b/include/phasar/Pointer/AliasSetOwner.h similarity index 59% rename from include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h rename to include/phasar/Pointer/AliasSetOwner.h index bce6d47d3..5d01d79ba 100644 --- a/include/phasar/PhasarLLVM/Pointer/PointsToSetOwner.h +++ b/include/phasar/Pointer/AliasSetOwner.h @@ -7,11 +7,12 @@ * Fabian Schiebel, Philipp Schubert and others *****************************************************************************/ -#ifndef PHASAR_PHASARLLVM_POINTER_POINTSTOSETOWNER_H -#define PHASAR_PHASARLLVM_POINTER_POINTSTOSETOWNER_H +#ifndef PHASAR_PHASARLLVM_POINTER_ALIASSETOWNER_H +#define PHASAR_PHASARLLVM_POINTER_ALIASSETOWNER_H -#include "phasar/PhasarLLVM/Pointer/DynamicPointsToSetPtr.h" -#include "phasar/PhasarLLVM/Pointer/LLVMPointsToInfo.h" +#include "phasar/Pointer/AliasInfoTraits.h" +#include "phasar/Utils/BoxedPointer.h" +#include "phasar/Utils/MemoryResource.h" #include "phasar/Utils/StableVector.h" #include "llvm/ADT/DenseSet.h" @@ -23,28 +24,25 @@ #include #include -#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 +#if !HAS_MEMORY_RESOURCE #include "llvm/Support/RecyclingAllocator.h" #endif namespace llvm { class Value; +class Instruction; } // namespace llvm namespace psr { -template class PointsToSetOwner { +template class AliasSetOwner { public: using allocator_type = #if HAS_MEMORY_RESOURCE - std::pmr::polymorphic_allocator + std::pmr::polymorphic_allocator #else - llvm::RecyclingAllocator * + llvm::RecyclingAllocator * #endif ; @@ -52,22 +50,22 @@ template class PointsToSetOwner { #if HAS_MEMORY_RESOURCE std::pmr::unsynchronized_pool_resource #else - llvm::RecyclingAllocator + llvm::RecyclingAllocator #endif ; - PointsToSetOwner(allocator_type Alloc) noexcept : Alloc(Alloc) { + AliasSetOwner(allocator_type Alloc) noexcept : Alloc(Alloc) { if constexpr (std::is_pointer_v) { assert(Alloc != nullptr); } } - PointsToSetOwner(PointsToSetOwner &&) noexcept = default; + AliasSetOwner(AliasSetOwner &&) noexcept = default; - PointsToSetOwner(const PointsToSetOwner &) = delete; - PointsToSetOwner &operator=(const PointsToSetOwner &) = delete; - PointsToSetOwner &operator=(PointsToSetOwner &&) = delete; + AliasSetOwner(const AliasSetOwner &) = delete; + AliasSetOwner &operator=(const AliasSetOwner &) = delete; + AliasSetOwner &operator=(AliasSetOwner &&) = delete; - ~PointsToSetOwner() { + ~AliasSetOwner() { for (auto PTS : OwnedPTS) { std::destroy_at(PTS); #if HAS_MEMORY_RESOURCE @@ -79,7 +77,7 @@ template class PointsToSetOwner { OwnedPTS.clear(); } - DynamicPointsToSetPtr acquire() { + BoxedPtr acquire() { auto RawMem = #if HAS_MEMORY_RESOURCE Alloc.allocate(1) @@ -87,16 +85,16 @@ template class PointsToSetOwner { Alloc->Allocate() #endif ; - auto Ptr = new (RawMem) PointsToSetTy(); + auto Ptr = new (RawMem) AliasSetTy(); OwnedPTS.insert(Ptr); return &AllPTS.emplace_back(Ptr); } - void release(PointsToSetTy *PTS) noexcept { + void release(AliasSetTy *PTS) noexcept { if (LLVM_UNLIKELY(!OwnedPTS.erase(PTS))) { llvm::report_fatal_error( - "ERROR: release PointsToSet that was either already " - "freed, or never allocated with this PointsToSetOwner!"); + "ERROR: release AliasSet that was either already " + "freed, or never allocated with this AliasSetOwner!"); } std::destroy_at(PTS); #if HAS_MEMORY_RESOURCE @@ -109,17 +107,18 @@ template class PointsToSetOwner { void reserve(size_t Capacity) { OwnedPTS.reserve(Capacity); } - [[nodiscard]] auto getAllPointsToSets() const noexcept { + [[nodiscard]] auto getAllAliasSets() const noexcept { return llvm::make_range(OwnedPTS.begin(), OwnedPTS.end()); } private: allocator_type Alloc{}; - llvm::DenseSet OwnedPTS; - StableVector AllPTS; + llvm::DenseSet OwnedPTS; + StableVector AllPTS; }; -extern template class PointsToSetOwner; +extern template class AliasSetOwner::AliasSetTy>; } // namespace psr -#endif // PHASAR_PHASARLLVM_POINTER_POINTSTOSETOWNER_H +#endif // PHASAR_PHASARLLVM_POINTER_ALIASSETOWNER_H diff --git a/include/phasar/Pointer/PointsToInfo.h b/include/phasar/Pointer/PointsToInfo.h new file mode 100644 index 000000000..c5511ec2b --- /dev/null +++ b/include/phasar/Pointer/PointsToInfo.h @@ -0,0 +1,267 @@ +/****************************************************************************** + * 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_POINTER_POINTSTOINFO_H +#define PHASAR_PHASARLLVM_POINTER_POINTSTOINFO_H + +#include "phasar/Pointer/PointsToInfoBase.h" +#include "phasar/Utils/ByRef.h" + +#include +#include +#include +#include +#include + +namespace psr { + +template class PointsToInfoRef; +template class PointsToInfo; + +template +struct PointsToTraits> : PTATraits {}; +template +struct PointsToTraits> : PTATraits {}; + +/// A type-erased reference to any object implementing th PointsToInfoBase +/// interface. Use this, if your analysis is not tied to a specific points-to +/// info implementation. +/// +/// This is a *non-owning* reference similar to std::string_view and +/// llvm::ArrayRef. Pass values of this type by value. +/// +template +class PointsToInfoRef>> + : PointsToInfoBase> { + friend class PointsToInfo; + using base_t = PointsToInfoBase>; + +public: + using typename base_t::n_t; + using typename base_t::o_t; + using typename base_t::PointsToSetPtrTy; + using typename base_t::PointsToSetTy; + using typename base_t::v_t; + + PointsToInfoRef() noexcept = default; + PointsToInfoRef(std::nullptr_t) noexcept : PointsToInfoRef() {} + + template && + is_equivalent_PointsToTraits_v>>> + PointsToInfoRef(const ConcretePTA *PT) noexcept + : PT(PT), VT(&VTableFor) { + if constexpr (!std::is_empty_v) { + assert(PT != nullptr); + } + } + + // Prevent dangling references + PointsToInfoRef(PointsToInfo &&) = delete; + PointsToInfoRef &operator=(PointsToInfo &&) = delete; + + PointsToInfoRef(const PointsToInfoRef &) noexcept = default; + PointsToInfoRef &operator=(const PointsToInfoRef &) noexcept = default; + ~PointsToInfoRef() noexcept = default; + + explicit operator bool() const noexcept { return VT != nullptr; } + +private: + struct VTableBase { + o_t (*AsAbstractObject)(const void *, ByConstRef) noexcept; + std::optional (*AsPointerOrNull)(const void *, + ByConstRef) noexcept; + bool (*MayPointsTo)(const void *, ByConstRef, ByConstRef, + ByConstRef); + PointsToSetPtrTy (*GetPointsToSet)(const void *, ByConstRef, + ByConstRef); + + std::vector (*GetInterestingPointersAt)(const void *, ByConstRef); + void (*Destroy)(const void *) noexcept; // Useful for the owning variant + }; + + template struct VTable : VTableBase {}; + template + struct VTable>> : VTableBase { + bool (*MayPointsToV)(const void *, ByConstRef, ByConstRef, + ByConstRef); + PointsToSetPtrTy (*GetPointsToSetV)(const void *, ByConstRef, + ByConstRef); + }; + + template + constexpr static VTable<> makeVTableFor() noexcept { + constexpr VTableBase Base = { + [](const void *PT, ByConstRef Pointer) noexcept { + return static_cast(PT)->asAbstractObject( + Pointer); + }, + [](const void *PT, ByConstRef Obj) noexcept { + return static_cast(PT)->asPointerOrNull(Obj); + }, + [](const void *PT, ByConstRef Pointer, ByConstRef Obj, + ByConstRef AtInstruction) { + return static_cast(PT)->mayPointsTo( + Pointer, Obj, AtInstruction); + }, + [](const void *PT, ByConstRef Pointer, + ByConstRef AtInstruction) { + return static_cast(PT)->getPointsToSet( + Pointer, AtInstruction); + }, + [](const void *PT, ByConstRef AtInstruction) { + std::vector Ret; + for (ByConstRef Ptr : + static_cast(PT)->getInterestingPointersAt( + AtInstruction)) { + Ret.push_back(Ptr); + } + return Ret; + }, + [](const void *PT) noexcept { + delete static_cast(PT); + }, + }; + if constexpr (std::is_same_v) { + return {Base}; + } else { + return { + Base, + [](const void *PT, ByConstRef Pointer, ByConstRef Obj, + ByConstRef AtInstruction) { + return static_cast(PT)->mayPointsTo( + Pointer, Obj, AtInstruction); + }, + [](const void *PT, ByConstRef Pointer, + ByConstRef AtInstruction) { + return static_cast(PT)->getPointsToSet( + Pointer, AtInstruction); + }, + }; + } + } + + template + static constexpr VTable<> VTableFor = makeVTableFor(); + + // --- Impl for PointsToInfoBase: + + [[nodiscard]] o_t + asAbstractObjectImpl(ByConstRef Pointer) const noexcept { + assert(VT); + return VT->AsAbstractObject(PT, Pointer); + } + + [[nodiscard]] std::optional + asPointerOrNull(ByConstRef Obj) const noexcept { + assert(VT); + return VT->AsPointerOrNull(PT, Obj); + } + + [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, + ByConstRef Obj, + ByConstRef AtInstruction) const { + assert(VT); + return VT->MayPointsTo(PT, Pointer, Obj, AtInstruction); + } + + template >> + [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, + ByConstRef Obj, + ByConstRef AtInstruction) const { + assert(VT); + return VT->MayPointsToV(PT, Pointer, Obj, AtInstruction); + } + + [[nodiscard]] PointsToSetPtrTy + getPointsToSetImpl(ByConstRef Pointer, + ByConstRef AtInstruction) const { + assert(VT); + return VT->GetPointsToSet(PT, Pointer, AtInstruction); + } + + template >> + [[nodiscard]] PointsToSetPtrTy + getPointsToSetImpl(ByConstRef Pointer, + ByConstRef AtInstruction) const { + assert(VT); + return VT->GetPointsToSetV(PT, Pointer, AtInstruction); + } + + std::vector + getInterestingPointersAtImpl(ByConstRef AtInstruction) const { + assert(VT); + return VT->GetInterestingPointersAt(PT, AtInstruction); + } + + // --- + const void *PT{}; + const VTable<> *VT{}; +}; + +/// Similar to PointsToInfoRef, but owns the held reference. Us this, if you +/// need to decide dynamically, which points-to info implementation to use. +/// +/// Implicitly convertible to PointsToInfoRef. +/// +template +class [[clang::trivial_abi]] PointsToInfo< + PTATraits, std::enable_if_t>> + final : public PointsToInfoRef { + using base_t = PointsToInfoRef; + +public: + using typename base_t::n_t; + using typename base_t::o_t; + using typename base_t::PointsToSetPtrTy; + using typename base_t::PointsToSetTy; + using typename base_t::v_t; + + PointsToInfo() noexcept = default; + PointsToInfo(std::nullptr_t) noexcept {}; + PointsToInfo(const PointsToInfo &) = delete; + PointsToInfo &operator=(const PointsToInfo &) = delete; + PointsToInfo(PointsToInfo &&Other) noexcept { swap(Other); } + PointsToInfo &operator=(PointsToInfo &&Other) noexcept { + auto Cpy{std::move(Other)}; + swap(Cpy); + return *this; + } + + void swap(PointsToInfo &Other) noexcept { + std::swap(this->PT, Other.PT); + std::swap(this->VT, Other.VT); + } + friend void swap(PointsToInfo &LHS, PointsToInfo &RHS) noexcept { + LHS.swap(RHS); + } + + template + explicit PointsToInfo(std::in_place_type_t /*unused*/, + ArgTys &&...Args) + : PointsToInfoRef( + new ConcretePTA(std::forward(Args)...)) {} + + ~PointsToInfo() noexcept { + if (*this) { + this->VT->Destroy(this->PT); + this->VT = nullptr; + this->PT = nullptr; + } + } +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_POINTSTOINFO_H diff --git a/include/phasar/Pointer/PointsToInfoBase.h b/include/phasar/Pointer/PointsToInfoBase.h new file mode 100644 index 000000000..923429d3c --- /dev/null +++ b/include/phasar/Pointer/PointsToInfoBase.h @@ -0,0 +1,148 @@ +/****************************************************************************** + * 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_POINTER_POINTSTOINFOBASE_H +#define PHASAR_PHASARLLVM_POINTER_POINTSTOINFOBASE_H + +#include "phasar/Utils/ByRef.h" +#include "phasar/Utils/TypeTraits.h" + +#include +#include + +namespace psr { +template struct PointsToTraits { + // using v_t -- Type of pointers + // using n_t -- Type of instructions (ICFG-nodes) + // using o_t -- Type of abstract objects (elements of the + // points-to sets) + // using PointsToSetTy -- Type of a points-to set (value-type) + // using PointsToSetPtrTy -- Type of a pointer to a points-to set + // (not necessarily PointsToSetTy const *) +}; + +template +struct is_PointsToTraits : std::false_type {}; // NOLINT +template +struct is_PointsToTraits< + T, std::void_t> + : std::true_type {}; + +template +static constexpr bool is_PointsToTraits_v = // NOLINT + is_PointsToTraits::value; + +// clang-format off +template +static constexpr bool is_equivalent_PointsToTraits_v = // NOLINT + is_PointsToTraits_v && is_PointsToTraits_v && + std::is_same_v && + std::is_same_v && + std::is_same_v && + std::is_same_v; +// clang-format on + +/// Base class of all points-to analysis implementations. Don't use this class +/// directly. For a type-erased variant, use PointsToInfoRef or PointsToInfo. +template class PointsToInfoBase { +public: + using v_t = typename PointsToTraits::v_t; + using n_t = typename PointsToTraits::n_t; + using o_t = typename PointsToTraits::o_t; + using PointsToSetTy = typename PointsToTraits::PointsToSetTy; + using PointsToSetPtrTy = typename PointsToTraits::PointsToSetPtrTy; + + explicit PointsToInfoBase() noexcept { + static_assert(std::is_base_of_v, + "Invalid CRTP instantiation: Derived must inherit from " + "PointsToInfoBase!"); + } + + /// Creates an abstract object corresponding to the given pointer + [[nodiscard]] o_t asAbstractObject(ByConstRef Pointer) const noexcept { + return self().asAbstractObjectImpl(Pointer); + } + + /// Inverse function of asAbstractObject. If Obj does not directly correspond + /// to a pointer, this function may return nullopt. + [[nodiscard]] std::optional + asPointerOrNull(ByConstRef Obj) const noexcept { + return self().asPointerOrNullImpl(Obj); + } + + [[nodiscard]] bool mayPointsTo(ByConstRef Pointer, ByConstRef Obj, + ByConstRef AtInstruction) const { + return self().mayPointsToImpl(Pointer, Obj, AtInstruction); + } + + template >> + [[nodiscard]] bool mayPointsTo(ByConstRef Pointer, ByConstRef Obj, + ByConstRef AtInstruction) const { + return self().mayPointsToImpl(Pointer, Obj, AtInstruction); + } + + [[nodiscard]] PointsToSetPtrTy + getPointsToSet(ByConstRef Pointer, ByConstRef AtInstruction) const { + return self().getPointsToSetImpl(Pointer, AtInstruction); + } + + template >> + [[nodiscard]] PointsToSetPtrTy + getPointsToSet(ByConstRef Pointer, ByConstRef AtInstruction) const { + return self().getPointsToSetImpl(Pointer, AtInstruction); + } + + /// Gets all pointers v_t where we have non-empty points-to information at + /// this instruction + [[nodiscard]] decltype(auto) + getInterestingPointersAt(ByConstRef AtInstruction) const { + static_assert( + is_iterable_over_v< + decltype(self().getInterestingPointersAtImpl(AtInstruction)), v_t>); + return self().getInterestingPointersAtImpl(AtInstruction); + } + +private: + template >> + [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, + ByConstRef Obj, + ByConstRef AtInstruction) const { + return getPointsToSet(asAbstractObject(Pointer), AtInstruction)->count(Obj); + } + + [[nodiscard]] bool mayPointsToImpl(ByConstRef Pointer, + ByConstRef Obj, + ByConstRef AtInstruction) const { + return getPointsToSet(Pointer, AtInstruction)->count(Obj); + } + + template >> + [[nodiscard]] PointsToSetPtrTy + getPointsToSetImpl(ByConstRef Pointer, + ByConstRef AtInstruction) const { + return self().getPointsToSetImpl(asAbstractObject(Pointer), AtInstruction); + } + + [[nodiscard]] Derived &self() noexcept { + return static_cast(*this); + } + [[nodiscard]] const Derived &self() const noexcept { + return static_cast(*this); + } +}; + +} // namespace psr + +#endif // PHASAR_PHASARLLVM_POINTER_POINTSTOINFOBASE_H diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h b/include/phasar/TypeHierarchy/TypeHierarchy.h similarity index 97% rename from include/phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h rename to include/phasar/TypeHierarchy/TypeHierarchy.h index c09e82dc1..db9d9c8db 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/TypeHierarchy.h +++ b/include/phasar/TypeHierarchy/TypeHierarchy.h @@ -10,14 +10,14 @@ #ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_TYPEHIERARCHY_H_ #define PHASAR_PHASARLLVM_TYPEHIERARCHY_TYPEHIERARCHY_H_ -#include -#include +#include "phasar/TypeHierarchy/VFTable.h" -#include "nlohmann/json.hpp" +#include "llvm/Support/raw_ostream.h" -#include "phasar/PhasarLLVM/TypeHierarchy/VFTable.h" +#include "nlohmann/json.hpp" -#include "llvm/Support/raw_ostream.h" +#include +#include namespace psr { diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/VFTable.h b/include/phasar/TypeHierarchy/VFTable.h similarity index 99% rename from include/phasar/PhasarLLVM/TypeHierarchy/VFTable.h rename to include/phasar/TypeHierarchy/VFTable.h index 146c29ccf..bfbd615e0 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/VFTable.h +++ b/include/phasar/TypeHierarchy/VFTable.h @@ -10,10 +10,11 @@ #ifndef PHASAR_PHASARLLVM_TYPEHIERARCHY_VFTABLE_H_ #define PHASAR_PHASARLLVM_TYPEHIERARCHY_VFTABLE_H_ -#include +#include "llvm/Support/raw_ostream.h" #include "nlohmann/json.hpp" -#include "llvm/Support/raw_ostream.h" + +#include namespace llvm { class raw_ostream; diff --git a/include/phasar/Utils/AnalysisProperties.h b/include/phasar/Utils/AnalysisProperties.h new file mode 100644 index 000000000..aa10d9f0c --- /dev/null +++ b/include/phasar/Utils/AnalysisProperties.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * 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 + *****************************************************************************/ + +#ifndef PHASAR_UTILS_ANALYSISPROPERTIES_H +#define PHASAR_UTILS_ANALYSISPROPERTIES_H + +#include "llvm/Support/raw_ostream.h" + +#include +#include + +namespace psr { +enum class AnalysisProperties { + None = 0, + FlowSensitive = (1 << 0), + ContextSensitive = (1 << 1), + FieldSensitive = (1 << 2), +}; + +std::string to_string(AnalysisProperties Prop); + +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + AnalysisProperties Prop) { + return OS << to_string(Prop); +} + +template class AnalysisPropertiesMixin { +public: + [[nodiscard]] bool isFieldSensitive() const noexcept { + return hasFlag(AnalysisProperties::FieldSensitive); + } + + [[nodiscard]] bool isContextSensitive() const noexcept { + return hasFlag(AnalysisProperties::ContextSensitive); + } + + [[nodiscard]] bool isFlowSensitive() const noexcept { + return hasFlag(AnalysisProperties::FlowSensitive); + } + +private: + [[nodiscard]] bool hasFlag(AnalysisProperties Prop) const noexcept { + static_assert(std::is_base_of_v, Derived>, + "Invalid CRTP instantiation! Derived must inherit from " + "AnalysisPropertiesMixin"); + return int(static_cast(this)->getAnalysisProperties()) & + int(Prop); + } +}; + +} // namespace psr + +#endif // PHASAR_UTILS_ANALYSISPROPERTIES_H diff --git a/include/phasar/Utils/BitVectorSet.h b/include/phasar/Utils/BitVectorSet.h index 11e6dd800..418d90e60 100644 --- a/include/phasar/Utils/BitVectorSet.h +++ b/include/phasar/Utils/BitVectorSet.h @@ -10,16 +10,17 @@ #ifndef PHASAR_UTILS_BITVECTORSET_H_ #define PHASAR_UTILS_BITVECTORSET_H_ -#include -#include -#include +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" #include "boost/bimap.hpp" #include "boost/bimap/unordered_set_of.hpp" -#include "llvm/ADT/BitVector.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/raw_ostream.h" +#include +#include +#include namespace psr { namespace internal { @@ -301,6 +302,20 @@ template class BitVectorSet { return internal::isLess(Lhs.Bits, Rhs.Bits); } + // NOLINTNEXTLINE(readability-identifier-naming) -- needed for ADL + friend llvm::hash_code hash_value(const BitVectorSet &BV) noexcept { + if (BV.Bits.empty()) { + return {}; + } + auto Words = BV.Bits.getData(); + size_t Idx = Words.size(); + while (Idx && Words[Idx - 1] == 0) { + --Idx; + } + return llvm::hash_combine_range(Words.begin(), + std::next(Words.begin(), Idx)); + } + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const BitVectorSet &B) { OS << '<'; diff --git a/include/phasar/Utils/BoxedPointer.h b/include/phasar/Utils/BoxedPointer.h new file mode 100644 index 000000000..0d43ba825 --- /dev/null +++ b/include/phasar/Utils/BoxedPointer.h @@ -0,0 +1,210 @@ +/****************************************************************************** + * 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_BOXEDPOINTER_H +#define PHASAR_UTILS_BOXEDPOINTER_H + +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Hashing.h" + +#include + +namespace llvm { +class Value; +} // namespace llvm + +namespace psr { + +template class BoxedConstPtr; +/// A T** that behaves like a T*. Used as AliasSetPtr in LLVMAliasSet +template class BoxedPtr { +public: + using value_type = T; + + constexpr BoxedPtr() noexcept = default; + constexpr BoxedPtr(std::nullptr_t) noexcept {} + constexpr BoxedPtr(value_type **Value) noexcept : Value(Value) { + assert(Value != nullptr); + } + constexpr BoxedPtr(const BoxedPtr &) noexcept = default; + constexpr BoxedPtr &operator=(const BoxedPtr &) noexcept = default; + ~BoxedPtr() noexcept = default; + + [[nodiscard]] constexpr value_type *get() noexcept { return *Value; } + [[nodiscard]] constexpr const value_type *get() const noexcept { + return *Value; + } + + constexpr value_type *operator->() noexcept { return get(); } + constexpr const value_type *operator->() const noexcept { return get(); } + + constexpr value_type &operator*() noexcept { return **Value; } + constexpr const value_type &operator*() const noexcept { return **Value; } + + constexpr operator bool() const noexcept { + return Value && *Value != nullptr; + } + + [[nodiscard]] constexpr value_type **value() noexcept { return Value; } + [[nodiscard]] constexpr value_type const *const *value() const noexcept { + return Value; + } + + [[nodiscard]] friend constexpr llvm::hash_code + hash_value(BoxedPtr // NOLINT(readability-identifier-naming) + Ptr) noexcept { + return llvm::hash_value(Ptr.Value); + } + + [[nodiscard]] friend constexpr bool operator==(BoxedPtr LHS, + BoxedPtr RHS) noexcept { + return LHS.Value == RHS.Value; + } + [[nodiscard]] friend constexpr bool operator!=(BoxedPtr LHS, + BoxedPtr RHS) noexcept { + return !(LHS == RHS); + } + + [[nodiscard]] friend constexpr bool operator<(BoxedPtr LHS, + BoxedPtr RHS) noexcept { + return LHS.Value < RHS.Value; + } + [[nodiscard]] friend constexpr bool operator>(BoxedPtr LHS, + BoxedPtr RHS) noexcept { + return LHS.Value > RHS.Value; + } + + [[nodiscard]] friend constexpr bool operator<=(BoxedPtr LHS, + BoxedPtr RHS) noexcept { + return LHS.Value <= RHS.Value; + } + [[nodiscard]] friend constexpr bool operator>=(BoxedPtr LHS, + BoxedPtr RHS) noexcept { + return LHS.Value >= RHS.Value; + } + +private: + friend class BoxedConstPtr; + + value_type **Value = nullptr; +}; + +/// A T const** that behaves like a const T*. +/// NOTE: This is different to const BoxedPtr which +/// propagates the const through all known layers of indirection +template class BoxedConstPtr : private BoxedPtr { +public: + using BoxedPtr::BoxedPtr; + using BoxedPtr::operator bool; + using typename BoxedPtr::value_type; + + constexpr BoxedConstPtr(BoxedPtr Other) noexcept : BoxedPtr(Other) {} + + [[nodiscard]] constexpr const value_type *get() const noexcept { + return BoxedPtr::get(); + } + + constexpr const value_type *operator->() const noexcept { return get(); } + + constexpr const value_type &operator*() const noexcept { + return *BoxedPtr::get(); + } + + [[nodiscard]] constexpr value_type const *const *value() const noexcept { + return BoxedPtr::value(); + } + + [[nodiscard]] friend constexpr llvm::hash_code + hash_value(BoxedConstPtr // NOLINT(readability-identifier-naming) + Ptr) noexcept { + return llvm::hash_value(Ptr.value()); + } + + [[nodiscard]] friend constexpr bool operator==(BoxedConstPtr LHS, + BoxedConstPtr RHS) noexcept { + return LHS.value() == RHS.value(); + } + [[nodiscard]] friend constexpr bool operator!=(BoxedConstPtr LHS, + BoxedConstPtr RHS) noexcept { + return !(LHS == RHS); + } + + [[nodiscard]] friend constexpr bool operator<(BoxedConstPtr LHS, + BoxedConstPtr RHS) noexcept { + return LHS.value() < RHS.value(); + } + [[nodiscard]] friend constexpr bool operator>(BoxedConstPtr LHS, + BoxedConstPtr RHS) noexcept { + return LHS.value() > RHS.value(); + } + + [[nodiscard]] friend constexpr bool operator<=(BoxedConstPtr LHS, + BoxedConstPtr RHS) noexcept { + return LHS.value() <= RHS.value(); + } + [[nodiscard]] friend constexpr bool operator>=(BoxedConstPtr LHS, + BoxedConstPtr RHS) noexcept { + return LHS.value() >= RHS.value(); + } +}; + +} // namespace psr + +namespace std { +template struct hash> { + constexpr size_t operator()(psr::BoxedPtr Ptr) const noexcept { + return std::hash{}(Ptr.value()); + } +}; +template struct hash> { + constexpr size_t operator()(psr::BoxedConstPtr Ptr) const noexcept { + return std::hash{}(Ptr.value()); + } +}; +} // namespace std + +namespace llvm { +template struct DenseMapInfo> { + inline static psr::BoxedPtr getEmptyKey() noexcept { + return DenseMapInfo::getEmptyKey(); + } + inline static psr::BoxedPtr getTombstoneKey() noexcept { + return DenseMapInfo::getTombstoneKey(); + } + + inline static bool isEqual(psr::BoxedPtr LHS, + psr::BoxedPtr RHS) noexcept { + return LHS == RHS; + } + + inline static unsigned getHashValue(psr::BoxedPtr Ptr) noexcept { + return hash_value(Ptr); + } +}; +template struct DenseMapInfo> { + inline static psr::BoxedConstPtr getEmptyKey() noexcept { + return DenseMapInfo::getEmptyKey(); + } + inline static psr::BoxedConstPtr getTombstoneKey() noexcept { + return DenseMapInfo::getTombstoneKey(); + } + + inline static bool isEqual(psr::BoxedConstPtr LHS, + psr::BoxedConstPtr RHS) noexcept { + return LHS == RHS; + } + + inline static unsigned getHashValue(psr::BoxedConstPtr Ptr) noexcept { + return hash_value(Ptr); + } +}; +} // namespace llvm + +#endif // PHASAR_UTILS_BOXEDPOINTER_H diff --git a/include/phasar/PhasarLLVM/Utils/ByRef.h b/include/phasar/Utils/ByRef.h similarity index 60% rename from include/phasar/PhasarLLVM/Utils/ByRef.h rename to include/phasar/Utils/ByRef.h index 4573956b9..4cd72f550 100644 --- a/include/phasar/PhasarLLVM/Utils/ByRef.h +++ b/include/phasar/Utils/ByRef.h @@ -13,14 +13,16 @@ #include namespace psr { + +template +static constexpr bool CanEfficientlyPassByValue = + sizeof(T) <= 2 * sizeof(void *) && std::is_trivially_copyable_v; + template -using ByConstRef = std::conditional_t, - T, const T &>; +using ByConstRef = + std::conditional_t, T, const T &>; template -using ByMoveRef = std::conditional_t, - T, T &&>; +using ByMoveRef = std::conditional_t, T, T &&>; } // namespace psr diff --git a/include/phasar/PhasarLLVM/Utils/DOTGraph.h b/include/phasar/Utils/DOTGraph.h similarity index 98% rename from include/phasar/PhasarLLVM/Utils/DOTGraph.h rename to include/phasar/Utils/DOTGraph.h index ee7bc9895..cae66e6fc 100644 --- a/include/phasar/PhasarLLVM/Utils/DOTGraph.h +++ b/include/phasar/Utils/DOTGraph.h @@ -17,13 +17,13 @@ #ifndef PHASAR_PHASARLLVM_UTILS_DOTGRAPH_H_ #define PHASAR_PHASARLLVM_UTILS_DOTGRAPH_H_ +#include "phasar/Config/Configuration.h" +#include "phasar/Utils/Utilities.h" + #include #include #include -#include "phasar/Config/Configuration.h" -#include "phasar/Utils/Utilities.h" - namespace psr { class DOTConfig { @@ -48,7 +48,7 @@ class DOTConfig { } static void - importDOTConfig(std::string ConfigPath = PhasarConfig::PhasarDirectory()); + importDOTConfig(llvm::StringRef ConfigPath = PhasarConfig::PhasarDirectory()); static DOTConfig &getDOTConfig(); ~DOTConfig() = default; diff --git a/include/phasar/Utils/DebugOutput.h b/include/phasar/Utils/DebugOutput.h index ed85859f0..e904ef531 100644 --- a/include/phasar/Utils/DebugOutput.h +++ b/include/phasar/Utils/DebugOutput.h @@ -67,9 +67,7 @@ template void printHelper(OS_t &OS, const T &Data) { } else if constexpr (is_iterable_v) { OS << "{ "; bool Frst = true; - size_t Cnt = 0; for (auto &&Elem : Data) { - ++Cnt; if (Frst) { Frst = false; } else { @@ -98,9 +96,9 @@ template struct PrettyPrinter { }; template -llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, - const PrettyPrinter &P) { - OS << P; +std::ostream &operator<<(std::ostream &OS, const PrettyPrinter &P) { + llvm::raw_os_ostream ROS(OS); + ROS << P; return OS; } diff --git a/include/phasar/Utils/EnumFlags.h b/include/phasar/Utils/EnumFlags.h index c965fefa1..b02c25a34 100644 --- a/include/phasar/Utils/EnumFlags.h +++ b/include/phasar/Utils/EnumFlags.h @@ -14,80 +14,74 @@ namespace psr { -template ::value, T>> -class EnumFlagAutoBool { - T Val; +template >> +struct EnumFlagAutoBool { + T Value; -public: - constexpr EnumFlagAutoBool(T Val) : Val(Val) {} - constexpr operator T() const { return Val; } - constexpr explicit operator bool() const { - return static_cast>(Val) != 0; + constexpr operator T() const noexcept { return Value; } + constexpr explicit operator bool() const noexcept { + return static_cast>(Value) != 0; } }; -template ::value, T>> -constexpr EnumFlagAutoBool operator&(T Lhs, T Rhs) { - return static_cast(static_cast>(Lhs) & - static_cast>(Rhs)); +template >> +constexpr EnumFlagAutoBool operator&(T Lhs, T Rhs) noexcept { + return {static_cast(static_cast>(Lhs) & + static_cast>(Rhs))}; } -template ::value, T>> -constexpr void operator&=(T &Lhs, T Rhs) { - Lhs = static_cast(static_cast>(Lhs) & - static_cast>(Rhs)); +template >> +constexpr void operator&=(T &Lhs, T Rhs) noexcept { + Lhs = Lhs & Rhs; } -template ::value, T>> -constexpr T operator|(T Lhs, T Rhs) { - return static_cast(static_cast>(Lhs) | - static_cast>(Rhs)); +template >> +constexpr T operator|(T Lhs, T Rhs) noexcept { + return static_cast(static_cast>(Lhs) | + static_cast>(Rhs)); } -template ::value, T>> -constexpr void operator|=(T &Lhs, T Rhs) { - Lhs = static_cast(static_cast>(Lhs) | - static_cast>(Rhs)); +template >> +constexpr void operator|=(T &Lhs, T Rhs) noexcept { + Lhs = Lhs | Rhs; } -template ::value, T>> -constexpr T operator^(T Lhs, T Rhs) { - return static_cast(static_cast>(Lhs) ^ - static_cast>(Rhs)); +template >> +constexpr T operator^(T Lhs, T Rhs) noexcept { + return static_cast(static_cast>(Lhs) ^ + static_cast>(Rhs)); } -template ::value, T>> -constexpr void operator^=(T &Lhs, T Rhs) { - Lhs = static_cast(static_cast>(Lhs) ^ - static_cast>(Rhs)); +template >> +constexpr void operator^=(T &Lhs, T Rhs) noexcept { + Lhs = Lhs ^ Rhs; } -template ::value, T>> -constexpr T operator~(T Rhs) { - return static_cast(~static_cast>(Rhs)); +template >> +constexpr T operator~(T Rhs) noexcept { + return static_cast(~static_cast>(Rhs)); } -template ::value, T>> -constexpr void setFlag(T &This, T Flag, bool Set = true) { +template >> +constexpr void setFlag(T &This, T Flag) noexcept { + This |= Flag; +} +template >> +constexpr void unsetFlag(T &This, T Flag) noexcept { + This &= ~Flag; +} +template >> +constexpr void setFlag(T &This, T Flag, bool Set) noexcept { if (Set) { - This |= Flag; + setFlag(This, Flag); } else { - This &= ~Flag; + unsetFlag(This, Flag); } } -template ::value, T>> -constexpr bool hasFlag(T This, T Flag) { - return static_cast(This & Flag); + +template >> +constexpr bool hasFlag(T This, T Flag) noexcept { + return (This & Flag) == Flag; } } // namespace psr diff --git a/include/phasar/Utils/EquivalenceClassMap.h b/include/phasar/Utils/EquivalenceClassMap.h index f8e6d33c7..7c84a168d 100644 --- a/include/phasar/Utils/EquivalenceClassMap.h +++ b/include/phasar/Utils/EquivalenceClassMap.h @@ -10,13 +10,13 @@ #ifndef PHASAR_UTILS_EQUIVALENCECLASSMAP_H #define PHASAR_UTILS_EQUIVALENCECLASSMAP_H +#include "llvm/ADT/iterator_range.h" + #include #include #include #include -#include "llvm/ADT/iterator_range.h" - namespace psr { // EquivalenceClassMap is a special map type that splits the keys into diff --git a/include/phasar/Utils/ErrorHandling.h b/include/phasar/Utils/ErrorHandling.h new file mode 100644 index 000000000..3e5920af1 --- /dev/null +++ b/include/phasar/Utils/ErrorHandling.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_ERRORHANDLING_H +#define PHASAR_UTILS_ERRORHANDLING_H + +#include "llvm/Support/ErrorOr.h" + +#include +#include +#include +#include + +namespace psr { +template T getOrThrow(llvm::ErrorOr ValOrErr) { + if (ValOrErr) { + return std::move(*ValOrErr); + } + throw std::system_error(ValOrErr.getError()); +} + +template +std::optional getOrNull(llvm::ErrorOr ValOrErr) noexcept( + std::is_nothrow_move_constructible_v) { + if (ValOrErr) { + return std::move(*ValOrErr); + } + return std::nullopt; +} + +template >> +T getOrEmpty(llvm::ErrorOr ValOrErr) noexcept( + std::is_nothrow_move_constructible_v) { + if (ValOrErr) { + return std::move(*ValOrErr); + } + return T(); +} + +template +llvm::ErrorOr> +mapValue(const llvm::ErrorOr &ValOrErr, + MapFn Mapper) noexcept(std::is_nothrow_invocable_v) { + if (ValOrErr) { + return std::invoke(std::move(Mapper), *ValOrErr); + } + return ValOrErr.getError(); +} + +template +llvm::ErrorOr> +mapValue(llvm::ErrorOr &&ValOrErr, + MapFn Mapper) noexcept(std::is_nothrow_invocable_v) { + if (ValOrErr) { + return std::invoke(std::move(Mapper), std::move(*ValOrErr)); + } + return ValOrErr.getError(); +} + +} // namespace psr + +#endif // PHASAR_UTILS_ERRORHANDLING_H diff --git a/include/phasar/Utils/IO.h b/include/phasar/Utils/IO.h index 33791f54e..f9966df63 100644 --- a/include/phasar/Utils/IO.h +++ b/include/phasar/Utils/IO.h @@ -17,31 +17,36 @@ #ifndef PHASAR_UTILS_IO_H #define PHASAR_UTILS_IO_H -#include -#include -#include +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" #include "nlohmann/json.hpp" -#include "llvm/ADT/StringRef.h" - -namespace llvm { -class MemoryBuffer; -class raw_fd_ostream; -class Twine; -} // namespace llvm +#include namespace psr { -std::string readTextFile(const llvm::Twine &Path); +[[nodiscard]] llvm::ErrorOr +readTextFileOrErr(const llvm::Twine &Path); +[[nodiscard]] llvm::ErrorOr> +readFileOrErr(const llvm::Twine &Path) noexcept; + +[[nodiscard]] std::string readTextFile(const llvm::Twine &Path); +[[nodiscard]] std::unique_ptr +readFile(const llvm::Twine &Path); -std::unique_ptr readFile(const llvm::Twine &Path); +[[nodiscard]] std::optional +readTextFileOrNull(const llvm::Twine &Path); +[[nodiscard]] std::unique_ptr +readFileOrNull(const llvm::Twine &Path) noexcept; -nlohmann::json readJsonFile(const llvm::Twine &Path); +[[nodiscard]] nlohmann::json readJsonFile(const llvm::Twine &Path); void writeTextFile(const llvm::Twine &Path, llvm::StringRef Content); -std::unique_ptr +[[nodiscard]] std::unique_ptr openFileStream(const llvm::Twine &Filename); } // namespace psr diff --git a/include/phasar/Utils/JoinLattice.h b/include/phasar/Utils/JoinLattice.h new file mode 100644 index 000000000..718eaf6f3 --- /dev/null +++ b/include/phasar/Utils/JoinLattice.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * 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 + *****************************************************************************/ + +/* + * AbstractJoinLattice.h + * + * Created on: 04.08.2016 + * Author: pdschbrt + */ + +#ifndef PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_JOINLATTICE_H +#define PHASAR_PHASARLLVM_DATAFLOWSOLVER_IFDSIDE_JOINLATTICE_H + +#include +#include + +namespace psr { + +template struct JoinLatticeTraits { + // static constexpr L top(); + // static constexpr L bottom(); + // static L join(L LHS, L RHS); +}; + +namespace detail { +template +struct HasJoinLatticeTraitsHelper : std::false_type {}; +template +struct HasJoinLatticeTraitsHelper< + L, std::enable_if_t< + std::is_convertible_v::top()), L> && + std::is_convertible_v::bottom()), L> && + std::is_convertible_v::join( + std::declval(), std::declval())), + L>>> : std::true_type {}; +} // namespace detail +template +static constexpr bool HasJoinLatticeTraits = + detail::HasJoinLatticeTraitsHelper::value; + +template class JoinLattice { +public: + using l_t = typename AnalysisDomainTy::l_t; + + virtual ~JoinLattice() = default; + virtual l_t topElement() = 0; + virtual l_t bottomElement() = 0; + virtual l_t join(l_t Lhs, l_t Rhs) = 0; +}; + +template +class JoinLattice< + AnalysisDomainTy, + std::enable_if_t>> { +public: + using l_t = typename AnalysisDomainTy::l_t; + + virtual ~JoinLattice() = default; + virtual l_t topElement() { return JoinLatticeTraits::top(); }; + virtual l_t bottomElement() { return JoinLatticeTraits::bottom(); }; + virtual l_t join(l_t Lhs, l_t Rhs) { + return JoinLatticeTraits::join(std::move(Lhs), std::move(Rhs)); + }; +}; + +template struct NonTopBotValue { + using type = L; + + static L unwrap(L Value) noexcept(std::is_nothrow_move_constructible_v) { + return Value; + } +}; + +} // namespace psr + +#endif diff --git a/include/phasar/Utils/Logger.h b/include/phasar/Utils/Logger.h index 825c86963..9dc9306b4 100644 --- a/include/phasar/Utils/Logger.h +++ b/include/phasar/Utils/Logger.h @@ -10,18 +10,18 @@ #ifndef PHASAR_UTILS_LOGGER_H #define PHASAR_UTILS_LOGGER_H -#include -#include -#include -#include -#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" +#include +#include +#include +#include +#include + namespace psr { enum SeverityLevel { diff --git a/include/phasar/Utils/MaybeUniquePtr.h b/include/phasar/Utils/MaybeUniquePtr.h index a755c31b4..4a20f6e75 100644 --- a/include/phasar/Utils/MaybeUniquePtr.h +++ b/include/phasar/Utils/MaybeUniquePtr.h @@ -43,7 +43,10 @@ template class MaybeUniquePtrBase { protected: llvm::PointerIntPair Data{}; - MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} {} + MaybeUniquePtrBase(T *Ptr, bool Owns) noexcept : Data{Ptr, Owns} { + static_assert(alignof(T) > 1, + "Using MaybeUniquePtr requires alignment > 1!"); + } MaybeUniquePtrBase() noexcept = default; }; } // namespace detail diff --git a/include/phasar/Utils/MemoryResource.h b/include/phasar/Utils/MemoryResource.h index 886e373d8..d6bf9c5de 100644 --- a/include/phasar/Utils/MemoryResource.h +++ b/include/phasar/Utils/MemoryResource.h @@ -4,6 +4,7 @@ #ifndef HAS_MEMORY_RESOURCE #if !defined(__has_include) || __has_include() #define HAS_MEMORY_RESOURCE 1 +#include #else #define HAS_MEMORY_RESOURCE 0 #endif diff --git a/include/phasar/Utils/NlohmannLogging.h b/include/phasar/Utils/NlohmannLogging.h index ce04280a7..b9ae2cbb7 100644 --- a/include/phasar/Utils/NlohmannLogging.h +++ b/include/phasar/Utils/NlohmannLogging.h @@ -10,42 +10,12 @@ #ifndef PHASAR_UTILS_NLOHMANNLOGGING_H #define PHASAR_UTILS_NLOHMANNLOGGING_H -#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Format.h" // -- ---------v +#include "llvm/Support/FormatVariadic.h" // -- for overload resolution #include "llvm/Support/raw_ostream.h" #include "nlohmann/json.hpp" -namespace nlohmann::detail { -class llvm_output_stream_adapter : public output_adapter_protocol { -public: - explicit llvm_output_stream_adapter(llvm::raw_ostream &OS) noexcept - : OS(OS) {} - - void write_character(char c) override { OS.write(c); } - - void write_characters(const char *Str, std::size_t Length) override { - OS.write(Str, static_cast(Length)); - } - -private: - llvm::raw_ostream &OS; -}; - -template > -class llvm_output_adapter { -public: - template > - - llvm_output_adapter(llvm::raw_ostream &OS) - : OA(std::make_shared(OS)) {} - - operator output_adapter_t() { return OA; } - -private: - output_adapter_t OA = nullptr; -}; -} // namespace nlohmann::detail - namespace psr { llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const nlohmann::json &J); } // namespace psr diff --git a/include/phasar/Utils/Nullable.h b/include/phasar/Utils/Nullable.h new file mode 100644 index 000000000..5bb3b2a9d --- /dev/null +++ b/include/phasar/Utils/Nullable.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (c) 2023 Fabian Schiebel. + * 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_NULLABLE_H +#define PHASAR_UTILS_NULLABLE_H + +#include +#include + +namespace psr { + +template +using Nullable = + std::conditional_t, T, std::optional>; +} // namespace psr + +#endif // PHASAR_UTILS_NULLABLE_H diff --git a/include/phasar/Utils/Printer.h b/include/phasar/Utils/Printer.h new file mode 100644 index 000000000..c30e21401 --- /dev/null +++ b/include/phasar/Utils/Printer.h @@ -0,0 +1,113 @@ +/****************************************************************************** + * 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_UTILS_PRINTER_H +#define PHASAR_PHASARLLVM_UTILS_PRINTER_H + +#include "llvm/Support/raw_ostream.h" + +#include +#include + +namespace psr { + +template +std::string toStringBuilder(void (P::*Printer)(llvm::raw_ostream &, T) const, + const P *This, const T &Arg) { + std::string Buffer; + llvm::raw_string_ostream StrS(Buffer); + std::invoke(Printer, This, std::ref(StrS), Arg); + return Buffer; +} + +template struct NodePrinterBase { + virtual ~NodePrinterBase() = default; + + virtual void printNode(llvm::raw_ostream &OS, N Stmt) const = 0; + + [[nodiscard]] std::string NtoString(N Stmt) const { // NOLINT + return toStringBuilder(&NodePrinterBase::printNode, this, Stmt); + } +}; +template +using NodePrinter = NodePrinterBase; + +template struct DataFlowFactPrinterBase { + virtual ~DataFlowFactPrinterBase() = default; + + virtual void printDataFlowFact(llvm::raw_ostream &OS, D Fact) const = 0; + + [[nodiscard]] std::string DtoString(D Fact) const { // NOLINT + return toStringBuilder(&DataFlowFactPrinterBase::printDataFlowFact, this, + Fact); + } +}; +template +using DataFlowFactPrinter = + DataFlowFactPrinterBase; + +template struct ValuePrinter { + virtual ~ValuePrinter() = default; + + virtual void printValue(llvm::raw_ostream &OS, V Val) const = 0; + + [[nodiscard]] std::string VtoString(V Val) const { // NOLINT + return toStringBuilder(&ValuePrinter::printValue, this, Val); + } +}; + +template struct TypePrinter { + virtual ~TypePrinter() = default; + + virtual void printType(llvm::raw_ostream &OS, T Ty) const = 0; + + [[nodiscard]] std::string TtoString(T Ty) const { // NOLINT + return toStringBuilder(&TypePrinter::printType, this, Ty); + } +}; + +template struct EdgeFactPrinter { + using l_t = typename AnalysisDomainTy::l_t; + + virtual ~EdgeFactPrinter() = default; + + virtual void printEdgeFact(llvm::raw_ostream &OS, l_t L) const = 0; + + [[nodiscard]] std::string LtoString(l_t L) const { // NOLINT + return toStringBuilder(&EdgeFactPrinter::printEdgeFact, this, L); + } +}; + +template struct FunctionPrinter { + using F = typename AnalysisDomainTy::f_t; + + virtual ~FunctionPrinter() = default; + + virtual void printFunction(llvm::raw_ostream &OS, F Func) const = 0; + + [[nodiscard]] std::string FtoString(F Func) const { // NOLINT + return toStringBuilder(&FunctionPrinter::printFunction, this, Func); + } +}; + +template struct ContainerPrinter { + virtual ~ContainerPrinter() = default; + + virtual void printContainer(llvm::raw_ostream &OS, + ContainerTy Container) const = 0; + + [[nodiscard]] std::string + ContainertoString(ContainerTy Container) const { // NOLINT + return toStringBuilder(&ContainerPrinter::printContainer, this, Container); + } +}; + +} // namespace psr + +#endif diff --git a/include/phasar/Utils/StableVector.h b/include/phasar/Utils/StableVector.h index 31b740924..f89ed5ab9 100644 --- a/include/phasar/Utils/StableVector.h +++ b/include/phasar/Utils/StableVector.h @@ -10,6 +10,10 @@ #ifndef PHASAR_UTILS_STABLEVECTOR_H_ #define PHASAR_UTILS_STABLEVECTOR_H_ +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" + #include #include #include @@ -17,10 +21,6 @@ #include #include -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/raw_ostream.h" - namespace psr { // NOLINTBEGIN(readability-identifier-naming) diff --git a/include/phasar/Utils/Table.h b/include/phasar/Utils/Table.h index 4141bf23a..6b5511f64 100644 --- a/include/phasar/Utils/Table.h +++ b/include/phasar/Utils/Table.h @@ -17,7 +17,8 @@ #ifndef PHASAR_UTILS_TABLE_H_ #define PHASAR_UTILS_TABLE_H_ -#include +#include "llvm/Support/raw_ostream.h" + #include #include #include diff --git a/include/phasar/Utils/TypeTraits.h b/include/phasar/Utils/TypeTraits.h index fec3553d5..0957292bb 100644 --- a/include/phasar/Utils/TypeTraits.h +++ b/include/phasar/Utils/TypeTraits.h @@ -10,26 +10,25 @@ #ifndef PHASAR_UTILS_TYPETRAITS_H #define PHASAR_UTILS_TYPETRAITS_H +#include "llvm/Support/raw_ostream.h" + #include #include #include +#include #include -#include "phasar/PhasarLLVM/DataFlowSolver/IfdsIde/IFDSIDESolverConfig.h" - -#include "llvm/Support/raw_ostream.h" - namespace psr { // NOLINTBEGIN(readability-identifier-naming) namespace detail { template -struct is_iterable : public std::false_type {}; // NOLINT +struct is_iterable : std::false_type {}; // NOLINT template struct is_iterable().begin()), - decltype(std::declval().end())>> - : public std::true_type {}; + decltype(std::declval().end())>> : std::true_type { +}; template struct is_iterable_over : std::false_type {}; // NOLINT template @@ -40,20 +39,20 @@ struct is_iterable_over< std::is_convertible_v().begin()), U>>> : std::true_type {}; -template struct is_pair : public std::false_type {}; // NOLINT +template struct is_pair : std::false_type {}; // NOLINT template -struct is_pair> : public std::true_type {}; // NOLINT +struct is_pair> : std::true_type {}; // NOLINT -template struct is_tuple : public std::false_type {}; // NOLINT +template struct is_tuple : std::false_type {}; // NOLINT template -struct is_tuple> : public std::true_type {}; // NOLINT +struct is_tuple> : std::true_type {}; // NOLINT template -struct is_printable : public std::false_type {}; // NOLINT +struct is_printable : std::false_type {}; // NOLINT template struct is_printable< // NOLINT T, OS, decltype(std::declval() << std::declval())> - : public std::true_type {}; + : std::true_type {}; template using is_llvm_printable = is_printable; // NOLINT @@ -62,9 +61,9 @@ template using is_std_printable = is_printable; // NOLINT template -struct has_str : public std::false_type {}; // NOLINT +struct has_str : std::false_type {}; // NOLINT template -struct has_str().str())> : public std::true_type { +struct has_str().str())> : std::true_type { }; // NOLINT template @@ -86,13 +85,6 @@ template struct is_llvm_hashable()))> // NOLINT : std::true_type {}; -template -struct has_setIFDSIDESolverConfig : std::false_type {}; -template -struct has_setIFDSIDESolverConfig< - T, decltype(std::declval().setIFDSIDESolverConfig( - std::declval()))> : std::true_type {}; - template