Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
db7f755
Start adding MonoIFDS to phasar
Mar 27, 2026
93d7054
Port rest of monoifds-solver
Mar 27, 2026
acb9696
Merge branch 'development' into f-MonoIFDS
Mar 30, 2026
940b219
Add rest of monoifds to phasar
Mar 30, 2026
d8b74b2
Integrating MonoIFDSTaintAnalysis into phasar-cli + make double_free0…
Mar 30, 2026
470a988
Fix ieration order + make tests pass
Mar 31, 2026
f4455fd
Add initializer to MonoIFDSSolver
Mar 31, 2026
1ff346b
Add some documentation + add summaryFlow() to MonoIFDS
Apr 10, 2026
79fe245
Add unittest for MonoIFDS and make it pass
Apr 10, 2026
d357de0
Merge branch 'development' into f-MonoIFDS
Apr 10, 2026
f281094
Add some more comments
Apr 13, 2026
cae247c
Add shouldBeInSummary
Apr 14, 2026
111713b
minor
Apr 14, 2026
dd6cd59
Make ICFG independent from analysis domain for MonoIFDSSolver
Apr 17, 2026
1cbb312
Add functionCompressor, usedGlobals, and CGSCCs to helperAnalyses to …
Apr 17, 2026
92ee790
Merge branch 'development' into f-MonoIFDS
Apr 27, 2026
04b2a99
minor
Apr 27, 2026
b160f02
Some somments + renaming
Apr 30, 2026
f831859
domain
Apr 30, 2026
fb56c12
Some nullable-correctness in analyzeBlockImpl
Apr 30, 2026
1f73bf6
Merge branch 'development' into f-MonoIFDS
May 4, 2026
259223b
Integrate MonoIFDS with HelperAnalyses
May 6, 2026
4a9cbe7
Use llvm::SmallBitVector in DataFlowEnvironment to match behavior pre…
May 6, 2026
755c37a
Merge branch 'development' into f-MonoIFDS
May 11, 2026
2a6528b
monir stuff + some general changes that should go into their own PR (…
May 11, 2026
c7f609a
As discussed, remove Eric from file headers
fabianbs96 May 13, 2026
fafc6c2
Add example, how to use MonoIFDS
fabianbs96 May 13, 2026
00a0c82
pre-commit + readme
fabianbs96 May 13, 2026
44f8f0d
modules
fabianbs96 May 13, 2026
1f599b2
llvm 22
fabianbs96 May 13, 2026
b1260a5
Fix dependency of UsedGlobals to ProjectIRDB
fabianbs96 May 13, 2026
3ffb334
Fix MonoIFDSSolver typo
fabianbs96 May 13, 2026
1775458
minor
fabianbs96 May 13, 2026
5a82b1d
Fix module compilation.
fabianbs96 May 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Checks: '-*,
-readability-identifier-length,
-readability-redundant-member-init,
-readability-use-anyofallof,
-readability-avoid-return-with-void-value,
-readability-use-std-min-max,
cppcoreguidelines-*,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
Expand Down
25 changes: 25 additions & 0 deletions examples/how-to/06-run-monoifds-analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.14...3.28)

project(run-monoifds-analysis)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

find_package(phasar REQUIRED CONFIG)


add_executable(run-monoifds-analysis-helper-analyses helper-analyses.cpp)
target_link_libraries(run-monoifds-analysis-helper-analyses PRIVATE phasar::phasar)

add_executable(run-monoifds-analysis-manual manual.cpp)
target_link_libraries(run-monoifds-analysis-manual PRIVATE phasar::phasar)


if (TARGET run_sample_programs)
add_custom_target(run_run_monoifds_analysis
DEPENDS run-monoifds-analysis-helper-analyses run-monoifds-analysis-manual LLFileGeneration
COMMAND $<TARGET_FILE:run-monoifds-analysis-helper-analyses> "${CMAKE_CURRENT_BINARY_DIR}/../llvm-hello-world/target/taint_cpp_dbg.ll"
COMMAND $<TARGET_FILE:run-monoifds-analysis-manual> "${CMAKE_CURRENT_BINARY_DIR}/../llvm-hello-world/target/taint_cpp_dbg.ll"
)

add_dependencies(run_sample_programs run_run_monoifds_analysis)
endif()
30 changes: 30 additions & 0 deletions examples/how-to/06-run-monoifds-analysis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Run a MonoIFDS Analysis

Shows some way, how you can use PhASAR to run an already existing MonoIFDS analysis on a LLVM IR module.
For this example, we selected the `MonoIFDSTaintAnalysis`.

You may look at the different C++ source files to see, how you can run an MonoIFDS taint analysis using PhASAR.
We suggest to start with the simplest example [helper-analyses.cpp](./helper-analyses.cpp).

## Build

This example program can be built using cmake.
It assumes, that you have installed PhASAR on your system. If you did not install PhASAR to a default location, you can specify `-Dphasar_ROOT=your/path/to/phasar` when invoking `cmake`, replacing "your/path/to/phasar" by the actual path where you have installed PhASAR.

```bash
# Invoked from the 06-run-monoifds-analysis root folder:
$ mkdir -p build && cd build
$ cmake ..
$ cmake --build .
```

## Test

You can test the example program on the target programs from [llvm-hello-world/target](../../llvm-hello-world/target/).

```bash
# Invoked from the 06-run-monoifds-analysis/build folder:
./run-monoifds-analysis-helper-analyses ../../../llvm-hello-world/target/taint.ll

./run-monoifds-analysis-manual ../../../llvm-hello-world/target/taint.ll
```
51 changes: 51 additions & 0 deletions examples/how-to/06-run-monoifds-analysis/helper-analyses.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "phasar/DataFlow.h" // For MonoIFDSSolver
#include "phasar/PhasarLLVM.h" // For the HelperAnalyses
#include "phasar/PhasarLLVM/DataFlow.h" // For the MonoIFDSTaintAnalysis
#include "phasar/PhasarLLVM/Pointer/FilteredLLVMAliasIterator.h"
#include "phasar/PhasarLLVM/TaintConfig.h" // For the LLVMTaintConfig

int main(int Argc, char *Argv[]) {
if (Argc < 2) {
llvm::errs()
<< "USAGE: run-monoifds-analysis-helper-analyses <LLVM-IR file>\n";
return 1;
}

using namespace std::string_literals;
std::vector EntryPoints = {"main"s};

// Instead of creating all the helper analyses ourselves, we can just use the
// HelperAnalyses class. It will create the necessary information on-demand.
//
// You can customize the underlying algorithms by passing a
// HelperAnalysisConfig as third parameter
psr::HelperAnalyses HA(Argv[1], EntryPoints);
if (!HA.getProjectIRDB()) {
return 1;
}

// Create the taint configuration
psr::LLVMTaintConfig TC(HA.getProjectIRDB());
TC.print();
llvm::outs() << "------------------------\n";

// More precise alias-information; techically, this is not required, but it
// helps a lot
psr::FilteredLLVMAliasIterator FAI(HA.getAliasInfo());

// Create the taint analysis problem:
psr::monoifds::TaintAnalysis TaintProblem(&TC, &HA.getUsedGlobals(), &FAI);

// To solve the taint problem, we now create an instance of the
// MonoIFDSSolver. Passing the HelperAnalyses here, lets the solver
// automatically grab the needed information
psr::monoifds::MonoIFDSSolver Solver(&TaintProblem, HA);

// Solves the taint problem. This may take some time.
Solver.solve();

// The monoifds::TaintAnalysis is set-up to use the analysis-printer (see
// ../04-run-ifds-analysis/otf-reporter.cpp). By default, it prints the
// detected leaks into the given llvm::raw_ostream
TaintProblem.emitTextReport(llvm::outs());
}
76 changes: 76 additions & 0 deletions examples/how-to/06-run-monoifds-analysis/manual.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include "phasar/DataFlow.h" // For MonoIFDSSolver
#include "phasar/PhasarLLVM/ControlFlow.h" // For FunctionCompressor & getEntryFunctions
#include "phasar/PhasarLLVM/DataFlow.h" // For the MonoIFDSTaintAnalysis
#include "phasar/PhasarLLVM/Pointer.h" // For the LLVMAliasSet
#include "phasar/PhasarLLVM/TaintConfig.h" // For the LLVMTaintConfig
#include "phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h"
#include "phasar/PhasarLLVM/Utils/UsedGlobals.h"

int main(int Argc, char *Argv[]) {
if (Argc < 2) {
llvm::errs() << "USAGE: run-monoifds-analysis-manual <LLVM-IR file>\n";
return 1;
}

using namespace std::string_literals;
std::vector EntryPoints = {"main"s};

// Load the IR
auto IRDB = psr::LLVMProjectIRDB::loadOrExit(Argv[1]);

// The MonoIFDSTaintAnalysis requires alias information, so create it here
psr::LLVMAliasSet AS(&IRDB);

// We use a type-hierarchy to build the call-graph (LLVMBasedICFG below)
psr::DIBasedTypeHierarchy TH(IRDB);

// Create the ICFG
psr::LLVMBasedICFG ICFG(&IRDB, psr::CallGraphAnalysisType::VTA, {"main"}, &TH,
&AS);

// Assign each reachable llvm::Function in the call-graph a sequential ID.
// This is needed for SCC computation and for the solver
auto Funs = psr::compressFunctions(ICFG.getCallGraph(),
psr::getEntryFunctions(IRDB, EntryPoints));

// Compute the call-graph SCCs.
auto CGSCCs = computeCGSCCs(ICFG, Funs);

// Build a dependency-graph induced by the call-graph, collapsing each SCC to
// a single node
auto SCCC = computeCGSCCCallers(ICFG, Funs, CGSCCs);

// For each CGSCC, compute which global variables are (transitively) used by
// any function in that SCC
auto UG = psr::computeUsedGlobals(IRDB, Funs, CGSCCs, SCCC);

// Create the taint configuration
psr::LLVMTaintConfig TC(IRDB);
TC.print();
llvm::outs() << "------------------------\n";

// More precise alias-information; techically, this is not required, but it
// helps a lot
psr::FilteredLLVMAliasIterator FAI(&AS);

// Create the taint analysis problem:
psr::monoifds::TaintAnalysis TaintProblem(&TC, &UG, &FAI);

// To solve the taint problem, we now create an instance of the
// MonoIFDSSolver. Passing the HelperAnalyses here, lets the solver
// automatically grab the needed information
psr::monoifds::MonoIFDSSolver Solver(&TaintProblem, &ICFG);

// Supply the solver with the previously computed helper information. If we
// don't provide this, the solver would compute them on its own once solve()
// is called.
Solver.setCGSCCs(&CGSCCs).setFunctionCompressor(&Funs);

// Solves the taint problem. This may take some time.
Solver.solve();

// The monoifds::TaintAnalysis is set-up to use the analysis-printer (see
// ../04-run-ifds-analysis/otf-reporter.cpp). By default, it prints the
// detected leaks into the given llvm::raw_ostream
TaintProblem.emitTextReport(llvm::outs());
}
74 changes: 54 additions & 20 deletions include/phasar/ControlFlow/CFG.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@
*****************************************************************************/
#pragma once

#include "phasar/Utils/Nullable.h"
#include "phasar/Utils/TypeTraits.h"

#include "llvm/Support/raw_ostream.h"

#include <concepts>
#include <type_traits>
#include <utility>

namespace psr {

template <typename T>
concept InstructionClassifier =
requires(const T &IC, typename T::n_t Inst, typename T::n_t Succ) {
requires(const T &IC, typename std::remove_cvref_t<T>::n_t Inst,
typename std::remove_cvref_t<T>::n_t Succ) {
{ IC.isCallSite(Inst) } -> std::convertible_to<bool>;
{ IC.isFieldLoad(Inst) } -> std::convertible_to<bool>;
{ IC.isFieldStore(Inst) } -> std::convertible_to<bool>;
Expand All @@ -28,27 +31,36 @@ concept InstructionClassifier =
};

template <typename T>
concept CFG = requires(const T &CF, typename T::n_t Inst, typename T::f_t Fun) {
typename T::n_t;
typename T::f_t;
concept CFG = requires(const T &CF, typename std::remove_cvref_t<T>::n_t Inst,
typename std::remove_cvref_t<T>::f_t Fun) {
typename std::remove_cvref_t<T>::n_t;
typename std::remove_cvref_t<T>::f_t;

/// Returns the function that contains the given instruction Inst.
// TODO: Actually belongs into ProjectIRDB!
{ CF.getFunctionOf(Inst) } -> std::convertible_to<typename T::f_t>;
{
CF.getFunctionOf(Inst)
} -> std::convertible_to<typename std::remove_cvref_t<T>::f_t>;
/// Returns an iterable range of all instructions of the given function that
/// are part of the control-flow graph.
// TODO: We should have sth like this in the ProjectIRDB as well!
{ CF.getAllInstructionsOf(Fun) } -> psr::is_iterable_over_v<typename T::n_t>;
{
CF.getAllInstructionsOf(Fun)
} -> psr::is_iterable_over_v<typename std::remove_cvref_t<T>::n_t>;

/// Returns an iterable range of all successor instructions of Inst in the
/// CFG.
/// NOTE: This function is typically being called in a hot part of the
/// analysis and should therefore be highly optimized for performance.
{ CF.getSuccsOf(Inst) } -> psr::is_iterable_over_v<typename T::n_t>;
{
CF.getSuccsOf(Inst)
} -> psr::is_iterable_over_v<typename std::remove_cvref_t<T>::n_t>;

/// Returns an iterable range of all starting instructions of the given
/// function. For a forward-CFG, this is typically a singleton range.
{ CF.getStartPointsOf(Fun) } -> psr::is_iterable_over_v<typename T::n_t>;
{
CF.getStartPointsOf(Fun)
} -> psr::is_iterable_over_v<typename std::remove_cvref_t<T>::n_t>;

/// Returns whether the given Inst is a root node of the CFG
{ CF.isStartPoint(Inst) } -> std::convertible_to<bool>;
Expand All @@ -59,32 +71,54 @@ concept CFG = requires(const T &CF, typename T::n_t Inst, typename T::f_t Fun) {
requires InstructionClassifier<T>;
};

template <typename T, typename N, typename F>
concept CFGOf =
CFG<T> && std::same_as<N, typename std::remove_cvref_t<T>::n_t> &&
std::same_as<F, typename std::remove_cvref_t<T>::f_t>;

template <typename T>
concept BidiCFG =
CFG<T> && requires(const T &CF, typename T::n_t Inst, typename T::f_t Fun) {
CFG<T> && requires(const T &CF, typename std::remove_cvref_t<T>::n_t Inst,
typename std::remove_cvref_t<T>::f_t Fun) {
/// Returns an iterable range of all predecessor instructions of Inst in
/// the CFG
{ CF.getPredsOf(Inst) } -> psr::is_iterable_over_v<typename T::n_t>;
{
CF.getPredsOf(Inst)
} -> psr::is_iterable_over_v<typename std::remove_cvref_t<T>::n_t>;

/// Returns an iterable range of all exit instructions (often return
/// instructions) of the given function. For a backward-CFG, this is
/// typically a singleton range
{ CF.getExitPointsOf(Fun) } -> psr::is_iterable_over_v<typename T::n_t>;
{
CF.getExitPointsOf(Fun)
} -> psr::is_iterable_over_v<typename std::remove_cvref_t<T>::n_t>;
};

template <typename T>
concept CFGDump = requires(const T &CF, typename T::n_t Inst,
typename T::f_t Fun, llvm::raw_ostream &OS) {
{ CF.getStatementId(Inst) } -> psr::is_string_like_v;
{ CF.getFunctionName(Fun) } -> psr::is_string_like_v;
{ CF.getDemangledFunctionName(Fun) } -> psr::is_string_like_v;
CF.print(Fun, OS);
};
concept CFGDump =
requires(const T &CF, typename std::remove_cvref_t<T>::n_t Inst,
typename std::remove_cvref_t<T>::f_t Fun, llvm::raw_ostream &OS) {
{ CF.getStatementId(Inst) } -> psr::is_string_like_v;
{ CF.getFunctionName(Fun) } -> psr::is_string_like_v;
{ CF.getDemangledFunctionName(Fun) } -> psr::is_string_like_v;
CF.print(Fun, OS);
};

template <typename T>
concept CFGEdgesProvider = requires(const T &CF, typename T::f_t Fun) {
concept CFGEdgesProvider = requires(const T &CF,
typename std::remove_cvref_t<T>::f_t Fun) {
{
CF.getAllControlFlowEdges(Fun)
} -> psr::is_iterable_over_v<std::pair<typename T::n_t, typename T::n_t>>;
} -> psr::is_iterable_over_v<std::pair<typename std::remove_cvref_t<T>::n_t,
typename std::remove_cvref_t<T>::n_t>>;
};

template <typename T>
concept IsBlockAwareControlFlow =
requires(const T &CF, typename std::remove_cvref_t<T>::n_t Inst) {
{
CF.getUniqueSuccessor(Inst)
} -> std::convertible_to<Nullable<typename std::remove_cvref_t<T>::n_t>>;
{ CF.hasUniquePredecessor(Inst) } -> std::convertible_to<bool>;
};
} // namespace psr
Loading
Loading