diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7e3a85c14e..82dba20155 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,9 +15,9 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-24.04, ubuntu-24.04-arm]
- compiler: [ [clang++-19, clang-19, "clang-19 libclang-rt-19-dev clang-tools-19"] ]
+ compiler: [ [clang++-22, clang-22, "clang-22 libclang-rt-22-dev clang-tools-22"] ]
build: [ Debug, Release, DebugLibdeps, DebugCov ]
- llvm-version: [ 16, 17 ]
+ llvm-version: [ 16, 22.1 ]
include:
- build: Debug
cmake_build_type: Debug
@@ -31,7 +31,7 @@ jobs:
- build: DebugCov
cmake_build_type: Debug
flags: -DCODE_COVERAGE=ON
- extra_dependencies: llvm-19 # For coverage
+ extra_dependencies: llvm-22 # For coverage
exclude:
- os: ubuntu-24.04-arm
build: Debug
@@ -43,7 +43,7 @@ jobs:
continue-on-error: false
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive
@@ -102,7 +102,7 @@ jobs:
- name: Upload coverage HTML report artifact
if: matrix.build == 'DebugCov'
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: phasar-coverage-report-llvm-${{ matrix.llvm-version }}
path: ./build/ccov/all-merged/
diff --git a/Dockerfile b/Dockerfile
index ae8b16d24f..94a9baebdd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,10 +3,10 @@ FROM "$baseimage" AS build
RUN --mount=type=bind,source=./utils/InstallAptDependencies.sh,target=/InstallAptDependencies.sh \
set -eux; \
- ./InstallAptDependencies.sh --noninteractive tzdata clang-19 libclang-rt-19-dev clang-tools-19
+ ./InstallAptDependencies.sh --noninteractive tzdata clang-22 libclang-rt-22-dev clang-tools-22
-ENV CC=/usr/bin/clang-19 \
- CXX=/usr/bin/clang++-19
+ENV CC=/usr/bin/clang-22 \
+ CXX=/usr/bin/clang++-22
FROM build
diff --git a/README.md b/README.md
index db217e8d39..d1baa01cc5 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@ PhASAR supports C++20 modules as an experimental feature.
## Currently Supported Version of LLVM
-**NEW**: PhASAR is currently set up to support **LLVM-16 and 17**, using LLVM 16 by default.
+**NEW**: PhASAR is currently set up to support LLVM versions **between LLVM-16 and LLVM-22.1**, using LLVM 16 by default. We actively test PHASAR with LLVM-16 and LLVM-22.1, so if something does not work, try these versions instead.
Specify the `PHASAR_LLVM_VERSION` cmake-variable to change the LLVM version to use.
diff --git a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h
index 63d97c29af..4599435d85 100644
--- a/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h
+++ b/include/phasar/DataFlow/PathSensitivity/PathSensitivityManagerMixin.h
@@ -192,7 +192,13 @@ class PathSensitivityManagerMixin {
return pathsDagToAll(Inst, llvm::ArrayRef(&Fact, 1), Config, PFilter);
}
- if (auto Next = Inst->getNextNonDebugInstruction()) {
+ if (auto Next =
+#if LLVM_VERSION_MAJOR <= 18
+ Inst->getNextNonDebugInstruction()
+#else
+ Inst->getNextNode()
+#endif
+ ) {
return pathsDagToAll(Next, llvm::ArrayRef(&Fact, 1), Config, PFilter);
}
@@ -203,9 +209,11 @@ class PathSensitivityManagerMixin {
for (const auto *BB : llvm::successors(Inst)) {
const auto *First = &BB->front();
+#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa(First)) {
First = First->getNextNonDebugInstruction();
}
+#endif
if (ESG.getNodeOrNull(First, Fact)) {
return pathsDagToAll(First, llvm::ArrayRef(&Fact, 1), Config, PFilter);
}
diff --git a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h
index 30c74931e0..26f58b36b4 100644
--- a/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h
+++ b/include/phasar/PhasarLLVM/DataFlow/IfdsIde/LLVMSolverResults.h
@@ -37,9 +37,11 @@ namespace psr::detail {
if (!Stmt->getNextNode()) {
auto GetStartRow = [&Self](const llvm::BasicBlock *BB) -> decltype(auto) {
const auto *First = &BB->front();
+#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa(First)) {
First = First->getNextNonDebugInstruction();
}
+#endif
return Self.row(First);
};
@@ -104,9 +106,11 @@ namespace psr::detail {
auto GetStartVal = [&Self,
&Fact](const llvm::BasicBlock *BB) -> decltype(auto) {
const auto *First = &BB->front();
+#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa(First)) {
First = First->getNextNonDebugInstruction();
}
+#endif
return Self.resultAt(First, Fact);
};
diff --git a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h
index dcad26415a..cdbe013a22 100644
--- a/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h
+++ b/include/phasar/PhasarLLVM/Utils/LLVMShorthands.h
@@ -70,6 +70,9 @@ bool isHeapAllocatingFunction(const llvm::Function *F) noexcept;
///
/// \note This function is less useful in practice than you may think. Consider
/// using isConsistentCall() instead.
+LLVM_DEPRECATED("With opaque pointers, this function is not very useful. Use "
+ "isConsistentCall() instead.",
+ "psr::isConsistentCall")
bool matchesSignature(const llvm::Function *F, const llvm::FunctionType *FType,
bool ExactMatch = true);
@@ -79,6 +82,9 @@ bool matchesSignature(const llvm::Function *F, const llvm::FunctionType *FType,
///
/// \note This function is less useful in practice than you may think. Consider
/// using isConsistentCall() instead.
+LLVM_DEPRECATED("With opaque pointers, this function is not very useful. Use "
+ "isConsistentCall() instead.",
+ "psr::isConsistentCall")
bool matchesSignature(const llvm::FunctionType *FType1,
const llvm::FunctionType *FType2);
diff --git a/lib/PhasarLLVM/ControlFlow/GlobalCtorsDtorsModel.cpp b/lib/PhasarLLVM/ControlFlow/GlobalCtorsDtorsModel.cpp
index 5eafe401cb..ff98d43255 100644
--- a/lib/PhasarLLVM/ControlFlow/GlobalCtorsDtorsModel.cpp
+++ b/lib/PhasarLLVM/ControlFlow/GlobalCtorsDtorsModel.cpp
@@ -379,10 +379,9 @@ bool GlobalCtorsDtorsModel::isPhasarGenerated(
const llvm::Function &F) noexcept {
if (F.hasName()) {
llvm::StringRef FunctionName = F.getName();
- return llvm::StringSwitch(FunctionName)
- .Cases(ModelName, DtorModelName, DtorsCallerName, UserEntrySelectorName,
- true)
- .Default(false);
+ const auto Cases = {ModelName, DtorModelName, DtorsCallerName,
+ UserEntrySelectorName};
+ return llvm::is_contained(Cases, FunctionName);
}
return false;
diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp
index 3eaf0f4fae..898e1e2ee3 100644
--- a/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp
+++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedCFG.cpp
@@ -34,6 +34,12 @@ auto detail::LLVMBasedCFGImpl::getFunctionOfImpl(
template
auto detail::LLVMBasedCFGImpl::getPredsOfImpl(n_t I) const
-> llvm::SmallVector {
+#if LLVM_VERSION_MAJOR > 18
+ if (const auto *PrevInst = I->getPrevNode()) {
+ return {PrevInst};
+ }
+#else
+
if (!IgnoreDbgInstructions) {
if (const auto *PrevInst = I->getPrevNode()) {
return {PrevInst};
@@ -44,6 +50,7 @@ auto detail::LLVMBasedCFGImpl::getPredsOfImpl(n_t I) const
return {PrevNonDbgInst};
}
}
+#endif
// If we do not have a predecessor yet, look for basic blocks which
// lead to our instruction in question!
@@ -53,10 +60,12 @@ auto detail::LLVMBasedCFGImpl::getPredsOfImpl(n_t I) const
[](const llvm::BasicBlock *BB) {
assert(BB && "BB under analysis was not well formed.");
const llvm::Instruction *Pred = BB->getTerminator();
+#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa(Pred)) {
Pred = Pred->getPrevNonDebugInstruction(
false /*Only debug instructions*/);
}
+#endif
return Pred;
});
@@ -66,6 +75,11 @@ auto detail::LLVMBasedCFGImpl::getPredsOfImpl(n_t I) const
template
auto detail::LLVMBasedCFGImpl::getSuccsOfImpl(n_t I) const
-> llvm::SmallVector {
+#if LLVM_VERSION_MAJOR > 18
+ if (const auto *NextInst = I->getNextNode()) {
+ return {NextInst};
+ }
+#else
// case we wish to consider LLVM's debug instructions
if (!IgnoreDbgInstructions) {
if (const auto *NextInst = I->getNextNode()) {
@@ -75,14 +89,18 @@ auto detail::LLVMBasedCFGImpl::getSuccsOfImpl(n_t I) const
false /*Only debug instructions*/)) {
return {NextNonDbgInst};
}
+#endif
+
if (const auto *Branch = llvm::dyn_cast(I);
Branch && isStaticVariableLazyInitializationBranch(Branch)) {
// Skip the "already initialized" case, such that the analysis is always
// aware of the initialized value.
const auto *NextInst = &Branch->getSuccessor(0)->front();
+#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDbgInstructions && llvm::isa(NextInst)) {
NextInst = NextInst->getNextNonDebugInstruction(false);
}
+#endif
return {NextInst};
}
@@ -93,10 +111,12 @@ auto detail::LLVMBasedCFGImpl::getSuccsOfImpl(n_t I) const
[IgnoreDbgInstructions{IgnoreDbgInstructions}](
const llvm::BasicBlock *BB) {
const llvm::Instruction *Succ = &BB->front();
+#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDbgInstructions && llvm::isa(Succ)) {
Succ = Succ->getNextNonDebugInstruction(
false /*Only debug instructions*/);
}
+#endif
return Succ;
});
return Successors;
@@ -133,10 +153,12 @@ auto detail::LLVMBasedCFGImpl::getStartPointsOfImpl(f_t Fun) const
}
if (!Fun->isDeclaration()) {
const auto *EntryInst = &Fun->front().front();
+#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDbgInstructions && llvm::isa(EntryInst)) {
return {EntryInst->getNextNonDebugInstruction(
false /*Only debug instructions*/)};
}
+#endif
return {EntryInst};
}
PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedCFG",
@@ -170,8 +192,13 @@ bool detail::LLVMBasedCFGImpl::isStartPointImpl(
if (Inst == FirstInst) {
return true;
}
- return llvm::isa(FirstInst) &&
- Inst == FirstInst->getNextNonDebugInstruction(false);
+#if LLVM_VERSION_MAJOR <= 18
+ if (llvm::isa(FirstInst)) {
+ FirstInst = FirstInst->getNextNonDebugInstruction(false);
+ }
+#endif
+
+ return Inst == FirstInst;
}
template
diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFGExportsImpl.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFGExportsImpl.cpp
index dcdf5bcaad..46de8ddc12 100644
--- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFGExportsImpl.cpp
+++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFGExportsImpl.cpp
@@ -75,9 +75,14 @@ LLVMBasedICFG::exportICFGAsDot(bool WithSourceCodeInfo) const {
assert(BB && !BB->empty());
const auto *InterTo = &BB->front();
+#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDbgInstructions && llvm::isa(InterTo)) {
InterTo = InterTo->getNextNonDebugInstruction(false);
}
+#else
+ (void)IgnoreDbgInstructions;
+#endif
+
// createEdge(From, InterTo);
OS << intptr_t(CS) << "->" << intptr_t(InterTo) << ";\n";
@@ -238,9 +243,11 @@ struct GetIR {
llvm::BasicBlock::const_iterator End) {
assert(It != End);
+#if LLVM_VERSION_MAJOR <= 18
if (It->isDebugOrPseudoInst()) {
return llvmIRToStableString(It->getNextNonDebugInstruction());
}
+#endif
return llvmIRToStableString(&*It);
}
diff --git a/lib/PhasarLLVM/ControlFlow/Resolver/Resolver.cpp b/lib/PhasarLLVM/ControlFlow/Resolver/Resolver.cpp
index db0423a194..03489a592b 100644
--- a/lib/PhasarLLVM/ControlFlow/Resolver/Resolver.cpp
+++ b/lib/PhasarLLVM/ControlFlow/Resolver/Resolver.cpp
@@ -29,6 +29,7 @@
#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"
#include "phasar/Utils/Logger.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
@@ -146,9 +147,58 @@ bool psr::isConsistentCall(const llvm::CallBase *CallSite,
if (CallSite->arg_size() != DestFun->arg_size() && !DestFun->isVarArg()) {
return false;
}
- if (!matchesSignature(DestFun, CallSite->getFunctionType(), false)) {
+
+ for (const auto &[Param, ArgOp] :
+ llvm::zip_first(DestFun->args(), CallSite->args())) {
+
+ const auto *ParamTy = Param.getType();
+ const auto *ArgTy = ArgOp->getType();
+
+ if (ParamTy == ArgTy) {
+ // Trivial equality
+ continue;
+ }
+
+ if (ParamTy->getTypeID() != ArgTy->getTypeID()) {
+ // Trivial non-equality, e.g. PointerType and IntegerType
+ return false;
+ }
+
+ if (ParamTy->isPointerTy()) {
+ if (Param.hasByValAttr() !=
+ CallSite->isByValArgument(ArgOp.getOperandNo())) {
+ return false;
+ }
+
+ const auto *ParamSRetTy = Param.getParamStructRetType();
+ const auto *ArgSRetTy =
+ CallSite->getParamStructRetType(ArgOp.getOperandNo());
+ if ((ParamSRetTy != nullptr) != (ArgSRetTy != nullptr)) {
+ return false;
+ }
+
+ if (ParamSRetTy && ArgSRetTy) {
+ // TODO: For better precision, compare the sret types as well
+ // Trivial non-equality, e.g. PointerType and IntegerType
+ if (ParamSRetTy->getTypeID() != ArgSRetTy->getTypeID()) {
+ // Trivial non-equality, e.g. PointerType and IntegerType
+ return false;
+ }
+ }
+ }
+
+ if (ParamTy->isStructTy()) {
+ // Copied comment from struct-case in isTypeMatchForFunctionArgument():
+ // > Well, we could do sanity checks here, but if the analysed code is
+ // > insane we would miss callees, so we don't do that.
+
+ continue;
+ }
+
+ // Types are non-equal and we could not find a reason to treat the same
return false;
}
+
return true;
}
diff --git a/lib/PhasarLLVM/ControlFlow/SVFGCache.cpp b/lib/PhasarLLVM/ControlFlow/SVFGCache.cpp
index 97b98e93d9..d1832d7b09 100644
--- a/lib/PhasarLLVM/ControlFlow/SVFGCache.cpp
+++ b/lib/PhasarLLVM/ControlFlow/SVFGCache.cpp
@@ -6,9 +6,11 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/ModRef.h"
using namespace psr;
+#if LLVM_VERSION_MAJOR <= 20
static bool isNonPointerType(const llvm::Type *Ty) {
if (const auto *Struct = llvm::dyn_cast(Ty)) {
for (const auto *ElemTy : Struct->elements()) {
@@ -24,6 +26,7 @@ static bool isNonPointerType(const llvm::Type *Ty) {
}
return Ty->isSingleValueType();
}
+#endif
static bool isNonAddressTakenVariable(const llvm::Value *Val) {
const auto *Alloca = llvm::dyn_cast(Val);
@@ -41,10 +44,20 @@ static bool isNonAddressTakenVariable(const llvm::Value *Val) {
if (Call->paramHasAttr(ArgNo, llvm::Attribute::StructRet)) {
continue;
}
+#if LLVM_VERSION_MAJOR <= 20
if (Call->paramHasAttr(ArgNo, llvm::Attribute::NoCapture) &&
isNonPointerType(Call->getType())) {
continue;
}
+#else
+ auto Captures = Call->getCaptureInfo(ArgNo);
+ auto CComp = Captures.getOtherComponents() | Captures.getRetComponents();
+ if (llvm::capturesAnyProvenance(CComp) ||
+ (llvm::capturesAddress(CComp) &&
+ !llvm::capturesAddressIsNullOnly(CComp))) {
+ return false;
+ }
+#endif
return false;
}
}
@@ -134,9 +147,11 @@ static void buildSparseCFG(const LLVMBasedCFG &CFG,
// -- Initialization
const auto *Entry = &Fun->getEntryBlock().front();
+#if LLVM_VERSION_MAJOR <= 18
if (llvm::isa(Entry)) {
Entry = Entry->getNextNonDebugInstruction();
}
+#endif
for (const auto *Succ : CFG.getSuccsOf(Entry)) {
WL.emplace_back(Entry, Succ);
diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.cpp
index 550d33e853..b5b103830c 100644
--- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.cpp
+++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/ExtendedTaintAnalysis/AbstractMemoryLocation.cpp
@@ -42,8 +42,12 @@ AbstractMemoryLocationImpl::AbstractMemoryLocationImpl(
const llvm::Value *Baseptr, llvm::ArrayRef Offsets,
unsigned Lifetime) noexcept
: AbstractMemoryLocationStorage(Baseptr, Lifetime, Offsets.size()) {
- memcpy(this->getTrailingObjects(), Offsets.data(),
- Offsets.size() * sizeof(ptrdiff_t));
+ memcpy(this->getTrailingObjects
+#if LLVM_VERSION_MAJOR <= 20
+
+#endif
+ (),
+ Offsets.data(), Offsets.size() * sizeof(ptrdiff_t));
}
bool AbstractMemoryLocationImpl::isZero() const {
@@ -51,7 +55,12 @@ bool AbstractMemoryLocationImpl::isZero() const {
}
llvm::ArrayRef AbstractMemoryLocationImpl::offsets() const {
- return llvm::ArrayRef(this->getTrailingObjects(), NumOffsets);
+ return llvm::ArrayRef(this->getTrailingObjects
+#if LLVM_VERSION_MAJOR <= 20
+
+#endif
+ (),
+ NumOffsets);
}
auto AbstractMemoryLocationImpl::computeOffset(const llvm::DataLayout &DL,
diff --git a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp
index 9f7424f02d..7910d70061 100644
--- a/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp
+++ b/lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp
@@ -422,7 +422,7 @@ auto IFDSTaintAnalysis::getSummaryFlowFunction([[maybe_unused]] n_t CallSite,
// $sSS1poiyS2S_SStFZ is Swift's String append method
// if concat a tainted string with something else the
// result should be tainted
- if (DestFun->getName().equals("$sSS1poiyS2S_SStFZ")) {
+ if (DestFun->getName() == "$sSS1poiyS2S_SStFZ") {
const auto *CS = llvm::cast(CallSite);
return generateFlowIf(CallSite, [CS](d_t Source) {
diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp
index f1ef9ee1c3..233f73f037 100644
--- a/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp
+++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/LLVMPathConstraints.cpp
@@ -27,11 +27,14 @@ auto LLVMPathConstraints::internalGetConstraintAndVariablesFromEdge(
return std::nullopt;
}
+#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDebugInstructions) {
while (const auto *Prev = To->getPrevNonDebugInstruction(false)) {
To = Prev;
}
- } else {
+ } else
+#endif
+ {
while (const auto *Prev = To->getPrevNode()) {
To = Prev;
}
@@ -171,9 +174,11 @@ auto LLVMPathConstraints::handleCondBrInst(const llvm::BranchInst *Br,
auto GetFirstInst = [IgnoreDebugInstructions{IgnoreDebugInstructions}](
const llvm::BasicBlock *BB) {
const auto *Ret = &BB->front();
+#if LLVM_VERSION_MAJOR <= 18
if (IgnoreDebugInstructions && llvm::isa(Ret)) {
Ret = Ret->getNextNonDebugInstruction(false);
}
+#endif
return Ret;
};
diff --git a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp
index 0406dbfbc9..0b9dab8418 100644
--- a/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp
+++ b/lib/PhasarLLVM/Pointer/LLVMBasedAliasAnalysis.cpp
@@ -126,9 +126,11 @@ static AliasResult translateAAResult(llvm::AliasResult Res) noexcept {
static llvm::Type *getPointeeTypeOrNull(const llvm::Value *Ptr) {
assert(Ptr->getType()->isPointerTy());
+#if LLVM_VERSION_MAJOR <= 16
if (!Ptr->getType()->isOpaquePointerTy()) {
return Ptr->getType()->getNonOpaquePointerElementType();
}
+#endif
if (const auto *Arg = llvm::dyn_cast(Ptr)) {
if (auto *Ty = Arg->getParamByValType()) {
diff --git a/lib/PhasarLLVM/Pointer/LLVMPointerAssignmentGraph.cpp b/lib/PhasarLLVM/Pointer/LLVMPointerAssignmentGraph.cpp
index 63ebf47d58..77adc71dc5 100644
--- a/lib/PhasarLLVM/Pointer/LLVMPointerAssignmentGraph.cpp
+++ b/lib/PhasarLLVM/Pointer/LLVMPointerAssignmentGraph.cpp
@@ -279,11 +279,19 @@ struct [[clang::internal_linkage]] LLVMPAGBuilder::PAGBuildData {
void propagateBB(LLVMPBStrategyRef Strategy, const llvm::BasicBlock &BB) {
const auto *Inst = &BB.front();
+#if LLVM_VERSION_MAJOR <= 18
if (Inst->isDebugOrPseudoInst()) {
Inst = Inst->getNextNonDebugInstruction();
}
+#endif
- for (; Inst; Inst = Inst->getNextNonDebugInstruction()) {
+ for (; Inst; Inst =
+#if LLVM_VERSION_MAJOR <= 18
+ Inst->getNextNonDebugInstruction()
+#else
+ Inst->getNextNode()
+#endif
+ ) {
dispatch(Strategy, *Inst);
}
}
diff --git a/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp b/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp
index 885adf8339..0d8e23b656 100644
--- a/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp
+++ b/lib/PhasarLLVM/TaintConfig/LLVMTaintConfig.cpp
@@ -12,6 +12,7 @@
#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h"
#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h"
#include "phasar/PhasarLLVM/TaintConfig/TaintConfigBase.h"
+#include "phasar/PhasarLLVM/TaintConfig/TaintConfigData.h"
#include "phasar/PhasarLLVM/Utils/Annotation.h"
#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"
#include "phasar/Utils/EnumFlags.h"
@@ -23,6 +24,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Metadata.h"
#include
@@ -133,14 +135,16 @@ LLVMTaintConfig::LLVMTaintConfig(const psr::LLVMProjectIRDB &Code,
std::unordered_map StructConfigMap;
// read all struct types from config
- for (const auto &VarDesc : Config.Variables) {
- llvm::DebugInfoFinder DIF;
- const auto *M = Code.getModule();
+ llvm::DebugInfoFinder DIF;
+ const auto *M = Code.getModule();
- DIF.processModule(*M);
+ DIF.processModule(*M);
+ for (const auto &VarDesc : Config.Variables) {
for (const auto &Ty : DIF.types()) {
if (Ty->getTag() == llvm::dwarf::DW_TAG_structure_type &&
- Ty->getName().equals(VarDesc.Scope)) {
+ Ty->getName() == VarDesc.Scope) {
+ // TODO: Below loop looks wrong! Why on earth are we looping over the
+ // SAME set of types every time?
for (const auto &LlvmStructTy : M->getIdentifiedStructTypes()) {
StructConfigMap.insert(
std::pair(LlvmStructTy,
@@ -148,31 +152,63 @@ LLVMTaintConfig::LLVMTaintConfig(const psr::LLVMProjectIRDB &Code,
}
}
}
- DIF.reset();
}
+
// add corresponding Allocas or getElementPtr instructions to the taint
// category
+
+ const auto AddVariable = [this](const VariableData &VarDesc,
+ const llvm::Instruction &I) -> bool {
+#if LLVM_VERSION_MAJOR > 18
+ for (const llvm::DbgVariableRecord &DbR :
+ llvm::filterDbgVars(I.getDbgRecordRange())) {
+ const auto *Var = DbR.getVariable();
+ assert(Var != nullptr);
+ if (Var->getName() == VarDesc.Name && Var->getLine() == VarDesc.Line) {
+ addTaintCategory(DbR.getAddress(), VarDesc.Cat);
+ return true;
+ }
+ }
+#endif
+
+ if (const auto *DbgDeclare = llvm::dyn_cast(&I)) {
+ const llvm::DILocalVariable *LocalVar = DbgDeclare->getVariable();
+ // matching line number with for Allocas
+ if (LocalVar->getName() == VarDesc.Name &&
+ LocalVar->getLine() == VarDesc.Line) {
+ addTaintCategory(DbgDeclare->getAddress(), VarDesc.Cat);
+ return true;
+ }
+ }
+ return false;
+ };
+
for (const auto &VarDesc : Config.Variables) {
for (const auto &Fun : Code.getAllFunctions()) {
+ const bool MatchingFunScope = [&] {
+ if (VarDesc.Scope == Fun->getName()) {
+ return true;
+ }
+ const auto *Subp = Fun->getSubprogram();
+ return Subp != nullptr && VarDesc.Name == Subp->getName();
+ }();
+
for (const auto &I : llvm::instructions(Fun)) {
- if (const auto *DbgDeclare = llvm::dyn_cast(&I)) {
- const llvm::DILocalVariable *LocalVar = DbgDeclare->getVariable();
- // matching line number with for Allocas
- if (LocalVar->getName().equals(VarDesc.Name) &&
- LocalVar->getLine() == VarDesc.Line) {
- addTaintCategory(DbgDeclare->getAddress(), VarDesc.Cat);
- }
- } else if (!StructConfigMap.empty()) {
+ if (MatchingFunScope && AddVariable(VarDesc, I)) {
+ continue;
+ }
+
+ if (!StructConfigMap.empty()) {
// Ignorning line numbers for getElementPtr instructions
if (const auto *Gep = llvm::dyn_cast(&I)) {
const auto *StType =
llvm::dyn_cast(Gep->getSourceElementType());
- if (StType && StructConfigMap.count(StType)) {
+ if (StType && StructConfigMap.contains(StType)) {
auto VarName = StructConfigMap.at(StType);
// using substr to cover the edge case in which same variable
// name is present as a local variable and also as a struct
// member variable. (Ex. JsonConfig/fun_member_02.cpp)
- if (Gep->getName().substr(0, VarName.size()).equals(VarName)) {
+ if (Gep->getName().starts_with(VarName)) {
addTaintCategory(Gep, VarDesc.Cat);
}
}
diff --git a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp
index 8296cccf97..d0240bce7e 100644
--- a/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp
+++ b/lib/PhasarLLVM/Utils/LLVMIRToSrc.cpp
@@ -69,6 +69,16 @@ static llvm::DbgVariableIntrinsic *getDbgVarIntrinsic(const llvm::Value *V) {
}
llvm::DILocalVariable *psr::getDILocalVariable(const llvm::Value *V) {
+#if LLVM_VERSION_MAJOR > 18
+ if (auto *VAM = llvm::ValueAsMetadata::getIfExists(
+ const_cast(V))) { // NOLINT FIXME when LLVM supports it
+ for (const auto &Use : VAM->getAllDbgVariableRecordUsers()) {
+ if (auto *Var = Use->getVariable()) {
+ return Var;
+ }
+ }
+ }
+#else
if (auto *DbgIntr = getDbgVarIntrinsic(V)) {
if (auto *DDI = llvm::dyn_cast(DbgIntr)) {
return DDI->getVariable();
@@ -77,6 +87,7 @@ llvm::DILocalVariable *psr::getDILocalVariable(const llvm::Value *V) {
return DVI->getVariable();
}
}
+#endif
return nullptr;
}
@@ -103,9 +114,34 @@ llvm::DILocation *psr::getDILocation(const llvm::Value *V) {
// Arguments and Instruction such as AllocaInst
if (const auto *I = llvm::dyn_cast(V)) {
- if (auto *MN = I->getMetadata(llvm::LLVMContext::MD_dbg)) {
- return llvm::dyn_cast(MN);
+ if (const auto &DbgLoc = I->getDebugLoc()) {
+ return DbgLoc;
}
+
+#if LLVM_VERSION_MAJOR > 18
+ const auto FindLocInDbgRecords =
+ [](const llvm::Value *Val) -> llvm::DILocation * {
+ if (auto *VAM = llvm::ValueAsMetadata::getIfExists(
+ const_cast(Val))) {
+ for (const auto &DbgRec : VAM->getAllDbgVariableRecordUsers()) {
+ if (const auto &Loc = DbgRec->getDebugLoc()) {
+ return Loc;
+ }
+ }
+ }
+ return nullptr;
+ };
+
+ if (const auto *Store = llvm::dyn_cast(I);
+ Store && llvm::isa(Store->getValueOperand())) {
+ // For each argument, clang creates an alloca + store; both have no !dbg
+ // metadata attached
+ return FindLocInDbgRecords(Store->getPointerOperand());
+ }
+ if (llvm::isa(I)) {
+ return FindLocInDbgRecords(I);
+ }
+#endif
}
if (auto *DbgIntr = getDbgVarIntrinsic(V)) {
@@ -377,11 +413,13 @@ std::pair psr::getLineAndColFromIR(const llvm::Value *V) {
if (auto *DILoc = getDILocation(V)) {
return {DILoc->getLine(), DILoc->getColumn()};
}
+
if (const auto *I = llvm::dyn_cast(V)) {
if (const auto *DIFun = I->getFunction()->getSubprogram()) {
return {DIFun->getLine(), 0};
}
}
+
if (auto *DISubpr = getDISubprogram(V)) { // Function
return {DISubpr->getLine(), 0};
}
diff --git a/lib/PhasarLLVM/Utils/LLVMShorthands.cpp b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp
index adca056732..7a97c297f9 100644
--- a/lib/PhasarLLVM/Utils/LLVMShorthands.cpp
+++ b/lib/PhasarLLVM/Utils/LLVMShorthands.cpp
@@ -95,7 +95,8 @@ static bool isTypeMatchForFunctionArgument(llvm::Type *Actual,
}
// For PointerType delegate into its element type
if (llvm::isa(Actual)) {
- // If formal argument is void *, we can pass anything.
+// If formal argument is void *, we can pass anything.
+#if LLVM_VERSION_MAJOR <= 16
if (Actual->isOpaquePointerTy() || Formal->isOpaquePointerTy() ||
Formal->getNonOpaquePointerElementType()->isIntegerTy(8)) {
return true;
@@ -103,6 +104,10 @@ static bool isTypeMatchForFunctionArgument(llvm::Type *Actual,
return isTypeMatchForFunctionArgument(
Actual->getNonOpaquePointerElementType(),
Formal->getNonOpaquePointerElementType());
+#endif
+ // XXX: Add better heuristics for the commented code above that are LLVM>16
+ // compatible
+ return true;
}
// For structs, Formal needs to be somehow contained in Actual.
if (llvm::isa(Actual)) {
diff --git a/lib/Utils/MemoryLocationAllocator.cpp b/lib/Utils/MemoryLocationAllocator.cpp
index 0706f6e410..a679076588 100644
--- a/lib/Utils/MemoryLocationAllocator.cpp
+++ b/lib/Utils/MemoryLocationAllocator.cpp
@@ -27,8 +27,12 @@ MemoryLocationAllocator::Block::create(Block *Next, size_t NumPointerEntries) {
auto *Ret = new (RetBytes) Block(Next);
- __asan_poison_memory_region(Ret->getTrailingObjects(),
- NumPointerEntries * sizeof(void *));
+ [[maybe_unused]] auto *DataPtr = Ret->getTrailingObjects
+#if LLVM_VERSION_MAJOR <= 20
+
+#endif
+ ();
+ __asan_poison_memory_region(DataPtr, NumPointerEntries * sizeof(void *));
return Ret;
}
@@ -36,8 +40,12 @@ MemoryLocationAllocator::Block::create(Block *Next, size_t NumPointerEntries) {
void MemoryLocationAllocator::Block::destroy(
MemoryLocationAllocator::Block *Blck,
[[maybe_unused]] size_t NumPointerEntries) {
- __asan_unpoison_memory_region(Blck->getTrailingObjects(),
- NumPointerEntries * sizeof(void *));
+ [[maybe_unused]] auto *DataPtr = Blck->getTrailingObjects
+#if LLVM_VERSION_MAJOR <= 20
+
+#endif
+ ();
+ __asan_unpoison_memory_region(DataPtr, NumPointerEntries * sizeof(void *));
delete[] reinterpret_cast(Blck);
}
@@ -55,7 +63,11 @@ MemoryLocationAllocator::MemoryLocationAllocator(size_t InitialCapacity,
}
Root = Block::create(nullptr, this->InitialCapacity);
- Pos = Root->getTrailingObjects();
+ Pos = Root->getTrailingObjects
+#if LLVM_VERSION_MAJOR <= 20
+
+#endif
+ ();
End = Pos + this->InitialCapacity;
}
@@ -85,7 +97,11 @@ MemoryLocationAllocator::allocate(size_t NumBytes) {
if (LLVM_UNLIKELY(End - Curr < ptrdiff_t(NumPointersRequired))) {
Root = Rt = Block::create(Rt, DynamicBlockSize);
- Pos = Curr = Rt->getTrailingObjects();
+ Pos = Curr = Rt->getTrailingObjects
+#if LLVM_VERSION_MAJOR <= 20
+
+#endif
+ ();
End = Curr + DynamicBlockSize;
}
diff --git a/lib/Utils/PAMM.cpp b/lib/Utils/PAMM.cpp
index 7d51f7defc..fe7072d59b 100644
--- a/lib/Utils/PAMM.cpp
+++ b/lib/Utils/PAMM.cpp
@@ -385,7 +385,7 @@ void PAMM::exportMeasuredData(
llvm::SmallString<128> Buf;
OutputPath.toStringRef(Buf);
- if (!Buf.endswith(".json")) {
+ if (!llvm::StringRef(Buf).ends_with(".json")) {
Buf.append(".json");
}
diff --git a/tools/ptaben/PTAUtils.cpp b/tools/ptaben/PTAUtils.cpp
index e200fc2bce..835261bee2 100755
--- a/tools/ptaben/PTAUtils.cpp
+++ b/tools/ptaben/PTAUtils.cpp
@@ -40,17 +40,21 @@ static ptaben::QueryId getQueryId(llvm::StringRef FileName, uint32_t SeqNo) {
llvm::SHA256 Hasher;
Hasher.update(FileName);
+ const auto LittleEndian = llvm::
+#if LLVM_VERSION_MAJOR < 18
+ support::
+#endif
+ endianness::little;
+
{
std::array Buf{};
- llvm::support::endian::write32(Buf.data(), SeqNo,
- llvm::support::endianness::little);
+ llvm::support::endian::write32(Buf.data(), SeqNo, LittleEndian);
Hasher.update(Buf);
}
auto Hash = Hasher.final();
- auto QId = llvm::support::endian::read64(Hash.data(),
- llvm::support::endianness::little);
+ auto QId = llvm::support::endian::read64(Hash.data(), LittleEndian);
return ptaben::QueryId(QId);
}
diff --git a/tools/ptaben/PTAUtils.h b/tools/ptaben/PTAUtils.h
index 93041c62ca..4110da1d57 100755
--- a/tools/ptaben/PTAUtils.h
+++ b/tools/ptaben/PTAUtils.h
@@ -61,7 +61,7 @@ checkDir(const llvm::Twine &DirName,
size_t NumTests = 0;
static constexpr auto IsLLVMIRFile = [](llvm::StringRef Path) {
- return Path.endswith(".ll") || Path.endswith(".bc");
+ return Path.ends_with(".ll") || Path.ends_with(".bc");
};
for (; It != End && !EC; It.increment(EC)) {
diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedCFGTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedCFGTest.cpp
index 546306de0e..809ec5c67e 100644
--- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedCFGTest.cpp
+++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedCFGTest.cpp
@@ -310,6 +310,8 @@ TEST(LLVMBasedCFGTest, HandleFunctionsContainingCodesInName) {
SpecialMemberFunctionType::None);
}
+#if LLVM_VERSION_MAJOR <= 18
+
TEST(LLVMBasedCFGTest, IgnoreSingleDbgInstructionsInSuccessors) {
LLVMBasedCFG Cfg;
LLVMProjectIRDB IRDB1({unittest::PathToLLTestFiles +
@@ -423,6 +425,9 @@ TEST(LLVMBasedCFGTest, IgnoreMultiSubsequentDbgInstructionsInControlFlowEdges) {
}
}
}
+#else
+// TODO: Create alternative test cases if necessary
+#endif
int main(int Argc, char **Argv) {
::testing::InitGoogleTest(&Argc, Argv);
diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFG_OTFTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFG_OTFTest.cpp
index 0c9c0406fb..cf0757ad49 100644
--- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFG_OTFTest.cpp
+++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFG_OTFTest.cpp
@@ -9,13 +9,29 @@
#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/Support/raw_ostream.h"
+#include "SrcCodeLocationEntry.h"
#include "TestConfig.h"
#include "gtest/gtest.h"
-using namespace std;
using namespace psr;
+using namespace psr::unittest;
+
+static constexpr auto printCallees // NOLINT
+ = [](auto &&Callees) {
+ std::string Ret;
+ llvm::raw_string_ostream OS(Ret);
+
+ OS << "{ ";
+ llvm::interleaveComma(
+ llvm::map_range(
+ Callees, [](const auto *Callee) { return Callee->getName(); }),
+ OS);
+ OS << " }";
+ return Ret;
+ };
TEST(LLVMBasedICFG_OTFTest, VirtualCallSite_7) {
LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles +
@@ -32,17 +48,22 @@ TEST(LLVMBasedICFG_OTFTest, VirtualCallSite_7) {
ASSERT_TRUE(VFuncA);
ASSERT_TRUE(VFuncB);
- const auto *CallToAFunc = getNthInstruction(F, 17);
+ const auto *CallToAFunc = llvm::cast(testingLocInIR(
+ LineColFunOp{19, 0, "main", llvm::Instruction::Call}, IRDB));
ASSERT_TRUE(ICFG.isVirtualFunctionCall(CallToAFunc));
const auto &AsCallees = ICFG.getCalleesOfCallAt(CallToAFunc);
- ASSERT_EQ(AsCallees.size(), 2U);
+ ASSERT_EQ(AsCallees.size(), 2U)
+ << "Computed A's Callees: " << printCallees(AsCallees);
+ ;
ASSERT_TRUE(llvm::is_contained(AsCallees, VFuncA));
ASSERT_TRUE(llvm::is_contained(ICFG.getCallersOf(VFuncA), CallToAFunc));
- const auto *CallToBFunc = getNthInstruction(F, 22);
+ const auto *CallToBFunc = llvm::cast(testingLocInIR(
+ LineColFunOp{20, 0, "main", llvm::Instruction::Call}, IRDB));
ASSERT_TRUE(ICFG.isVirtualFunctionCall(CallToBFunc));
const auto &BsCallees = ICFG.getCalleesOfCallAt(CallToBFunc);
- ASSERT_EQ(BsCallees.size(), 2U);
+ ASSERT_EQ(BsCallees.size(), 2U)
+ << "Computed B's Callees: " << printCallees(BsCallees);
ASSERT_TRUE(llvm::is_contained(BsCallees, VFuncB));
ASSERT_TRUE(llvm::is_contained(ICFG.getCallersOf(VFuncB), CallToBFunc));
@@ -76,34 +97,14 @@ TEST(LLVMBasedICFG_OTFTest, FunctionPtrCall_2) {
LLVMAliasSet PT(&IRDB, false);
LLVMBasedICFG ICFG(&IRDB, CallGraphAnalysisType::OTF, {"main"}, &TH, &PT);
- const llvm::Function *Main = IRDB.getFunctionDefinition("main");
const llvm::Function *Bar = IRDB.getFunctionDefinition("_Z3barv");
- const auto *FPtrCall = getNthInstruction(Main, 9);
+ const auto *FPtrCall = llvm::cast(testingLocInIR(
+ LineColFunOp{8, 0, "main", llvm::Instruction::Call}, IRDB));
const auto &Callees = ICFG.getCalleesOfCallAt(FPtrCall);
- auto printCallees // NOLINT
- = [&]() {
- std::string Ret;
- llvm::raw_string_ostream OS(Ret);
-
- OS << "{ ";
- bool First = true;
- for (const auto *Callee : Callees) {
- if (First) {
- First = false;
- } else {
- OS << ", ";
- }
-
- OS << Callee->getName();
- }
-
- OS << " }";
- return Ret;
- };
-
- ASSERT_EQ(Callees.size(), 1U) << "Too many callees: " << printCallees();
+ ASSERT_EQ(Callees.size(), 1U)
+ << "Too many callees: " << printCallees(Callees);
ASSERT_EQ(llvm::is_contained(Callees, Bar), 1U);
}
@@ -114,14 +115,15 @@ TEST(LLVMBasedICFG_OTFTest, FunctionPtrCall_3) {
LLVMAliasSet PT(&IRDB, false);
LLVMBasedICFG ICFG(&IRDB, CallGraphAnalysisType::OTF, {"main"}, &TH, &PT);
- const llvm::Function *Main = IRDB.getFunctionDefinition("main");
const llvm::Function *Foo = IRDB.getFunctionDefinition("_Z3foov");
- const auto *FPtrCall = getNthInstruction(Main, 10);
+ const auto *FPtrCall = llvm::cast(testingLocInIR(
+ LineColFunOp{10, 0, "main", llvm::Instruction::Call}, IRDB));
const auto &Callees = ICFG.getCalleesOfCallAt(FPtrCall);
- ASSERT_EQ(Callees.size(), 1U);
+ ASSERT_EQ(Callees.size(), 1U)
+ << "Computed Callees: " << printCallees(Callees);
ASSERT_EQ(llvm::is_contained(Callees, Foo), 1U);
}
diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFG_RTA_MultipleInheritanceTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFG_RTA_MultipleInheritanceTest.cpp
index 594aa828cc..5aa327c4c4 100644
--- a/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFG_RTA_MultipleInheritanceTest.cpp
+++ b/unittests/PhasarLLVM/ControlFlow/LLVMBasedICFG_RTA_MultipleInheritanceTest.cpp
@@ -6,6 +6,7 @@
#include "phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h"
#include "phasar/PhasarLLVM/Utils/LLVMIRToSrc.h"
#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"
+#include "phasar/Utils/DebugOutput.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/InstrTypes.h"
@@ -50,9 +51,11 @@ TEST(LLVMBasedICFG_RTATest, VirtualCallSite_10) {
const auto *BarF = IRDB.getFunction("_ZThn8_N6ABImpl3barEv");
ASSERT_TRUE(BarF);
+ ASSERT_TRUE(ICFG.isVirtualFunctionCall(CallToBar));
+
auto BarCallees = ICFG.getCalleesOfCallAt(CallToBar);
// non-virtual thunk to ABImpl::bar()
- EXPECT_EQ(llvm::ArrayRef{BarF}, BarCallees);
+ EXPECT_EQ(llvm::ArrayRef{BarF}, BarCallees) << PrettyPrinter{BarCallees};
// --- At Line 21: delete ABptr;
diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysisTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysisTest.cpp
index 8eec062309..b500ea4414 100644
--- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysisTest.cpp
+++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysisTest.cpp
@@ -11,6 +11,7 @@
#include "TestConfig.h"
#include "gtest/gtest.h"
+#include
#include
using namespace psr;
@@ -59,8 +60,10 @@ class IDELinearConstantAnalysisTest : public ::testing::Test {
* @param groundTruth results to compare against
* @param solver provides the results
*/
- static void compareResults(IDELinearConstantAnalysis::lca_results_t &Results,
- std::set &GroundTruth) {
+ static void compareResults(
+ IDELinearConstantAnalysis::lca_results_t &Results,
+ std::set &GroundTruth,
+ std::source_location SrcLoc = std::source_location::current()) {
std::set RelevantResults;
for (auto G : GroundTruth) {
std::string FName = std::get<0>(G);
@@ -74,7 +77,9 @@ class IDELinearConstantAnalysisTest : public ::testing::Test {
}
}
}
- EXPECT_EQ(RelevantResults, GroundTruth);
+ EXPECT_EQ(RelevantResults, GroundTruth)
+ << "Called from " << SrcLoc.file_name() << ":" << SrcLoc.line() << ":"
+ << SrcLoc.column();
}
}; // Test Fixture
@@ -433,8 +438,11 @@ TEST_F(IDELinearConstantAnalysisTest, HandleCallTest_08) {
GroundTruth.emplace("main", 6, "i", 10);
GroundTruth.emplace("main", 7, "i", 10);
GroundTruth.emplace("main", 7, "j", 1);
+#if LLVM_VERSION_MAJOR <= 18
+ // With >18 there is no llvm::Instruction for line 8
GroundTruth.emplace("main", 8, "i", 10);
GroundTruth.emplace("main", 8, "j", 1);
+#endif
GroundTruth.emplace("main", 9, "i", 10);
GroundTruth.emplace("main", 9, "j", 1);
GroundTruth.emplace("main", 10, "i", 10);
diff --git a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis_DotTest.cpp b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis_DotTest.cpp
index d755dce01c..fafd1f0911 100644
--- a/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis_DotTest.cpp
+++ b/unittests/PhasarLLVM/DataFlow/IfdsIde/Problems/IDELinearConstantAnalysis_DotTest.cpp
@@ -406,8 +406,11 @@ TEST_F(IDELinearConstantAnalysisTest, HandleCallTest_08) {
GroundTruth.emplace("main", 6, "i", 10);
GroundTruth.emplace("main", 7, "i", 10);
GroundTruth.emplace("main", 7, "j", 1);
+#if LLVM_VERSION_MAJOR <= 18
+ // With >18 there is no llvm::Instruction for line 8
GroundTruth.emplace("main", 8, "i", 10);
GroundTruth.emplace("main", 8, "j", 1);
+#endif
GroundTruth.emplace("main", 9, "i", 10);
GroundTruth.emplace("main", 9, "j", 1);
GroundTruth.emplace("main", 10, "i", 10);
diff --git a/unittests/PhasarLLVM/Pointer/LLVMUnionFindAATest.cpp b/unittests/PhasarLLVM/Pointer/LLVMUnionFindAATest.cpp
index e8e0e9b450..14f5d89854 100644
--- a/unittests/PhasarLLVM/Pointer/LLVMUnionFindAATest.cpp
+++ b/unittests/PhasarLLVM/Pointer/LLVMUnionFindAATest.cpp
@@ -262,7 +262,11 @@ TEST(CtxSensUnionFindAATest, Basic04) {
.InFunction = "main",
.OpCode = llvm::Instruction::Alloca},
LineColFunOp{.Line = 11,
+#if LLVM_VERSION_MAJOR <= 20
.Col = 11,
+#else
+ .Col = 10,
+#endif
.InFunction = "main",
.OpCode = llvm::Instruction::Load},
LineColFunOp{.Line = 11,
diff --git a/unittests/PhasarLLVM/TaintConfig/TaintConfigTest.cpp b/unittests/PhasarLLVM/TaintConfig/TaintConfigTest.cpp
index 6c62a308ac..b25df13084 100644
--- a/unittests/PhasarLLVM/TaintConfig/TaintConfigTest.cpp
+++ b/unittests/PhasarLLVM/TaintConfig/TaintConfigTest.cpp
@@ -242,7 +242,7 @@ TEST_F(TaintConfigTest, Array_01_Json) {
const llvm::Value *I = testingLocInIR(
OperandOf{1, LineColFunOp{8, 9, "main", llvm::Instruction::Store}}, IR);
- ASSERT_TRUE(TConfig.isSource(I));
+ ASSERT_TRUE(TConfig.isSource(I)) << psr::llvmIRToString(I);
}
TEST_F(TaintConfigTest, Array_02_Json) {
@@ -253,9 +253,12 @@ TEST_F(TaintConfigTest, Array_02_Json) {
psr::LLVMProjectIRDB IR({PathToJsonTaintConfigTestCode + File});
// IR.emitPreprocessedIR(llvm::outs(), false);
psr::LLVMTaintConfig TConfig(IR, JsonConfig);
+
+ TConfig.print(llvm::errs());
+
const llvm::Value *I = testingLocInIR(
OperandOf{1, LineColFunOp{9, 9, "main", llvm::Instruction::Store}}, IR);
- ASSERT_TRUE(TConfig.isSource(I));
+ ASSERT_TRUE(TConfig.isSource(I)) << psr::llvmIRToString(I);
}
TEST_F(TaintConfigTest, Basic_01_Json) {
diff --git a/unittests/TestUtils/SrcCodeLocationEntry.h b/unittests/TestUtils/SrcCodeLocationEntry.h
index 61f6b7c37f..75867df332 100644
--- a/unittests/TestUtils/SrcCodeLocationEntry.h
+++ b/unittests/TestUtils/SrcCodeLocationEntry.h
@@ -309,6 +309,8 @@ getInstAtOrNull(const llvm::Function *F, uint32_t ReqLine,
}
auto [Line, Column] = psr::getLineAndColFromIR(&I);
+ // llvm::errs() << "For Inst at " << Line << ":" << Column << ": "
+ // << llvmIRToString(&I) << '\n';
if (Line == ReqLine && (ReqColumn == 0 || ReqColumn == Column) &&
std::invoke(Pred, &I)) {
return &I;
diff --git a/unittests/Utils/OnTheFlyAnalysisPrinterTest.cpp b/unittests/Utils/OnTheFlyAnalysisPrinterTest.cpp
index 30c9e88351..cac20bf580 100644
--- a/unittests/Utils/OnTheFlyAnalysisPrinterTest.cpp
+++ b/unittests/Utils/OnTheFlyAnalysisPrinterTest.cpp
@@ -2,17 +2,26 @@
#include "phasar/DataFlow/IfdsIde/Solver/IFDSSolver.h"
#include "phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h"
+#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h"
#include "phasar/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSUninitializedVariables.h"
#include "phasar/PhasarLLVM/HelperAnalyses.h"
#include "phasar/PhasarLLVM/SimpleAnalysisConstructor.h"
+#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
+#include "SrcCodeLocationEntry.h"
#include "TestConfig.h"
#include "gtest/gtest.h"
+namespace {
+
using namespace psr;
+using namespace psr::unittest;
+
+using GroundTruthTy =
+ std::map>;
class GroundTruthCollector
: public OnTheFlyAnalysisPrinter {
@@ -22,35 +31,40 @@ class GroundTruthCollector
public:
// constructor init Groundtruth in each fixture
- GroundTruthCollector(llvm::DenseMap> &GroundTruth)
- : GroundTruth(GroundTruth) {};
+ GroundTruthCollector(GroundTruthTy GroundTruth)
+ : GroundTruth(std::move(GroundTruth)) {};
- void findAndRemove(int LeakId, const std::string &LeakedFactId) {
+ void convertGT(const LLVMProjectIRDB &IRDB) {
+ LLVMGroundTruth = convertTestingLocationSetMapInIR(GroundTruth, IRDB);
+ }
- auto It = GroundTruth.find(LeakId);
- ASSERT_NE(It, GroundTruth.end())
- << "Found leak at unexpected location: " << LeakId << ": '"
- << LeakedFactId << "'";
+private:
+ void doOnResult(n_t Instr, d_t DfFact, l_t /*LatticeElement*/,
+ DataFlowAnalysisType /*AnalysisType*/) override {
+ assert(LLVMGroundTruth);
+ auto It = LLVMGroundTruth->find(Instr);
+ ASSERT_NE(It, LLVMGroundTruth->end())
+ << "Found leak at unexpected location: " << llvmIRToString(Instr)
+ << ": '" << llvmIRToString(DfFact) << "'";
- bool Erased = It->second.erase(LeakedFactId);
- ASSERT_TRUE(Erased) << "Did not expect leak '" << LeakedFactId
- << "' at instruction " << LeakId;
+ bool Erased = It->second.erase(DfFact);
+ ASSERT_TRUE(Erased) << "Did not expect leak '" << llvmIRToString(DfFact)
+ << "' at instruction " << llvmIRToString(Instr);
if (It->second.empty()) {
- GroundTruth.erase(It);
+ LLVMGroundTruth->erase(It);
}
}
-private:
- void doOnResult(n_t Instr, d_t DfFact, l_t /*LatticeElement*/,
- DataFlowAnalysisType /*AnalysisType*/) override {
- int LeakId = stoi(getMetaDataID(Instr));
- findAndRemove(LeakId, getMetaDataID(DfFact));
+ void doOnFinalize() override {
+ assert(LLVMGroundTruth);
+ EXPECT_TRUE(LLVMGroundTruth->empty());
}
- void doOnFinalize() override { EXPECT_TRUE(GroundTruth.empty()); }
-
- llvm::DenseMap> GroundTruth{};
+ GroundTruthTy GroundTruth{};
+ std::optional<
+ std::map>>
+ LLVMGroundTruth;
};
class OnTheFlyAnalysisPrinterTest : public ::testing::Test {
@@ -70,6 +84,7 @@ class OnTheFlyAnalysisPrinterTest : public ::testing::Test {
void doAnalysisTest(llvm::StringRef IRFile, GroundTruthCollector >Printer) {
initialize(IRFile);
+ GTPrinter.convertGT(HA->getProjectIRDB());
UnInitProblem->setAnalysisPrinter(>Printer);
IFDSSolver Solver(*UnInitProblem, &HA->getICFG());
Solver.solve();
@@ -81,22 +96,23 @@ class OnTheFlyAnalysisPrinterTest : public ::testing::Test {
TEST_F(OnTheFlyAnalysisPrinterTest, UninitTest_01_LEAK) {
- llvm::DenseMap> GroundTruth;
- // %4 = load i32, i32* %2, ID: 6 ; %2 is the uninitialized variable i
- GroundTruth[6] = {"1"};
- // %5 = add nsw i32 %4, 10 ; %4 is undef, since it is loaded from
- // undefined alloca; not sure if it is necessary to report again
- GroundTruth[7] = {"6"};
+ GroundTruthTy GroundTruth;
+ const auto Entry = LineColFun{2, 0, "main"};
+ const auto EntryTwo = LineColFun{3, 11, "main"};
+ const auto EntryThree = LineColFun{3, 13, "main"};
+ GroundTruth.insert({EntryTwo, {Entry}});
+ GroundTruth.insert({EntryThree, {EntryTwo}});
GroundTruthCollector GroundTruthPrinter = {GroundTruth};
doAnalysisTest("binop_uninit_cpp_dbg.ll", GroundTruthPrinter);
}
TEST_F(OnTheFlyAnalysisPrinterTest, UninitTest_02_NOLEAK) {
- llvm::DenseMap> GroundTruth;
+ GroundTruthTy GroundTruth;
GroundTruthCollector GroundTruthPrinter = {GroundTruth};
doAnalysisTest("ctor_default_cpp_dbg.ll", GroundTruthPrinter);
}
+} // namespace
// main function for the test case
int main(int Argc, char **Argv) {
diff --git a/utils/InstallAptDependencies.sh b/utils/InstallAptDependencies.sh
index 95134331b3..ee34e1eda7 100755
--- a/utils/InstallAptDependencies.sh
+++ b/utils/InstallAptDependencies.sh
@@ -43,8 +43,8 @@ done
set -- "${POSITIONAL[@]}" # restore positional parameters
# End - Parsing command-line-parameters
-if [ "$LLVM_IR_VERSION" -ne "16" ] && [ "$LLVM_IR_VERSION" -ne "17" ]; then
- echo "Invalid LLVM version: $LLVM_IR_VERSION, expected 16 or 17" >&2
+if [ "$LLVM_IR_VERSION" != "16" ] && [ "$LLVM_IR_VERSION" != "17" ] && [[ ! "$LLVM_IR_VERSION" =~ ^"22."[0-9] ]]; then
+ echo "Invalid LLVM version: $LLVM_IR_VERSION, expected 16 or 22.1" >&2
exit 1
fi