From 1911968aef9e1d0266c96ec1ab9804de803ab91f Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Sat, 16 May 2026 00:22:23 +0200 Subject: [PATCH 01/11] feat(TDA): add TypeDeductionAnalysis library and bump to c++20 --- .gitmodules | 3 +++ CMakeLists.txt | 3 ++- libs/TypeDeductionAnalysis | 1 + passes/ASPIS.h | 3 +++ passes/CMakeLists.txt | 9 +++++++++ passes/EDDI.cpp | 11 ++++++++++- 6 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 .gitmodules create mode 160000 libs/TypeDeductionAnalysis diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5b0aac4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libs/TypeDeductionAnalysis"] + path = libs/TypeDeductionAnalysis + url = https://github.com/NiccoloN/TypeDeductionAnalysis.git diff --git a/CMakeLists.txt b/CMakeLists.txt index dad6028..45ea11d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,10 +21,11 @@ include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") #endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20") message(STATUS "Found LLVM definitions ${LLVM_DEFINITIONS_LIST}") message(STATUS "Found LLVM include dirs ${LLVM_INCLUDE_DIRS}") message(STATUS "RTTI: ${LLVM_ENABLE_RTTI}") +add_subdirectory(libs/TypeDeductionAnalysis) add_subdirectory(passes) \ No newline at end of file diff --git a/libs/TypeDeductionAnalysis b/libs/TypeDeductionAnalysis new file mode 160000 index 0000000..f9f6e44 --- /dev/null +++ b/libs/TypeDeductionAnalysis @@ -0,0 +1 @@ +Subproject commit f9f6e4450ae8d1bf7ad398c0541cb39211eb3075 diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 5807769..84aa252 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -6,6 +6,7 @@ #include "llvm/Pass.h" #include #include "Utils/Utils.h" +#include "TypeDeductionAnalysis.hpp" #include #include #include @@ -44,6 +45,8 @@ class EDDI : public PassInfoMixin { std::unordered_multimap DuplicatedInstructionMap; std::unordered_set ClonedInstructions; + tda::TypeDeductionAnalysis tda; + tda::TypeDeductionAnalysis::Result deducedTypes; std::string entryPoint; LinkageMap linkageMap; diff --git a/passes/CMakeLists.txt b/passes/CMakeLists.txt index 2d8ef3b..083287b 100644 --- a/passes/CMakeLists.txt +++ b/passes/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(EDDI SHARED FuncRetToRef.cpp Utils/Utils.cpp ) +target_link_libraries(EDDI PUBLIC TypeDeductionAnalysis) target_compile_definitions(EDDI PRIVATE DUPLICATE_ALL SELECTIVE_CHECKING=0 CHECK_AT_STORES CHECK_AT_CALLS CHECK_AT_BRANCH) # REDDI @@ -16,6 +17,7 @@ add_library(REDDI SHARED FuncRetToRef.cpp Utils/Utils.cpp ) +target_link_libraries(REDDI PUBLIC TypeDeductionAnalysis) target_compile_definitions(REDDI PRIVATE SELECTIVE_CHECKING=0 CHECK_AT_STORES CHECK_AT_CALLS CHECK_AT_BRANCH) @@ -26,6 +28,7 @@ add_library(FDSC SHARED FuncRetToRef.cpp Utils/Utils.cpp ) +target_link_libraries(FDSC PUBLIC TypeDeductionAnalysis) target_compile_definitions(FDSC PRIVATE DUPLICATE_ALL SELECTIVE_CHECKING=1 CHECK_AT_STORES CHECK_AT_CALLS CHECK_AT_BRANCH) # sEDDI @@ -35,6 +38,7 @@ add_library(SEDDI SHARED FuncRetToRef.cpp Utils/Utils.cpp ) +target_link_libraries(SEDDI PUBLIC TypeDeductionAnalysis) target_compile_definitions(SEDDI PRIVATE DUPLICATE_ALL SELECTIVE_CHECKING=0 CHECK_AT_CALLS CHECK_AT_BRANCH) @@ -43,12 +47,14 @@ add_library(CFCSS SHARED CFCSS.cpp Utils/Utils.cpp ) +target_link_libraries(CFCSS PUBLIC TypeDeductionAnalysis) # RASM add_library(RASM SHARED RASM.cpp Utils/Utils.cpp ) +target_link_libraries(RASM PUBLIC TypeDeductionAnalysis) target_compile_definitions(RASM PRIVATE INTER_FUNCTION_CFC=0) @@ -57,6 +63,7 @@ add_library(INTER_RASM SHARED RASM.cpp Utils/Utils.cpp ) +target_link_libraries(INTER_RASM PUBLIC TypeDeductionAnalysis) target_compile_definitions(INTER_RASM PRIVATE INTER_FUNCTION_CFC=1) # RACFED @@ -64,8 +71,10 @@ add_library(RACFED SHARED RACFED.cpp Utils/Utils.cpp ) +target_link_libraries(RACFED PUBLIC TypeDeductionAnalysis) add_library(PROFILER SHARED Profiling/ASPISCheckProfiler.cpp Utils/Utils.cpp ) +target_link_libraries(PROFILER PUBLIC TypeDeductionAnalysis) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index b0e5394..7b6c171 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -37,11 +37,11 @@ #include #include #include -// #include "../TypeDeductionAnalysis/TypeDeductionAnalysis.hpp" #include "Utils/Utils.h" using namespace llvm; +using namespace tda; #define DEBUG_TYPE "eddi_verification" @@ -1590,6 +1590,15 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { // Fixing the duplicated constructors fixDuplicatedConstructors(Md); + deducedTypes = tda.run(Md, AM); + + // Save deduced transparent types + for (auto& [value, deducedTypes] : deducedTypes.transparentTypes) { + if (!deducedTypes.empty()) { + errs() << "Deduced transparent type for " << *value << ": " << (*deducedTypes.begin()).get()->toString() << "\n"; + } + } + // list of duplicated instructions to remove since they are equal to the original std::set GrayAreaCallsToFix; ClonedInstructions.clear(); From 2e4a09556717332cbec18947e350a0d702cc1e69 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Fri, 1 May 2026 22:24:50 +0200 Subject: [PATCH 02/11] feat(EDDI): enhance creation of consistency checks --- passes/ASPIS.h | 5 +- passes/EDDI.cpp | 186 ++++++++++++++++++++++-------------------------- 2 files changed, 89 insertions(+), 102 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 84aa252..2d3a3f5 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -63,7 +63,7 @@ class EDDI : public PassInfoMixin { Instruction* cloneInstr(Instruction &I); void duplicateOperands (Instruction &I, BasicBlock &ErrBB); Value* getPtrFinalValue(Value &V); - Value* comparePtrs(Value &V1, Value &V2, IRBuilder<> &B); + void comparePtrs(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B); void addConsistencyChecks(Instruction &I, BasicBlock &ErrBB); void fixFuncValsPassedByReference(Instruction &I, IRBuilder<> &B); int transformCallBaseInst(CallBase *CInstr, IRBuilder<> &B, BasicBlock &ErrBB) ; @@ -77,7 +77,8 @@ class EDDI : public PassInfoMixin { void CreateErrBB(Module &Md, Function &Fn, BasicBlock *ErrBB); bool temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilder<> &B); Value *getDuplicateValue(Value *V, Instruction *I); - + void createCompareOnOperand(std::vector *CmpInstructions, Value *V, Instruction &I, IRBuilder<> &B); + void compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B); void fixGlobalCtors(Module &M); void repairBasicBlock(BasicBlock &BB); public: diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 7b6c171..a16f212 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -719,7 +719,7 @@ void EDDI::duplicateOperands( Value *EDDI::getPtrFinalValue(Value &V) { Value *res = NULL; - if (V.getType()->isPointerTy()) { + if (V.getType()->isPointerTy() && V.hasUseList()) { // find the store using V as ptr for (User *U : V.users()) { if (isa(U)) { @@ -743,7 +743,7 @@ Value *EDDI::getPtrFinalValue(Value &V) { // Follows the pointers V1 and V2 using getPtrFinalValue() and adds a compare // instruction using the IRBuilder B. -Value *EDDI::comparePtrs(Value &V1, Value &V2, IRBuilder<> &B) { +void EDDI::comparePtrs(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B) { /** * synthax `store val, ptr` * @@ -761,15 +761,8 @@ Value *EDDI::comparePtrs(Value &V1, Value &V2, IRBuilder<> &B) { if (F1 != NULL && F2 != NULL && !F1->getType()->isPointerTy()) { Instruction *L1 = B.CreateLoad(F1->getType(), F1); Instruction *L2 = B.CreateLoad(F2->getType(), F2); - if (L1->getType()->isFloatingPointTy()) { - comparisonCounter++; - return B.CreateCmp(CmpInst::FCMP_UEQ, L1, L2); - } else { - comparisonCounter++; - return B.CreateCmp(CmpInst::ICMP_EQ, L1, L2); - } + compareValues(CmpInstructions, *L1, *L2, B); } - return NULL; } /** @@ -801,93 +794,14 @@ void EDDI::addConsistencyChecks( if (Duplicate != nullptr) { Value *Original = cast(I).getCalledOperand(); Value *Copy = Duplicate; - if (Original->getType()->isIntOrIntVectorTy() || Original->getType()->isPtrOrPtrVectorTy()) { - // DuplicatedInstructionMap.insert(std::pair(&I, &I)); - CmpInstructions.push_back(B.CreateCmp(CmpInst::ICMP_EQ, Original, Copy)); - comparisonCounter++; - } + + compareValues(&CmpInstructions, *Original, *Copy, B); } } // add a comparison for each operand for (Value *V : I.operand_values()) { - // we compare the operands if they are instructions - if (isa(V)) { - // get the duplicate of the operand - Instruction *Operand = cast(V); - - // If the operand is a pointer and is not used by any store, we skip the - // operand - if (Operand->getType()->isPointerTy() && !isUsedByStore(*Operand, I)) { - continue; - } - - Value *Duplicate = getDuplicateValue(Operand, &I); - - // if the duplicate exists we perform a compare - if (Duplicate != nullptr) { - Value *Original = Operand; - Value *Copy = Duplicate; - - // if the operand is a pointer we try to get a compare on pointers - if (Original->getType()->isPointerTy()) { - Value *CmpInstr = comparePtrs(*Original, *Copy, B); - if (CmpInstr != NULL) { - CmpInstructions.push_back(CmpInstr); - } - } - // if the operand is an array we have to compare all its elements - else if (Original->getType()->isArrayTy()) { - if (!Original->getType()->getArrayElementType()->isAggregateType()) { - int arraysize = Original->getType()->getArrayNumElements(); - - for (int i = 0; i < arraysize; i++) { - Value *OriginalElem = B.CreateExtractValue(Original, i); - Value *CopyElem = B.CreateExtractValue(Copy, i); - DuplicatedInstructionMap.insert( - std::pair(OriginalElem, CopyElem)); - DuplicatedInstructionMap.insert( - std::pair(CopyElem, OriginalElem)); - - if (OriginalElem->getType()->isPointerTy()) { - Value *CmpInstr = comparePtrs(*OriginalElem, *CopyElem, B); - if (CmpInstr != NULL) { - CmpInstructions.push_back(CmpInstr); - } - } else { - if (OriginalElem->getType()->isFloatingPointTy()) { - CmpInstructions.push_back( - B.CreateCmp(CmpInst::FCMP_UEQ, OriginalElem, CopyElem)); - comparisonCounter++; - } else if (OriginalElem->getType()->isIntOrIntVectorTy() || OriginalElem->getType()->isPtrOrPtrVectorTy()) { - CmpInstructions.push_back( - B.CreateCmp(CmpInst::ICMP_EQ, OriginalElem, CopyElem)); - comparisonCounter++; - } else { - errs() << "Warning: Didn't create a comparison for "; - OriginalElem->getType()->print(errs()); - errs() << " type\n"; - } - } - } - } - } - // else we just add a compare - else { - if (Original->getType()->isFloatingPointTy()) { - CmpInstructions.push_back( - B.CreateCmp(CmpInst::FCMP_UEQ, Original, Copy)); - comparisonCounter++; - } else if (Original->getType()->isIntOrIntVectorTy() || Original->getType()->isPtrOrPtrVectorTy()) { - CmpInstructions.push_back( - B.CreateCmp(CmpInst::ICMP_EQ, Original, Copy)); - comparisonCounter++; - } else { - errs() << "Warning: Didn't create a comparison for " << Original->getType() << " type\n"; - } - } - } - } + createCompareOnOperand(&CmpInstructions, V, I, B); } // if in the end we have a set of compare instructions, we check that all of @@ -900,7 +814,11 @@ void EDDI::addConsistencyChecks( CondBrInst->setDebugLoc(I.getDebugLoc()); } } else { - errs() << "Warning: no consistency check added for instruction: " << I << "\n"; + errs() << "Warning: no consistency check added for instruction: " << I; + if (I.getFunction()) { + errs() << " in function " << I.getFunction()->getName(); + } + errs() << "\n"; } if (VerificationBB->size() == 0) { @@ -911,6 +829,74 @@ void EDDI::addConsistencyChecks( } } +void EDDI::createCompareOnOperand(std::vector *CmpInstructions, Value *V, Instruction &I, IRBuilder<> &B) { + auto Duplicate = DuplicatedInstructionMap.find(V); + + // if the duplicate doesn't exist, we cannot perform a compare + if (Duplicate == DuplicatedInstructionMap.end()) { + return; + } + + Value *Original = Duplicate->first; + Value *Copy = Duplicate->second; + + // we compare the operands only if they are found in the TDA transparent types + if(deducedTypes.transparentTypes.find(V) == deducedTypes.transparentTypes.end()) { + errs() << "Warning: Didn't find transparent type for operand " << V->getName() << " of instruction " << I << "\n"; + return; + } + + compareValues(CmpInstructions, *Original, *Copy, B); +} + +void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B) { + auto VTy = deducedTypes.transparentTypes.find(&V1)->second.begin()->get(); + + if(V1.getType() != V2.getType()) { + errs() << "Warning: Can't compare values of different types: " << *V1.getType() << " and " << *V2.getType() << "\n"; + return; + } + + if (V1.getType()->isFPOrFPVectorTy()) { + CmpInstructions->push_back(B.CreateCmp(CmpInst::FCMP_UEQ, &V1, &V2)); + comparisonCounter++; + } else if (V1.getType()->isIntOrIntVectorTy()) { + CmpInstructions->push_back(B.CreateCmp(CmpInst::ICMP_EQ, &V1, &V2)); + comparisonCounter++; + } else if (V1.getType()->isPtrOrPtrVectorTy()) { + comparePtrs(CmpInstructions, V1, V2, B); + } else if (V1.getType()->isArrayTy()) { + if (!V1.getType()->getArrayElementType()->isAggregateType()) { + int arraysize = V1.getType()->getArrayNumElements(); + + for (int i = 0; i < arraysize; i++) { + Value *OriginalElem = B.CreateExtractValue(&V1, i); + Value *CopyElem = B.CreateExtractValue(&V2, i); + DuplicatedInstructionMap.insert( + std::pair(OriginalElem, CopyElem)); + DuplicatedInstructionMap.insert( + std::pair(CopyElem, OriginalElem)); + + compareValues(CmpInstructions,*OriginalElem, *CopyElem, B); + } + } + } else if (V1.getType()->isStructTy()) { + for (unsigned i = 0; i < V1.getType()->getStructNumElements(); i++) { + Value *OriginalElem = B.CreateExtractValue(&V1, i); + Value *CopyElem = B.CreateExtractValue(&V2, i); + DuplicatedInstructionMap.insert( + std::pair(OriginalElem, CopyElem)); + DuplicatedInstructionMap.insert( + std::pair(CopyElem, OriginalElem)); + + compareValues(CmpInstructions, *OriginalElem, *CopyElem, B); + } + } else { + errs() << "Warning: Didn't create a comparison for " << *V1.getType() << " type\n"; + } +} + + // Given an instruction, loads and stores the pointers passed to the // instruction. This is useful in the case I is a CallBase, since the function // called might not be in the compilation unit, and the function called may @@ -1592,12 +1578,12 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { deducedTypes = tda.run(Md, AM); - // Save deduced transparent types - for (auto& [value, deducedTypes] : deducedTypes.transparentTypes) { - if (!deducedTypes.empty()) { - errs() << "Deduced transparent type for " << *value << ": " << (*deducedTypes.begin()).get()->toString() << "\n"; - } - } + // // Save deduced transparent types + // for (auto& [value, deducedType] : deducedTypes.transparentTypes) { + // if (!deducedType.empty()) { + // errs() << "Deduced transparent type for " << *value << ": " << (*deducedType.begin()).get()->toString() << "\n"; + // } + // } // list of duplicated instructions to remove since they are equal to the original std::set GrayAreaCallsToFix; @@ -1875,7 +1861,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { LLVM_DEBUG(dbgs() << "Persisting Compiled Functions...\n"); persistCompiledFunctions(CompiledFuncs, "compiled_eddi_functions.csv"); - + std::cout << "Comparison Counter: " << comparisonCounter << "\n"; return PreservedAnalyses::none(); From 436ce42f5e64225f84b2b27b8747563d78e5e691 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Sat, 2 May 2026 11:37:47 +0200 Subject: [PATCH 03/11] feat(EDDI): use TDA for generating consistency checks --- passes/EDDI.cpp | 50 ++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index a16f212..983dcb5 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -857,30 +857,20 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value return; } - if (V1.getType()->isFPOrFPVectorTy()) { - CmpInstructions->push_back(B.CreateCmp(CmpInst::FCMP_UEQ, &V1, &V2)); - comparisonCounter++; - } else if (V1.getType()->isIntOrIntVectorTy()) { - CmpInstructions->push_back(B.CreateCmp(CmpInst::ICMP_EQ, &V1, &V2)); - comparisonCounter++; - } else if (V1.getType()->isPtrOrPtrVectorTy()) { + if(VTy->isPointerTT()) { comparePtrs(CmpInstructions, V1, V2, B); - } else if (V1.getType()->isArrayTy()) { - if (!V1.getType()->getArrayElementType()->isAggregateType()) { - int arraysize = V1.getType()->getArrayNumElements(); - - for (int i = 0; i < arraysize; i++) { - Value *OriginalElem = B.CreateExtractValue(&V1, i); - Value *CopyElem = B.CreateExtractValue(&V2, i); - DuplicatedInstructionMap.insert( - std::pair(OriginalElem, CopyElem)); - DuplicatedInstructionMap.insert( - std::pair(CopyElem, OriginalElem)); - - compareValues(CmpInstructions,*OriginalElem, *CopyElem, B); - } + } else if(VTy->isPrimitiveTT()) { + if(VTy->isIntegerTyOrPtrTo()) { + CmpInstructions->push_back(B.CreateCmp(CmpInst::ICMP_EQ, &V1, &V2)); + comparisonCounter++; + } else if(VTy->isFloatingPointTyOrPtrTo()) { + CmpInstructions->push_back(B.CreateCmp(CmpInst::FCMP_UEQ, &V1, &V2)); + comparisonCounter++; + } else { + errs() << "Warning: Unsupported primitive type for comparison: " << VTy->toString() << "\n"; + return; } - } else if (V1.getType()->isStructTy()) { + } else if(VTy->isStructTT()) { for (unsigned i = 0; i < V1.getType()->getStructNumElements(); i++) { Value *OriginalElem = B.CreateExtractValue(&V1, i); Value *CopyElem = B.CreateExtractValue(&V2, i); @@ -891,8 +881,22 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value compareValues(CmpInstructions, *OriginalElem, *CopyElem, B); } + } else if(VTy->isArrayTT()) { + int arraysize = V1.getType()->getArrayNumElements(); + + for (int i = 0; i < arraysize; i++) { + Value *OriginalElem = B.CreateExtractValue(&V1, i); + Value *CopyElem = B.CreateExtractValue(&V2, i); + DuplicatedInstructionMap.insert( + std::pair(OriginalElem, CopyElem)); + DuplicatedInstructionMap.insert( + std::pair(CopyElem, OriginalElem)); + + compareValues(CmpInstructions,*OriginalElem, *CopyElem, B); + } } else { - errs() << "Warning: Didn't create a comparison for " << *V1.getType() << " type\n"; + errs() << "Warning: Unsupported type for comparison: " << VTy->toString() << "\n"; + return; } } From 605b72c42c0d97eb24710132a0004a7c1453747a Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Mon, 11 May 2026 18:00:47 +0200 Subject: [PATCH 04/11] upd(EDDI): enhance usage of TDA - Enhance pointer comparison using TDA - Try following the pointers to reach the final value with loads and finally call compareValues - created isLocalValueInitializedBefore to check if a value is initialized before a certain instruction in all the possible paths (if not, avoid creating a consistency check on an uninitialized value) - checks on stores are done only on valueOperands - Tried to update TDA transparent types during duplicates creation --- passes/EDDI.cpp | 256 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 215 insertions(+), 41 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 983dcb5..21868f8 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -717,7 +717,7 @@ void EDDI::duplicateOperands( // if the value cannot be found (e.g. when the pointer is passed as function // argument) we return NULL. Value *EDDI::getPtrFinalValue(Value &V) { - Value *res = NULL; + Value *res = nullptr; if (V.getType()->isPointerTy() && V.hasUseList()) { // find the store using V as ptr @@ -755,14 +755,153 @@ void EDDI::comparePtrs(std::vector *CmpInstructions, Value &V1, Value & * for finding a _b = load c _a = load _b */ - Value *F1 = getPtrFinalValue(V1); - Value *F2 = getPtrFinalValue(V2); + if(isa(V1) || isa(V2)) { + errs() << "Warning: Comparing functions\n"; + return; + } + + Value *F1 = &V1; + Value *F2 = &V2; + + if(!deducedTypes.transparentTypes.contains(&V1) || !deducedTypes.transparentTypes.contains(&V2)) { + errs() << "Warning: " << V1 << " or " << V2 << " not in deduced types\n"; + return; + } + + if(deducedTypes.transparentTypes.find(&V1)->second.size() != 1) { + errs() << "\tMultiple types 1!\n"; + for(auto el=deducedTypes.transparentTypes.find(&V1)->second.cbegin(); el != deducedTypes.transparentTypes.find(&V1)->second.cend(); el++) { + errs() << "\t" << el->get()->toString() << "\n"; + } + return; + } + + if(deducedTypes.transparentTypes.find(&V2)->second.size() != 1) { + errs() << "\tMultiple types 2!\n"; + for(auto el=deducedTypes.transparentTypes.find(&V2)->second.cbegin(); el != deducedTypes.transparentTypes.find(&V2)->second.cend(); el++) { + errs() << "\t" << el->get()->toString() << "\n"; + } + return; + } + + auto V1Ty = deducedTypes.transparentTypes.find(&V1)->second.begin()->get(); + auto V2Ty = deducedTypes.transparentTypes.find(&V2)->second.begin()->get(); + + if(!V1Ty || V1Ty->isOpaquePtr()) { + errs() << "Warning 1: Can't find final value for pointer " << V1 << "\n"; + return; + } + + if(!V2Ty || V2Ty->isOpaquePtr()) { + errs() << "Warning 2: Can't find final value for pointer " << V1 << "\n"; + return; + } + + assert(((V1Ty->isPointerTT() && V1.getType()->isPointerTy()) || (V2Ty->isPointerTT() && V2.getType()->isPointerTy())) && "No pointers found"); + + while(V1Ty->isPointerTT()) { + V1Ty = V1Ty->getPointedType(); + + if(V1Ty == nullptr) { + errs() << "Warning1: Can't find final value for pointer " << V1 << "\n"; + return; + } + + if(F1->getType()->isPointerTy()) { + F1 = B.CreateLoad(V1Ty->getLLVMType(), F1); + } + } + + while(V2Ty->isPointerTT()) { + V2Ty = V2Ty->getPointedType(); + + if(V2Ty == nullptr) { + errs() << "Warning2: Can't find final value for pointer " << V2 << "\n"; + return; + } + + if(F2->getType()->isPointerTy()) { + F2 = B.CreateLoad(V2Ty->getLLVMType(), F2); + } + } + + if(F1->getType() != F2->getType()) { + errs() << "Warning: Can't compare pointers " << V1.getName() << " and " << V2.getName() << " because their final value have incompatible types: " << *F1 << " and " << *F2 << "\n"; + return; + } + + deducedTypes.transparentTypes[F1].insert(V1Ty->clone()); + deducedTypes.transparentTypes[F2].insert(V2Ty->clone()); + + compareValues(CmpInstructions, *F1, *F2, B); +} + + +bool isLocalValueInitializedBefore(Instruction *AI, Instruction *At) { + + assert(AI->getParent()->getParent() == At->getParent()->getParent() && "Alloca and Instruction not in the same function!"); + + std::unordered_set storeInsts; + + // TODO: Check if it is needed to consider other virtual registers that alias that same value + for (User *U : AI->users()) { + if (auto *SI = dyn_cast(U)) { + if (SI->getPointerOperand() == AI) { + storeInsts.insert(SI); + errs() << "\t[store] " << *SI << "\n"; + } + } + } + + // If no store instructions found with target to that alloca + if(storeInsts.empty()) { + return false; + } + + std::vector InstToBeCheckedFrom{AI}; + std::set InstCheckedFrom; + while(!InstToBeCheckedFrom.empty()) { + Instruction *I = InstToBeCheckedFrom.back(); + InstToBeCheckedFrom.pop_back(); + InstCheckedFrom.insert(I); + + if(I == nullptr) { + errs() << "\tCONTINUED!\n"; + continue; + } + + do { + if(I == At) { + return false; + } + + if(isa(I)) { + for(int i = 0; i < cast(I)->getNumSuccessors(); i++) { + auto addInst = cast(I)->getSuccessor(i)->getFirstNonPHI(); + // If doesn't exist the first instruction in the BB it will probably be the BB for the check we are building + if(addInst == nullptr) { + return false; + } else if(InstCheckedFrom.find(addInst) == InstCheckedFrom.end()) { + InstToBeCheckedFrom.push_back(addInst); + } + } + } else if (isa(I)) { + auto addInst = cast(I)->getNormalDest()->getFirstNonPHI(); + if(addInst == nullptr) { + return false; + } else if(InstCheckedFrom.find(addInst) == InstCheckedFrom.end()) { + InstToBeCheckedFrom.push_back(addInst); + } + } - if (F1 != NULL && F2 != NULL && !F1->getType()->isPointerTy()) { - Instruction *L1 = B.CreateLoad(F1->getType(), F1); - Instruction *L2 = B.CreateLoad(F2->getType(), F2); - compareValues(CmpInstructions, *L1, *L2, B); + // If it is a valid store to end, continue to search for another path that does not initialize the alloca variale. + if(isa(I) && storeInsts.find(cast(I)) != storeInsts.end()) { + break; + } + } while(I = I->getNextNode()); } + + return true; } /** @@ -799,9 +938,15 @@ void EDDI::addConsistencyChecks( } } - // add a comparison for each operand - for (Value *V : I.operand_values()) { - createCompareOnOperand(&CmpInstructions, V, I, B); + if(isa(I)) { + IRBuilder<> tmpB(VerificationBB); + createCompareOnOperand(&CmpInstructions, cast(I).getValueOperand(), I, tmpB); + } else { + // add a comparison for each operand + for (Value *V : I.operand_values()) { + IRBuilder<> tmpB(VerificationBB); + createCompareOnOperand(&CmpInstructions, V, I, tmpB); + } } // if in the end we have a set of compare instructions, we check that all of @@ -813,15 +958,9 @@ void EDDI::addConsistencyChecks( if (DebugEnabled) { CondBrInst->setDebugLoc(I.getDebugLoc()); } - } else { - errs() << "Warning: no consistency check added for instruction: " << I; - if (I.getFunction()) { - errs() << " in function " << I.getFunction()->getName(); - } - errs() << "\n"; } - if (VerificationBB->size() == 0) { + if (!VerificationBB->getTerminator()) { auto BrInst = B.CreateBr(I.getParent()); if (DebugEnabled) { BrInst->setDebugLoc(I.getDebugLoc()); @@ -837,12 +976,24 @@ void EDDI::createCompareOnOperand(std::vector *CmpInstructions, Value * return; } + if(isa(V)) { + if(!isLocalValueInitializedBefore(cast(V), &I)) { + return; + } + } else if(isa(V)) { + // TODO: What to do here? + if(!isLocalValueInitializedBefore(cast(V), &I)) { + return; + } + } else { + // TODO: are there other cases to support? + } + Value *Original = Duplicate->first; Value *Copy = Duplicate->second; // we compare the operands only if they are found in the TDA transparent types if(deducedTypes.transparentTypes.find(V) == deducedTypes.transparentTypes.end()) { - errs() << "Warning: Didn't find transparent type for operand " << V->getName() << " of instruction " << I << "\n"; return; } @@ -850,28 +1001,37 @@ void EDDI::createCompareOnOperand(std::vector *CmpInstructions, Value * } void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B) { - auto VTy = deducedTypes.transparentTypes.find(&V1)->second.begin()->get(); + if(isa(V1) || isa(V2)) { + errs() << "Not comparing functions\n"; + return; + } + + if(deducedTypes.transparentTypes.find(&V1) == deducedTypes.transparentTypes.end()) { + return; + } - if(V1.getType() != V2.getType()) { - errs() << "Warning: Can't compare values of different types: " << *V1.getType() << " and " << *V2.getType() << "\n"; + if(deducedTypes.transparentTypes.find(&V2) == deducedTypes.transparentTypes.end()) { return; } - if(VTy->isPointerTT()) { + TransparentType *V1Ty = deducedTypes.transparentTypes.find(&V1)->second.begin()->get(); + TransparentType *V2Ty = deducedTypes.transparentTypes.find(&V2)->second.begin()->get(); + + if(V1Ty->isPointerTT() || V2Ty->isPointerTT()) { comparePtrs(CmpInstructions, V1, V2, B); - } else if(VTy->isPrimitiveTT()) { - if(VTy->isIntegerTyOrPtrTo()) { + } else if(V1Ty->isPrimitiveTT()) { + if(V1Ty->isIntegerTyOrPtrTo()) { CmpInstructions->push_back(B.CreateCmp(CmpInst::ICMP_EQ, &V1, &V2)); comparisonCounter++; - } else if(VTy->isFloatingPointTyOrPtrTo()) { + } else if(V1Ty->isFloatingPointTyOrPtrTo()) { CmpInstructions->push_back(B.CreateCmp(CmpInst::FCMP_UEQ, &V1, &V2)); comparisonCounter++; } else { - errs() << "Warning: Unsupported primitive type for comparison: " << VTy->toString() << "\n"; + errs() << "Warning: Unsupported primitive type for comparison: " << V1Ty->toString() << "\n"; return; } - } else if(VTy->isStructTT()) { - for (unsigned i = 0; i < V1.getType()->getStructNumElements(); i++) { + } else if(V1Ty->isStructTT()) { + for (unsigned i = 0; i < V1Ty->getLLVMType()->getStructNumElements(); i++) { Value *OriginalElem = B.CreateExtractValue(&V1, i); Value *CopyElem = B.CreateExtractValue(&V2, i); DuplicatedInstructionMap.insert( @@ -881,8 +1041,8 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value compareValues(CmpInstructions, *OriginalElem, *CopyElem, B); } - } else if(VTy->isArrayTT()) { - int arraysize = V1.getType()->getArrayNumElements(); + } else if(V1Ty->isArrayTT()) { + int arraysize = V1Ty->getLLVMType()->getArrayNumElements(); for (int i = 0; i < arraysize; i++) { Value *OriginalElem = B.CreateExtractValue(&V1, i); @@ -895,7 +1055,7 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value compareValues(CmpInstructions,*OriginalElem, *CopyElem, B); } } else { - errs() << "Warning: Unsupported type for comparison: " << VTy->toString() << "\n"; + errs() << "Warning: Unsupported type for comparison: " << V1Ty->toString() << "\n"; return; } } @@ -1206,6 +1366,7 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { return 0; } + Instruction *clonedInst = nullptr; int res = 0; // if the instruction is an alloca instruction we need to duplicate it @@ -1213,7 +1374,7 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { if (!isAllocaForExceptionHandling(cast(I))){ - cloneInstr(I); + clonedInst = cloneInstr(I); }; @@ -1225,7 +1386,7 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { else if (isa(I)) { // duplicate the instruction - cloneInstr(I); + clonedInst = cloneInstr(I); // duplicate the operands duplicateOperands(I, ErrBB); @@ -1300,7 +1461,7 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { if ((FuncAnnotations.find(Callee) != FuncAnnotations.end() && FuncAnnotations.find(Callee)->second.starts_with("to_duplicate")) || isToDuplicate(CInstr)) { // duplicate the instruction - cloneInstr(*CInstr); + clonedInst = cloneInstr(*CInstr); // duplicate the operands duplicateOperands(I, ErrBB); @@ -1363,6 +1524,11 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { } } + if(clonedInst && deducedTypes.transparentTypes.find(&I) != deducedTypes.transparentTypes.end()) { + auto V1Ty = deducedTypes.transparentTypes.find(&I)->second.begin()->get(); + deducedTypes.transparentTypes[clonedInst].insert(V1Ty->clone()); + } + return res; } @@ -1582,13 +1748,6 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { deducedTypes = tda.run(Md, AM); - // // Save deduced transparent types - // for (auto& [value, deducedType] : deducedTypes.transparentTypes) { - // if (!deducedType.empty()) { - // errs() << "Deduced transparent type for " << *value << ": " << (*deducedType.begin()).get()->toString() << "\n"; - // } - // } - // list of duplicated instructions to remove since they are equal to the original std::set GrayAreaCallsToFix; ClonedInstructions.clear(); @@ -1874,6 +2033,12 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { bool EDDI::temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilder<> &B) { const llvm::DataLayout &DL = Md.getDataLayout(); Type *valueType; + + tda::TransparentType *VTy = nullptr; + + if(deducedTypes.transparentTypes.find(value) != deducedTypes.transparentTypes.end()) { + VTy = deducedTypes.transparentTypes.find(value)->second.begin()->get(); + } Align valueAlign; valueType = getValueType(value, &valueAlign); @@ -1902,6 +2067,15 @@ bool EDDI::temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilde DuplicatedInstructionMap.insert(std::pair(value, Copyvalue)); DuplicatedInstructionMap.insert(std::pair(memcpy_call, memcpy_call)); + if(VTy != nullptr) { + deducedTypes.transparentTypes[Copyvalue].insert(VTy->clone()); + } else { + tda::TransparentType *type = new TransparentType(); + type->setLLVMType(valueType); + deducedTypes.transparentTypes[value].insert(type->clone()); + deducedTypes.transparentTypes[Copyvalue].insert(type->clone()); + } + return true; } From 5d4b782c41770f2a58408b1408d5a49e597982f0 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Wed, 13 May 2026 14:28:23 +0200 Subject: [PATCH 05/11] feat(EDDI): enhance temporary argument duplication in case of pointers --- passes/EDDI.cpp | 79 ++++++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 21868f8..9240739 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -2032,50 +2032,67 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { bool EDDI::temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilder<> &B) { const llvm::DataLayout &DL = Md.getDataLayout(); - Type *valueType; - tda::TransparentType *VTy = nullptr; - - if(deducedTypes.transparentTypes.find(value) != deducedTypes.transparentTypes.end()) { - VTy = deducedTypes.transparentTypes.find(value)->second.begin()->get(); + auto TTIter = deducedTypes.transparentTypes.find(value); + if (TTIter == deducedTypes.transparentTypes.end()) { + errs() << "Warning: Cannot TDA value " << *value << "\n"; + return false; } - - Align valueAlign; - valueType = getValueType(value, &valueAlign); - // If can't find type, do not duplicate value - if(valueType->isVoidTy()) { - errs() << "Error: Cannot find type of value: " << *value << "\n"; + tda::TransparentType *VTy = TTIter->second.begin()->get(); + // Cannot do argument duplication if the type contains opaque pointers since we cannot find the final value to duplicate + if (VTy->containsOpaquePtr()) { + errs() << "Error! TAD value contains opaque pointer " << *value << "\n"; return false; } - uint64_t SizeInBytes = DL.getTypeAllocSize(valueType); - Value *Size = llvm::ConstantInt::get(B.getInt64Ty(), SizeInBytes); - - // Alignment (assuming alignment of 1 here; adjust as necessary) - llvm::ConstantInt *Align = B.getInt32(valueAlign.value()); + int indirections = 0; + Value *currentPtr = value; - // Volatility (non-volatile in this example) - llvm::ConstantInt *IsVolatile = B.getInt1(false); + // We need to find the final value pointed by the argument in order to duplicate it, + // so we iterate over the pointer types until we find a non-pointer type + while (VTy->isPointerTT()) { - // Create the memcpy call - auto Copyvalue = B.CreateAlloca(valueType); + VTy = VTy->getPointedType(); + if (!VTy) { + errs() << "Error! Can't find final value for pointer " << *currentPtr << "\n"; + return false; + } - llvm::CallInst *memcpy_call = B.CreateMemCpy(Copyvalue, value->getPointerAlignment(DL), value, value->getPointerAlignment(DL), Size); + if (VTy->isPointerTT()) { + indirections++; + currentPtr = B.CreateLoad(VTy->getLLVMType(), currentPtr); + } + } - DuplicatedInstructionMap.insert(std::pair(Copyvalue, value)); - DuplicatedInstructionMap.insert(std::pair(value, Copyvalue)); - DuplicatedInstructionMap.insert(std::pair(memcpy_call, memcpy_call)); + // currentPtr is now the pointer to the final value - if(VTy != nullptr) { - deducedTypes.transparentTypes[Copyvalue].insert(VTy->clone()); - } else { - tda::TransparentType *type = new TransparentType(); - type->setLLVMType(valueType); - deducedTypes.transparentTypes[value].insert(type->clone()); - deducedTypes.transparentTypes[Copyvalue].insert(type->clone()); + auto *allocaPrev = B.CreateAlloca(VTy->getLLVMType()); + deducedTypes.transparentTypes[allocaPrev].insert(VTy->clone()); + + uint64_t Size = DL.getTypeAllocSize(VTy->getLLVMType()); + + llvm::CallInst *memcpy_call = B.CreateMemCpy( + allocaPrev, allocaPrev->getPointerAlignment(DL), + currentPtr, allocaPrev->getPointerAlignment(DL), + Size); + + auto VTyPtr = VTy->clone(); + + // Now we need to create as many allocas as the number of pointer indirections + // in order to duplicate the whole pointer chain + for (int i = 0; i < indirections; ++i) { + VTyPtr = VTyPtr->getPointerToType(); + auto *allocaCurr = B.CreateAlloca(VTyPtr->getLLVMType()); + deducedTypes.transparentTypes[allocaCurr].insert(VTyPtr->getPointerToType()->clone()); + B.CreateStore(allocaPrev, allocaCurr); + allocaPrev = allocaCurr; } + DuplicatedInstructionMap.emplace(allocaPrev, value); + DuplicatedInstructionMap.emplace(value, allocaPrev); + DuplicatedInstructionMap.insert(std::pair(memcpy_call, memcpy_call)); + return true; } From c7372d2c428f854dc4a77253b41f040ad0ee005d Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Wed, 13 May 2026 16:01:31 +0200 Subject: [PATCH 06/11] feat(EDDI): enhance temporary argument duplication of arrays --- .github/workflows/main.yml | 9 +++++++++ passes/EDDI.cpp | 17 ++++++++++++++--- testing/test.py | 35 +++++++++++++++++++++++++++-------- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cceefe6..8d29c28 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -88,3 +88,12 @@ jobs: path: ${{ github.workspace }}/ASPIS/testing/build/comparison_counter.csv if-no-files-found: warn + - name: Upload failed test IR artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: failed-out-ll + path: | + ASPIS/testing/failed-out-ll/** + if-no-files-found: warn + diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 9240739..aec5b92 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -2052,7 +2052,6 @@ bool EDDI::temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilde // We need to find the final value pointed by the argument in order to duplicate it, // so we iterate over the pointer types until we find a non-pointer type while (VTy->isPointerTT()) { - VTy = VTy->getPointedType(); if (!VTy) { errs() << "Error! Can't find final value for pointer " << *currentPtr << "\n"; @@ -2067,10 +2066,22 @@ bool EDDI::temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilde // currentPtr is now the pointer to the final value - auto *allocaPrev = B.CreateAlloca(VTy->getLLVMType()); + uint64_t SizeInBytes = 0; + AllocaInst *allocaPrev = nullptr; + + if(isa(currentPtr)) { + auto *gepInst = cast(currentPtr); + SizeInBytes = DL.getTypeAllocSize(gepInst->getSourceElementType()); + allocaPrev = B.CreateAlloca(VTy->getLLVMType(), ConstantInt::get(VTy->getLLVMType(), SizeInBytes)); + } else { + SizeInBytes = DL.getTypeAllocSize(VTy->getLLVMType()); + allocaPrev = B.CreateAlloca(VTy->getLLVMType()); + } + deducedTypes.transparentTypes[allocaPrev].insert(VTy->clone()); - uint64_t Size = DL.getTypeAllocSize(VTy->getLLVMType()); + + Value *Size = llvm::ConstantInt::get(B.getInt8Ty(), SizeInBytes); llvm::CallInst *memcpy_call = B.CreateMemCpy( allocaPrev, allocaPrev->getPointerAlignment(DL), diff --git a/testing/test.py b/testing/test.py index bcb5bfa..b3125ce 100644 --- a/testing/test.py +++ b/testing/test.py @@ -1,4 +1,5 @@ import os +import shutil import subprocess import pytest @@ -46,13 +47,25 @@ def run_command(command, cwd=None): def compile_with_aspis(source_file, output_file, options, llvm_bin, build_dir): """Compile a file using ASPIS with specified options.""" - command = f"{ASPIS_SCRIPT} --llvm-bin {llvm_bin} {options} {source_file} -o {output_file}.out --build-dir ./{build_dir} --verbose" + command = f"{ASPIS_SCRIPT} --llvm-bin {llvm_bin} {options} {source_file} -o {output_file}.out --build-dir ./{build_dir} --no-cleanup --verbose" print(command) stdout, stderr, exit_code = run_command(command) if exit_code != 0: raise RuntimeError(f"[{output_file}] Compilation failed: {stderr}") return stdout +def preserve_out_ll(build_dir, test_name): + out_ll = os.path.join(build_dir, "out.ll") + if os.path.exists(out_ll): + os.makedirs("failed-out-ll", exist_ok=True) + dest = os.path.join("failed-out-ll", f"{test_name}.ll") + shutil.copyfile(out_ll, dest) + +def cleanup_out_ll(build_dir): + out_ll = os.path.join(build_dir, "out.ll") + if os.path.exists(out_ll): + os.remove(out_ll) + # Compile without ASPIS to get expected output def compile_without_aspis(source_file, output_file, llvm_bin, build_dir): """Compile a file without ASPIS.""" @@ -142,13 +155,19 @@ def test_aspis(test_data, use_container, aspis_addopt, data_technique, cfc_techn test_name_complete = f"{test_name}_{data_technique}_{cfc_technique}".replace("--", "").replace(" ", "_").replace("=", "") - # Compile the source file - compilation_result = compile_with_aspis(source_path, test_name_complete, aspis_options, llvm_bin, docker_build_dir) - record_comparison_counter(test_name_complete, compilation_result) - - # Execute the binary and check output - result = execute_binary(local_build_dir, test_name_complete) - assert result == expected_output, f"Test {test_name_complete} failed: {result}" + try: + # Compile the source file + compilation_result = compile_with_aspis(source_path, test_name_complete, aspis_options, llvm_bin, docker_build_dir) + record_comparison_counter(test_name_complete, compilation_result) + + # Execute the binary and check output + result = execute_binary(local_build_dir, test_name_complete) + assert result == expected_output, f"Test {test_name_complete} failed: {result}" + except Exception: + preserve_out_ll(local_build_dir, test_name_complete) + raise + else: + cleanup_out_ll(local_build_dir) if __name__ == "__main__": pytest.main() From 5cc19f89282ea345dd499ca48ec9b45b8b047e71 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Sat, 16 May 2026 11:12:55 +0200 Subject: [PATCH 07/11] upd(EDDI): restored consistency checks on function pointers --- passes/EDDI.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index aec5b92..5696c30 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -755,11 +755,6 @@ void EDDI::comparePtrs(std::vector *CmpInstructions, Value &V1, Value & * for finding a _b = load c _a = load _b */ - if(isa(V1) || isa(V2)) { - errs() << "Warning: Comparing functions\n"; - return; - } - Value *F1 = &V1; Value *F2 = &V2; @@ -934,7 +929,9 @@ void EDDI::addConsistencyChecks( Value *Original = cast(I).getCalledOperand(); Value *Copy = Duplicate; - compareValues(&CmpInstructions, *Original, *Copy, B); + // Directly comparing the function pointers + CmpInstructions.push_back(B.CreateCmp(CmpInst::ICMP_EQ, Original, Copy)); + comparisonCounter++; } } @@ -1001,11 +998,6 @@ void EDDI::createCompareOnOperand(std::vector *CmpInstructions, Value * } void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B) { - if(isa(V1) || isa(V2)) { - errs() << "Not comparing functions\n"; - return; - } - if(deducedTypes.transparentTypes.find(&V1) == deducedTypes.transparentTypes.end()) { return; } From b8a0b2e4f6c8d8024c318a4970d076c26058dd33 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Sat, 16 May 2026 12:25:19 +0200 Subject: [PATCH 08/11] fix(EDDI): avoid duplication of consistency checks --- passes/EDDI.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 5696c30..538d535 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -930,7 +930,9 @@ void EDDI::addConsistencyChecks( Value *Copy = Duplicate; // Directly comparing the function pointers - CmpInstructions.push_back(B.CreateCmp(CmpInst::ICMP_EQ, Original, Copy)); + auto Cmp = B.CreateCmp(CmpInst::ICMP_EQ, Original, Copy); + CmpInstructions.push_back(Cmp); + DuplicatedInstructionMap.insert(std::pair(Cmp, Cmp)); comparisonCounter++; } } @@ -1013,10 +1015,14 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value comparePtrs(CmpInstructions, V1, V2, B); } else if(V1Ty->isPrimitiveTT()) { if(V1Ty->isIntegerTyOrPtrTo()) { - CmpInstructions->push_back(B.CreateCmp(CmpInst::ICMP_EQ, &V1, &V2)); + auto Cmp = B.CreateCmp(CmpInst::ICMP_EQ, &V1, &V2); + CmpInstructions->push_back(Cmp); + DuplicatedInstructionMap.insert(std::pair(Cmp, Cmp)); comparisonCounter++; } else if(V1Ty->isFloatingPointTyOrPtrTo()) { - CmpInstructions->push_back(B.CreateCmp(CmpInst::FCMP_UEQ, &V1, &V2)); + auto Cmp = B.CreateCmp(CmpInst::FCMP_UEQ, &V1, &V2); + CmpInstructions->push_back(Cmp); + DuplicatedInstructionMap.insert(std::pair(Cmp, Cmp)); comparisonCounter++; } else { errs() << "Warning: Unsupported primitive type for comparison: " << V1Ty->toString() << "\n"; From 431c1670ff339afaf99ef47e3d9a8c870e0fa109 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Sat, 16 May 2026 13:39:44 +0200 Subject: [PATCH 09/11] fix(EDDI): correctly check to exclude or to duplicate names in case of _ret functions --- passes/EDDI.cpp | 6 ++++-- passes/Utils/Utils.cpp | 21 +++++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 538d535..f5ae8cd 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -505,8 +505,10 @@ void EDDI::preprocess(Module &Md) { if(to_harden && toHardenFunctions.find(CalledFn) == toHardenFunctions.end() && JustAddedFns.find(CalledFn) == JustAddedFns.end() && getFunctionDuplicate(CalledFn) == NULL && - (FuncAnnotations.find(CalledFn) == FuncAnnotations.end() || !FuncAnnotations.find(CalledFn)->second.starts_with("exclude")) && - !CalledFn->getName().starts_with("__clang_call_terminate")) { + (FuncAnnotations.find(CalledFn) == FuncAnnotations.end() || + (!FuncAnnotations.find(CalledFn)->second.starts_with("exclude") && + !FuncAnnotations.find(CalledFn)->second.starts_with("to_duplicate"))) && + !isToDuplicateName(CalledFn->getName()) && !CalledFn->getName().starts_with("__clang_call_terminate")) { // If is a new function to and it isn't/hasn't a duplicate version toAddFns.insert(CalledFn); // LLVM_DEBUG(dbgs() << "[REDDI] Added: " << CalledFn->getName() << "\n"); diff --git a/passes/Utils/Utils.cpp b/passes/Utils/Utils.cpp index 6cabb1c..581b0bb 100644 --- a/passes/Utils/Utils.cpp +++ b/passes/Utils/Utils.cpp @@ -230,17 +230,18 @@ bool isToDuplicate(CallBase *CInstr) { } bool isToDuplicateName(StringRef FnMangledName) { + if(FnMangledName.ends_with("_ret")) { + FnMangledName = FnMangledName.substr(0, FnMangledName.size() - 4); + } + auto FnName = demangle(FnMangledName.str()); - // outs() << FnName << " " << FnName.find("std::") << "\n"; - if(FnName.find("operator new") == 0 || FnName.find("std::") != FnName.npos || FnName.find("fmt::") != FnName.npos || FnName.find("Eigen::") != FnName.npos) { - // outs() << "duplicated\n"; - if(FnName.find("std::ostream") != FnName.npos || FnName.find("std::basic_ostream") != FnName.npos || FnName.find("std::basic_ios") != FnName.npos || FnName.find("std::basic_ios") != FnName.npos) { - // outs() << "not duplicated\n"; - return false; - } + if(FnName.find("operator new") == 0 || FnName.find("std::") != FnName.npos || FnName.find("fmt::") != FnName.npos || FnName.find("Eigen::") != FnName.npos) { - if(FnName.find("std::thread") != FnName.npos) { + if(FnName.find("std::ostream") != FnName.npos || + FnName.find("std::basic_ostream") != FnName.npos || + FnName.find("std::basic_ios") != FnName.npos || + FnName.find("std::thread") != FnName.npos) { return false; } @@ -251,6 +252,10 @@ bool isToDuplicateName(StringRef FnMangledName) { } bool isToExcludeName(StringRef FnMangledName) { + if(FnMangledName.ends_with("_ret")) { + FnMangledName = FnMangledName.substr(0, FnMangledName.size() - 4); + } + auto FnName = demangle(FnMangledName.str()); if(FnName.find("std::thread") != FnName.npos) { From d88f8b8f2cc28fe1dc7ecf228993227ea31ce7dc Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Sun, 17 May 2026 17:03:42 +0200 Subject: [PATCH 10/11] upd(EDDI): avoid creating the _ret version of std:: functions and avoid dereferencing ::end() iterator --- passes/ASPIS.h | 1 + passes/EDDI.cpp | 18 ++++++++++++++++++ passes/FuncRetToRef.cpp | 9 +++++++++ 3 files changed, 28 insertions(+) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 2d3a3f5..1d250c5 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -63,6 +63,7 @@ class EDDI : public PassInfoMixin { Instruction* cloneInstr(Instruction &I); void duplicateOperands (Instruction &I, BasicBlock &ErrBB); Value* getPtrFinalValue(Value &V); + bool ptrNotDereferenceable(Value &V); void comparePtrs(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B); void addConsistencyChecks(Instruction &I, BasicBlock &ErrBB); void fixFuncValsPassedByReference(Instruction &I, IRBuilder<> &B); diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index f5ae8cd..c6935e3 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -743,6 +743,19 @@ Value *EDDI::getPtrFinalValue(Value &V) { return res; } +bool EDDI::ptrNotDereferenceable(Value &V) { + if(isa(V) && cast(V).getCalledFunction() != nullptr) { + auto DemangledName = demangle(cast(V).getCalledFunction()->getName().str()); + + if(DemangledName.find("std::") != DemangledName.npos && DemangledName.find("::end()") != DemangledName.npos) { + errs() << "Warning: Pointer " << V << " is not dereferenceable because it is the result of an end() function\n"; + return true; + } + } + + return false; +} + // Follows the pointers V1 and V2 using getPtrFinalValue() and adds a compare // instruction using the IRBuilder B. void EDDI::comparePtrs(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B) { @@ -793,6 +806,11 @@ void EDDI::comparePtrs(std::vector *CmpInstructions, Value &V1, Value & errs() << "Warning 2: Can't find final value for pointer " << V1 << "\n"; return; } + + if(ptrNotDereferenceable(V1)) { + errs() << "Warning 1: Pointer " << V1 << " is not dereferenceable\n"; + return; + } assert(((V1Ty->isPointerTT() && V1.getType()->isPointerTy()) || (V2Ty->isPointerTT() && V2.getType()->isPointerTy())) && "No pointers found"); diff --git a/passes/FuncRetToRef.cpp b/passes/FuncRetToRef.cpp index b6c07c0..3b46c9e 100644 --- a/passes/FuncRetToRef.cpp +++ b/passes/FuncRetToRef.cpp @@ -20,6 +20,7 @@ #include "llvm/Transforms/Utils/Cloning.h" #include "Utils/Utils.h" #include "llvm/Passes/PassBuilder.h" +#include "llvm/Demangle/Demangle.h" #include "llvm/Passes/PassPlugin.h" #include @@ -243,6 +244,14 @@ PreservedAnalyses FuncRetToRef::run(Module &Md, ModuleAnalysisManager &AM) { } for (Function *Fn : FnList) { + // Skip library functions as we don't want to change their signature + if(Fn->hasName()) { + auto demangledName = demangle(Fn->getName().str()); + if(demangledName.find("std::") != demangledName.npos) { + continue; + } + } + Function *newFn = updateFnSignature(*Fn, Md); if (newFn != NULL) { updateFunctionCalls(*Fn, *newFn); From f19db407926c74d4670a3e233c2c140667967226 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Mon, 18 May 2026 16:13:43 +0200 Subject: [PATCH 11/11] upd(EDDI): temporary argument duplication best effort in case the type contains an opaque pointer --- passes/EDDI.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index c6935e3..c0e861a 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -2059,9 +2059,15 @@ bool EDDI::temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilde tda::TransparentType *VTy = TTIter->second.begin()->get(); // Cannot do argument duplication if the type contains opaque pointers since we cannot find the final value to duplicate - if (VTy->containsOpaquePtr()) { - errs() << "Error! TAD value contains opaque pointer " << *value << "\n"; - return false; + { + auto VTyCopy = VTy; + while(VTyCopy->isPointerTT()) { + if (VTyCopy->isOpaquePtr()) { + errs() << "Warning! TAD value contains opaque pointer " << *value << "\n"; + return false; + } + VTyCopy = VTyCopy->getPointedType(); + } } int indirections = 0;