From 211fe9dacdea8784d4d3ca2c537225a050acda61 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Tue, 16 Jun 2026 19:28:41 +0200 Subject: [PATCH 01/20] upd(FuncRetToRef): removed volatile load and stores --- passes/FuncRetToRef.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/FuncRetToRef.cpp b/passes/FuncRetToRef.cpp index 3b46c9e..5f4c364 100644 --- a/passes/FuncRetToRef.cpp +++ b/passes/FuncRetToRef.cpp @@ -118,7 +118,7 @@ void FuncRetToRef::updateRetInstructions(Function &Fn) { Value *ReturnPtr = Fn.getArg(Fn.arg_size()-1); // the last argument is the return ptr // Store the returnvalue in the returnptr - B.CreateStore(ReturnValue, ReturnPtr, true); + B.CreateStore(ReturnValue, ReturnPtr); // create a ret instruction B.CreateRetVoid(); @@ -208,7 +208,7 @@ void FuncRetToRef::updateFunctionCalls(Function &Fn, Function &NewFn) { abort(); } // use the load on the return value instead of the previous function output - Instruction *TmpLoad = B.CreateLoad(CInstr->getType(), TmpAlloca, true); + Instruction *TmpLoad = B.CreateLoad(CInstr->getType(), TmpAlloca); createdNewCall = true; CInstr->replaceNonMetadataUsesWith(TmpLoad); } From 2840ffafb86dc3369e583c04c8021f4d604c6138 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Tue, 16 Jun 2026 19:29:37 +0200 Subject: [PATCH 02/20] upd(Utils): update functions to exclude and duplicate values --- passes/Utils/Utils.cpp | 33 +++++++++++++++++++++++++++------ passes/Utils/Utils.h | 3 ++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/passes/Utils/Utils.cpp b/passes/Utils/Utils.cpp index 581b0bb..abc0ea1 100644 --- a/passes/Utils/Utils.cpp +++ b/passes/Utils/Utils.cpp @@ -218,12 +218,15 @@ StringRef getLinkageName(const LinkageMap &linkageMap, const std::string &functi } } -bool isToDuplicate(CallBase *CInstr) { - Intrinsic::ID intrinsicID = CInstr->getIntrinsicID(); - if (intrinsicID != Intrinsic::not_intrinsic) { - return true; - } else if(CInstr->getCalledFunction() != NULL && isToDuplicateName(CInstr->getCalledFunction()->getName())) { - return true; +bool isToDuplicate(Value *V) { + if(isa(V)) { + CallBase *CInstr = cast(V); + Intrinsic::ID intrinsicID = CInstr->getIntrinsicID(); + if (intrinsicID != Intrinsic::not_intrinsic) { + return true; + } else if(CInstr->getCalledFunction() != NULL && isToDuplicateName(CInstr->getCalledFunction()->getName())) { + return true; + } } return false; @@ -251,6 +254,24 @@ bool isToDuplicateName(StringRef FnMangledName) { return false; } +bool isToExclude(Value *V) { + if(isa(V)) { + Instruction *Inst = cast(V); + if (Inst->isVolatile()) { + return true; + } + } + + if(isa(V)) { + CallBase *CInstr = cast(V); + if(CInstr->getCalledFunction() != NULL && isToExcludeName(CInstr->getCalledFunction()->getName())) { + return true; + } + } + + return false; +} + bool isToExcludeName(StringRef FnMangledName) { if(FnMangledName.ends_with("_ret")) { FnMangledName = FnMangledName.substr(0, FnMangledName.size() - 4); diff --git a/passes/Utils/Utils.h b/passes/Utils/Utils.h index cdc7f0b..22313f8 100644 --- a/passes/Utils/Utils.h +++ b/passes/Utils/Utils.h @@ -45,8 +45,9 @@ LinkageMap mapFunctionLinkageNames(const Module &M); void printLinkageMap(const LinkageMap &linkageMap); StringRef getLinkageName(const LinkageMap &linkageMap, const std::string &functionName); bool isToDuplicateName(StringRef FnMangledName); -bool isToDuplicate(CallBase *CInstr); +bool isToDuplicate(Value *CInstr); bool isToExcludeName(StringRef FnMangledName); +bool isToExclude(Value *V); void createFtFuncs(Module &Md); From ee9147f22f8171c0b1b0e61ed9764eaf11562cd1 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Tue, 16 Jun 2026 19:31:45 +0200 Subject: [PATCH 03/20] upd(EDDI): create synchronizeFunctionArguments --- passes/ASPIS.h | 2 +- passes/EDDI.cpp | 76 ++++++++++++++++++++++++++----------------------- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 1d250c5..c1c756e 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -76,7 +76,7 @@ class EDDI : public PassInfoMixin { bool isValueDuplicated(Instruction &V); Function *duplicateFnArgs(Function &Fn, Module &Md); void CreateErrBB(Module &Md, Function &Fn, BasicBlock *ErrBB); - bool temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilder<> &B); + bool synchronizeFunctionArguments(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); diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index c0e861a..dfa6809 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -701,7 +701,7 @@ void EDDI::duplicateOperands( } } else if (isa(I) && isa(V) && cast(V)->isConstant()) { IRBuilder<> B(&I); - temporaryArgumentDuplication(*I.getModule(), V, B); + synchronizeFunctionArguments(*I.getModule(), V, B); } if (IClone != nullptr) { @@ -780,17 +780,11 @@ void EDDI::comparePtrs(std::vector *CmpInstructions, Value &V1, Value & 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; } @@ -1096,16 +1090,8 @@ void EDDI::fixFuncValsPassedByReference( Value *Duplicate = getDuplicateValue(Operand, &I); if (Duplicate != nullptr) { - Value *Original = Operand; - Value *Copy = Duplicate; - if(Original->getType()->isPointerTy() && Copy->getType()->isPointerTy()) { - Type *OriginalType = Original->getType(); - Instruction *TmpLoad = B.CreateLoad(OriginalType, Original); - Instruction *TmpStore = B.CreateStore(TmpLoad, Copy); - DuplicatedInstructionMap.insert( - std::pair(TmpLoad, TmpLoad)); - DuplicatedInstructionMap.insert( - std::pair(TmpStore, TmpStore)); + if(Operand->getType()->isPointerTy() && Duplicate->getType()->isPointerTy()) { + synchronizeFunctionArguments(*I.getModule(), Operand, B); } } } @@ -1975,7 +1961,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { if(Arg->getType()->isPointerTy() && !CInstr->isByValArgument(i) && isa(Arg) && !isa(Arg)) { // If cannot perform TAD, do not duplicate Arg - temporaryArgumentDuplication(Md, Arg, B); + synchronizeFunctionArguments(Md, Arg, B); } else { // Otherwise pass two times the same arg DuplicatedInstructionMap.insert(std::pair(Arg, Arg)); // TODO: Check if needed @@ -2048,7 +2034,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { return PreservedAnalyses::none(); } -bool EDDI::temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilder<> &B) { +bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B) { const llvm::DataLayout &DL = Md.getDataLayout(); auto TTIter = deducedTypes.transparentTypes.find(value); @@ -2088,44 +2074,62 @@ bool EDDI::temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilde } } - // currentPtr is now the pointer to the final value - + bool hasPerformedTAD = false; + Value *valueDup = nullptr; 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()); + auto valueDupIt = DuplicatedInstructionMap.find(value); + if(valueDupIt == DuplicatedInstructionMap.end()) { + hasPerformedTAD = true; + // currentPtr is now the pointer to the final value + + AllocaInst *allocaPrev = nullptr; + + if(isa(currentPtr)) { + allocaPrev = B.CreateAlloca(VTy->getLLVMType(), ConstantInt::get(B.getInt8Ty(), SizeInBytes)); + } else { + allocaPrev = B.CreateAlloca(VTy->getLLVMType()); + } + allocaPrev->moveAfter(allocaPrev->getParent()->getParent()->getEntryBlock().getFirstNonPHIOrDbgOrAlloca()); + deducedTypes.transparentTypes[allocaPrev].insert(VTy->clone()); + valueDup = allocaPrev; + } else { + hasPerformedTAD = false; + valueDup = valueDupIt->second; + } Value *Size = llvm::ConstantInt::get(B.getInt8Ty(), SizeInBytes); llvm::CallInst *memcpy_call = B.CreateMemCpy( - allocaPrev, allocaPrev->getPointerAlignment(DL), - currentPtr, allocaPrev->getPointerAlignment(DL), + valueDup, valueDup->getPointerAlignment(DL), + currentPtr, valueDup->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; + if(hasPerformedTAD) { + for (int i = 0; i < indirections; ++i) { + VTyPtr = VTyPtr->getPointerToType(); + auto *allocaCurr = B.CreateAlloca(VTyPtr->getLLVMType()); + allocaCurr->moveAfter(allocaCurr->getParent()->getParent()->getEntryBlock().getFirstNonPHIOrDbgOrAlloca()); + deducedTypes.transparentTypes[allocaCurr].insert(VTyPtr->getPointerToType()->clone()); + B.CreateStore(valueDup, allocaCurr); + valueDup = allocaCurr; + } + + DuplicatedInstructionMap.emplace(valueDup, value); + DuplicatedInstructionMap.emplace(value, valueDup); } - DuplicatedInstructionMap.emplace(allocaPrev, value); - DuplicatedInstructionMap.emplace(value, allocaPrev); DuplicatedInstructionMap.insert(std::pair(memcpy_call, memcpy_call)); return true; From e3c46c6da6455e5d63cffbbf33344972cfdc0cbb Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Tue, 16 Jun 2026 19:32:15 +0200 Subject: [PATCH 04/20] upd(EDDI): exclude volatile and inline asm --- passes/EDDI.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index dfa6809..b7031dd 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -1370,6 +1370,10 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { return 0; } + if(I.isVolatile() || (isa(I) && cast(I).isInlineAsm())) { + return 0; + } + Instruction *clonedInst = nullptr; int res = 0; From df6a83c83cbf392f7be7bd5530928005db5f45be Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Tue, 16 Jun 2026 19:32:55 +0200 Subject: [PATCH 05/20] upd(EDDI): update to exclude and to duplicate functions --- passes/EDDI.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index b7031dd..5e4d0dc 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -1461,13 +1461,13 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { Function *Callee = CInstr->getCalledFunction(); Callee = getFunctionFromDuplicate(Callee); - if(CInstr->getCalledFunction() != NULL && isToExcludeName(CInstr->getCalledFunction()->getName())) { + if((FuncAnnotations.find(Callee) != FuncAnnotations.end() && FuncAnnotations.find(Callee)->second.starts_with("exclude")) || (Callee != NULL && isToExclude(CInstr))) { return 0; } // check if the function call has to be duplicated if ((FuncAnnotations.find(Callee) != FuncAnnotations.end() && FuncAnnotations.find(Callee)->second.starts_with("to_duplicate")) || - isToDuplicate(CInstr)) { + (Callee != NULL && isToDuplicate(CInstr))) { // duplicate the instruction clonedInst = cloneInstr(*CInstr); From 48cf366a57e9a2993acaffc5cf10166b4382b609 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Wed, 17 Jun 2026 01:00:21 +0200 Subject: [PATCH 06/20] fix(EDDI): fix TAD in case of global variables --- passes/ASPIS.h | 4 ++-- passes/EDDI.cpp | 38 ++++++++++++++++++-------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index c1c756e..8678b3e 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -76,8 +76,8 @@ class EDDI : public PassInfoMixin { bool isValueDuplicated(Instruction &V); Function *duplicateFnArgs(Function &Fn, Module &Md); void CreateErrBB(Module &Md, Function &Fn, BasicBlock *ErrBB); - bool synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B); - Value *getDuplicateValue(Value *V, Instruction *I); + bool synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B, Instruction *I); + Value *getDuplicateValue(Value *V, Function *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); diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 5e4d0dc..4a4390a 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -597,7 +597,7 @@ EDDI::cloneInstr(Instruction &I) { return IClone; } -Value *EDDI::getDuplicateValue(Value *V, Instruction *I) { +Value *EDDI::getDuplicateValue(Value *V, Function *Fn) { // Fast path if V is a local variable, it should have only one duplicate if(!isa(V) || isa(V)) { assert((DuplicatedInstructionMap.count(V) <= 1) && "Local variable has more than one duplicate"); @@ -620,7 +620,7 @@ Value *EDDI::getDuplicateValue(Value *V, Instruction *I) { return duplicate; } else { // If it is an instruction, we need to check if it is in the same function of I - if (isa(duplicate) && cast(duplicate)->getParent()->getParent() == I->getParent()->getParent()) { + if (isa(duplicate) && cast(duplicate)->getParent()->getParent() == Fn) { return duplicate; } } @@ -643,7 +643,7 @@ void EDDI::duplicateOperands( BasicBlock &ErrBB) { // see if I has a clone - Value *Clone = getDuplicateValue(&I, &I); + Value *Clone = getDuplicateValue(&I, I.getFunction()); Instruction *IClone = nullptr; if(Clone != nullptr && isa(Clone)) { IClone = cast(Clone); @@ -671,7 +671,7 @@ void EDDI::duplicateOperands( if (IClone != nullptr) { GEPOperator *GEPOperand = cast(IClone->getOperand(J)); Value *PtrOperand = GEPOperand->getPointerOperand(); - Value *ClonePtrOperand = getDuplicateValue(PtrOperand, &I); + Value *ClonePtrOperand = getDuplicateValue(PtrOperand, I.getFunction()); // update the duplicate GEP operator using the duplicate of the pointer // operand if (ClonePtrOperand != nullptr) { @@ -701,12 +701,12 @@ void EDDI::duplicateOperands( } } else if (isa(I) && isa(V) && cast(V)->isConstant()) { IRBuilder<> B(&I); - synchronizeFunctionArguments(*I.getModule(), V, B); + synchronizeFunctionArguments(*I.getModule(), V, B, &I); } if (IClone != nullptr) { // use the duplicated instruction as operand of IClone - Value *CloneOperand = getDuplicateValue(V, &I); + Value *CloneOperand = getDuplicateValue(V, I.getFunction()); if (CloneOperand != nullptr) { IClone->setOperand(J, CloneOperand); // set the J-th operand with the duplicate value } @@ -938,7 +938,7 @@ void EDDI::addConsistencyChecks( // if the instruction is a call with indirect function, we try to get a compare if(isa(I) && cast(I).isIndirectCall()) { - Value *Duplicate = getDuplicateValue(cast(I).getCalledOperand(), &I); + Value *Duplicate = getDuplicateValue(cast(I).getCalledOperand(), I.getFunction()); if (Duplicate != nullptr) { Value *Original = cast(I).getCalledOperand(); Value *Copy = Duplicate; @@ -1087,11 +1087,11 @@ void EDDI::fixFuncValsPassedByReference( Value *V = I.getOperand(i); if (isa(V)) { Instruction *Operand = cast(V); - Value *Duplicate = getDuplicateValue(Operand, &I); + Value *Duplicate = getDuplicateValue(Operand, I.getFunction()); if (Duplicate != nullptr) { if(Operand->getType()->isPointerTy() && Duplicate->getType()->isPointerTy()) { - synchronizeFunctionArguments(*I.getModule(), Operand, B); + synchronizeFunctionArguments(*I.getModule(), Operand, B, &I); } } } @@ -1257,7 +1257,7 @@ int EDDI::transformCallBaseInst(CallBase *CInstr, IRBuilder<> &B, BasicBlock &Er Value *Arg = CInstr->getArgOperand(i); // see if Original has a copy - Value *Copy = getDuplicateValue(Arg, CInstr); + Value *Copy = getDuplicateValue(Arg, CInstr->getFunction()); if(Copy == nullptr) { Copy = Arg; } @@ -1425,7 +1425,7 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { if (IClone->isIdenticalTo(&I)) { IClone->eraseFromParent(); - Value *Copy = getDuplicateValue(&I, &I); + Value *Copy = getDuplicateValue(&I, I.getFunction()); if(Copy != nullptr) { DuplicatedInstructionMap.erase(Copy); DuplicatedInstructionMap.erase(&I); @@ -1956,7 +1956,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { Value *Arg = CInstr->getArgOperand(i); // If argument has already a duplicate, nothing to do - if(getDuplicateValue(Arg, CInstr) != nullptr || !isa(Arg)) { + if(getDuplicateValue(Arg, CInstr->getFunction()) != nullptr || !isa(Arg)) { // If Argument already duplicated continue to next argument continue; } @@ -1965,7 +1965,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { if(Arg->getType()->isPointerTy() && !CInstr->isByValArgument(i) && isa(Arg) && !isa(Arg)) { // If cannot perform TAD, do not duplicate Arg - synchronizeFunctionArguments(Md, Arg, B); + synchronizeFunctionArguments(Md, Arg, B, CInstr); } else { // Otherwise pass two times the same arg DuplicatedInstructionMap.insert(std::pair(Arg, Arg)); // TODO: Check if needed @@ -2038,7 +2038,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { return PreservedAnalyses::none(); } -bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B) { +bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B, Instruction *I) { const llvm::DataLayout &DL = Md.getDataLayout(); auto TTIter = deducedTypes.transparentTypes.find(value); @@ -2079,7 +2079,7 @@ bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilde } bool hasPerformedTAD = false; - Value *valueDup = nullptr; + Value *valueDup = getDuplicateValue(value, I->getFunction()); uint64_t SizeInBytes = 0; if(isa(currentPtr)) { auto *gepInst = cast(currentPtr); @@ -2088,8 +2088,7 @@ bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilde SizeInBytes = DL.getTypeAllocSize(VTy->getLLVMType()); } - auto valueDupIt = DuplicatedInstructionMap.find(value); - if(valueDupIt == DuplicatedInstructionMap.end()) { + if(valueDup == nullptr) { hasPerformedTAD = true; // currentPtr is now the pointer to the final value @@ -2106,7 +2105,6 @@ bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilde valueDup = allocaPrev; } else { hasPerformedTAD = false; - valueDup = valueDupIt->second; } Value *Size = llvm::ConstantInt::get(B.getInt8Ty(), SizeInBytes); @@ -2130,8 +2128,8 @@ bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilde valueDup = allocaCurr; } - DuplicatedInstructionMap.emplace(valueDup, value); - DuplicatedInstructionMap.emplace(value, valueDup); + DuplicatedInstructionMap.insert(std::pair(valueDup, value)); + DuplicatedInstructionMap.insert(std::pair(value, valueDup)); } DuplicatedInstructionMap.insert(std::pair(memcpy_call, memcpy_call)); From 931f7bf391b83b1ceaae3237f1dab728298270a6 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Wed, 17 Jun 2026 14:15:07 +0200 Subject: [PATCH 07/20] upd(EDDI): now synchronizeFunctionArguments can synchronize the argument before or after the instruction --- passes/ASPIS.h | 2 +- passes/EDDI.cpp | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 8678b3e..2cc4fca 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -76,7 +76,7 @@ class EDDI : public PassInfoMixin { bool isValueDuplicated(Instruction &V); Function *duplicateFnArgs(Function &Fn, Module &Md); void CreateErrBB(Module &Md, Function &Fn, BasicBlock *ErrBB); - bool synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B, Instruction *I); + bool synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B, Instruction *I, bool before); Value *getDuplicateValue(Value *V, Function *I); void createCompareOnOperand(std::vector *CmpInstructions, Value *V, Instruction &I, IRBuilder<> &B); void compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B); diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 4a4390a..e2ef9dd 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -701,7 +701,7 @@ void EDDI::duplicateOperands( } } else if (isa(I) && isa(V) && cast(V)->isConstant()) { IRBuilder<> B(&I); - synchronizeFunctionArguments(*I.getModule(), V, B, &I); + synchronizeFunctionArguments(*I.getModule(), V, B, &I, true); } if (IClone != nullptr) { @@ -1091,7 +1091,7 @@ void EDDI::fixFuncValsPassedByReference( if (Duplicate != nullptr) { if(Operand->getType()->isPointerTy() && Duplicate->getType()->isPointerTy()) { - synchronizeFunctionArguments(*I.getModule(), Operand, B, &I); + synchronizeFunctionArguments(*I.getModule(), Operand, B, &I, false); } } } @@ -1462,6 +1462,19 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { Callee = getFunctionFromDuplicate(Callee); if((FuncAnnotations.find(Callee) != FuncAnnotations.end() && FuncAnnotations.find(Callee)->second.starts_with("exclude")) || (Callee != NULL && isToExclude(CInstr))) { + IRBuilder<> B(CInstr); + fixFuncValsPassedByReference(*CInstr, B); + +#ifdef CHECK_AT_CALLS +#if (SELECTIVE_CHECKING == 1) + if(I.getParent()->getTerminator() == NULL) { + errs() << "Malformed block!\n"; + I.getParent()->print(errs()); + errs() << "\n"; + } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) +#endif + addConsistencyChecks(I, ErrBB); +#endif return 0; } @@ -1965,7 +1978,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { if(Arg->getType()->isPointerTy() && !CInstr->isByValArgument(i) && isa(Arg) && !isa(Arg)) { // If cannot perform TAD, do not duplicate Arg - synchronizeFunctionArguments(Md, Arg, B, CInstr); + synchronizeFunctionArguments(Md, Arg, B, CInstr, true); } else { // Otherwise pass two times the same arg DuplicatedInstructionMap.insert(std::pair(Arg, Arg)); // TODO: Check if needed @@ -2038,7 +2051,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { return PreservedAnalyses::none(); } -bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B, Instruction *I) { +bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B, Instruction *I, bool before) { const llvm::DataLayout &DL = Md.getDataLayout(); auto TTIter = deducedTypes.transparentTypes.find(value); @@ -2090,6 +2103,7 @@ bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilde if(valueDup == nullptr) { hasPerformedTAD = true; + assert(hasPerformedTAD && before && "TAD shall be performed only for syncrhonization before the instruction"); // currentPtr is now the pointer to the final value AllocaInst *allocaPrev = nullptr; @@ -2113,7 +2127,19 @@ bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilde valueDup, valueDup->getPointerAlignment(DL), currentPtr, valueDup->getPointerAlignment(DL), Size); - + if(!before) { + if(!I->isTerminator()) { + memcpy_call->moveAfter(I); + } else { + if(isa(I)) { + memcpy_call->moveBefore(cast(I)->getNormalDest()->getFirstNonPHIOrDbgOrAlloca()); + } else { + errs() << "Error: not handled instruction for synchronize function arguments\n"; + abort(); + } + } + } + auto VTyPtr = VTy->clone(); // Now we need to create as many allocas as the number of pointer indirections From 9d78358efce2dc433bc51bb1711a80804627e291 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Wed, 17 Jun 2026 17:09:37 +0200 Subject: [PATCH 08/20] feat(EDDI): duplicate volatile integer after loads and create consistency checks before store --- passes/EDDI.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index e2ef9dd..3b49342 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -1370,7 +1370,27 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { return 0; } - if(I.isVolatile() || (isa(I) && cast(I).isInlineAsm())) { + if(I.isVolatile()) { + if(isa(I) && I.getType()->isIntegerTy()) { + IRBuilder<> B(&I); + auto Idup = B.CreateAdd(&I, llvm::ConstantInt::get(I.getType(), 0)); + cast(Idup)->moveAfter(&I); + DuplicatedInstructionMap.insert(std::pair(&I, Idup)); + DuplicatedInstructionMap.insert(std::pair(Idup, &I)); + } else if(isa(I)) { +#ifdef CHECK_AT_STORES +#if (SELECTIVE_CHECKING == 1) + if(I.getParent()->getTerminator() == NULL) { + errs() << "Malformed block!\n"; + I.getParent()->print(errs()); + errs() << "\n"; + } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) +#endif + addConsistencyChecks(I, ErrBB); +#endif + } + return 0; + } else if (isa(I) && cast(I).isInlineAsm()) { return 0; } From 3ec5ee94c0586e6edb4ca78f1be8076df1e287c4 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Wed, 17 Jun 2026 17:52:45 +0200 Subject: [PATCH 09/20] feat(EDDI): duplicate volatiles explicitly marked as to_duplicate or to_harden --- passes/EDDI.cpp | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 3b49342..668989f 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -1371,25 +1371,43 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { } if(I.isVolatile()) { - if(isa(I) && I.getType()->isIntegerTy()) { - IRBuilder<> B(&I); - auto Idup = B.CreateAdd(&I, llvm::ConstantInt::get(I.getType(), 0)); - cast(Idup)->moveAfter(&I); - DuplicatedInstructionMap.insert(std::pair(&I, Idup)); - DuplicatedInstructionMap.insert(std::pair(Idup, &I)); + bool shouldDuplicateAnyway = false; + if(isa(I)) { + if(FuncAnnotations.find(cast(I).getPointerOperand()) != FuncAnnotations.end() && + (FuncAnnotations.find(cast(I).getPointerOperand())->second.starts_with("to_duplicate") || FuncAnnotations.find(cast(I).getPointerOperand())->second.starts_with("to_harden"))) { + shouldDuplicateAnyway = true; + } else if(I.getType()->isIntegerTy()) { + IRBuilder<> B(&I); + auto Idup = B.CreateAdd(&I, llvm::ConstantInt::get(I.getType(), 0)); + cast(Idup)->moveAfter(&I); + DuplicatedInstructionMap.insert(std::pair(&I, Idup)); + DuplicatedInstructionMap.insert(std::pair(Idup, &I)); + } else if(I.getType()->isFloatingPointTy()) { + IRBuilder<> B(&I); + auto Idup = B.CreateAdd(&I, llvm::ConstantFP::get(I.getType(), 0)); + cast(Idup)->moveAfter(&I); + DuplicatedInstructionMap.insert(std::pair(&I, Idup)); + DuplicatedInstructionMap.insert(std::pair(Idup, &I)); + } } else if(isa(I)) { + if(getDuplicateValue(cast(I).getPointerOperand(), I.getFunction()) != nullptr) { + shouldDuplicateAnyway = true; + } else { #ifdef CHECK_AT_STORES #if (SELECTIVE_CHECKING == 1) - if(I.getParent()->getTerminator() == NULL) { - errs() << "Malformed block!\n"; - I.getParent()->print(errs()); - errs() << "\n"; - } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) + if(I.getParent()->getTerminator() == NULL) { + errs() << "Malformed block!\n"; + I.getParent()->print(errs()); + errs() << "\n"; + } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) #endif - addConsistencyChecks(I, ErrBB); + addConsistencyChecks(I, ErrBB); #endif + } + } + if(!shouldDuplicateAnyway) { + return 0; } - return 0; } else if (isa(I) && cast(I).isInlineAsm()) { return 0; } From e8e6925d4b9ef7032edadfea6c0c3e078f266c6b Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Wed, 17 Jun 2026 23:43:34 +0200 Subject: [PATCH 10/20] feat(EDDI): add other functions to be excluded by default --- passes/EDDI.cpp | 9 +++++---- passes/Utils/Utils.cpp | 9 +++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 668989f..9fdb104 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -982,10 +982,10 @@ void EDDI::addConsistencyChecks( } void EDDI::createCompareOnOperand(std::vector *CmpInstructions, Value *V, Instruction &I, IRBuilder<> &B) { - auto Duplicate = DuplicatedInstructionMap.find(V); + auto Duplicate = getDuplicateValue(V, I.getFunction()); // if the duplicate doesn't exist, we cannot perform a compare - if (Duplicate == DuplicatedInstructionMap.end()) { + if (Duplicate == nullptr) { return; } @@ -1002,8 +1002,8 @@ void EDDI::createCompareOnOperand(std::vector *CmpInstructions, Value * // TODO: are there other cases to support? } - Value *Original = Duplicate->first; - Value *Copy = Duplicate->second; + Value *Original = V; + Value *Copy = Duplicate; // we compare the operands only if they are found in the TDA transparent types if(deducedTypes.transparentTypes.find(V) == deducedTypes.transparentTypes.end()) { @@ -1056,6 +1056,7 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value } else if(V1Ty->isArrayTT()) { int arraysize = V1Ty->getLLVMType()->getArrayNumElements(); + // TODO: understand if is possible to remove the extracted values when no check is performed for (int i = 0; i < arraysize; i++) { Value *OriginalElem = B.CreateExtractValue(&V1, i); Value *CopyElem = B.CreateExtractValue(&V2, i); diff --git a/passes/Utils/Utils.cpp b/passes/Utils/Utils.cpp index abc0ea1..e96910e 100644 --- a/passes/Utils/Utils.cpp +++ b/passes/Utils/Utils.cpp @@ -244,7 +244,8 @@ bool isToDuplicateName(StringRef FnMangledName) { 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) { + FnName.find("std::thread") != FnName.npos || + FnName.find("printf") != FnName.npos) { return false; } @@ -279,7 +280,11 @@ bool isToExcludeName(StringRef FnMangledName) { auto FnName = demangle(FnMangledName.str()); - 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 || + FnName.find("printf") != FnName.npos) { return true; } From eca0927ea222f5623a2079c38be045d51dea7296 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Fri, 19 Jun 2026 18:53:53 +0200 Subject: [PATCH 11/20] fix(EDDI): fixed isLocalValueInitializedBefore function --- passes/EDDI.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 9fdb104..cffda60 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -847,7 +847,7 @@ void EDDI::comparePtrs(std::vector *CmpInstructions, Value &V1, Value & 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; @@ -907,6 +907,11 @@ bool isLocalValueInitializedBefore(Instruction *AI, Instruction *At) { if(isa(I) && storeInsts.find(cast(I)) != storeInsts.end()) { break; } + + // return false if we don't have a next node before encountering a store + if(I->getNextNode() == nullptr) { + return false; + } } while(I = I->getNextNode()); } From 2fcc8dfb5fcfe3eb2e23656a141d016c72cd48b5 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Fri, 21 Aug 2026 11:33:46 +0200 Subject: [PATCH 12/20] upd(isToDuplicate): duplicate by default if the value doesn't have an implementation --- passes/Utils/Utils.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/passes/Utils/Utils.cpp b/passes/Utils/Utils.cpp index e96910e..1e92aba 100644 --- a/passes/Utils/Utils.cpp +++ b/passes/Utils/Utils.cpp @@ -224,7 +224,7 @@ bool isToDuplicate(Value *V) { Intrinsic::ID intrinsicID = CInstr->getIntrinsicID(); if (intrinsicID != Intrinsic::not_intrinsic) { return true; - } else if(CInstr->getCalledFunction() != NULL && isToDuplicateName(CInstr->getCalledFunction()->getName())) { + } else if(CInstr->getCalledFunction() != NULL && (isToDuplicateName(CInstr->getCalledFunction()->getName()) || (CInstr->getCalledFunction()->hasExternalLinkage() && CInstr->getCalledFunction()->isDeclaration()))) { return true; } } @@ -279,12 +279,14 @@ bool isToExcludeName(StringRef FnMangledName) { } auto FnName = demangle(FnMangledName.str()); + auto FnNameStrRef = StringRef(FnName); 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 || - FnName.find("printf") != FnName.npos) { + FnName.find("printf") != FnName.npos || + FnNameStrRef.equals_insensitive("rand")) { return true; } From e1f900cb4ead7be02b377cde9b451002d6e08552 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Fri, 21 Aug 2026 11:37:22 +0200 Subject: [PATCH 13/20] upd(EDDI): synchronize also global variables when fixing func values passed by reference --- passes/EDDI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index cffda60..76a7648 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -1096,7 +1096,7 @@ void EDDI::fixFuncValsPassedByReference( Value *Duplicate = getDuplicateValue(Operand, I.getFunction()); if (Duplicate != nullptr) { - if(Operand->getType()->isPointerTy() && Duplicate->getType()->isPointerTy()) { + if((Operand->getType()->isPointerTy() && Duplicate->getType()->isPointerTy()) || (isa(Operand) && isa(Duplicate))) { synchronizeFunctionArguments(*I.getModule(), Operand, B, &I, false); } } From 90b514290b0e91b2c0bdd3a830636462b70029a9 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Fri, 21 Aug 2026 11:47:31 +0200 Subject: [PATCH 14/20] upd(EDDI): base-case covered also without TDA to infere alloca types warning: the retrieving of the "first" type --- passes/EDDI.cpp | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 76a7648..08b8838 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -2104,7 +2104,35 @@ bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilde return false; } - tda::TransparentType *VTy = TTIter->second.begin()->get(); + tda::TransparentType *VTy = nullptr; + TransparentTypeFactory ttf; + + // TODO: fix this in TDA! + if (value->getType()->isPointerTy()) { + if (isa(value) && + cast(value)->getAllocatedType() && + !cast(value)->getAllocatedType()->isPointerTy()) { + + auto newTy = ttf.createFromType(cast(value)->getAllocatedType(), 1); + VTy = newTy.get(); // grab the raw pointer while we still own it + deducedTypes.transparentTypes[value].insert(std::move(newTy)); // then transfer ownership into the map + + } else { + auto TTIter = deducedTypes.transparentTypes.find(value); + if (TTIter == deducedTypes.transparentTypes.end() || TTIter->second.empty()) { + errs() << "Warning: Cannot TDA value " << *value << "\n"; + return false; + } + // WARNING: THIS IS JUST BEST EFFORT, COULD MESS THINGS UP! + VTy = TTIter->second.begin()->get(); + errs() << "ERROR: Best effort inference of type. could be wrong! value: " << *value << " type " << VTy->toString() << "\n"; + } + } else { + auto newTy = ttf.createFromType(value->getType()); + VTy = newTy.get(); + deducedTypes.transparentTypes[value].insert(std::move(newTy)); + } + // Cannot do argument duplication if the type contains opaque pointers since we cannot find the final value to duplicate { auto VTyCopy = VTy; From 3e30d699cc60da0dffbc421b8e0dd3d9a3c5c8ef Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Wed, 26 Aug 2026 19:29:51 +0200 Subject: [PATCH 15/20] upd(EDDI): add the consistency checks at the end of duplication process --- passes/ASPIS.h | 6 +- passes/EDDI.cpp | 216 +++++++++++++++--------------------------------- 2 files changed, 71 insertions(+), 151 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 2cc4fca..0b1e653 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -61,18 +61,18 @@ class EDDI : public PassInfoMixin { std::set getVirtualMethodsFromConstructor(Function *Fn); int isUsedByStore(Instruction &I, Instruction &Use); Instruction* cloneInstr(Instruction &I); - void duplicateOperands (Instruction &I, BasicBlock &ErrBB); + void duplicateOperands (Instruction &I); 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); - int transformCallBaseInst(CallBase *CInstr, IRBuilder<> &B, BasicBlock &ErrBB) ; + int transformCallBaseInst(CallBase *CInstr, IRBuilder<> &B) ; Function *getFunctionDuplicate(Function *Fn); Function *getFunctionFromDuplicate(Function *Fn); void duplicateGlobals (Module &Md); bool isAllocaForExceptionHandling(AllocaInst &I); - int duplicateInstruction (Instruction &I, BasicBlock &ErrBB); + int duplicateInstruction (Instruction &I); bool isValueDuplicated(Instruction &V); Function *duplicateFnArgs(Function &Fn, Module &Md); void CreateErrBB(Module &Md, Function &Fn, BasicBlock *ErrBB); diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 08b8838..8999ede 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -573,8 +573,7 @@ int EDDI::isUsedByStore(Instruction &I, Instruction &Use) { * Clones instruction `I` and adds the pair to * DuplicatedInstructionMap, inserting the clone right after the original. */ -Instruction * -EDDI::cloneInstr(Instruction &I) { +Instruction *EDDI::cloneInstr(Instruction &I) { Instruction *IClone = I.clone(); if (!I.getType()->isVoidTy() && I.hasName()) { @@ -632,16 +631,8 @@ Value *EDDI::getDuplicateValue(Value *V, Function *Fn) { /** * Takes instruction I and duplicates its operands. Then substitutes each * duplicated operand in the duplicated instruction IClone. - * - * @param DuplicatedInstructionMap is the map of duplicated instructions, needed - * for the recursive duplicateInstruction call - * @param ErrBB is the error basic block to jump to in case of error needed for - * the recursive duplicateInstruction call */ -void EDDI::duplicateOperands( - Instruction &I, - BasicBlock &ErrBB) { - +void EDDI::duplicateOperands(Instruction &I) { // see if I has a clone Value *Clone = getDuplicateValue(&I, I.getFunction()); Instruction *IClone = nullptr; @@ -657,7 +648,7 @@ void EDDI::duplicateOperands( if (isa(V)) { Instruction *Operand = cast(V); if (!isValueDuplicated(*Operand)) { - if(duplicateInstruction(*Operand, ErrBB)) { + if(duplicateInstruction(*Operand)) { if(InstructionsToRemove.find(Operand) == InstructionsToRemove.end()) { InstructionsToRemove.insert(Operand); } @@ -921,10 +912,7 @@ bool isLocalValueInitializedBefore(Instruction *AI, Instruction *At) { /** * Adds a consistency check on the instruction I */ -void EDDI::addConsistencyChecks( - Instruction &I, - BasicBlock &ErrBB) { - +void EDDI::addConsistencyChecks(Instruction &I, BasicBlock &ErrBB) { if(InstructionsToRemove.find(&I) != InstructionsToRemove.end()) { return ; } @@ -1245,7 +1233,7 @@ bool EDDI::isAllocaForExceptionHandling(AllocaInst &I){ return false; } -int EDDI::transformCallBaseInst(CallBase *CInstr, IRBuilder<> &B, BasicBlock &ErrBB) { +int EDDI::transformCallBaseInst(CallBase *CInstr, IRBuilder<> &B) { int res = 0; SmallVector args; SmallVector ParamTypes; @@ -1368,10 +1356,9 @@ int EDDI::transformCallBaseInst(CallBase *CInstr, IRBuilder<> &B, BasicBlock &Er * operations depending on the class of I: * - Clone the instruction; * - Duplicate the instruction operands; - * - Add consistency checks on the operands (if I is a synchronization point). * @returns 1 if the cloned instruction has to be removed, 0 otherwise */ -int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { +int EDDI::duplicateInstruction(Instruction &I) { if (isValueDuplicated(I)) { return 0; } @@ -1398,17 +1385,6 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { } else if(isa(I)) { if(getDuplicateValue(cast(I).getPointerOperand(), I.getFunction()) != nullptr) { shouldDuplicateAnyway = true; - } else { -#ifdef CHECK_AT_STORES -#if (SELECTIVE_CHECKING == 1) - if(I.getParent()->getTerminator() == NULL) { - errs() << "Malformed block!\n"; - I.getParent()->print(errs()); - errs() << "\n"; - } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) -#endif - addConsistencyChecks(I, ErrBB); -#endif } } if(!shouldDuplicateAnyway) { @@ -1441,7 +1417,7 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { clonedInst = cloneInstr(I); // duplicate the operands - duplicateOperands(I, ErrBB); + duplicateOperands(I); } // if the instruction is a store instruction we need to duplicate it and its @@ -1450,20 +1426,8 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { Instruction *IClone = cloneInstr(I); // duplicate the operands - duplicateOperands(I, ErrBB); - - // add consistency checks on I + duplicateOperands(I); -#ifdef CHECK_AT_STORES -#if (SELECTIVE_CHECKING == 1) - if(I.getParent()->getTerminator() == NULL) { - errs() << "Malformed block!\n"; - I.getParent()->print(errs()); - errs() << "\n"; - } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) -#endif - addConsistencyChecks(I, ErrBB); -#endif // it may happen that I duplicate a store but don't change its operands, if // that happens I just remove the duplicate if (IClone->isIdenticalTo(&I)) { @@ -1482,17 +1446,7 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { // checks else if (isa(I)) { // duplicate the operands - duplicateOperands(I, ErrBB); - -// add consistency checks on I -#ifdef CHECK_AT_BRANCH - if(I.getParent()->getTerminator() == NULL) { - errs() << "Malformed block!\n"; - I.getParent()->print(errs()); - errs() << "\n"; - } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) - addConsistencyChecks(I, ErrBB); -#endif + duplicateOperands(I); } // if the istruction is a non-already-duplicated call, we duplicate the operands and add consistency @@ -1509,16 +1463,6 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { IRBuilder<> B(CInstr); fixFuncValsPassedByReference(*CInstr, B); -#ifdef CHECK_AT_CALLS -#if (SELECTIVE_CHECKING == 1) - if(I.getParent()->getTerminator() == NULL) { - errs() << "Malformed block!\n"; - I.getParent()->print(errs()); - errs() << "\n"; - } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) -#endif - addConsistencyChecks(I, ErrBB); -#endif return 0; } @@ -1529,7 +1473,7 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { clonedInst = cloneInstr(*CInstr); // duplicate the operands - duplicateOperands(I, ErrBB); + duplicateOperands(I); if(isa(I)) { // In case of an invoke instruction, we have to fix the first invoke since @@ -1537,35 +1481,11 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { auto *IInstr = &cast(I); toFixInvokes.insert(IInstr); } - -// add consistency checks on I -#ifdef CHECK_AT_CALLS -#if (SELECTIVE_CHECKING == 1) - if(I.getParent()->getTerminator() == NULL) { - errs() << "Malformed block!\n"; - I.getParent()->print(errs()); - errs() << "\n"; - } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) -#endif - addConsistencyChecks(I, ErrBB); -#endif } else { // duplicate the operands - duplicateOperands(I, ErrBB); - -// add consistency checks on I -#ifdef CHECK_AT_CALLS -#if (SELECTIVE_CHECKING == 1) - if(I.getParent()->getTerminator() == NULL) { - errs() << "Malformed block!\n"; - I.getParent()->print(errs()); - errs() << "\n"; - } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) -#endif - addConsistencyChecks(I, ErrBB); -#endif + duplicateOperands(I); IRBuilder<> B(CInstr); if (!isa(CInstr) && I.getNextNonDebugInstruction()) { @@ -1582,7 +1502,7 @@ int EDDI::duplicateInstruction(Instruction &I, BasicBlock &ErrBB) { // if the _dup function exists (and it is not itself the dup version) or is an indirect call, // we substitute the call instruction with a call to the function with duplicated arguments if (CInstr->getCalledFunction() == NULL || (Fn != NULL && Fn != CInstr->getCalledFunction())) { - res = transformCallBaseInst(CInstr, B, ErrBB); + res = transformCallBaseInst(CInstr, B); } else { fixFuncValsPassedByReference(*CInstr, B); } @@ -1793,6 +1713,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { DuplicatedFns.insert(entryPointFn); } else { errs() << "[EDDI] Entry point function not found: " << entryPoint << "\n"; + exit(1); } #endif @@ -1824,8 +1745,6 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { << Fn->getName() << "\n"); CompiledFuncs.insert(Fn); - BasicBlock *ErrBB = BasicBlock::Create(Fn->getContext(), "ErrBB", Fn); - LLVM_DEBUG(dbgs() << "function arguments"); // save the function arguments and their duplicates for (int i = 0; i < Fn->arg_size(); i++) { @@ -1850,7 +1769,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { if (isa(U)) { Instruction *I = cast(U); // duplicate the uses of each argument - if (duplicateInstruction(*I, *ErrBB)) { + if (duplicateInstruction(*I)) { if(InstructionsToRemove.find(I) == InstructionsToRemove.end()) { InstructionsToRemove.insert(I); } @@ -1872,7 +1791,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { for (Instruction *I : InstToDuplicate) { if (!isValueDuplicated(*I)) { // perform the duplication - int shouldDelete = duplicateInstruction(*I, *ErrBB); + int shouldDelete = duplicateInstruction(*I); // the instruction duplicated may be equal to the original, so we // return shouldDelete in order to drop the duplicates @@ -1884,18 +1803,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { } } - if(CoarseGrainedDuplicationEnabled) { - LLVM_DEBUG(dbgs() << "Applying coarse grained duplication\n"); - // Apply coarse grained duplication - for (BasicBlock &BB : *Fn) { - repairBasicBlock(BB); - } - } - LLVM_DEBUG(dbgs() << " [done]\n"); - - // insert the code for calling the error basic block in case of a mismatch - CreateErrBB(Md, *Fn, ErrBB); } LLVM_DEBUG(dbgs() << "Iterating over variables...\n"); @@ -1918,25 +1826,8 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { // Duplicate instruction only if this isn't an already duplicated function if(!Fn->getName().ends_with("_dup")) { - BasicBlock *ErrBB = nullptr; - bool newErrBB = true; - - // Search pre-existant ErrBB if single basic block error handling is enabled - if(!MultipleErrBBEnabled) { - for(BasicBlock &BB : *Fn) { - if(BB.getName().starts_with("ErrBB")) { - ErrBB = &BB; - newErrBB = false; // ErrBB already present - } - } - } - - if(newErrBB) { - ErrBB = BasicBlock::Create(Fn->getContext(), "ErrBB", Fn); - } - if(!isa(I)) { - if(duplicateInstruction(*I, *ErrBB)) { + if(duplicateInstruction(*I)) { if(InstructionsToRemove.find(I) == InstructionsToRemove.end()) { InstructionsToRemove.insert(I); } @@ -1944,9 +1835,6 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { } else { GrayAreaCallsToFix.insert(cast(I)); } - - // insert the code for calling the error basic block in case of a mismatch - CreateErrBB(Md, *Fn, ErrBB); } } } @@ -1987,22 +1875,6 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { // Map with the duplicated instructions, including the temporary load ones Function *Fn = CInstr->getFunction(); - BasicBlock *ErrBB = nullptr; - bool newErrBB = true; - - // Search pre-existant ErrBB if single basic block error handling is enabled - if(!MultipleErrBBEnabled) { - for(BasicBlock &BB : *Fn) { - if(BB.getName().starts_with("ErrBB")) { - ErrBB = &BB; - newErrBB = false; // ErrBB already present - } - } - } - - if(newErrBB) { - ErrBB = BasicBlock::Create(Fn->getContext(), "ErrBB", Fn); - } // Set insertion point for the load instructions IRBuilder<> B(CInstr); @@ -2030,14 +1902,11 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { } // Finally, duplicate the call - if(duplicateInstruction(*CInstr, *ErrBB)) { + if(duplicateInstruction(*CInstr)) { if(InstructionsToRemove.find(CInstr) == InstructionsToRemove.end()) { InstructionsToRemove.insert(CInstr); } } - - // insert the code for calling the error basic block in case of a mismatch - CreateErrBB(Md, *Fn, ErrBB); } LLVM_DEBUG(dbgs() << "Fixing invokes\n"); @@ -2057,6 +1926,57 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { // Update the first invoke's normal destination IInstr->setNormalDest(NewBB->getNextNode()); } + + // Add consistency checks and, if needed, transform in coarse-grained duplication + for(auto &Fn : Md) { + for(auto &BB : Fn) { + BasicBlock *ErrBB = BasicBlock::Create(Fn.getContext(), "ErrBB", &Fn); + for(auto &I : BB) { + Value *valueDup = getDuplicateValue(&I, &Fn); + + if(valueDup && (!isa(valueDup) || (cast(valueDup)->getParent() == &BB && I.comesBefore(cast(valueDup))))) { + if(isa(I)) { + #ifdef CHECK_AT_CALLS + #if (SELECTIVE_CHECKING == 1) + if(I.getParent()->getTerminator() == NULL) { + errs() << "Malformed block!\n"; + I.getParent()->print(errs()); + errs() << "\n"; + } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) + #endif + addConsistencyChecks(I, *ErrBB); + #endif + } else if (isa(I)) { + #ifdef CHECK_AT_BRANCH + if(I.getParent()->getTerminator() == NULL) { + errs() << "Malformed block!\n"; + I.getParent()->print(errs()); + errs() << "\n"; + } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) + addConsistencyChecks(I, *ErrBB); + #endif + } else if (isa(I)) { + #ifdef CHECK_AT_STORES + #if (SELECTIVE_CHECKING == 1) + if(I.getParent()->getTerminator() == NULL) { + errs() << "Malformed block!\n"; + I.getParent()->print(errs()); + errs() << "\n"; + } else if (I.getParent()->getTerminator()->getNumSuccessors() > 1) + #endif + addConsistencyChecks(I, *ErrBB); + #endif + } + } + } + // insert the code for calling the error basic block in case of a mismatch + CreateErrBB(Md, Fn, ErrBB); + + if(CoarseGrainedDuplicationEnabled) { + repairBasicBlock(BB); + } + } + } LLVM_DEBUG(dbgs() << "Remove instructions\n"); // Drop the instructions that have been marked for removal earlier From f49cce4be71d8b755bbaf782edd510746908a3cc Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Thu, 27 Aug 2026 14:39:44 +0200 Subject: [PATCH 16/20] upd(EDDI): enhanced checking of structs and arrays --- passes/EDDI.cpp | 52 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 8999ede..2f0b585 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -913,10 +913,6 @@ bool isLocalValueInitializedBefore(Instruction *AI, Instruction *At) { * Adds a consistency check on the instruction I */ void EDDI::addConsistencyChecks(Instruction &I, BasicBlock &ErrBB) { - if(InstructionsToRemove.find(&I) != InstructionsToRemove.end()) { - return ; - } - std::vector CmpInstructions; // split and add the verification BB @@ -949,9 +945,18 @@ void EDDI::addConsistencyChecks(Instruction &I, BasicBlock &ErrBB) { createCompareOnOperand(&CmpInstructions, cast(I).getValueOperand(), I, tmpB); } else { // add a comparison for each operand + std::set checked; for (Value *V : I.operand_values()) { - IRBuilder<> tmpB(VerificationBB); - createCompareOnOperand(&CmpInstructions, V, I, tmpB); + if(checked.find(V) == checked.end()) { + IRBuilder<> tmpB(VerificationBB); + createCompareOnOperand(&CmpInstructions, V, I, tmpB); + + auto dupV = getDuplicateValue(V, I.getFunction()); + checked.insert(V); + if(dupV) { + checked.insert(dupV); + } + } } } @@ -1036,6 +1041,7 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value return; } } else if(V1Ty->isStructTT()) { + TransparentTypeFactory ttf; for (unsigned i = 0; i < V1Ty->getLLVMType()->getStructNumElements(); i++) { Value *OriginalElem = B.CreateExtractValue(&V1, i); Value *CopyElem = B.CreateExtractValue(&V2, i); @@ -1044,12 +1050,18 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value DuplicatedInstructionMap.insert( std::pair(CopyElem, OriginalElem)); + auto newTy = ttf.createFromType(cast(OriginalElem)->getIndexedType(V1Ty->getLLVMType(), i), 0); + auto ElTy = newTy.get(); + deducedTypes.transparentTypes[OriginalElem].insert(ElTy->clone()); + deducedTypes.transparentTypes[CopyElem].insert(ElTy->clone()); + compareValues(CmpInstructions, *OriginalElem, *CopyElem, B); } } else if(V1Ty->isArrayTT()) { int arraysize = V1Ty->getLLVMType()->getArrayNumElements(); // TODO: understand if is possible to remove the extracted values when no check is performed + TransparentTypeFactory ttf; for (int i = 0; i < arraysize; i++) { Value *OriginalElem = B.CreateExtractValue(&V1, i); Value *CopyElem = B.CreateExtractValue(&V2, i); @@ -1058,6 +1070,11 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value DuplicatedInstructionMap.insert( std::pair(CopyElem, OriginalElem)); + auto newTy = ttf.createFromType(cast(OriginalElem)->getIndexedType(V1Ty->getLLVMType(), i), 0); + auto ElTy = newTy.get(); + deducedTypes.transparentTypes[OriginalElem].insert(ElTy->clone()); + deducedTypes.transparentTypes[CopyElem].insert(ElTy->clone()); + compareValues(CmpInstructions,*OriginalElem, *CopyElem, B); } } else { @@ -1927,6 +1944,17 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { IInstr->setNormalDest(NewBB->getNextNode()); } + LLVM_DEBUG(dbgs() << "Remove instructions\n"); + // Drop the instructions that have been marked for removal earlier + for (Instruction *I2rm : InstructionsToRemove) { + if(I2rm == NULL) { + errs() << "Error: To remove a null instruction\n"; + continue; + } + + I2rm->eraseFromParent(); + } + // Add consistency checks and, if needed, transform in coarse-grained duplication for(auto &Fn : Md) { for(auto &BB : Fn) { @@ -1934,7 +1962,7 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { for(auto &I : BB) { Value *valueDup = getDuplicateValue(&I, &Fn); - if(valueDup && (!isa(valueDup) || (cast(valueDup)->getParent() == &BB && I.comesBefore(cast(valueDup))))) { + if(!valueDup || !isa(valueDup) || cast(valueDup)->getParent() != &BB || I.comesBefore(cast(valueDup))) { if(isa(I)) { #ifdef CHECK_AT_CALLS #if (SELECTIVE_CHECKING == 1) @@ -1978,16 +2006,6 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { } } - LLVM_DEBUG(dbgs() << "Remove instructions\n"); - // Drop the instructions that have been marked for removal earlier - for (Instruction *I2rm : InstructionsToRemove) { - if(I2rm == NULL) { - errs() << "Error: To remove a null instruction\n"; - continue; - } - - I2rm->eraseFromParent(); - } LLVM_DEBUG(dbgs() << "Fixing global ctors\n"); fixGlobalCtors(Md); From 92646f13a9c54e329c553a80f7a748986fa54c06 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Thu, 27 Aug 2026 18:52:14 +0200 Subject: [PATCH 17/20] TEMP - fix(EDDI): harden instead of TAD if the resources is in heap --- passes/ASPIS.h | 5 +- passes/EDDI.cpp | 225 +++++++++++++++++++++++++++++++++-------- passes/Utils/Utils.cpp | 22 +++- passes/Utils/Utils.h | 1 + 4 files changed, 211 insertions(+), 42 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 0b1e653..5a8e7ed 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -79,9 +79,12 @@ class EDDI : public PassInfoMixin { bool synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B, Instruction *I, bool before); Value *getDuplicateValue(Value *V, Function *I); void createCompareOnOperand(std::vector *CmpInstructions, Value *V, Instruction &I, IRBuilder<> &B); - void compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B); + void compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B, bool checkCompositeTypes = true); void fixGlobalCtors(Module &M); void repairBasicBlock(BasicBlock &BB); + bool isHeapOriginated(llvm::Value *V, unsigned depth = 0); + bool isHeapOriginatedThroughAlloca(llvm::AllocaInst *AI, unsigned depth = 0); + bool synchronizeHeapValue(llvm::Value *value, Instruction *I, bool before); public: explicit EDDI(bool duplicateAll, bool MultipleErrBBEnabled = false, bool CoarseGrainedDuplicationEnabled = true, std::string entryPoint = "main") : duplicateAll(duplicateAll), MultipleErrBBEnabled(MultipleErrBBEnabled), CoarseGrainedDuplicationEnabled(CoarseGrainedDuplicationEnabled), entryPoint(entryPoint) {} diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 2f0b585..33280b1 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -1011,7 +1011,7 @@ void EDDI::createCompareOnOperand(std::vector *CmpInstructions, Value * compareValues(CmpInstructions, *Original, *Copy, B); } -void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B) { +void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B, bool checkCompositeTypes) { if(deducedTypes.transparentTypes.find(&V1) == deducedTypes.transparentTypes.end()) { return; } @@ -1040,46 +1040,48 @@ void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value errs() << "Warning: Unsupported primitive type for comparison: " << V1Ty->toString() << "\n"; return; } - } else if(V1Ty->isStructTT()) { - TransparentTypeFactory ttf; - for (unsigned i = 0; i < V1Ty->getLLVMType()->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)); - - auto newTy = ttf.createFromType(cast(OriginalElem)->getIndexedType(V1Ty->getLLVMType(), i), 0); - auto ElTy = newTy.get(); - deducedTypes.transparentTypes[OriginalElem].insert(ElTy->clone()); - deducedTypes.transparentTypes[CopyElem].insert(ElTy->clone()); - - compareValues(CmpInstructions, *OriginalElem, *CopyElem, B); - } - } else if(V1Ty->isArrayTT()) { - int arraysize = V1Ty->getLLVMType()->getArrayNumElements(); - - // TODO: understand if is possible to remove the extracted values when no check is performed - TransparentTypeFactory ttf; - 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)); - - auto newTy = ttf.createFromType(cast(OriginalElem)->getIndexedType(V1Ty->getLLVMType(), i), 0); - auto ElTy = newTy.get(); - deducedTypes.transparentTypes[OriginalElem].insert(ElTy->clone()); - deducedTypes.transparentTypes[CopyElem].insert(ElTy->clone()); - - compareValues(CmpInstructions,*OriginalElem, *CopyElem, B); + } else if(checkCompositeTypes) { + if(V1Ty->isStructTT()) { + TransparentTypeFactory ttf; + for (unsigned i = 0; i < V1Ty->getLLVMType()->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)); + + auto newTy = ttf.createFromType(cast(OriginalElem)->getIndexedType(V1Ty->getLLVMType(), i), 0); + auto ElTy = newTy.get(); + deducedTypes.transparentTypes[OriginalElem].insert(ElTy->clone()); + deducedTypes.transparentTypes[CopyElem].insert(ElTy->clone()); + + compareValues(CmpInstructions, *OriginalElem, *CopyElem, B, false); + } + } else if(V1Ty->isArrayTT()) { + int arraysize = V1Ty->getLLVMType()->getArrayNumElements(); + + // TODO: understand if is possible to remove the extracted values when no check is performed + TransparentTypeFactory ttf; + 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)); + + auto newTy = ttf.createFromType(cast(OriginalElem)->getIndexedType(V1Ty->getLLVMType(), i), 0); + auto ElTy = newTy.get(); + deducedTypes.transparentTypes[OriginalElem].insert(ElTy->clone()); + deducedTypes.transparentTypes[CopyElem].insert(ElTy->clone()); + + compareValues(CmpInstructions,*OriginalElem, *CopyElem, B, false); + } + } else { + errs() << "Warning: Unsupported type for comparison: " << V1Ty->toString() << "\n"; + return; } - } else { - errs() << "Warning: Unsupported type for comparison: " << V1Ty->toString() << "\n"; - return; } } @@ -2033,9 +2035,152 @@ PreservedAnalyses EDDI::run(Module &Md, ModuleAnalysisManager &AM) { return PreservedAnalyses::none(); } +bool EDDI::isHeapOriginatedThroughAlloca(llvm::AllocaInst *AI, unsigned depth) { + static constexpr unsigned MaxHeapOriginSearchDepth = 8; + if (depth > MaxHeapOriginSearchDepth) + return false; + + for (User *U : AI->users()) { + auto *SI = dyn_cast(U); + if (SI && SI->getPointerOperand() == AI && + isHeapOriginated(SI->getValueOperand(), depth + 1)) + return true; + } + return false; +} + +// Walks back through simple pointer-forwarding instructions to determine +// whether `V` ultimately comes from a heap-allocation call (malloc/new/...). +bool EDDI::isHeapOriginated(llvm::Value *V, unsigned depth) { + static constexpr unsigned MaxHeapOriginSearchDepth = 8; // guard against pathological/cyclic chains + errs() << "isHeapOriginated " << depth << ": " << *V << "\n"; + if (depth > MaxHeapOriginSearchDepth) { + errs() << "MaxHeapOriginSearchDepth\n"; + return false; + } + + if (auto *CI = dyn_cast(V)) { + if (Function *callee = CI->getCalledFunction()) { + if(isHeapFunction(callee->getName())) { + errs() << "isHeapFunction!\n"; + synchronizeHeapValue(V, cast(V), true); + return true; + } + } + errs() << "isn't HeapFunction\n"; + return false; + } + + if (auto *AI = dyn_cast(V)) + return isHeapOriginatedThroughAlloca(AI, depth + 1); + + if (auto *GEP = dyn_cast(V)) + return isHeapOriginated(GEP->getPointerOperand(), depth + 1); + + if (auto *LI = dyn_cast(V)) + return isHeapOriginated(LI->getPointerOperand(), depth + 1); + + if (auto *PN = dyn_cast(V)) { + for (Value *incoming : PN->incoming_values()) + if (isHeapOriginated(incoming, depth + 1)) { + errs() << "isHeapOriginated phi\n"; + return true; + } + } + + errs() << "false\n"; + return false; +} + +// Instead of TAD (alloca + memcpy snapshot), make sure the instruction that +// produced this heap value has itself been duplicated, and reuse that real +// duplicate as the synchronized value. +bool EDDI::synchronizeHeapValue(llvm::Value *value, Instruction *I, bool before) { + Instruction *defInst = cast(value); + duplicateInstruction(*defInst); + + std::set toHardenHeapVariables{value}; + std::set toCheckVariables{toHardenHeapVariables}; + while(!toCheckVariables.empty()) { + std::set toAddVariables; // support set to contain new to-be-checked values + for(Value *V : toCheckVariables) { + // Just protect the return value of the call, not the operands + if((isa(V) || isa(V)) && !isa(V)) { + auto Instr = cast(V); + + // Check parameters of function + for(int i = 0; i < Instr->getNumOperands(); i++) { + Value *operand = nullptr; + + // Get operand + if(isa(Instr)) { + auto PhiInst = cast(Instr); + operand = PhiInst->getIncomingValue(i); + } else if(isa(Instr->getOperand(i)) || isa(Instr->getOperand(i)) || isa(Instr->getOperand(i))) { + operand = Instr->getOperand(i); + } + + // Check if to add operand to toAddVariables + if(operand != NULL && operand != V && isa(operand) && + toHardenHeapVariables.find(operand) == toHardenHeapVariables.end() && + toCheckVariables.find(operand) == toCheckVariables.end() && + (FuncAnnotations.find(operand) == FuncAnnotations.end() || !FuncAnnotations.find(operand)->second.starts_with("exclude")) && + (!operand->hasName() || !isToDuplicateName(operand->getName())) && + (!isa(operand) || !isAllocaForExceptionHandling(*cast(operand)))) { + toAddVariables.insert(operand); + } + } + } + + for(User *U : V->users()) { + if(isa(U) || isa(U)) { + if(U != NULL && U != V && + toHardenHeapVariables.find(U) == toHardenHeapVariables.end() && + toCheckVariables.find(U) == toCheckVariables.end() && + (FuncAnnotations.find(U) == FuncAnnotations.end() || !FuncAnnotations.find(U)->second.starts_with("exclude")) && + (!U->hasName() || !isToDuplicateName(U->getName())) && + (!isa(U) || !isAllocaForExceptionHandling(*cast(U)))) { + // If it is a call, add also the called function in the toHardenFunction set + if(isa(U)) { + CallBase *CallI = cast(U); + Function *Fn = CallI->getCalledFunction(); + if (Fn != NULL && getFunctionDuplicate(Fn) == NULL && + (FuncAnnotations.find(Fn) == FuncAnnotations.end() || + (!FuncAnnotations.find(Fn)->second.starts_with("exclude") && !FuncAnnotations.find(Fn)->second.starts_with("to_duplicate"))) && + !isToDuplicateName(Fn->getName()) && !Fn->getName().starts_with("__clang_call_terminate")) { + // If it isn't/hasn't a duplicate version already + // toHardenFunctions.insert(Fn); + toAddVariables.insert(U); + } + } else { + toAddVariables.insert(U); + } + } + } + } + } + toHardenHeapVariables.merge(toCheckVariables); + toCheckVariables = toAddVariables; + } + + for(auto &V : toHardenHeapVariables) { + if(isa(V)) { + duplicateInstruction(*cast(V)); + } + } + + return true; +} + + bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B, Instruction *I, bool before) { const llvm::DataLayout &DL = Md.getDataLayout(); + if (isHeapOriginated(value)) { + errs() << *value << " isHeapOriginated\n"; + return synchronizeHeapValue(value, I, before); + } + auto TTIter = deducedTypes.transparentTypes.find(value); if (TTIter == deducedTypes.transparentTypes.end()) { errs() << "Warning: Cannot TDA value " << *value << "\n"; diff --git a/passes/Utils/Utils.cpp b/passes/Utils/Utils.cpp index 1e92aba..ed1162d 100644 --- a/passes/Utils/Utils.cpp +++ b/passes/Utils/Utils.cpp @@ -239,7 +239,7 @@ bool isToDuplicateName(StringRef FnMangledName) { auto FnName = demangle(FnMangledName.str()); - if(FnName.find("operator new") == 0 || FnName.find("std::") != FnName.npos || FnName.find("fmt::") != FnName.npos || FnName.find("Eigen::") != FnName.npos) { + if(isHeapFunction(FnMangledName) || FnName.find("std::") != FnName.npos || FnName.find("fmt::") != FnName.npos || FnName.find("Eigen::") != FnName.npos) { if(FnName.find("std::ostream") != FnName.npos || FnName.find("std::basic_ostream") != FnName.npos || @@ -255,6 +255,26 @@ bool isToDuplicateName(StringRef FnMangledName) { return false; } +bool isHeapFunction(StringRef FnMangledName) { + if(FnMangledName.ends_with("_ret")) { + FnMangledName = FnMangledName.substr(0, FnMangledName.size() - 4); + } + + auto FnName = demangle(FnMangledName.str()); + + if(FnName.find("malloc") != FnName.npos || + FnName.find("free") != FnName.npos || + FnName.find("operator new") != FnName.npos || + FnName.find("operator delete") != FnName.npos || + FnName.find("calloc") != FnName.npos || + FnName.find("memset") != FnName.npos) { + return true; + } + + return false; +} + + bool isToExclude(Value *V) { if(isa(V)) { Instruction *Inst = cast(V); diff --git a/passes/Utils/Utils.h b/passes/Utils/Utils.h index 22313f8..3911f88 100644 --- a/passes/Utils/Utils.h +++ b/passes/Utils/Utils.h @@ -48,6 +48,7 @@ bool isToDuplicateName(StringRef FnMangledName); bool isToDuplicate(Value *CInstr); bool isToExcludeName(StringRef FnMangledName); bool isToExclude(Value *V); +bool isHeapFunction(StringRef FnMangledName); void createFtFuncs(Module &Md); From b724595d48e49451e2df806917591b944f08f9dd Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Fri, 28 Aug 2026 20:21:35 +0200 Subject: [PATCH 18/20] upd(EDDI): fix "this" value in case of empty class --- passes/EDDI.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 33280b1..23174e7 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -185,6 +185,24 @@ void EDDI::fixDuplicatedConstructors(Module &Md) { continue; } + // Handle the case where the class has no attribute: zero the padding byte + auto zeroThisPointee = [&](Function *F) { + if (F->arg_empty()) + return; + + Argument *ThisArg = F->getArg(0); + if (!ThisArg->getType()->isPointerTy()) + return; + + BasicBlock &Entry = F->getEntryBlock(); + IRBuilder<> B(&Entry, Entry.getFirstNonPHIOrDbgOrAlloca()); + + B.CreateStore(B.getInt8(0), ThisArg); + }; + + zeroThisPointee(Fn); + zeroThisPointee(FnDup); + // Find vtable LLVM_DEBUG(dbgs() << "[REDDI] Finding vtable for " << Fn->getName() << "\n"); for(auto &BB : *Fn) { From 868aea1ed37acb34dc66a48bda739a905fd8b16d Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Fri, 28 Aug 2026 20:22:39 +0200 Subject: [PATCH 19/20] fix(EDDI): now when duplicating instruction we transfer all deduced types of the original to the duplicate --- passes/EDDI.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 23174e7..8333133 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -1546,9 +1546,22 @@ int EDDI::duplicateInstruction(Instruction &I) { } } - if(clonedInst && deducedTypes.transparentTypes.find(&I) != deducedTypes.transparentTypes.end()) { - auto V1Ty = deducedTypes.transparentTypes.find(&I)->second.begin()->get(); - deducedTypes.transparentTypes[clonedInst].insert(V1Ty->clone()); + + if (clonedInst) { + auto SrcIt = deducedTypes.transparentTypes.find(&I); + if (SrcIt != deducedTypes.transparentTypes.end()) { + + std::vector> ClonedTypes; + ClonedTypes.reserve(SrcIt->second.size()); + for (auto &TyPtr : SrcIt->second) { + ClonedTypes.push_back(TyPtr->clone()); + } + + auto &DestSet = deducedTypes.transparentTypes[clonedInst]; + for (auto &ClonedTy : ClonedTypes) { + DestSet.insert(std::move(ClonedTy)); + } + } } return res; From 037bf7c79a44da9446e432f874b4b19e9bf6eff1 Mon Sep 17 00:00:00 2001 From: EmilioCorigliano Date: Fri, 28 Aug 2026 20:34:49 +0200 Subject: [PATCH 20/20] upd(EDDI): now getBestType handles the retrieving of types --- passes/ASPIS.h | 4 +- passes/EDDI.cpp | 114 +++++++++++++----------------------------------- 2 files changed, 33 insertions(+), 85 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 5a8e7ed..4e3f116 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -62,7 +62,6 @@ class EDDI : public PassInfoMixin { int isUsedByStore(Instruction &I, Instruction &Use); Instruction* cloneInstr(Instruction &I); void duplicateOperands (Instruction &I); - 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); @@ -77,7 +76,8 @@ class EDDI : public PassInfoMixin { Function *duplicateFnArgs(Function &Fn, Module &Md); void CreateErrBB(Module &Md, Function &Fn, BasicBlock *ErrBB); bool synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilder<> &B, Instruction *I, bool before); - Value *getDuplicateValue(Value *V, Function *I); + Value *getDuplicateValue(Value *V, Function *Fn); + tda::TransparentType *getBestType(Value *V); void createCompareOnOperand(std::vector *CmpInstructions, Value *V, Instruction &I, IRBuilder<> &B); void compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B, bool checkCompositeTypes = true); void fixGlobalCtors(Module &M); diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 8333133..7420d66 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -724,32 +724,27 @@ void EDDI::duplicateOperands(Instruction &I) { } } -// recursively follow store instructions to find the pointer final value, -// 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 = nullptr; - - if (V.getType()->isPointerTy() && V.hasUseList()) { - // find the store using V as ptr - for (User *U : V.users()) { - if (isa(U)) { - StoreInst *SI = cast(U); - if (SI->getPointerOperand() == &V) { // we found the store - - // if the store saves a pointer we work recursively to find the - // original value - if (SI->getValueOperand()->getType()->isPointerTy()) { - return getPtrFinalValue(*(SI->getValueOperand())); - } else { - return &V; - } - } - } - } +tda::TransparentType *EDDI::getBestType(Value *V) { + TransparentTypeFactory ttf; + tda::TransparentType *VTy = nullptr; + + auto TTIter = deducedTypes.transparentTypes.find(V); + + if (TTIter != deducedTypes.transparentTypes.end() && TTIter->second.size() == 1) { + VTy = TTIter->second.begin()->get(); + return VTy; } - return res; + if (isa(V) && + cast(V)->getAllocatedType() && + !cast(V)->getAllocatedType()->isPointerTy()) { + + auto newTy = ttf.createFromType(cast(V)->getAllocatedType(), 1); + VTy = newTy.get(); // grab the raw pointer while we still own it + deducedTypes.transparentTypes[V].insert(std::move(newTy)); // then transfer ownership into the map + } + + return VTy; } bool EDDI::ptrNotDereferenceable(Value &V) { @@ -765,7 +760,7 @@ bool EDDI::ptrNotDereferenceable(Value &V) { return false; } -// Follows the pointers V1 and V2 using getPtrFinalValue() and adds a compare +// Follows the pointers V1 and V2 and adds a compare // instruction using the IRBuilder B. void EDDI::comparePtrs(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B) { /** @@ -787,25 +782,15 @@ void EDDI::comparePtrs(std::vector *CmpInstructions, Value &V1, Value & return; } - if(deducedTypes.transparentTypes.find(&V1)->second.size() != 1) { - errs() << "\tMultiple types 1!\n"; - return; - } - - if(deducedTypes.transparentTypes.find(&V2)->second.size() != 1) { - errs() << "\tMultiple types 2!\n"; - return; - } - - auto V1Ty = deducedTypes.transparentTypes.find(&V1)->second.begin()->get(); - auto V2Ty = deducedTypes.transparentTypes.find(&V2)->second.begin()->get(); + tda::TransparentType *V1Ty = getBestType(F1); + tda::TransparentType *V2Ty = getBestType(F2); - if(!V1Ty || V1Ty->isOpaquePtr()) { + if(V1Ty == nullptr || V1Ty->isOpaquePtr()) { errs() << "Warning 1: Can't find final value for pointer " << V1 << "\n"; return; } - if(!V2Ty || V2Ty->isOpaquePtr()) { + if(V2Ty == nullptr || V2Ty->isOpaquePtr()) { errs() << "Warning 2: Can't find final value for pointer " << V1 << "\n"; return; } @@ -1021,26 +1006,17 @@ void EDDI::createCompareOnOperand(std::vector *CmpInstructions, Value * Value *Original = V; Value *Copy = Duplicate; - // we compare the operands only if they are found in the TDA transparent types - if(deducedTypes.transparentTypes.find(V) == deducedTypes.transparentTypes.end()) { - return; - } - compareValues(CmpInstructions, *Original, *Copy, B); } void EDDI::compareValues(std::vector *CmpInstructions, Value &V1, Value &V2, IRBuilder<> &B, bool checkCompositeTypes) { - if(deducedTypes.transparentTypes.find(&V1) == deducedTypes.transparentTypes.end()) { - return; - } + TransparentType *V1Ty = getBestType(&V1); + TransparentType *V2Ty = getBestType(&V2); - if(deducedTypes.transparentTypes.find(&V2) == deducedTypes.transparentTypes.end()) { + if(V1Ty == nullptr || V1Ty->containsOpaquePtr() || V2Ty == nullptr || V2Ty->containsOpaquePtr() ) { return; } - 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(V1Ty->isPrimitiveTT()) { @@ -2212,42 +2188,13 @@ bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilde return synchronizeHeapValue(value, I, before); } - auto TTIter = deducedTypes.transparentTypes.find(value); - if (TTIter == deducedTypes.transparentTypes.end()) { - errs() << "Warning: Cannot TDA value " << *value << "\n"; + tda::TransparentType *VTy = getBestType(value); + if (VTy == nullptr) { return false; } - tda::TransparentType *VTy = nullptr; - TransparentTypeFactory ttf; - - // TODO: fix this in TDA! - if (value->getType()->isPointerTy()) { - if (isa(value) && - cast(value)->getAllocatedType() && - !cast(value)->getAllocatedType()->isPointerTy()) { - - auto newTy = ttf.createFromType(cast(value)->getAllocatedType(), 1); - VTy = newTy.get(); // grab the raw pointer while we still own it - deducedTypes.transparentTypes[value].insert(std::move(newTy)); // then transfer ownership into the map - - } else { - auto TTIter = deducedTypes.transparentTypes.find(value); - if (TTIter == deducedTypes.transparentTypes.end() || TTIter->second.empty()) { - errs() << "Warning: Cannot TDA value " << *value << "\n"; - return false; - } - // WARNING: THIS IS JUST BEST EFFORT, COULD MESS THINGS UP! - VTy = TTIter->second.begin()->get(); - errs() << "ERROR: Best effort inference of type. could be wrong! value: " << *value << " type " << VTy->toString() << "\n"; - } - } else { - auto newTy = ttf.createFromType(value->getType()); - VTy = newTy.get(); - deducedTypes.transparentTypes[value].insert(std::move(newTy)); - } - // Cannot do argument duplication if the type contains opaque pointers since we cannot find the final value to duplicate + // Limitation: if the type found is a pointer to a struct containing opaque pointers, it could not appear as opaque pointer { auto VTyCopy = VTy; while(VTyCopy->isPointerTT()) { @@ -2331,6 +2278,7 @@ bool EDDI::synchronizeFunctionArguments(Module &Md, llvm::Value *value, IRBuilde // Now we need to create as many allocas as the number of pointer indirections // in order to duplicate the whole pointer chain if(hasPerformedTAD) { + errs() << "TAD of " << *value << " -in- " << I->getFunction()->getName() << "\n"; for (int i = 0; i < indirections; ++i) { VTyPtr = VTyPtr->getPointerToType(); auto *allocaCurr = B.CreateAlloca(VTyPtr->getLLVMType());