From e1490b447560bafd96e9d803f5db100b0be61395 Mon Sep 17 00:00:00 2001 From: Gab-San Date: Tue, 25 Nov 2025 19:52:14 +0100 Subject: [PATCH 01/29] LLVM Patch 16 to 21 on RASM Patching ASPIS to LLVM 21 (some functions/headers/classes are not compatible) Didn't manage to run test Simple changes on RASM.cpp --- .gitignore | 5 ++++- passes/RASM.cpp | 2 +- passes/Utils/Utils.cpp | 4 +--- passes/Utils/Utils.h | 6 ++---- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 8851850..5158451 100644 --- a/.gitignore +++ b/.gitignore @@ -62,4 +62,7 @@ examples/sha/*.csv examples/sha/sha examples/cuda/*.txt -examples/cuda/add \ No newline at end of file +examples/cuda/add + +# IDE +.idea/ diff --git a/passes/RASM.cpp b/passes/RASM.cpp index 36e8714..4da04f9 100644 --- a/passes/RASM.cpp +++ b/passes/RASM.cpp @@ -264,7 +264,7 @@ void RASM::createCFGVerificationBB ( BasicBlock &BB, * 3) more than three successors -> we have a switch: impossible since we lower switches in a previous pass */ int numSuccessors = Terminator->getNumSuccessors(); - if (numSuccessors>1 and Terminator->isExceptionalTerminator()){ + if (numSuccessors>1 and Terminator->isSpecialTerminator()){ numSuccessors=1; } switch (numSuccessors) diff --git a/passes/Utils/Utils.cpp b/passes/Utils/Utils.cpp index 9584f55..8fea5b8 100644 --- a/passes/Utils/Utils.cpp +++ b/passes/Utils/Utils.cpp @@ -5,10 +5,8 @@ #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" -#include "llvm/IR/Metadata.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" -#include #include #include #include @@ -117,7 +115,7 @@ bool shouldCompile(Function &Fn, !Fn.getName().contains("aspis.syncpt") // Moreover, it does not have to be marked as excluded or to_duplicate && (FuncAnnotations.find(&Fn) == FuncAnnotations.end() || - (!FuncAnnotations.find(&Fn)->second.startswith("exclude") /* && + (!FuncAnnotations.find(&Fn)->second.starts_with("exclude") /* && !FuncAnnotations.find(&Fn)->second.startswith("to_duplicate") */)) // nor it is one of the original functions && OriginalFunctions.find(&Fn) == OriginalFunctions.end(); diff --git a/passes/Utils/Utils.h b/passes/Utils/Utils.h index c34824c..f0c5d37 100644 --- a/passes/Utils/Utils.h +++ b/passes/Utils/Utils.h @@ -1,16 +1,14 @@ #ifndef UTILS_H #define UTILS_H -#include "llvm/ADT/Statistic.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" -#include "llvm/IR/Metadata.h" -#include "llvm/Pass.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/IR/Module.h" #include #include +#include using namespace llvm; using LinkageMap = std::unordered_map>; From 0f521c1840a118d4b608151d16ebf2dd918f4a2b Mon Sep 17 00:00:00 2001 From: Gab-San Date: Tue, 25 Nov 2025 23:17:49 +0100 Subject: [PATCH 02/29] Small modifications to aspis.sh Removed some enable-new-pm flags Fixed the not equal on dup check. Commented lowerswitch pass --- aspis.sh | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/aspis.sh b/aspis.sh index c0c92c3..b775f5b 100755 --- a/aspis.sh +++ b/aspis.sh @@ -319,19 +319,19 @@ run_aspis() { done ## LINK & PREPROCESS - exe $LLVM_LINK $build_dir/*.ll -o $build_dir/out.ll -opaque-pointers + exe $LLVM_LINK $build_dir/*.ll -o $build_dir/out.ll success_msg "Emitted and linked IR." if [[ $debug_enabled == false ]]; then - exe $OPT --enable-new-pm=1 --passes="strip" $build_dir/out.ll -o $build_dir/out.ll + exe $OPT --passes="strip" $build_dir/out.ll -o $build_dir/out.ll echo " Debug mode disabled, stripped debug symbols." fi - - exe $OPT --enable-new-pm=1 --passes="lowerswitch" $build_dir/out.ll -o $build_dir/out.ll + #TODO: decomment the following + #exe $OPT --passes="lowerswitch" $build_dir/out.ll -o $build_dir/out.ll ## FuncRetToRef - if [[ dup != -1 ]]; then + if [[ dup -ne -1 ]]; then exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="func-ret-to-ref" $build_dir/out.ll -o $build_dir/out.ll fi; @@ -352,19 +352,18 @@ run_aspis() { esac success_msg "Applied data protection passes." - exe $OPT --enable-new-pm=1 --passes="simplifycfg" $build_dir/out.ll -o $build_dir/out.ll - + exe $OPT --passes="simplifycfg" $build_dir/out.ll -o $build_dir/out.ll ## CONTROL-FLOW CHECKING case $cfc in 0) - exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libCFCSS.so --passes="cfcss-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options + exe $OPT -load-pass-plugin=$DIR/build/passes/libCFCSS.so --passes="cfcss-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options ;; 1) - exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libRASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options + exe $OPT -load-pass-plugin=$DIR/build/passes/libRASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options ;; 2) - exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libINTER_RASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options + exe $OPT -load-pass-plugin=$DIR/build/passes/libINTER_RASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options ;; *) echo -e "\t--no-cfc specified!" @@ -393,8 +392,8 @@ run_aspis() { success_msg "Linked excluded files to the compilation." ## DuplicateGlobals - if [[ dup != -1 ]]; then - exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="duplicate-globals" $build_dir/out.ll -o $build_dir/out.ll -S $eddi_options + if [[ dup -ne -1 ]]; then + exe $OPT -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="duplicate-globals" $build_dir/out.ll -o $build_dir/out.ll -S $eddi_options success_msg "Duplicated globals." fi; @@ -411,7 +410,7 @@ run_aspis() { exe $OPT $build_dir/out.ll -o $build_dir/out.ll -S $opt_flags if [[ "$enable_profiling" == "true" ]]; then title_msg "ASPIS Profiling" - exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libPROFILER.so --passes="aspis-insert-check-profile" $build_dir/out.ll -o $build_dir/out.ll -S + exe $OPT -load-pass-plugin=$DIR/build/passes/libPROFILER.so --passes="aspis-insert-check-profile" $build_dir/out.ll -o $build_dir/out.ll -S success_msg "Code instrumented." exe $CLANG $clang_options $build_dir/out.ll $asm_files -o $build_dir/$output_file @@ -421,7 +420,7 @@ run_aspis() { success_msg "Profiled code executed." echo -e "Analyzing..." - exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libPROFILER.so --passes="aspis-check-profile" $build_dir/out.ll -o $build_dir/out.ll -S + exe $OPT -load-pass-plugin=$DIR/build/passes/libPROFILER.so --passes="aspis-check-profile" $build_dir/out.ll -o $build_dir/out.ll -S exit fi; @@ -439,4 +438,4 @@ run_aspis() { parse_commands $@ perform_platform_checks $CLANG $OPT $LLVM_LINK -run_aspis \ No newline at end of file +run_aspis From bcc18d4bee07a40428ed6f93e370e3ea5d1ff72d Mon Sep 17 00:00:00 2001 From: Gab-San Date: Mon, 8 Dec 2025 18:22:28 +0100 Subject: [PATCH 03/29] Reinstated lower-switch pass --- aspis.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aspis.sh b/aspis.sh index b775f5b..9039d50 100755 --- a/aspis.sh +++ b/aspis.sh @@ -65,15 +65,15 @@ title_msg () { perform_platform_checks() { if [ ! -f $1 ]; then - error_msg "\nCommand clang not found. Expected path: ${1}. Please check --llvm_bin parameter." + error_msg "\nCommand clang not found. Expected path: ${1}. Please check --llvm-bin parameter." fi if [ ! -f $2 ]; then - error_msg "\nCommand opt not found. Expected path: ${2}. Please check --llvm_bin parameter." + error_msg "\nCommand opt not found. Expected path: ${2}. Please check --llvm-bin parameter." fi if [ ! -f $3 ]; then - error_msg "\nCommand llvm-link not found. Expected path: ${3}. Please check --llvm_bin parameter." + error_msg "\nCommand llvm-link not found. Expected path: ${3}. Please check --llvm-bin parameter." fi } @@ -327,8 +327,8 @@ run_aspis() { exe $OPT --passes="strip" $build_dir/out.ll -o $build_dir/out.ll echo " Debug mode disabled, stripped debug symbols." fi - #TODO: decomment the following - #exe $OPT --passes="lowerswitch" $build_dir/out.ll -o $build_dir/out.ll + + exe $OPT --passes="lower-switch" $build_dir/out.ll -o $build_dir/out.ll ## FuncRetToRef if [[ dup -ne -1 ]]; then From 4f98f817b2f6e784cf3f13eff4eb70183e46a48a Mon Sep 17 00:00:00 2001 From: Gab-San Date: Wed, 14 Jan 2026 00:22:38 +0100 Subject: [PATCH 04/29] Patched EDDI to LLVM 21 Since LLVM 17 all pointers are opaques so checks for opaque pointers have been removed endswith and startswith methods have been replaced by ends_with and starts_with StringRef .equals method has been replaced by llvm::operator== --- aspis.sh | 4 ++-- passes/DuplicateGlobals.cpp | 12 ++++++------ passes/EDDI.cpp | 20 ++++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/aspis.sh b/aspis.sh index 9039d50..5644163 100755 --- a/aspis.sh +++ b/aspis.sh @@ -332,14 +332,14 @@ run_aspis() { ## FuncRetToRef if [[ dup -ne -1 ]]; then - exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="func-ret-to-ref" $build_dir/out.ll -o $build_dir/out.ll + exe $OPT -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="func-ret-to-ref" $build_dir/out.ll -o $build_dir/out.ll fi; title_msg "ASPIS transformations" ## DATA PROTECTION case $dup in 0) - exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="eddi-verify" $build_dir/out.ll -o $build_dir/out.ll $eddi_options + exe $OPT -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="eddi-verify" $build_dir/out.ll -o $build_dir/out.ll $eddi_options ;; 1) exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libSEDDI.so --passes="eddi-verify" $build_dir/out.ll -o $build_dir/out.ll $eddi_options diff --git a/passes/DuplicateGlobals.cpp b/passes/DuplicateGlobals.cpp index 247a79a..a66c89e 100755 --- a/passes/DuplicateGlobals.cpp +++ b/passes/DuplicateGlobals.cpp @@ -54,7 +54,7 @@ GlobalVariable* DuplicateGlobals::getDuplicatedGlobal(Module &Md, GlobalVariable if (DuplicatedGlobals.find(&GV) != DuplicatedGlobals.end()) { return DuplicatedGlobals.find(&GV)->second; } - else if (GV.getName().endswith("_dup")) { + else if (GV.getName().ends_with("_dup")) { return NULL; } else { @@ -71,7 +71,7 @@ void DuplicateGlobals::duplicateCall(Module &Md, CallBase* UCall, Value* Origina return; } // if the function is already a _dup function, we just duplicate the operand corresponding to our global - if (UCall->getCalledFunction()->getName().endswith("_dup")) { + if (UCall->getCalledFunction()->getName().ends_with("_dup")) { int i = 0; for (auto &Op : UCall->args()) { if (Op == Original) { @@ -167,9 +167,9 @@ PreservedAnalyses DuplicateGlobals::run(Module &Md, ModuleAnalysisManager &AM) { // if the global is a struct or an array we cannot just duplicate the stores bool toDuplicate = !isa(GV) && FuncAnnotations.find(GV) != FuncAnnotations.end() && - (FuncAnnotations.find(GV))->second.startswith("to_duplicate"); - if (! (GV->getType()->isFunctionTy() || GV->isConstant() || GV->getValueType()->isStructTy() || GV->getValueType()->isArrayTy() || GV->getValueType()->isOpaquePointerTy()) - || toDuplicate/* && ! GV.getName().endswith("_dup") */) { + (FuncAnnotations.find(GV))->second.starts_with("to_duplicate"); + if (! (GV->getType()->isFunctionTy() || GV->isConstant() || GV->getValueType()->isStructTy() || GV->getValueType()->isArrayTy() || GV->getValueType()->isPointerTy()) + || toDuplicate/* && ! GV.getName().ends_with("_dup") */) { // see if the global variable has already been cloned GlobalVariable *GVCopy = Md.getGlobalVariable((GV->getName() + "_dup").str(), true); Constant *Initializer = NULL; @@ -182,7 +182,7 @@ PreservedAnalyses DuplicateGlobals::run(Module &Md, ModuleAnalysisManager &AM) { GVCopy->setExternallyInitialized(GV->isExternallyInitialized()); } } - if (GVCopy == NULL && !GV->getName().endswith_insensitive("_dup")) { + if (GVCopy == NULL && !GV->getName().ends_with_insensitive("_dup")) { // get a copy of the global variable GVCopy = new GlobalVariable( Md, diff --git a/passes/EDDI.cpp b/passes/EDDI.cpp index 7f110a9..d8e5a35 100755 --- a/passes/EDDI.cpp +++ b/passes/EDDI.cpp @@ -414,7 +414,7 @@ void EDDI::fixFuncValsPassedByReference( Function *EDDI::getFunctionDuplicate(Function *Fn) { // If Fn ends with "_dup" we have already the duplicated function. // If Fn is NULL, it means that we don't have a duplicate - if (Fn == NULL || Fn->getName().endswith("_dup")) { + if (Fn == NULL || Fn->getName().ends_with("_dup")) { return Fn; } @@ -432,7 +432,7 @@ Function *EDDI::getFunctionDuplicate(Function *Fn) { Function *EDDI::getFunctionFromDuplicate(Function *Fn) { // If Fn ends with "_dup" we have already the duplicated function. // If Fn is NULL, it means that we don't have a duplicate - if (Fn == NULL || !Fn->getName().endswith("_dup")) { + if (Fn == NULL || !Fn->getName().ends_with("_dup")) { return Fn; } @@ -486,8 +486,8 @@ void EDDI::duplicateGlobals( for (auto GV : GVars) { if (!isa(GV) && FuncAnnotations.find(GV) != FuncAnnotations.end()) { - if ((FuncAnnotations.find(GV))->second.startswith("runtime_sig") || - (FuncAnnotations.find(GV))->second.startswith("run_adj_sig")) { + if ((FuncAnnotations.find(GV))->second.starts_with("runtime_sig") || + (FuncAnnotations.find(GV))->second.starts_with("run_adj_sig")) { continue; } } @@ -505,13 +505,13 @@ void EDDI::duplicateGlobals( bool isConstant = GV->isConstant(); bool isStruct = GV->getValueType()->isStructTy(); bool isArray = GV->getValueType()->isArrayTy(); - bool isPointer = GV->getValueType()->isOpaquePointerTy(); - bool endsWithDup = GV->getName().endswith("_dup"); + bool isPointer = GV->getValueType()->isPointerTy(); + bool endsWithDup = GV->getName().ends_with("_dup"); bool hasExternalLinkage = GV->isExternallyInitialized() || GV->hasExternalLinkage(); bool isMetadataInfo = GV->getSection() == "llvm.metadata"; bool toExclude = !isa(GV) && FuncAnnotations.find(GV) != FuncAnnotations.end() && - (FuncAnnotations.find(GV))->second.startswith("exclude"); + (FuncAnnotations.find(GV))->second.starts_with("exclude"); bool isConstStruct = GV->getSection() != "llvm.metadata" && GV->hasInitializer() && isa(GV->getInitializer()); bool isStructOfGlobals = false; // is true if and only if the global variable that we are duplicating contains at least a global pointer bool isStructOfFunctions = false; // is true if the global variable that we are duplicating contains at least a global pointer, and such global pointer is a function pointer @@ -579,7 +579,7 @@ void EDDI::duplicateGlobals( auto *valueOperand =storeInst->getValueOperand(); if(isa(valueOperand)){ CallBase *callInst = cast(valueOperand); - if (callInst->getCalledFunction() && callInst->getCalledFunction()->getName().equals("__cxa_begin_catch")) + if (callInst->getCalledFunction() && callInst->getCalledFunction()->getName() == "__cxa_begin_catch") {return true;} } @@ -822,7 +822,7 @@ int EDDI::duplicateInstruction( Callee = getFunctionFromDuplicate(Callee); // check if the function call has to be duplicated if ((FuncAnnotations.find(Callee) != FuncAnnotations.end() && - (*FuncAnnotations.find(Callee)).second.startswith("to_duplicate")) || + (*FuncAnnotations.find(Callee)).second.starts_with("to_duplicate")) || isIntrinsicToDuplicate(CInstr)) { // duplicate the instruction cloneInstr(*CInstr, DuplicatedInstructionMap); @@ -1247,4 +1247,4 @@ llvm::PassPluginLibraryInfo getEDDIPluginInfo() { extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() { return getEDDIPluginInfo(); -} \ No newline at end of file +} From 22d776372aeded61e343c0a81567a8c699b588a3 Mon Sep 17 00:00:00 2001 From: MartinaStarone <167168165+MartinaStarone@users.noreply.github.com> Date: Sun, 21 Dec 2025 12:30:53 +0100 Subject: [PATCH 05/29] Init RACFED Class RACFED.cpp --- passes/ASPIS.h | 67 ++++++++++ passes/RACFED.cpp | 302 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 369 insertions(+) create mode 100644 passes/RACFED.cpp diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 4117034..a2f0eb0 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -156,4 +156,71 @@ class RASM : public PassInfoMixin { }; +class RacfedTry : public PassInfoMixin { +private: + std::map FuncAnnotations; + std::map NewBBs; + + +#if (LOG_COMPILED_FUNCS == 1) + std::set CompiledFuncs; +#endif + + void initializeBlocksSignatures(Module &Md, + std::map &RandomNumberBBs, + std::map &SubRanPrevVals, + std::map &SumIntraInstruction); + + void originalInstruction(BasicBlock &BB,std::vector OrigInstructions); + + void splitBBsAtCalls(Module &Md); + int countOriginalInstructions(BasicBlock &BB); + CallBase *isCallBB(BasicBlock &BB); + void initializeEntryBlocksMap(Module &Md); + Value *getCondition(Instruction &I); + void createCFGVerificationBB(BasicBlock &BB, + std::map &RandomNumberBBs, + std::map &SubRanPrevVals, + Value &RuntimeSig, Value &RetSig, + BasicBlock &ErrBB); + +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); + + static bool isRequired() { return true; } +}; +class RacfedTry : public PassInfoMixin { +private: + std::map FuncAnnotations; + std::map NewBBs; + + +#if (LOG_COMPILED_FUNCS == 1) + std::set CompiledFuncs; +#endif + + void initializeBlocksSignatures(Module &Md, + std::map &RandomNumberBBs, + std::map &SubRanPrevVals, + std::map &SumIntraInstruction); + + void originalInstruction(BasicBlock &BB,std::vector OrigInstructions); + + void splitBBsAtCalls(Module &Md); + int countOriginalInstructions(BasicBlock &BB); + CallBase *isCallBB(BasicBlock &BB); + void initializeEntryBlocksMap(Module &Md); + Value *getCondition(Instruction &I); + void createCFGVerificationBB(BasicBlock &BB, + std::map &RandomNumberBBs, + std::map &SubRanPrevVals, + Value &RuntimeSig, Value &RetSig, + BasicBlock &ErrBB); + +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); + + static bool isRequired() { return true; } +}; + #endif \ No newline at end of file diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp new file mode 100644 index 0000000..f83c147 --- /dev/null +++ b/passes/RACFED.cpp @@ -0,0 +1,302 @@ +#include "ASPIS.h" +#include "Utilis.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" + +#include + +#define INIT_SIGNATURE \ + -0xDEAD // The same value has to be used as initializer for the signatures in + // the code +#define INTRA_FUNCTION_CFC 0 // Default to 0 if not defined + +using namespace llvm; + +bool unicity(int candidate, + const std::map &Values) { + for (const auto &pair : Values) { + if (pair.second == candidate) { + return true; + } + + } + return false; +} + +void RacfedTry::initializeBlocksSignatures( + Module &Md, std::map &RandomNumberBBs, + std::map &SubRanPrevVals, + std::map &SumIntraInstruction) { + int i = 0; + srand((unsigned)time(NULL)); // compileTimeSig weak random generator + + for (Function &Fn : Md) { + if (shouldCompile(Fn, FuncAnnotations)) { + for (BasicBlock &BB : Fn) { + + int randomBB = rand(); //unused for debugging purposes. From paper used in BB number + int randomSub = rand(); + do { + int randomSub = rand(); + }while (unicity(randomSub, SubRanPrevVals)); + RandomNumberBBs.insert(std::pair(&BB, i));//not random, guarantees unicity + SubRanPrevVals.insert(std::pair(&BB, randomSub)); //In this way the sub value is random + SumIntraInstruction.insert(std::pair(&BB, 0));//assign value to the sum of the instr + i= i+1; + + } + } + } + return; +} + +void originalInstruction(BasicBlock &BB, std::vector OrigInstructions) { + + for (Instruction &I : BB) { + if (isa(&I)) continue; // NON è originale + if (I.isTerminator()) continue; // NON è originale + if (isa(&I)) continue; // debug, ignora OrigInstructions.push_back(&I); + OrigInstructions.push_back(&I); + } + int numOrig = OrigInstructions.size(); +} + +int countOriginalInstructions(BasicBlock &BB) { + int count = 0; + for (Instruction &I : BB) { + if (isa(&I)) continue; // NON è originale + if (I.isTerminator()) continue; // NON è originale + if (isa(&I)) continue; // debug, ignora + count++; + } + return count; +} + +void RacfedTry::splitBBsAtCalls(Module &Md) { + for (Function &Fn : Md) { + if (shouldCompile(Fn, FuncAnnotations)) { + std::vector CallInsts; + for (BasicBlock &BB : Fn) { + for (Instruction &I : BB) { + if (isa(&I) && !isa(&I)) { + CallInsts.push_back(cast(&I)); + } + } + } + + for (CallBase *Call : CallInsts) { + if (Call->getParent()->getTerminator() != Call) { + SplitBlock(Call->getParent(), Call->getNextNode()); + } + } + } + } +} + +CallBase *RacfedTry::isCallBB(BasicBlock &BB) { + for (Instruction &I : BB) { + if (isa(&I) && !isa(&I)) { + return cast(&I); + } + } + return nullptr; +} + +void RacfedTry::initializeEntryBlocksMap(Module &Md) { + // Implementation for INTRA_FUNCTION_CFC == 1, left empty for now as we + // default to 0 +} + +Value *RacfedTry::getCondition(Instruction &I) { + // Helper to get condition from terminator if it's a branch + if (BranchInst *BI = dyn_cast(&I)) { + if (BI->isConditional()) { + return BI->getCondition(); + } + } + return nullptr; +} + +void RacfedTry::createCFGVerificationBB( + BasicBlock &BB, std::map &RandomNumberBBs, + std::map &SubRanPrevVals, Value &RuntimeSig, + Value &RetSig, BasicBlock &ErrBB) { + + auto *IntType = llvm::Type::getInt32Ty(BB.getContext()); + + int randomNumberBB = RandomNumberBBs.find(&BB)->second; + int subRanPrevVal = SubRanPrevVals.find(&BB)->second; + // in this case BB is not the first Basic Block of the function, so it has to + // update RuntimeSig and check it + if (!BB.isEntryBlock()) { + if (isa(BB.getFirstNonPHI()) || + BB.getName().contains_insensitive("verification")) { + IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); + BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), + &RuntimeSig, true); + } else if (!BB.getName().contains_insensitive("errbb")) { + BasicBlock *NewBB = BasicBlock::Create( + BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB); + IRBuilder<> BChecker(NewBB); + + // add instructions for the first runtime signature update + Value *InstrRuntimeSig = BChecker.CreateLoad(IntType, &RuntimeSig, true); + + Value *RuntimeSignatureVal = BChecker.CreateSub( + InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevVal)); + BChecker.CreateStore(RuntimeSignatureVal, &RuntimeSig, true); + + // update phi placing them in the new block + while (isa(&BB.front())) { + Instruction *PhiInst = &BB.front(); + PhiInst->removeFromParent(); + PhiInst->insertBefore(&NewBB->front()); + } + + // replace the uses of BB with NewBB + for (BasicBlock &BB_ : *BB.getParent()) { + if (&BB_ != NewBB) { + BB_.getTerminator()->replaceSuccessorWith(&BB, NewBB); + } + } + + // add instructions for checking the runtime signature + Value *CmpVal = + BChecker.CreateCmp(llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, + llvm::ConstantInt::get(IntType, randomNumberBB)); + BChecker.CreateCondBr(CmpVal, &BB, &ErrBB); + + // add NewBB and BB into the NewBBs map + NewBBs.insert(std::pair(NewBB, &BB)); + } + } + + // update the signature for the successors + int randomNumberBB_succ; + int subRanPrevVal_succ; + + Instruction *Term = BB.getTerminator(); + int successors = Term->getNumSuccessors(); + + for (int i = 0; i < successors; i++) { + BasicBlock *Succ = Term->getSuccessor(i); + if (!Succ->getName().contains_insensitive("errbb")) { + randomNumberBB_succ = RandomNumberBBs.find(Succ)->second; + subRanPrevVal_succ = randomNumberBB - randomNumberBB_succ; + + // update the map + if (SubRanPrevVals.find(Succ)->second == 1) { + SubRanPrevVals.erase(Succ); + SubRanPrevVals.insert( + std::pair(Succ, subRanPrevVal_succ)); + } else { + // if the successor has already been visited, we have to check if the + // signature is consistent + if (SubRanPrevVals.find(Succ)->second != subRanPrevVal_succ) { + // if not, we have to update the signature + int diff = subRanPrevVal_succ - SubRanPrevVals.find(Succ)->second; + IRBuilder<> B(&*BB.getFirstInsertionPt()); + if (isa(Term) && + cast(Term)->isConditional()) { + // if the terminator is a conditional branch, we have to update the + // signature only if the condition is true or false, depending on + // the successor + B.SetInsertPoint(Term); + } else { + B.SetInsertPoint(Term); + } + // For simplicity in this implementation, we just update before + // terminator. Real RACFED might need more complex handling for + // conditional branches if diff depends on path. But here diff depends + // on (Pred, Succ) pair. Actually, we need to update RuntimeSig in the + // predecessor (BB) so that when we subtract subRanPrevVal_succ in + // Succ, we get randomNumberBB_succ. Current RuntimeSig is + // randomNumberBB. We want (randomNumberBB - adjustment) - + // subRanPrevVal_succ_stored = randomNumberBB_succ But + // subRanPrevVal_succ_stored is fixed for Succ. So we need to adjust + // RuntimeSig in BB before jumping to Succ. + + // This part is tricky in RACFED/RASM. + // For now, let's assume simple adjustment. + } + } + } + } + + // Handle return instructions + if (isa(Term)) { + BasicBlock *RetVerificationBB = BasicBlock::Create( + BB.getContext(), "RACFED_ret_Verification_BB", BB.getParent(), &BB); + // Move instructions from BB to RetVerificationBB, except the verification + // logic we just added? No, we want to verify BEFORE return. Actually, the + // verification block is already added at the beginning of BB. Now we want + // to update signature before return? RASM updates signature at exit? Let's + // look at the provided RACFED.cpp from previous turn. + + // It seems I missed copying the full logic for return handling from the + // previous view. I will implement a basic return check. + + IRBuilder<> BRet(RetVerificationBB); + Value *InstrRuntimeSig = BRet.CreateLoad(IntType, &RuntimeSig, true); + Value *InstrRetSig = BRet.CreateLoad(IntType, &RetSig, true); + + // In RASM/RACFED, we might check if RuntimeSig matches RetSig (or some + // derived value) at return. For now, let's just check if they are + // consistent. But RetSig is initialized to RandomNumberBBs.size() + + // currSig. + + // Let's stick to the basic block verification for now. + } +} + +PreservedAnalyses RacfedTry::run(Module &Md, ModuleAnalysisManager &AM) { + std::map RandomNumberBBs; + std::map SubRanPrevVals; + std::map SumIntraInstruction; + // mappa: istruzione originale -> random r usato per S = S + r + std::map InstrUpdates; + createFtFuncs(Md); + getFuncAnnotations(Md, FuncAnnotations); + initializeBlocksSignatures(Md, RandomNumberBBs, SubRanPrevVals, SumIntraInstruction); + LinkageMap linkageMap = mapFunctionLinkageNames(Md); // Sta funzione è inutile a meno di scopi di debug + // Ma allora dovrebbe essere utilizzata solo all'interno di un blocco di DEBUG + std::map ErrBBs; + for (Function &Fn : Md) { + if (!shouldCompile(Fn, FuncAnnotations)) + continue; + + for (BasicBlock &BB : Fn) { + std::vector OrigInstructions; + originalInstruction(BB,OrigInstructions); + if (OrigInstructions.size()<=2) { + continue; + } + for (Instruction *I: OrigInstructions) { + int r = rand(); + InstrUpdates[I] = r; + SumIntraInstruction[&BB] += r; + } + } + + + } + auto *IntType = llvm::Type::getInt32Ty(Md.getContext()); +} + +extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK + +llvmGetPassPluginInfo() { + return {LLVM_PLUGIN_API_VERSION, "RacfedTry", "v0.1", [](PassBuilder &PB) { + PB.registerPipelineParsingCallback( + [](StringRef Name, ModulePassManager &MPM, + ArrayRef) { + if (Name == "racfed-verify") { + MPM.addPass(RacfedTry()); + return true; + } + return false; + }); + }}; +} From eeaab323b1e0806548fd8bb3d3ebbb29f37c1112 Mon Sep 17 00:00:00 2001 From: Gab-San Date: Sun, 21 Dec 2025 12:34:40 +0100 Subject: [PATCH 06/29] small fix --- passes/ASPIS.h | 35 +---------------------------------- passes/RACFED.cpp | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 44 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index a2f0eb0..a79c2b6 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -156,7 +156,7 @@ class RASM : public PassInfoMixin { }; -class RacfedTry : public PassInfoMixin { +class RACFED : public PassInfoMixin { private: std::map FuncAnnotations; std::map NewBBs; @@ -189,38 +189,5 @@ class RacfedTry : public PassInfoMixin { static bool isRequired() { return true; } }; -class RacfedTry : public PassInfoMixin { -private: - std::map FuncAnnotations; - std::map NewBBs; - -#if (LOG_COMPILED_FUNCS == 1) - std::set CompiledFuncs; #endif - - void initializeBlocksSignatures(Module &Md, - std::map &RandomNumberBBs, - std::map &SubRanPrevVals, - std::map &SumIntraInstruction); - - void originalInstruction(BasicBlock &BB,std::vector OrigInstructions); - - void splitBBsAtCalls(Module &Md); - int countOriginalInstructions(BasicBlock &BB); - CallBase *isCallBB(BasicBlock &BB); - void initializeEntryBlocksMap(Module &Md); - Value *getCondition(Instruction &I); - void createCFGVerificationBB(BasicBlock &BB, - std::map &RandomNumberBBs, - std::map &SubRanPrevVals, - Value &RuntimeSig, Value &RetSig, - BasicBlock &ErrBB); - -public: - PreservedAnalyses run(Module &M, ModuleAnalysisManager &); - - static bool isRequired() { return true; } -}; - -#endif \ No newline at end of file diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index f83c147..0e93084 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -1,5 +1,5 @@ #include "ASPIS.h" -#include "Utilis.h" +#include "Utils/Utils.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/PassPlugin.h" @@ -25,7 +25,7 @@ bool unicity(int candidate, return false; } -void RacfedTry::initializeBlocksSignatures( +void RACFED::initializeBlocksSignatures( Module &Md, std::map &RandomNumberBBs, std::map &SubRanPrevVals, std::map &SumIntraInstruction) { @@ -74,7 +74,7 @@ int countOriginalInstructions(BasicBlock &BB) { return count; } -void RacfedTry::splitBBsAtCalls(Module &Md) { +void RACFED::splitBBsAtCalls(Module &Md) { for (Function &Fn : Md) { if (shouldCompile(Fn, FuncAnnotations)) { std::vector CallInsts; @@ -95,7 +95,7 @@ void RacfedTry::splitBBsAtCalls(Module &Md) { } } -CallBase *RacfedTry::isCallBB(BasicBlock &BB) { +CallBase *RACFED::isCallBB(BasicBlock &BB) { for (Instruction &I : BB) { if (isa(&I) && !isa(&I)) { return cast(&I); @@ -104,12 +104,12 @@ CallBase *RacfedTry::isCallBB(BasicBlock &BB) { return nullptr; } -void RacfedTry::initializeEntryBlocksMap(Module &Md) { +void RACFED::initializeEntryBlocksMap(Module &Md) { // Implementation for INTRA_FUNCTION_CFC == 1, left empty for now as we // default to 0 } -Value *RacfedTry::getCondition(Instruction &I) { +Value *RACFED::getCondition(Instruction &I) { // Helper to get condition from terminator if it's a branch if (BranchInst *BI = dyn_cast(&I)) { if (BI->isConditional()) { @@ -119,7 +119,7 @@ Value *RacfedTry::getCondition(Instruction &I) { return nullptr; } -void RacfedTry::createCFGVerificationBB( +void RACFED::createCFGVerificationBB( BasicBlock &BB, std::map &RandomNumberBBs, std::map &SubRanPrevVals, Value &RuntimeSig, Value &RetSig, BasicBlock &ErrBB) { @@ -251,7 +251,7 @@ void RacfedTry::createCFGVerificationBB( } } -PreservedAnalyses RacfedTry::run(Module &Md, ModuleAnalysisManager &AM) { +PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { std::map RandomNumberBBs; std::map SubRanPrevVals; std::map SumIntraInstruction; @@ -288,12 +288,12 @@ PreservedAnalyses RacfedTry::run(Module &Md, ModuleAnalysisManager &AM) { extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() { - return {LLVM_PLUGIN_API_VERSION, "RacfedTry", "v0.1", [](PassBuilder &PB) { + return {LLVM_PLUGIN_API_VERSION, "RACFED", "v0.1", [](PassBuilder &PB) { PB.registerPipelineParsingCallback( [](StringRef Name, ModulePassManager &MPM, ArrayRef) { if (Name == "racfed-verify") { - MPM.addPass(RacfedTry()); + MPM.addPass(RACFED()); return true; } return false; From 184b24e0ba242e16696e60a4400ee0ea69f2a8b1 Mon Sep 17 00:00:00 2001 From: Gab-San Date: Mon, 22 Dec 2025 12:40:13 +0100 Subject: [PATCH 07/29] Small Refactor and Work Organization --- aspis.sh | 10 ++- passes/ASPIS.h | 21 +++-- passes/CMakeLists.txt | 6 ++ passes/RACFED.cpp | 173 ++++++++++++++++++++++++++++-------------- passes/RASM.cpp | 4 +- 5 files changed, 147 insertions(+), 67 deletions(-) diff --git a/aspis.sh b/aspis.sh index 5644163..ec8552b 100755 --- a/aspis.sh +++ b/aspis.sh @@ -19,7 +19,7 @@ input_files="" clang_options= eddi_options="-S" cfc_options="-S" -llvm_bin=$(dirname $(which clang &> /dev/null) &> /dev/null) +llvm_bin=$(dirname "$(which clang)") build_dir="." dup=0 # 0 = eddi, 1 = seddi, 2 = fdsc cfc=0 # 0 = cfcss, 1 = rasm, 2 = inter-rasm @@ -207,6 +207,9 @@ EOF --inter-rasm) cfc=2 ;; + --racfed) + cfc=3 + ;; --no-cfc) cfc=-1 ;; @@ -365,6 +368,9 @@ run_aspis() { 2) exe $OPT -load-pass-plugin=$DIR/build/passes/libINTER_RASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options ;; +# 3) +# exe $OPT -load-pass-plugin=$DIR/build/passes/libRACFED.so --passes="racfed-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options +# ;; *) echo -e "\t--no-cfc specified!" esac @@ -436,6 +442,6 @@ run_aspis() { success_msg "Done!" } -parse_commands $@ +parse_commands "$@" perform_platform_checks $CLANG $OPT $LLVM_LINK run_aspis diff --git a/passes/ASPIS.h b/passes/ASPIS.h index a79c2b6..9bad658 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -160,16 +160,23 @@ class RACFED : public PassInfoMixin { private: std::map FuncAnnotations; std::map NewBBs; + std::unordered_map compileTimeSig; + std::unordered_map subRanPrevVals; + std::unordered_map &sumIntraInstruction; #if (LOG_COMPILED_FUNCS == 1) std::set CompiledFuncs; #endif - void initializeBlocksSignatures(Module &Md, - std::map &RandomNumberBBs, - std::map &SubRanPrevVals, - std::map &SumIntraInstruction); + // -- INITIALIZE BLOCKS -- + void initializeBlocksSignatures(Module &Md); + bool isNotUniqueCompileTimeSig(int bb_num); + // -- UPDATE COMPILE SIG RANDOM -- + void updateCompileSigRandom(); + + // -- CREATE CFG VERIFICATION -- + void originalInstruction(BasicBlock &BB,std::vector OrigInstructions); @@ -179,13 +186,13 @@ class RACFED : public PassInfoMixin { void initializeEntryBlocksMap(Module &Md); Value *getCondition(Instruction &I); void createCFGVerificationBB(BasicBlock &BB, - std::map &RandomNumberBBs, - std::map &SubRanPrevVals, + std::unordered_map &RandomNumberBBs, + std::unordered_map &SubRanPrevVals, Value &RuntimeSig, Value &RetSig, BasicBlock &ErrBB); public: - PreservedAnalyses run(Module &M, ModuleAnalysisManager &); + PreservedAnalyses run(Module &Md, ModuleAnalysisManager &); static bool isRequired() { return true; } }; diff --git a/passes/CMakeLists.txt b/passes/CMakeLists.txt index b522814..691f0ac 100644 --- a/passes/CMakeLists.txt +++ b/passes/CMakeLists.txt @@ -49,6 +49,12 @@ add_library(INTER_RASM SHARED ) target_compile_definitions(INTER_RASM PRIVATE INTRA_FUNCTION_CFC=1) +# RACFED +add_library(RACFED SHARED + RACFED.cpp + Utils/Utils.cpp +) + add_library(PROFILER SHARED Profiling/ASPISCheckProfiler.cpp Utils/Utils.cpp diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 0e93084..2f41e0f 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -14,44 +14,103 @@ using namespace llvm; -bool unicity(int candidate, - const std::map &Values) { - for (const auto &pair : Values) { - if (pair.second == candidate) { +/** + * initializeBlockSignatures +1:for all Basic Block (BB) in CFG do +2: repeat compileTimeSig ← random number +3: until compileTimeSig is unique +4: repeat subRanPrevVal ← random number +5: until (compileTimeSig + subRanP revV al) is unique + * updateSignatureRandom +6:for all BB in CFG do +7: if NrInstrBB > 2 then +8: for all original instructions insert after +9: signature ← signature + random number + * create CFG + * checkBeginning +10:for all BB in CFG insert at beginning +11: signature ← signature − subRanP revV al +12: if signature != compileTimeSig error() +13:for all BB in CFG do + * checkRetVal +14: if Last Instr. is return instr. and NrIntrBB > 1 then +15: Calculate needed variables +16: return Val ← random number +17: adjust Value ← (compile TimeSigBB + Sum{instrMonUpdates}) - +18: return Val +19: Insert signature update before return instr. +20: signature ← signature + adjustValue +21: if signature != returnVal error() +22: else + * checkJump +23: for all Successor of BB do +24: adjust Value ← (compile TimeSigBB + \Sum{instrMonUpdates}) - +25: (compile TimeSigsuccs + subRanPrevValsuccs ) +26: Insert signature update at BB end +27: signature ← signature + adjust Value +*/ + + +// --- INITIALIZE BLOCKS RANDOM --- + +bool RACFED::isNotUniqueCompileTimeSig(int bb_num) { + for (const auto &pair : compileTimeSig) { + if (pair.second == bb_num) return true; + } + return false; +} + +bool unicity( + const int bb_num, const int subrun_num, + const std::unordered_map &RandomNumBBs, + const std::unordered_map &SubRanPrevVals +) { + + for (const auto &pair : RandomNumBBs) { + if (pair.second + SubRanPrevVals.at(pair.first) == bb_num + subrun_num) { return true; } - } + return false; } -void RACFED::initializeBlocksSignatures( - Module &Md, std::map &RandomNumberBBs, - std::map &SubRanPrevVals, - std::map &SumIntraInstruction) { +void RACFED::initializeBlocksSignatures(Module &Md) { int i = 0; - srand((unsigned)time(NULL)); // compileTimeSig weak random generator + srand(static_cast(time(nullptr))); // compileTimeSig weak random generator + int randomBB; + int randomSub; for (Function &Fn : Md) { if (shouldCompile(Fn, FuncAnnotations)) { for (BasicBlock &BB : Fn) { - - int randomBB = rand(); //unused for debugging purposes. From paper used in BB number - int randomSub = rand(); do { - int randomSub = rand(); - }while (unicity(randomSub, SubRanPrevVals)); - RandomNumberBBs.insert(std::pair(&BB, i));//not random, guarantees unicity - SubRanPrevVals.insert(std::pair(&BB, randomSub)); //In this way the sub value is random - SumIntraInstruction.insert(std::pair(&BB, 0));//assign value to the sum of the instr - i= i+1; + randomBB = rand(); + } while (isNotUniqueCompileTimeSig(randomBB)); + do { + randomSub = rand(); + } while (unicity(i, randomSub, compileTimeSig, subRanPrevVals)); + compileTimeSig.insert(std::pair(&BB, randomBB));//not random, guarantees unicity + subRanPrevVals.insert(std::pair(&BB, randomSub)); //In this way the sub value is random + sumIntraInstruction.insert(std::pair(&BB, 0));//assign value to the sum of the instr + i++; } } } - return; } + +// --- UPDATE SIGNATURE RANDOM --- + +void RACFED::updateCompileSigRandom() { + +} + +// --- CREATE CFG VERIFICATION --- + + + void originalInstruction(BasicBlock &BB, std::vector OrigInstructions) { for (Instruction &I : BB) { @@ -120,8 +179,8 @@ Value *RACFED::getCondition(Instruction &I) { } void RACFED::createCFGVerificationBB( - BasicBlock &BB, std::map &RandomNumberBBs, - std::map &SubRanPrevVals, Value &RuntimeSig, + BasicBlock &BB, std::unordered_map &RandomNumberBBs, + std::unordered_map &SubRanPrevVals, Value &RuntimeSig, Value &RetSig, BasicBlock &ErrBB) { auto *IntType = llvm::Type::getInt32Ty(BB.getContext()); @@ -207,19 +266,7 @@ void RACFED::createCFGVerificationBB( } else { B.SetInsertPoint(Term); } - // For simplicity in this implementation, we just update before - // terminator. Real RACFED might need more complex handling for - // conditional branches if diff depends on path. But here diff depends - // on (Pred, Succ) pair. Actually, we need to update RuntimeSig in the - // predecessor (BB) so that when we subtract subRanPrevVal_succ in - // Succ, we get randomNumberBB_succ. Current RuntimeSig is - // randomNumberBB. We want (randomNumberBB - adjustment) - - // subRanPrevVal_succ_stored = randomNumberBB_succ But - // subRanPrevVal_succ_stored is fixed for Succ. So we need to adjust - // RuntimeSig in BB before jumping to Succ. - - // This part is tricky in RACFED/RASM. - // For now, let's assume simple adjustment. + } } } @@ -232,11 +279,9 @@ void RACFED::createCFGVerificationBB( // Move instructions from BB to RetVerificationBB, except the verification // logic we just added? No, we want to verify BEFORE return. Actually, the // verification block is already added at the beginning of BB. Now we want - // to update signature before return? RASM updates signature at exit? Let's - // look at the provided RACFED.cpp from previous turn. + // to update signature before return? RASM updates signature at exit? + - // It seems I missed copying the full logic for return handling from the - // previous view. I will implement a basic return check. IRBuilder<> BRet(RetVerificationBB); Value *InstrRuntimeSig = BRet.CreateLoad(IntType, &RuntimeSig, true); @@ -252,39 +297,55 @@ void RACFED::createCFGVerificationBB( } PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { - std::map RandomNumberBBs; - std::map SubRanPrevVals; - std::map SumIntraInstruction; + // mappa: istruzione originale -> random r usato per S = S + r - std::map InstrUpdates; + std::unordered_map InstrUpdates; + auto *IntType = llvm::Type::getInt32Ty(Md.getContext()); + std::unordered_map ErrBBs; + createFtFuncs(Md); getFuncAnnotations(Md, FuncAnnotations); - initializeBlocksSignatures(Md, RandomNumberBBs, SubRanPrevVals, SumIntraInstruction); - LinkageMap linkageMap = mapFunctionLinkageNames(Md); // Sta funzione è inutile a meno di scopi di debug - // Ma allora dovrebbe essere utilizzata solo all'interno di un blocco di DEBUG - std::map ErrBBs; + LinkageMap linkageMap = mapFunctionLinkageNames((Md)); + + initializeBlocksSignatures(Md); + + updateCompileSigRandom(); + + createCFGVerificationBB(); + for (Function &Fn : Md) { if (!shouldCompile(Fn, FuncAnnotations)) continue; + if (shouldCompile(Fn, FuncAnnotations)) { + DebugLoc debugLoc; + for (auto &I : Fn.front()) { + if (I.getDebugLoc()) { + debugLoc = I.getDebugLoc(); + break; + } + } + for (BasicBlock &BB : Fn) { std::vector OrigInstructions; - originalInstruction(BB,OrigInstructions); - if (OrigInstructions.size()<=2) { + originalInstruction(BB, OrigInstructions); + if (OrigInstructions.size()<2) continue; - } - for (Instruction *I: OrigInstructions) { + int sumOfIntraUpdates = 0; + auto *IntType = llvm::Type::getInt32Ty(BB.getContext()); // control to get context for add and compare ... + + for (Instruction *I:OrigInstructions) { int r = rand(); - InstrUpdates[I] = r; - SumIntraInstruction[&BB] += r; + sumOfIntraUpdates += r; + InstrUpdates[I]=r; } + sumIntraInstruction[&BB] = sumOfIntraUpdates; } - - } - auto *IntType = llvm::Type::getInt32Ty(Md.getContext()); } + + extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() { diff --git a/passes/RASM.cpp b/passes/RASM.cpp index 4da04f9..10e9ca4 100644 --- a/passes/RASM.cpp +++ b/passes/RASM.cpp @@ -348,10 +348,10 @@ PreservedAnalyses RASM::run(Module &Md, ModuleAnalysisManager &AM) { // find the global variables required for the runtime signatures for (GlobalVariable &GV : Md.globals()) { if (!isa(GV) && FuncAnnotations.find(&GV) != FuncAnnotations.end()) { - if ((FuncAnnotations.find(&GV))->second.startswith("runtime_sig")) { + if ((FuncAnnotations.find(&GV))->second.starts_with("runtime_sig")) { RuntimeSig = &GV; } - else if ((FuncAnnotations.find(&GV))->second.startswith("run_adj_sig")) { + else if ((FuncAnnotations.find(&GV))->second.starts_with("run_adj_sig")) { RetSig = &GV; } } From 5670a53215fa14f105b703c4e44187f764a78a7f Mon Sep 17 00:00:00 2001 From: martina Date: Wed, 24 Dec 2025 10:58:10 +0100 Subject: [PATCH 08/29] updateCompileSigRandom function update --- passes/ASPIS.h | 2 +- passes/RACFED.cpp | 69 +++++++++++++------ .../c/multi_instruction/simpleMultiLine.c | 12 ++++ 3 files changed, 62 insertions(+), 21 deletions(-) create mode 100644 testing/tests/c/multi_instruction/simpleMultiLine.c diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 9bad658..fc80f14 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -19,7 +19,7 @@ using namespace llvm; // DATA PROTECTION class FuncRetToRef : public PassInfoMixin { private: - Function* updateFnSignature(Function &Fn, Module &Md); + void updateFnSignature(Function &Fn, Module &Md); void updateRetInstructions(Function &Fn); void updateFunctionCalls(Function &Fn, Function &NewFn); diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 2f41e0f..112e3fa 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -103,36 +103,65 @@ void RACFED::initializeBlocksSignatures(Module &Md) { // --- UPDATE SIGNATURE RANDOM --- -void RACFED::updateCompileSigRandom() { +void RACFED::updateCompileSigRandom(Function &F, Module &Md) { + LLVMContext &Ctx = Md.getContext(); + GlobalVariable *SigGV = Md.getNamedGlobal("signature"); + std::mt19937 rng(0xC0FFEE); // seed fisso per riproducibilità + std::uniform_int_distribution dist(1, 0x7fffffff); + auto *I32 = Type::getInt32Ty(Ctx); + if (!SigGV) { + SigGV = new GlobalVariable( + Md, + I32, + /*isConstant=*/false, + GlobalValue::ExternalLinkage, + ConstantInt::get(I32, 0), + "signature"); + } -} + bool changed = false; -// --- CREATE CFG VERIFICATION --- + for (auto &BB: F){ + std::vector OrigInstructions; + originalInstruction(BB, OrigInstructions); + if (OrigInstructions.size() <= 2) + continue; + for (Instruction *I : OrigInstructions) { + Instruction *InsertPt = nullptr; -void originalInstruction(BasicBlock &BB, std::vector OrigInstructions) { - for (Instruction &I : BB) { - if (isa(&I)) continue; // NON è originale - if (I.isTerminator()) continue; // NON è originale - if (isa(&I)) continue; // debug, ignora OrigInstructions.push_back(&I); - OrigInstructions.push_back(&I); - } - int numOrig = OrigInstructions.size(); -} + // Non puoi inserire "dopo" un terminator: inserisci prima del terminator stesso + if (I->isTerminator()) { + InsertPt = I; // insert BEFORE terminator + } else { + InsertPt = I->getNextNode(); // insert BEFORE next instruction (equivale a "dopo I") + } -int countOriginalInstructions(BasicBlock &BB) { - int count = 0; - for (Instruction &I : BB) { - if (isa(&I)) continue; // NON è originale - if (I.isTerminator()) continue; // NON è originale - if (isa(&I)) continue; // debug, ignora - count++; + IRBuilder<> B(InsertPt); + + // signature = signature + randomConstant + uint32_t K = dist(rng); + #if MARTI_DEBUG + errs() << "Dist value: " << K << "\n"; + #endif + Value *OldSig = B.CreateLoad(I32, SigGV); +#if MARTI_DEBUG + errs() << "Loaded Signature" << "\n"; +#endif + Value *Add = B.CreateAdd(OldSig, ConstantInt::get(I32, K), "sig_add"); + B.CreateStore(Add, SigGV); + changed= true; + } } - return count; } +// --- CREATE CFG VERIFICATION --- + + + + void RACFED::splitBBsAtCalls(Module &Md) { for (Function &Fn : Md) { if (shouldCompile(Fn, FuncAnnotations)) { diff --git a/testing/tests/c/multi_instruction/simpleMultiLine.c b/testing/tests/c/multi_instruction/simpleMultiLine.c new file mode 100644 index 0000000..dc623ae --- /dev/null +++ b/testing/tests/c/multi_instruction/simpleMultiLine.c @@ -0,0 +1,12 @@ +// +// Created by Martina Starone on 24/12/25. +// +#include + +int main() { + int a = 10; + int b = 20; + int c = a + b; + printf("c=%d\n", c); + return 0; +} \ No newline at end of file From acad4c7ceefa4157156fff77de8d3b32cc1ba543 Mon Sep 17 00:00:00 2001 From: martina Date: Wed, 24 Dec 2025 11:03:30 +0100 Subject: [PATCH 09/29] Changes by gamba --- passes/ASPIS.h | 12 ++---- passes/RACFED.cpp | 105 +++++++++++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 47 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index fc80f14..ab89cc4 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -160,9 +160,9 @@ class RACFED : public PassInfoMixin { private: std::map FuncAnnotations; std::map NewBBs; - std::unordered_map compileTimeSig; - std::unordered_map subRanPrevVals; - std::unordered_map &sumIntraInstruction; + std::unordered_map compileTimeSig; + std::unordered_map subRanPrevVals; + std::unordered_map sumIntraInstruction; #if (LOG_COMPILED_FUNCS == 1) @@ -171,15 +171,11 @@ class RACFED : public PassInfoMixin { // -- INITIALIZE BLOCKS -- void initializeBlocksSignatures(Module &Md); - bool isNotUniqueCompileTimeSig(int bb_num); // -- UPDATE COMPILE SIG RANDOM -- - void updateCompileSigRandom(); + void updateCompileSigRandom(Function &F, Module &Md); // -- CREATE CFG VERIFICATION -- - - void originalInstruction(BasicBlock &BB,std::vector OrigInstructions); - void splitBBsAtCalls(Module &Md); int countOriginalInstructions(BasicBlock &BB); CallBase *isCallBB(BasicBlock &BB); diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 112e3fa..d152135 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -12,6 +12,8 @@ // the code #define INTRA_FUNCTION_CFC 0 // Default to 0 if not defined +#define MARTI_DEBUG true + using namespace llvm; /** @@ -53,7 +55,9 @@ using namespace llvm; // --- INITIALIZE BLOCKS RANDOM --- -bool RACFED::isNotUniqueCompileTimeSig(int bb_num) { +bool isNotUniqueCompileTimeSig(int bb_num, + const std::unordered_map &compileTimeSig +) { for (const auto &pair : compileTimeSig) { if (pair.second == bb_num) return true; } @@ -86,7 +90,7 @@ void RACFED::initializeBlocksSignatures(Module &Md) { for (BasicBlock &BB : Fn) { do { randomBB = rand(); - } while (isNotUniqueCompileTimeSig(randomBB)); + } while (isNotUniqueCompileTimeSig(randomBB, compileTimeSig)); do { randomSub = rand(); @@ -102,6 +106,26 @@ void RACFED::initializeBlocksSignatures(Module &Md) { // --- UPDATE SIGNATURE RANDOM --- +void originalInstruction(BasicBlock &BB, std::vector &OrigInstructions) { + + for (Instruction &I : BB) { + if (isa(&I)) continue; // NON è originale + if (I.isTerminator()) continue; // NON è originale + if (isa(&I)) continue; // debug, ignora OrigInstructions.push_back(&I); + OrigInstructions.push_back(&I); + } +} + +int countOriginalInstructions(BasicBlock &BB) { + int count = 0; + for (Instruction &I : BB) { + if (isa(&I)) continue; // NON è originale + if (I.isTerminator()) continue; // NON è originale + if (isa(&I)) continue; // debug, ignora + count++; + } + return count; +} void RACFED::updateCompileSigRandom(Function &F, Module &Md) { LLVMContext &Ctx = Md.getContext(); @@ -110,6 +134,9 @@ void RACFED::updateCompileSigRandom(Function &F, Module &Md) { std::uniform_int_distribution dist(1, 0x7fffffff); auto *I32 = Type::getInt32Ty(Ctx); if (!SigGV) { +#if MARTI_DEBUG + errs() << "SigGV " << SigGV << "\n"; +#endif SigGV = new GlobalVariable( Md, I32, @@ -160,8 +187,6 @@ void RACFED::updateCompileSigRandom(Function &F, Module &Md) { // --- CREATE CFG VERIFICATION --- - - void RACFED::splitBBsAtCalls(Module &Md) { for (Function &Fn : Md) { if (shouldCompile(Fn, FuncAnnotations)) { @@ -326,51 +351,53 @@ void RACFED::createCFGVerificationBB( } PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { - // mappa: istruzione originale -> random r usato per S = S + r std::unordered_map InstrUpdates; auto *IntType = llvm::Type::getInt32Ty(Md.getContext()); std::unordered_map ErrBBs; - createFtFuncs(Md); + // createFtFuncs(Md); getFuncAnnotations(Md, FuncAnnotations); - LinkageMap linkageMap = mapFunctionLinkageNames((Md)); + LinkageMap linkageMap = mapFunctionLinkageNames((Md)); initializeBlocksSignatures(Md); - updateCompileSigRandom(); - - createCFGVerificationBB(); - - for (Function &Fn : Md) { - if (!shouldCompile(Fn, FuncAnnotations)) - continue; - - if (shouldCompile(Fn, FuncAnnotations)) { - DebugLoc debugLoc; - for (auto &I : Fn.front()) { - if (I.getDebugLoc()) { - debugLoc = I.getDebugLoc(); - break; - } - } - - for (BasicBlock &BB : Fn) { - std::vector OrigInstructions; - originalInstruction(BB, OrigInstructions); - if (OrigInstructions.size()<2) - continue; - int sumOfIntraUpdates = 0; - auto *IntType = llvm::Type::getInt32Ty(BB.getContext()); // control to get context for add and compare ... - - for (Instruction *I:OrigInstructions) { - int r = rand(); - sumOfIntraUpdates += r; - InstrUpdates[I]=r; - } - sumIntraInstruction[&BB] = sumOfIntraUpdates; - } + for (Function &F: Md){ + updateCompileSigRandom(F, Md); } + + // createCFGVerificationBB(); + // + // for (Function &Fn : Md) { + // if (!shouldCompile(Fn, FuncAnnotations)) + // continue; + // + // if (shouldCompile(Fn, FuncAnnotations)) { + // DebugLoc debugLoc; + // for (auto &I : Fn.front()) { + // if (I.getDebugLoc()) { + // debugLoc = I.getDebugLoc(); + // break; + // } + // } + // + // for (BasicBlock &BB : Fn) { + // std::vector OrigInstructions; + // originalInstruction(BB, OrigInstructions); + // if (OrigInstructions.size()<2) + // continue; + // int sumOfIntraUpdates = 0; + // auto *IntType = llvm::Type::getInt32Ty(BB.getContext()); // control to get context for add and compare ... + // + // for (Instruction *I:OrigInstructions) { + // int r = rand(); + // sumOfIntraUpdates += r; + // InstrUpdates[I]=r; + // } + // sumIntraInstruction[&BB] = sumOfIntraUpdates; + // } + // } + return PreservedAnalyses::all(); } From 46a06791f4131cd68948a65114abada0b20b62de Mon Sep 17 00:00:00 2001 From: martina Date: Wed, 24 Dec 2025 11:42:28 +0100 Subject: [PATCH 10/29] Fixes --- .gitignore | 3 + passes/ASPIS.h | 2 +- passes/RACFED.cpp | 224 ++++++++++++++++++++++------------------------ 3 files changed, 112 insertions(+), 117 deletions(-) diff --git a/.gitignore b/.gitignore index 5158451..50f5d77 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,9 @@ *.a *.lib +# IR files +*.ll + # Executables *.exe *.out diff --git a/passes/ASPIS.h b/passes/ASPIS.h index ab89cc4..f783ae5 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -162,7 +162,7 @@ class RACFED : public PassInfoMixin { std::map NewBBs; std::unordered_map compileTimeSig; std::unordered_map subRanPrevVals; - std::unordered_map sumIntraInstruction; + std::unordered_map sumIntraInstruction; #if (LOG_COMPILED_FUNCS == 1) diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index d152135..201306a 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -31,14 +31,14 @@ using namespace llvm; * create CFG * checkBeginning 10:for all BB in CFG insert at beginning -11: signature ← signature − subRanP revV al +11: signature ← signature − subRanPrevVal 12: if signature != compileTimeSig error() 13:for all BB in CFG do * checkRetVal 14: if Last Instr. is return instr. and NrIntrBB > 1 then 15: Calculate needed variables 16: return Val ← random number -17: adjust Value ← (compile TimeSigBB + Sum{instrMonUpdates}) - +17: adjust Value ← (compileTimeSigBB + Sum{instrMonUpdates}) - 18: return Val 19: Insert signature update before return instr. 20: signature ← signature + adjustValue @@ -46,16 +46,17 @@ using namespace llvm; 22: else * checkJump 23: for all Successor of BB do -24: adjust Value ← (compile TimeSigBB + \Sum{instrMonUpdates}) - -25: (compile TimeSigsuccs + subRanPrevValsuccs ) +24: adjustValue ← (compileTimeSigBB + \Sum{instrMonUpdates}) - +25: (compileTimeSigsuccs + subRanPrevValsuccs) 26: Insert signature update at BB end -27: signature ← signature + adjust Value +27: signature ← signature + adjustValue */ // --- INITIALIZE BLOCKS RANDOM --- -bool isNotUniqueCompileTimeSig(int bb_num, +bool isNotUniqueCompileTimeSig( + const int bb_num, const std::unordered_map &compileTimeSig ) { for (const auto &pair : compileTimeSig) { @@ -64,7 +65,7 @@ bool isNotUniqueCompileTimeSig(int bb_num, return false; } -bool unicity( +bool isNotUnique( const int bb_num, const int subrun_num, const std::unordered_map &RandomNumBBs, const std::unordered_map &SubRanPrevVals @@ -88,17 +89,20 @@ void RACFED::initializeBlocksSignatures(Module &Md) { for (Function &Fn : Md) { if (shouldCompile(Fn, FuncAnnotations)) { for (BasicBlock &BB : Fn) { + do { randomBB = rand(); } while (isNotUniqueCompileTimeSig(randomBB, compileTimeSig)); do { randomSub = rand(); - } while (unicity(i, randomSub, compileTimeSig, subRanPrevVals)); + } while (isNotUnique(i, randomSub, compileTimeSig, subRanPrevVals)); + compileTimeSig.insert(std::pair(&BB, randomBB));//not random, guarantees unicity subRanPrevVals.insert(std::pair(&BB, randomSub)); //In this way the sub value is random sumIntraInstruction.insert(std::pair(&BB, 0));//assign value to the sum of the instr i++; + } } } @@ -116,17 +120,6 @@ void originalInstruction(BasicBlock &BB, std::vector &OrigInstruc } } -int countOriginalInstructions(BasicBlock &BB) { - int count = 0; - for (Instruction &I : BB) { - if (isa(&I)) continue; // NON è originale - if (I.isTerminator()) continue; // NON è originale - if (isa(&I)) continue; // debug, ignora - count++; - } - return count; -} - void RACFED::updateCompileSigRandom(Function &F, Module &Md) { LLVMContext &Ctx = Md.getContext(); GlobalVariable *SigGV = Md.getNamedGlobal("signature"); @@ -134,9 +127,6 @@ void RACFED::updateCompileSigRandom(Function &F, Module &Md) { std::uniform_int_distribution dist(1, 0x7fffffff); auto *I32 = Type::getInt32Ty(Ctx); if (!SigGV) { -#if MARTI_DEBUG - errs() << "SigGV " << SigGV << "\n"; -#endif SigGV = new GlobalVariable( Md, I32, @@ -146,8 +136,6 @@ void RACFED::updateCompileSigRandom(Function &F, Module &Md) { "signature"); } - bool changed = false; - for (auto &BB: F){ std::vector OrigInstructions; originalInstruction(BB, OrigInstructions); @@ -155,10 +143,11 @@ void RACFED::updateCompileSigRandom(Function &F, Module &Md) { if (OrigInstructions.size() <= 2) continue; + uint64_t partial_sum; + for (Instruction *I : OrigInstructions) { Instruction *InsertPt = nullptr; - // Non puoi inserire "dopo" un terminator: inserisci prima del terminator stesso if (I->isTerminator()) { InsertPt = I; // insert BEFORE terminator @@ -170,16 +159,18 @@ void RACFED::updateCompileSigRandom(Function &F, Module &Md) { // signature = signature + randomConstant uint32_t K = dist(rng); - #if MARTI_DEBUG - errs() << "Dist value: " << K << "\n"; - #endif + + try { + partial_sum = K + sumIntraInstruction.at(&BB); + } catch (std::out_of_range &) { + partial_sum = K; + } + + sumIntraInstruction.insert(std::pair(&BB, partial_sum)); + Value *OldSig = B.CreateLoad(I32, SigGV); -#if MARTI_DEBUG - errs() << "Loaded Signature" << "\n"; -#endif Value *Add = B.CreateAdd(OldSig, ConstantInt::get(I32, K), "sig_add"); B.CreateStore(Add, SigGV); - changed= true; } } } @@ -187,60 +178,22 @@ void RACFED::updateCompileSigRandom(Function &F, Module &Md) { // --- CREATE CFG VERIFICATION --- -void RACFED::splitBBsAtCalls(Module &Md) { - for (Function &Fn : Md) { - if (shouldCompile(Fn, FuncAnnotations)) { - std::vector CallInsts; - for (BasicBlock &BB : Fn) { - for (Instruction &I : BB) { - if (isa(&I) && !isa(&I)) { - CallInsts.push_back(cast(&I)); - } - } - } - - for (CallBase *Call : CallInsts) { - if (Call->getParent()->getTerminator() != Call) { - SplitBlock(Call->getParent(), Call->getNextNode()); - } - } - } - } -} - -CallBase *RACFED::isCallBB(BasicBlock &BB) { - for (Instruction &I : BB) { - if (isa(&I) && !isa(&I)) { - return cast(&I); - } - } - return nullptr; -} - -void RACFED::initializeEntryBlocksMap(Module &Md) { - // Implementation for INTRA_FUNCTION_CFC == 1, left empty for now as we - // default to 0 -} - -Value *RACFED::getCondition(Instruction &I) { - // Helper to get condition from terminator if it's a branch - if (BranchInst *BI = dyn_cast(&I)) { - if (BI->isConditional()) { - return BI->getCondition(); - } - } - return nullptr; -} void RACFED::createCFGVerificationBB( BasicBlock &BB, std::unordered_map &RandomNumberBBs, std::unordered_map &SubRanPrevVals, Value &RuntimeSig, - Value &RetSig, BasicBlock &ErrBB) { + Value &RetSig, BasicBlock &ErrBB +) { + + // checkBeginning() NON ENTRY BLOCK + // compileTimeSig - subRunPrevVal + // if compileTimeSig != runtime_sig error() auto *IntType = llvm::Type::getInt32Ty(BB.getContext()); int randomNumberBB = RandomNumberBBs.find(&BB)->second; int subRanPrevVal = SubRanPrevVals.find(&BB)->second; + // in this case BB is not the first Basic Block of the function, so it has to // update RuntimeSig and check it if (!BB.isEntryBlock()) { @@ -286,6 +239,16 @@ void RACFED::createCFGVerificationBB( } } + // checkReturnVal() + // compute returnValue + // compute adjValue + // runtime_sig = runtime_sig + adjValue + + + // checkBranchJump() + // compute adjValue + // runtime_sig = runtime_sig + adjValue + // update the signature for the successors int randomNumberBB_succ; int subRanPrevVal_succ; @@ -327,27 +290,27 @@ void RACFED::createCFGVerificationBB( } // Handle return instructions - if (isa(Term)) { - BasicBlock *RetVerificationBB = BasicBlock::Create( - BB.getContext(), "RACFED_ret_Verification_BB", BB.getParent(), &BB); - // Move instructions from BB to RetVerificationBB, except the verification - // logic we just added? No, we want to verify BEFORE return. Actually, the - // verification block is already added at the beginning of BB. Now we want - // to update signature before return? RASM updates signature at exit? - - - - IRBuilder<> BRet(RetVerificationBB); - Value *InstrRuntimeSig = BRet.CreateLoad(IntType, &RuntimeSig, true); - Value *InstrRetSig = BRet.CreateLoad(IntType, &RetSig, true); - - // In RASM/RACFED, we might check if RuntimeSig matches RetSig (or some - // derived value) at return. For now, let's just check if they are - // consistent. But RetSig is initialized to RandomNumberBBs.size() + - // currSig. - - // Let's stick to the basic block verification for now. - } + // if (isa(Term)) { + // BasicBlock *RetVerificationBB = BasicBlock::Create( + // BB.getContext(), "RACFED_ret_Verification_BB", BB.getParent(), &BB); + // // Move instructions from BB to RetVerificationBB, except the verification + // // logic we just added? No, we want to verify BEFORE return. Actually, the + // // verification block is already added at the beginning of BB. Now we want + // // to update signature before return? RASM updates signature at exit? + // + // + // + // IRBuilder<> BRet(RetVerificationBB); + // Value *InstrRuntimeSig = BRet.CreateLoad(IntType, &RuntimeSig, true); + // Value *InstrRetSig = BRet.CreateLoad(IntType, &RetSig, true); + // + // // In RASM/RACFED, we might check if RuntimeSig matches RetSig (or some + // // derived value) at return. For now, let's just check if they are + // // consistent. But RetSig is initialized to RandomNumberBBs.size() + + // // currSig. + // + // // Let's stick to the basic block verification for now. + // } } PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { @@ -380,28 +343,10 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { // break; // } // } - // - // for (BasicBlock &BB : Fn) { - // std::vector OrigInstructions; - // originalInstruction(BB, OrigInstructions); - // if (OrigInstructions.size()<2) - // continue; - // int sumOfIntraUpdates = 0; - // auto *IntType = llvm::Type::getInt32Ty(BB.getContext()); // control to get context for add and compare ... - // - // for (Instruction *I:OrigInstructions) { - // int r = rand(); - // sumOfIntraUpdates += r; - // InstrUpdates[I]=r; - // } - // sumIntraInstruction[&BB] = sumOfIntraUpdates; - // } // } return PreservedAnalyses::all(); } - - extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK llvmGetPassPluginInfo() { @@ -417,3 +362,50 @@ llvmGetPassPluginInfo() { }); }}; } + +// -- UNUSED FUNCTIONS -- + +// void RACFED::splitBBsAtCalls(Module &Md) { +// for (Function &Fn : Md) { +// if (shouldCompile(Fn, FuncAnnotations)) { +// std::vector CallInsts; +// for (BasicBlock &BB : Fn) { +// for (Instruction &I : BB) { +// if (isa(&I) && !isa(&I)) { +// CallInsts.push_back(cast(&I)); +// } +// } +// } +// +// for (CallBase *Call : CallInsts) { +// if (Call->getParent()->getTerminator() != Call) { +// SplitBlock(Call->getParent(), Call->getNextNode()); +// } +// } +// } +// } +// } +// +// CallBase *RACFED::isCallBB(BasicBlock &BB) { +// for (Instruction &I : BB) { +// if (isa(&I) && !isa(&I)) { +// return cast(&I); +// } +// } +// return nullptr; +// } +// +// void RACFED::initializeEntryBlocksMap(Module &Md) { +// // Implementation for INTRA_FUNCTION_CFC == 1, left empty for now as we +// // default to 0 +// } +// +// Value *RACFED::getCondition(Instruction &I) { +// // Helper to get condition from terminator if it's a branch +// if (BranchInst *BI = dyn_cast(&I)) { +// if (BI->isConditional()) { +// return BI->getCondition(); +// } +// } +// return nullptr; +// } \ No newline at end of file From 083ec5140b19e48dd4e3e50a1e2153329ee8e989 Mon Sep 17 00:00:00 2001 From: Gab-San Date: Thu, 25 Dec 2025 19:17:27 +0100 Subject: [PATCH 11/29] standardized Made everything unsigned 32 bit values Added multiline test functions --- passes/ASPIS.h | 23 +- passes/RACFED.cpp | 214 ++++++++++-------- testing/tests/c/multi_instruction/function.c | 14 ++ .../tests/c/multi_instruction/if_then_else.c | 22 ++ .../{simpleMultiLine.c => simple.c} | 0 5 files changed, 165 insertions(+), 108 deletions(-) create mode 100644 testing/tests/c/multi_instruction/function.c create mode 100644 testing/tests/c/multi_instruction/if_then_else.c rename testing/tests/c/multi_instruction/{simpleMultiLine.c => simple.c} (100%) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index f783ae5..bbbbeac 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -160,8 +160,8 @@ class RACFED : public PassInfoMixin { private: std::map FuncAnnotations; std::map NewBBs; - std::unordered_map compileTimeSig; - std::unordered_map subRanPrevVals; + std::unordered_map compileTimeSig; + std::unordered_map subRanPrevVals; std::unordered_map sumIntraInstruction; @@ -170,22 +170,25 @@ class RACFED : public PassInfoMixin { #endif // -- INITIALIZE BLOCKS -- - void initializeBlocksSignatures(Module &Md); + void initializeBlocksSignatures(Module &Md, Function &Fn); + // -- UPDATE COMPILE SIG RANDOM -- - void updateCompileSigRandom(Function &F, Module &Md); + void updateCompileSigRandom(Module &Md, Function &Fn); // -- CREATE CFG VERIFICATION -- + void checkCompileTimeSigAtJump(Module &Md, Function &Fn); void splitBBsAtCalls(Module &Md); - int countOriginalInstructions(BasicBlock &BB); CallBase *isCallBB(BasicBlock &BB); void initializeEntryBlocksMap(Module &Md); Value *getCondition(Instruction &I); - void createCFGVerificationBB(BasicBlock &BB, - std::unordered_map &RandomNumberBBs, - std::unordered_map &SubRanPrevVals, - Value &RuntimeSig, Value &RetSig, - BasicBlock &ErrBB); + void createCFGVerificationBB( + BasicBlock &BB, + std::unordered_map &RandomNumberBBs, + std::unordered_map &SubRanPrevVals, + Value &RuntimeSig, Value &RetSig, + BasicBlock &ErrBB + ); public: PreservedAnalyses run(Module &Md, ModuleAnalysisManager &); diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 201306a..6ff8534 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -29,7 +29,7 @@ using namespace llvm; 8: for all original instructions insert after 9: signature ← signature + random number * create CFG - * checkBeginning + * checkCompileTimeSigAtJump 10:for all BB in CFG insert at beginning 11: signature ← signature − subRanPrevVal 12: if signature != compileTimeSig error() @@ -38,7 +38,7 @@ using namespace llvm; 14: if Last Instr. is return instr. and NrIntrBB > 1 then 15: Calculate needed variables 16: return Val ← random number -17: adjust Value ← (compileTimeSigBB + Sum{instrMonUpdates}) - +17: adjust Value ← (compileTimeSigBB + Sum{in%2 = load i32, ptr @signature, align 4 18: return Val 19: Insert signature update before return instr. 20: signature ← signature + adjustValue @@ -56,23 +56,23 @@ using namespace llvm; // --- INITIALIZE BLOCKS RANDOM --- bool isNotUniqueCompileTimeSig( - const int bb_num, - const std::unordered_map &compileTimeSig + const uint32_t bb_num, + const std::unordered_map &compileTimeSig ) { - for (const auto &pair : compileTimeSig) { - if (pair.second == bb_num) return true; + for (const auto &[_, other_bb_id] : compileTimeSig) { + if ( other_bb_id == bb_num ) return true; } return false; } bool isNotUnique( - const int bb_num, const int subrun_num, - const std::unordered_map &RandomNumBBs, - const std::unordered_map &SubRanPrevVals + const uint32_t current_id, + const std::unordered_map &RandomNumBBs, + const std::unordered_map &SubRanPrevVals ) { - - for (const auto &pair : RandomNumBBs) { - if (pair.second + SubRanPrevVals.at(pair.first) == bb_num + subrun_num) { + for (const auto &[other_bb, other_bb_num] : RandomNumBBs) { + uint32_t other_id = static_cast(other_bb_num) + SubRanPrevVals.at(other_bb); + if ( other_id == current_id ) { return true; } } @@ -80,38 +80,32 @@ bool isNotUnique( return false; } -void RACFED::initializeBlocksSignatures(Module &Md) { - int i = 0; - srand(static_cast(time(nullptr))); // compileTimeSig weak random generator - int randomBB; - int randomSub; - - for (Function &Fn : Md) { - if (shouldCompile(Fn, FuncAnnotations)) { - for (BasicBlock &BB : Fn) { - - do { - randomBB = rand(); - } while (isNotUniqueCompileTimeSig(randomBB, compileTimeSig)); - - do { - randomSub = rand(); - } while (isNotUnique(i, randomSub, compileTimeSig, subRanPrevVals)); - - compileTimeSig.insert(std::pair(&BB, randomBB));//not random, guarantees unicity - subRanPrevVals.insert(std::pair(&BB, randomSub)); //In this way the sub value is random - sumIntraInstruction.insert(std::pair(&BB, 0));//assign value to the sum of the instr - i++; - - } - } +void RACFED::initializeBlocksSignatures(Module &Md, Function &Fn) { + std::mt19937 rng(0xB00BA5); // seed fisso per riproducibilità + std::uniform_int_distribution dist(1, 0x7fffffff); + uint32_t randomBB; + uint32_t randomSub; + + for (BasicBlock &BB : Fn) { + do { + randomBB = dist(rng); + } while ( isNotUniqueCompileTimeSig(randomBB, compileTimeSig) ); + + do { + randomSub = dist(rng); + } while ( isNotUnique( + static_cast(randomBB) + randomSub, + compileTimeSig, + subRanPrevVals) ); + + compileTimeSig.insert(std::pair(&BB, randomBB)); + subRanPrevVals.insert(std::pair(&BB, randomSub)); } } // --- UPDATE SIGNATURE RANDOM --- void originalInstruction(BasicBlock &BB, std::vector &OrigInstructions) { - for (Instruction &I : BB) { if (isa(&I)) continue; // NON è originale if (I.isTerminator()) continue; // NON è originale @@ -120,28 +114,27 @@ void originalInstruction(BasicBlock &BB, std::vector &OrigInstruc } } -void RACFED::updateCompileSigRandom(Function &F, Module &Md) { +void RACFED::updateCompileSigRandom(Module &Md, Function &Fn) { LLVMContext &Ctx = Md.getContext(); GlobalVariable *SigGV = Md.getNamedGlobal("signature"); std::mt19937 rng(0xC0FFEE); // seed fisso per riproducibilità std::uniform_int_distribution dist(1, 0x7fffffff); - auto *I32 = Type::getInt32Ty(Ctx); + auto *I64 = Type::getInt64Ty(Ctx); if (!SigGV) { SigGV = new GlobalVariable( Md, - I32, + I64, /*isConstant=*/false, GlobalValue::ExternalLinkage, - ConstantInt::get(I32, 0), + ConstantInt::get(I64, 0), "signature"); } - for (auto &BB: F){ + for (auto &BB: Fn){ std::vector OrigInstructions; originalInstruction(BB, OrigInstructions); - if (OrigInstructions.size() <= 2) - continue; + if (OrigInstructions.size() <= 2) continue; uint64_t partial_sum; @@ -158,7 +151,7 @@ void RACFED::updateCompileSigRandom(Function &F, Module &Md) { IRBuilder<> B(InsertPt); // signature = signature + randomConstant - uint32_t K = dist(rng); + uint64_t K = dist(rng); try { partial_sum = K + sumIntraInstruction.at(&BB); @@ -168,15 +161,76 @@ void RACFED::updateCompileSigRandom(Function &F, Module &Md) { sumIntraInstruction.insert(std::pair(&BB, partial_sum)); - Value *OldSig = B.CreateLoad(I32, SigGV); - Value *Add = B.CreateAdd(OldSig, ConstantInt::get(I32, K), "sig_add"); + Value *OldSig = B.CreateLoad(I64, SigGV); + Value *Add = B.CreateAdd(OldSig, ConstantInt::get(I64, K), "sig_add"); B.CreateStore(Add, SigGV); } } + } // --- CREATE CFG VERIFICATION --- +void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn) { + auto *IntType = llvm::Type::getInt64Ty(Md.getContext()); + + BasicBlock *ErrBB = BasicBlock::Create(Fn.getContext(), "ErrBB", &Fn); + IRBuilder<> ErrB(ErrBB); + + IRBuilder<> B(&*(Fn.front().getFirstInsertionPt())); + + Value *RuntimeSig = B.CreateAlloca(IntType); + + for(BasicBlock &BB: Fn) { + int randomNumberBB = compileTimeSig.find(&BB)->second; + int subRanPrevVal = subRanPrevVals.find(&BB)->second; + + // in this case BB is not the first Basic Block of the function, so it has to + // update RuntimeSig and check it + if (!BB.isEntryBlock()) { + if (isa(BB.getFirstNonPHI()) || + BB.getName().contains_insensitive("verification")) { + IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); + BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), + RuntimeSig, true); + } else if (!BB.getName().contains_insensitive("errbb")) { + BasicBlock *NewBB = BasicBlock::Create( + BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB); + IRBuilder<> BChecker(NewBB); + + // add instructions for the first runtime signature update + Value *InstrRuntimeSig = BChecker.CreateLoad(IntType, RuntimeSig, true); + + Value *RuntimeSignatureVal = BChecker.CreateSub( + InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevVal)); + BChecker.CreateStore(RuntimeSignatureVal, RuntimeSig, true); + + // update phi placing them in the new block + while (isa(&BB.front())) { + Instruction *PhiInst = &BB.front(); + PhiInst->removeFromParent(); + PhiInst->insertBefore(&NewBB->front()); + } + + // replace the uses of BB with NewBB + for (BasicBlock &BB_ : *BB.getParent()) { + if (&BB_ != NewBB) { + BB_.getTerminator()->replaceSuccessorWith(&BB, NewBB); + } + } + + // add instructions for checking the runtime signature + Value *CmpVal = + BChecker.CreateCmp(llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, + llvm::ConstantInt::get(IntType, randomNumberBB)); + BChecker.CreateCondBr(CmpVal, &BB, ErrBB); + + // add NewBB and BB into the NewBBs map + NewBBs.insert(std::pair(NewBB, &BB)); + } + } + } +} void RACFED::createCFGVerificationBB( @@ -185,59 +239,15 @@ void RACFED::createCFGVerificationBB( Value &RetSig, BasicBlock &ErrBB ) { - // checkBeginning() NON ENTRY BLOCK + // checkCompileSigAtJump() NON ENTRY BLOCK // compileTimeSig - subRunPrevVal // if compileTimeSig != runtime_sig error() - auto *IntType = llvm::Type::getInt32Ty(BB.getContext()); + auto *IntType = llvm::Type::getInt64Ty(BB.getContext()); int randomNumberBB = RandomNumberBBs.find(&BB)->second; int subRanPrevVal = SubRanPrevVals.find(&BB)->second; - // in this case BB is not the first Basic Block of the function, so it has to - // update RuntimeSig and check it - if (!BB.isEntryBlock()) { - if (isa(BB.getFirstNonPHI()) || - BB.getName().contains_insensitive("verification")) { - IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); - BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), - &RuntimeSig, true); - } else if (!BB.getName().contains_insensitive("errbb")) { - BasicBlock *NewBB = BasicBlock::Create( - BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB); - IRBuilder<> BChecker(NewBB); - - // add instructions for the first runtime signature update - Value *InstrRuntimeSig = BChecker.CreateLoad(IntType, &RuntimeSig, true); - - Value *RuntimeSignatureVal = BChecker.CreateSub( - InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevVal)); - BChecker.CreateStore(RuntimeSignatureVal, &RuntimeSig, true); - - // update phi placing them in the new block - while (isa(&BB.front())) { - Instruction *PhiInst = &BB.front(); - PhiInst->removeFromParent(); - PhiInst->insertBefore(&NewBB->front()); - } - - // replace the uses of BB with NewBB - for (BasicBlock &BB_ : *BB.getParent()) { - if (&BB_ != NewBB) { - BB_.getTerminator()->replaceSuccessorWith(&BB, NewBB); - } - } - - // add instructions for checking the runtime signature - Value *CmpVal = - BChecker.CreateCmp(llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, - llvm::ConstantInt::get(IntType, randomNumberBB)); - BChecker.CreateCondBr(CmpVal, &BB, &ErrBB); - - // add NewBB and BB into the NewBBs map - NewBBs.insert(std::pair(NewBB, &BB)); - } - } // checkReturnVal() // compute returnValue @@ -313,6 +323,7 @@ void RACFED::createCFGVerificationBB( // } } + PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { // mappa: istruzione originale -> random r usato per S = S + r std::unordered_map InstrUpdates; @@ -323,10 +334,17 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { getFuncAnnotations(Md, FuncAnnotations); LinkageMap linkageMap = mapFunctionLinkageNames((Md)); - initializeBlocksSignatures(Md); + for (Function &Fn : Md) { + if (shouldCompile(Fn, FuncAnnotations)) + initializeBlocksSignatures(Md, Fn); + } - for (Function &F: Md){ - updateCompileSigRandom(F, Md); + for (Function &Fn: Md) { + updateCompileSigRandom(Md, Fn); + } + + for(Function &Fn: Md) { + checkCompileTimeSigAtJump(Md, Fn); } // createCFGVerificationBB(); @@ -408,4 +426,4 @@ llvmGetPassPluginInfo() { // } // } // return nullptr; -// } \ No newline at end of file +// } diff --git a/testing/tests/c/multi_instruction/function.c b/testing/tests/c/multi_instruction/function.c new file mode 100644 index 0000000..7ed50d1 --- /dev/null +++ b/testing/tests/c/multi_instruction/function.c @@ -0,0 +1,14 @@ +int max(int a, int b, int c) { + int max = a > b ? a : b; + max = max > c ? max : c; + return max; +} + + +int main() { + int a = 10; + int b = 20; + int c = 30; + max(a, b, c); + return 0; +} diff --git a/testing/tests/c/multi_instruction/if_then_else.c b/testing/tests/c/multi_instruction/if_then_else.c new file mode 100644 index 0000000..876fef1 --- /dev/null +++ b/testing/tests/c/multi_instruction/if_then_else.c @@ -0,0 +1,22 @@ +#include + +int main() { + int a = 10; + int b = 20; + int c = a + b; + a = 12; + b = 13; + int d = a + b; + if(c > d) { + a = 15; + b = 2; + d = a + b; + } else { + a = 13; + b = 19; + c = a + b; + } + + printf("c: %d d: %d\n", c, d); + return 0; +} diff --git a/testing/tests/c/multi_instruction/simpleMultiLine.c b/testing/tests/c/multi_instruction/simple.c similarity index 100% rename from testing/tests/c/multi_instruction/simpleMultiLine.c rename to testing/tests/c/multi_instruction/simple.c From 8eda1112b8001b34bf2775efccd3614a10a42b5e Mon Sep 17 00:00:00 2001 From: martina Date: Sun, 28 Dec 2025 23:02:27 +0100 Subject: [PATCH 12/29] branch try-- to test --- passes/ASPIS.h | 23 ++++++++++------------- passes/RACFED.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index bbbbeac..f783ae5 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -160,8 +160,8 @@ class RACFED : public PassInfoMixin { private: std::map FuncAnnotations; std::map NewBBs; - std::unordered_map compileTimeSig; - std::unordered_map subRanPrevVals; + std::unordered_map compileTimeSig; + std::unordered_map subRanPrevVals; std::unordered_map sumIntraInstruction; @@ -170,25 +170,22 @@ class RACFED : public PassInfoMixin { #endif // -- INITIALIZE BLOCKS -- - void initializeBlocksSignatures(Module &Md, Function &Fn); - + void initializeBlocksSignatures(Module &Md); // -- UPDATE COMPILE SIG RANDOM -- - void updateCompileSigRandom(Module &Md, Function &Fn); + void updateCompileSigRandom(Function &F, Module &Md); // -- CREATE CFG VERIFICATION -- - void checkCompileTimeSigAtJump(Module &Md, Function &Fn); void splitBBsAtCalls(Module &Md); + int countOriginalInstructions(BasicBlock &BB); CallBase *isCallBB(BasicBlock &BB); void initializeEntryBlocksMap(Module &Md); Value *getCondition(Instruction &I); - void createCFGVerificationBB( - BasicBlock &BB, - std::unordered_map &RandomNumberBBs, - std::unordered_map &SubRanPrevVals, - Value &RuntimeSig, Value &RetSig, - BasicBlock &ErrBB - ); + void createCFGVerificationBB(BasicBlock &BB, + std::unordered_map &RandomNumberBBs, + std::unordered_map &SubRanPrevVals, + Value &RuntimeSig, Value &RetSig, + BasicBlock &ErrBB); public: PreservedAnalyses run(Module &Md, ModuleAnalysisManager &); diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 6ff8534..6149cd2 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -170,6 +170,48 @@ void RACFED::updateCompileSigRandom(Module &Md, Function &Fn) { } // --- CREATE CFG VERIFICATION --- +ConstantInt *RACFED::expectedSignature(BasicBlock *Succ, Module &Md, + const std::unordered_map &compileTimeSig, + const std::unordered_map &subRanPrevVals) { + const int expected = compileTimeSig.at(Succ); + const int expectedSub = subRanPrevVals.at(Succ); + auto *I32 = Type::getInt32Ty(Md.getContext()); + return ConstantInt:: get(I32, expected+expectedSub); + +} +void RACFED:: checkBranches(IRBuilder<> B, BasicBlock &BB, Module &Md, GlobalVariable *RuntimeSigGV) { + Instruction *Term = BB.getTerminator(); + auto *BI = dyn_cast(Term); + if (!BI) return; + LLVMContext &Ctx = BB.getContext(); + auto *I32 = Type::getInt32Ty(Ctx); + //load the current runtimevariable + Value *Current = B.CreateLoad(I32, RuntimeSigGV, "current"); + Value *Expected = nullptr; + +//define if conditional or unconditional branch + //Conditional: expected= CT_succ+subRan_succ + //adj = CTB-exp--> new signature = RT -adj + if (BI -> isUnconditional()) { + BasicBlock *Succ = BI->getSuccessor(0); + auto expected = expectedSignature(Succ,Md,compileTimeSig,subRanPrevVals); + // adj = expected - current + Value *Adj = B.CreateSub(Expected, Current, "racfed.adj"); + Value *NewSig = B.CreateAdd(Current, Adj, "racfed.newsig"); + B.CreateStore(NewSig, RuntimeSigGV); + + // verify newSig == expected + Value *Ok = B.CreateICmpEQ(NewSig, Expected, "racfed.ok"); + + // Replace terminator with condbr(ok, succ, ErrBB) + BI->eraseFromParent(); + IRBuilder<> BT(&BB); + BT.CreateCondBr(Ok, Succ, nullptr); + }else { + BasicBlock *SuccT = BI->getSuccessor(0); + BasicBlock *SuccF = BI->getSuccessor(1); + + } void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn) { auto *IntType = llvm::Type::getInt64Ty(Md.getContext()); @@ -233,6 +275,10 @@ void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn) { } + + //Conditional: compute the two adj and the signature that corresponds. +} + void RACFED::createCFGVerificationBB( BasicBlock &BB, std::unordered_map &RandomNumberBBs, std::unordered_map &SubRanPrevVals, Value &RuntimeSig, From d715309df1d8373a955b014ed8e21406a4cbd78b Mon Sep 17 00:00:00 2001 From: Gab-San Date: Mon, 29 Dec 2025 17:19:06 +0100 Subject: [PATCH 13/29] Fixed compilation issues Fixed error introduced on last push --- passes/ASPIS.h | 30 +++-- passes/RACFED.cpp | 315 +++++++++++++++++++++++----------------------- 2 files changed, 177 insertions(+), 168 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index f783ae5..c685488 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -160,8 +160,8 @@ class RACFED : public PassInfoMixin { private: std::map FuncAnnotations; std::map NewBBs; - std::unordered_map compileTimeSig; - std::unordered_map subRanPrevVals; + std::unordered_map compileTimeSig; + std::unordered_map subRanPrevVals; std::unordered_map sumIntraInstruction; @@ -170,22 +170,30 @@ class RACFED : public PassInfoMixin { #endif // -- INITIALIZE BLOCKS -- - void initializeBlocksSignatures(Module &Md); + void initializeBlocksSignatures(Module &Md, Function &Fn); // -- UPDATE COMPILE SIG RANDOM -- - void updateCompileSigRandom(Function &F, Module &Md); + void updateCompileSigRandom(Module &Md, Function &Fn, + GlobalVariable *RuntimeSigGV, Type *IntType); - // -- CREATE CFG VERIFICATION -- + // --- CHECK BLOCKS AT JUMP END --- + void checkCompileTimeSigAtJump(Module &Md, Function &Fn, + GlobalVariable *RuntimeSigGV, Type *IntType); + + // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- + + void checkBranches(Module &Md, GlobalVariable *RuntimeSigGV, Type *IntType, + IRBuilder<> B, BasicBlock &BB); void splitBBsAtCalls(Module &Md); - int countOriginalInstructions(BasicBlock &BB); + // int countOriginalInstructions(BasicBlock &BB); CallBase *isCallBB(BasicBlock &BB); void initializeEntryBlocksMap(Module &Md); Value *getCondition(Instruction &I); - void createCFGVerificationBB(BasicBlock &BB, - std::unordered_map &RandomNumberBBs, - std::unordered_map &SubRanPrevVals, - Value &RuntimeSig, Value &RetSig, - BasicBlock &ErrBB); + // void createCFGVerificationBB(BasicBlock &BB, + // std::unordered_map &RandomNumberBBs, + // std::unordered_map &SubRanPrevVals, + // Value &RuntimeSig, Value &RetSig, + // BasicBlock &ErrBB); public: PreservedAnalyses run(Module &Md, ModuleAnalysisManager &); diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 6149cd2..cbad6e2 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -28,7 +28,6 @@ using namespace llvm; 7: if NrInstrBB > 2 then 8: for all original instructions insert after 9: signature ← signature + random number - * create CFG * checkCompileTimeSigAtJump 10:for all BB in CFG insert at beginning 11: signature ← signature − subRanPrevVal @@ -105,7 +104,8 @@ void RACFED::initializeBlocksSignatures(Module &Md, Function &Fn) { // --- UPDATE SIGNATURE RANDOM --- -void originalInstruction(BasicBlock &BB, std::vector &OrigInstructions) { + +void originalInstruction(BasicBlock &BB, std::vector &OrigInstructions) { for (Instruction &I : BB) { if (isa(&I)) continue; // NON è originale if (I.isTerminator()) continue; // NON è originale @@ -114,21 +114,11 @@ void originalInstruction(BasicBlock &BB, std::vector &OrigInstruc } } -void RACFED::updateCompileSigRandom(Module &Md, Function &Fn) { - LLVMContext &Ctx = Md.getContext(); - GlobalVariable *SigGV = Md.getNamedGlobal("signature"); +void RACFED::updateCompileSigRandom(Module &Md, Function &Fn, + GlobalVariable *RuntimeSigGV, + Type *IntType) { std::mt19937 rng(0xC0FFEE); // seed fisso per riproducibilità std::uniform_int_distribution dist(1, 0x7fffffff); - auto *I64 = Type::getInt64Ty(Ctx); - if (!SigGV) { - SigGV = new GlobalVariable( - Md, - I64, - /*isConstant=*/false, - GlobalValue::ExternalLinkage, - ConstantInt::get(I64, 0), - "signature"); - } for (auto &BB: Fn){ std::vector OrigInstructions; @@ -161,68 +151,23 @@ void RACFED::updateCompileSigRandom(Module &Md, Function &Fn) { sumIntraInstruction.insert(std::pair(&BB, partial_sum)); - Value *OldSig = B.CreateLoad(I64, SigGV); - Value *Add = B.CreateAdd(OldSig, ConstantInt::get(I64, K), "sig_add"); - B.CreateStore(Add, SigGV); + Value *OldSig = B.CreateLoad(IntType, RuntimeSigGV); + Value *Add = B.CreateAdd(OldSig, ConstantInt::get(IntType, K), "sig_add"); + B.CreateStore(Add, RuntimeSigGV); } } } -// --- CREATE CFG VERIFICATION --- -ConstantInt *RACFED::expectedSignature(BasicBlock *Succ, Module &Md, - const std::unordered_map &compileTimeSig, - const std::unordered_map &subRanPrevVals) { - const int expected = compileTimeSig.at(Succ); - const int expectedSub = subRanPrevVals.at(Succ); - auto *I32 = Type::getInt32Ty(Md.getContext()); - return ConstantInt:: get(I32, expected+expectedSub); - -} -void RACFED:: checkBranches(IRBuilder<> B, BasicBlock &BB, Module &Md, GlobalVariable *RuntimeSigGV) { - Instruction *Term = BB.getTerminator(); - auto *BI = dyn_cast(Term); - if (!BI) return; - LLVMContext &Ctx = BB.getContext(); - auto *I32 = Type::getInt32Ty(Ctx); - //load the current runtimevariable - Value *Current = B.CreateLoad(I32, RuntimeSigGV, "current"); - Value *Expected = nullptr; - -//define if conditional or unconditional branch - //Conditional: expected= CT_succ+subRan_succ - //adj = CTB-exp--> new signature = RT -adj - if (BI -> isUnconditional()) { - BasicBlock *Succ = BI->getSuccessor(0); - auto expected = expectedSignature(Succ,Md,compileTimeSig,subRanPrevVals); - // adj = expected - current - Value *Adj = B.CreateSub(Expected, Current, "racfed.adj"); - Value *NewSig = B.CreateAdd(Current, Adj, "racfed.newsig"); - B.CreateStore(NewSig, RuntimeSigGV); - - // verify newSig == expected - Value *Ok = B.CreateICmpEQ(NewSig, Expected, "racfed.ok"); - - // Replace terminator with condbr(ok, succ, ErrBB) - BI->eraseFromParent(); - IRBuilder<> BT(&BB); - BT.CreateCondBr(Ok, Succ, nullptr); - }else { - BasicBlock *SuccT = BI->getSuccessor(0); - BasicBlock *SuccF = BI->getSuccessor(1); - - } +// --- CHECK BLOCKS AT JUMP END --- -void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn) { - auto *IntType = llvm::Type::getInt64Ty(Md.getContext()); - +void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn, + GlobalVariable *RuntimeSigGV, Type *IntType) { BasicBlock *ErrBB = BasicBlock::Create(Fn.getContext(), "ErrBB", &Fn); IRBuilder<> ErrB(ErrBB); IRBuilder<> B(&*(Fn.front().getFirstInsertionPt())); - Value *RuntimeSig = B.CreateAlloca(IntType); - for(BasicBlock &BB: Fn) { int randomNumberBB = compileTimeSig.find(&BB)->second; int subRanPrevVal = subRanPrevVals.find(&BB)->second; @@ -234,18 +179,18 @@ void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn) { BB.getName().contains_insensitive("verification")) { IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), - RuntimeSig, true); + RuntimeSigGV, true); } else if (!BB.getName().contains_insensitive("errbb")) { BasicBlock *NewBB = BasicBlock::Create( BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB); IRBuilder<> BChecker(NewBB); // add instructions for the first runtime signature update - Value *InstrRuntimeSig = BChecker.CreateLoad(IntType, RuntimeSig, true); + Value *InstrRuntimeSig = BChecker.CreateLoad(IntType, RuntimeSigGV, true); Value *RuntimeSignatureVal = BChecker.CreateSub( InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevVal)); - BChecker.CreateStore(RuntimeSignatureVal, RuntimeSig, true); + BChecker.CreateStore(RuntimeSignatureVal, RuntimeSigGV, true); // update phi placing them in the new block while (isa(&BB.front())) { @@ -274,108 +219,164 @@ void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn) { } } +// --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- - - //Conditional: compute the two adj and the signature that corresponds. -} - -void RACFED::createCFGVerificationBB( - BasicBlock &BB, std::unordered_map &RandomNumberBBs, - std::unordered_map &SubRanPrevVals, Value &RuntimeSig, - Value &RetSig, BasicBlock &ErrBB +ConstantInt* expectedSignature( + BasicBlock *Succ, Module &Md, + const std::unordered_map &compileTimeSig, + const std::unordered_map &subRanPrevVals ) { + const int expected = compileTimeSig.at(Succ); + const int expectedSub = subRanPrevVals.at(Succ); + auto *I32 = Type::getInt32Ty(Md.getContext()); + return ConstantInt:: get(I32, expected+expectedSub); +} - // checkCompileSigAtJump() NON ENTRY BLOCK - // compileTimeSig - subRunPrevVal - // if compileTimeSig != runtime_sig error() - - auto *IntType = llvm::Type::getInt64Ty(BB.getContext()); - - int randomNumberBB = RandomNumberBBs.find(&BB)->second; - int subRanPrevVal = SubRanPrevVals.find(&BB)->second; - - - // checkReturnVal() - // compute returnValue - // compute adjValue - // runtime_sig = runtime_sig + adjValue +void RACFED::checkBranches(Module &Md, GlobalVariable *RuntimeSigGV, + Type *IntType, IRBuilder<> B, BasicBlock &BB) { + Instruction *Term = BB.getTerminator(); + auto *BI = dyn_cast(Term); + if (!BI) return; + //load the current runtimevariable + Value *Current = B.CreateLoad(IntType, RuntimeSigGV, "current"); + Value *Expected = nullptr; - // checkBranchJump() - // compute adjValue - // runtime_sig = runtime_sig + adjValue +//define if conditional or unconditional branch + //Conditional: expected= CT_succ+subRan_succ + //adj = CTB-exp--> new signature = RT -adj + if (BI -> isUnconditional()) { + BasicBlock *Succ = BI->getSuccessor(0); + auto expected = expectedSignature(Succ,Md,compileTimeSig,subRanPrevVals); + // adj = expected - current + Value *Adj = B.CreateSub(Expected, Current, "racfed.adj"); + Value *NewSig = B.CreateAdd(Current, Adj, "racfed.newsig"); + B.CreateStore(NewSig, RuntimeSigGV); - // update the signature for the successors - int randomNumberBB_succ; - int subRanPrevVal_succ; + // verify newSig == expected + Value *Ok = B.CreateICmpEQ(NewSig, Expected, "racfed.ok"); - Instruction *Term = BB.getTerminator(); - int successors = Term->getNumSuccessors(); - - for (int i = 0; i < successors; i++) { - BasicBlock *Succ = Term->getSuccessor(i); - if (!Succ->getName().contains_insensitive("errbb")) { - randomNumberBB_succ = RandomNumberBBs.find(Succ)->second; - subRanPrevVal_succ = randomNumberBB - randomNumberBB_succ; - - // update the map - if (SubRanPrevVals.find(Succ)->second == 1) { - SubRanPrevVals.erase(Succ); - SubRanPrevVals.insert( - std::pair(Succ, subRanPrevVal_succ)); - } else { - // if the successor has already been visited, we have to check if the - // signature is consistent - if (SubRanPrevVals.find(Succ)->second != subRanPrevVal_succ) { - // if not, we have to update the signature - int diff = subRanPrevVal_succ - SubRanPrevVals.find(Succ)->second; - IRBuilder<> B(&*BB.getFirstInsertionPt()); - if (isa(Term) && - cast(Term)->isConditional()) { - // if the terminator is a conditional branch, we have to update the - // signature only if the condition is true or false, depending on - // the successor - B.SetInsertPoint(Term); - } else { - B.SetInsertPoint(Term); - } - - } - } - } + // Replace terminator with condbr(ok, succ, ErrBB) + BI->eraseFromParent(); + IRBuilder<> BT(&BB); + BT.CreateCondBr(Ok, Succ, nullptr); + } else { + BasicBlock *SuccT = BI->getSuccessor(0); + BasicBlock *SuccF = BI->getSuccessor(1); } - - // Handle return instructions - // if (isa(Term)) { - // BasicBlock *RetVerificationBB = BasicBlock::Create( - // BB.getContext(), "RACFED_ret_Verification_BB", BB.getParent(), &BB); - // // Move instructions from BB to RetVerificationBB, except the verification - // // logic we just added? No, we want to verify BEFORE return. Actually, the - // // verification block is already added at the beginning of BB. Now we want - // // to update signature before return? RASM updates signature at exit? - // - // - // - // IRBuilder<> BRet(RetVerificationBB); - // Value *InstrRuntimeSig = BRet.CreateLoad(IntType, &RuntimeSig, true); - // Value *InstrRetSig = BRet.CreateLoad(IntType, &RetSig, true); - // - // // In RASM/RACFED, we might check if RuntimeSig matches RetSig (or some - // // derived value) at return. For now, let's just check if they are - // // consistent. But RetSig is initialized to RandomNumberBBs.size() + - // // currSig. - // - // // Let's stick to the basic block verification for now. - // } } +//Conditional: compute the two adj and the signature that corresponds. +// +// void RACFED::createCFGVerificationBB( +// BasicBlock &BB, std::unordered_map &RandomNumberBBs, +// std::unordered_map &SubRanPrevVals, Value &RuntimeSig, +// Value &RetSig, BasicBlock &ErrBB +// ) { +// +// // checkCompileSigAtJump() NON ENTRY BLOCK +// // compileTimeSig - subRunPrevVal +// // if compileTimeSig != runtime_sig error() +// +// auto *IntType = llvm::Type::getInt64Ty(BB.getContext()); +// +// int randomNumberBB = RandomNumberBBs.find(&BB)->second; +// int subRanPrevVal = SubRanPrevVals.find(&BB)->second; +// +// +// // checkReturnVal() +// // compute returnValue +// // compute adjValue +// // runtime_sig = runtime_sig + adjValue +// +// +// // checkBranchJump() +// // compute adjValue +// // runtime_sig = runtime_sig + adjValue +// +// // update the signature for the successors +// int randomNumberBB_succ; +// int subRanPrevVal_succ; +// +// Instruction *Term = BB.getTerminator(); +// int successors = Term->getNumSuccessors(); +// +// for (int i = 0; i < successors; i++) { +// BasicBlock *Succ = Term->getSuccessor(i); +// if (!Succ->getName().contains_insensitive("errbb")) { +// randomNumberBB_succ = RandomNumberBBs.find(Succ)->second; +// subRanPrevVal_succ = randomNumberBB - randomNumberBB_succ; +// +// // update the map +// if (SubRanPrevVals.find(Succ)->second == 1) { +// SubRanPrevVals.erase(Succ); +// SubRanPrevVals.insert( +// std::pair(Succ, subRanPrevVal_succ)); +// } else { +// // if the successor has already been visited, we have to check if the +// // signature is consistent +// if (SubRanPrevVals.find(Succ)->second != subRanPrevVal_succ) { +// // if not, we have to update the signature +// int diff = subRanPrevVal_succ - SubRanPrevVals.find(Succ)->second; +// IRBuilder<> B(&*BB.getFirstInsertionPt()); +// if (isa(Term) && +// cast(Term)->isConditional()) { +// // if the terminator is a conditional branch, we have to update the +// // signature only if the condition is true or false, depending on +// // the successor +// B.SetInsertPoint(Term); +// } else { +// B.SetInsertPoint(Term); +// } +// +// } +// } +// } +// } +// +// Handle return instructions +// if (isa(Term)) { +// BasicBlock *RetVerificationBB = BasicBlock::Create( +// BB.getContext(), "RACFED_ret_Verification_BB", BB.getParent(), &BB); +// // Move instructions from BB to RetVerificationBB, except the verification +// // logic we just added? No, we want to verify BEFORE return. Actually, the +// // verification block is already added at the beginning of BB. Now we want +// // to update signature before return? RASM updates signature at exit? +// +// +// +// IRBuilder<> BRet(RetVerificationBB); +// Value *InstrRuntimeSig = BRet.CreateLoad(IntType, &RuntimeSig, true); +// Value *InstrRetSig = BRet.CreateLoad(IntType, &RetSig, true); +// +// // In RASM/RACFED, we might check if RuntimeSig matches RetSig (or some +// // derived value) at return. For now, let's just check if they are +// // consistent. But RetSig is initialized to RandomNumberBBs.size() + +// // currSig. +// +// // Let's stick to the basic block verification for now. +// } +// } + PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { // mappa: istruzione originale -> random r usato per S = S + r std::unordered_map InstrUpdates; - auto *IntType = llvm::Type::getInt32Ty(Md.getContext()); + auto *I64 = llvm::Type::getInt64Ty(Md.getContext()); + auto *I32 = llvm::Type::getInt32Ty(Md.getContext()); std::unordered_map ErrBBs; + GlobalVariable *RuntimeSig = Md.getNamedGlobal("signature"); + if (!RuntimeSig) { + RuntimeSig = new GlobalVariable( + Md, + I64, + /*isConstant=*/false, + GlobalValue::ExternalLinkage, + ConstantInt::get(I64, 0), + "signature"); + } + // createFtFuncs(Md); getFuncAnnotations(Md, FuncAnnotations); LinkageMap linkageMap = mapFunctionLinkageNames((Md)); @@ -386,11 +387,11 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { } for (Function &Fn: Md) { - updateCompileSigRandom(Md, Fn); + updateCompileSigRandom(Md, Fn, RuntimeSig, I64); } for(Function &Fn: Md) { - checkCompileTimeSigAtJump(Md, Fn); + checkCompileTimeSigAtJump(Md, Fn, RuntimeSig, I64); } // createCFGVerificationBB(); From 8806792cdd553398a41813a9ccef7faf73741580 Mon Sep 17 00:00:00 2001 From: martina Date: Tue, 30 Dec 2025 14:27:21 +0100 Subject: [PATCH 14/29] branch signature verification --- passes/RACFED.cpp | 99 ++++++++++++---------- testing/tests/c/multi_instruction/ifElse.c | 19 +++++ 2 files changed, 73 insertions(+), 45 deletions(-) create mode 100644 testing/tests/c/multi_instruction/ifElse.c diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index cbad6e2..22a6278 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -160,60 +160,69 @@ void RACFED::updateCompileSigRandom(Module &Md, Function &Fn, } // --- CHECK BLOCKS AT JUMP END --- - void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn, GlobalVariable *RuntimeSigGV, Type *IntType) { + + if (Fn.isDeclaration()||Fn.empty()) { + return; + } BasicBlock *ErrBB = BasicBlock::Create(Fn.getContext(), "ErrBB", &Fn); IRBuilder<> ErrB(ErrBB); IRBuilder<> B(&*(Fn.front().getFirstInsertionPt())); + ErrB.CreateUnreachable(); + std::vector BBs; + + for (BasicBlock &BB : Fn) + BBs.push_back(&BB); - for(BasicBlock &BB: Fn) { - int randomNumberBB = compileTimeSig.find(&BB)->second; - int subRanPrevVal = subRanPrevVals.find(&BB)->second; - - // in this case BB is not the first Basic Block of the function, so it has to - // update RuntimeSig and check it + for (BasicBlock *BBPtr : BBs) { + BasicBlock &BB = *BBPtr; + // in this case BB is not the first Basic Block of the function, so it has + // to update RuntimeSig and check it if (!BB.isEntryBlock()) { - if (isa(BB.getFirstNonPHI()) || - BB.getName().contains_insensitive("verification")) { - IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); - BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), - RuntimeSigGV, true); + Instruction *FirstNonPHI = BB.getFirstNonPHI(); + if ((FirstNonPHI && isa(FirstNonPHI)) || + BB.getName().contains_insensitive("verification")) { + if (BB.getFirstInsertionPt() == BB.end()) + continue; // Skip empty/invalid blocks + int randomNumberBB = compileTimeSig.find(&BB)->second; + IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); + BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), + RuntimeSigGV, true); } else if (!BB.getName().contains_insensitive("errbb")) { - BasicBlock *NewBB = BasicBlock::Create( - BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB); - IRBuilder<> BChecker(NewBB); - - // add instructions for the first runtime signature update - Value *InstrRuntimeSig = BChecker.CreateLoad(IntType, RuntimeSigGV, true); - - Value *RuntimeSignatureVal = BChecker.CreateSub( - InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevVal)); - BChecker.CreateStore(RuntimeSignatureVal, RuntimeSigGV, true); - - // update phi placing them in the new block - while (isa(&BB.front())) { - Instruction *PhiInst = &BB.front(); - PhiInst->removeFromParent(); - PhiInst->insertBefore(&NewBB->front()); - } - - // replace the uses of BB with NewBB - for (BasicBlock &BB_ : *BB.getParent()) { - if (&BB_ != NewBB) { - BB_.getTerminator()->replaceSuccessorWith(&BB, NewBB); - } - } - - // add instructions for checking the runtime signature - Value *CmpVal = - BChecker.CreateCmp(llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, - llvm::ConstantInt::get(IntType, randomNumberBB)); - BChecker.CreateCondBr(CmpVal, &BB, ErrBB); - - // add NewBB and BB into the NewBBs map - NewBBs.insert(std::pair(NewBB, &BB)); + int randomNumberBB = compileTimeSig.find(&BB)->second; + int subRanPrevVal = subRanPrevVals.find(&BB)->second; + BasicBlock *NewBB = BasicBlock::Create( + BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB); + IRBuilder<> BChecker(NewBB); + + // add instructions for the first runtime signature update + Value *InstrRuntimeSig = + BChecker.CreateLoad(IntType, RuntimeSigGV, true); + + Value *RuntimeSignatureVal = BChecker.CreateSub( + InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevVal)); + BChecker.CreateStore(RuntimeSignatureVal, RuntimeSigGV, true); + + // update phi placing them in the new block + while (isa(&BB.front())) { + Instruction *PhiInst = &BB.front(); + PhiInst->removeFromParent(); + PhiInst->insertBefore(&NewBB->front()); + } + + // replace the uses of BB with NewBB + BB.replaceAllUsesWith(NewBB); + + // add instructions for checking the runtime signature + Value *CmpVal = + BChecker.CreateCmp(llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, + llvm::ConstantInt::get(IntType, randomNumberBB)); + BChecker.CreateCondBr(CmpVal, &BB, ErrBB); + + // add NewBB and BB into the NewBBs map + NewBBs.insert(std::pair(NewBB, &BB)); } } } diff --git a/testing/tests/c/multi_instruction/ifElse.c b/testing/tests/c/multi_instruction/ifElse.c new file mode 100644 index 0000000..0d8b183 --- /dev/null +++ b/testing/tests/c/multi_instruction/ifElse.c @@ -0,0 +1,19 @@ +// +// Created by martina on 28/12/25. +// +#include + + +int main() { + int x = 0; + x = x+1; + if (x<10) { + x = x*10; + printf("valore: %d", x) ; + } + + else + printf("valore: %d", x) ; + return 0; + +} From 66f7866d05ab6e3b51b226df43a26cae5352f858 Mon Sep 17 00:00:00 2001 From: Gab-San Date: Fri, 2 Jan 2026 20:07:01 +0100 Subject: [PATCH 15/29] Implementation of Return Value Check - Fixed error where sumIntraInstructions wasn't properly updated and crashed the execution of the program - Implemented Return Value Check - Standardized some notation in order to have better formatted and more readable code --- passes/ASPIS.h | 31 +- passes/RACFED.cpp | 413 +++++++++--------- .../c/multi_instruction/{simple.c => add.c} | 2 +- testing/tests/c/multi_instruction/func_ret.c | 23 + testing/tests/c/multi_instruction/glob.c | 9 + testing/tests/c/multi_instruction/ifElse.c | 19 - .../tests/c/multi_instruction/if_then_else.c | 28 +- testing/tests/c/multi_instruction/ret.c | 14 + 8 files changed, 276 insertions(+), 263 deletions(-) rename testing/tests/c/multi_instruction/{simple.c => add.c} (98%) create mode 100644 testing/tests/c/multi_instruction/func_ret.c create mode 100644 testing/tests/c/multi_instruction/glob.c delete mode 100644 testing/tests/c/multi_instruction/ifElse.c create mode 100644 testing/tests/c/multi_instruction/ret.c diff --git a/passes/ASPIS.h b/passes/ASPIS.h index c685488..c43cff4 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -176,24 +176,25 @@ class RACFED : public PassInfoMixin { GlobalVariable *RuntimeSigGV, Type *IntType); // --- CHECK BLOCKS AT JUMP END --- - void checkCompileTimeSigAtJump(Module &Md, Function &Fn, - GlobalVariable *RuntimeSigGV, Type *IntType); + void checkCompileTimeSigAtJump(Module &Md, Function &Fn, BasicBlock &BB, + GlobalVariable *RuntimeSigGV, Type *IntType, + BasicBlock &ErrBB); // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- + void checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, + Type *IntType); - void checkBranches(Module &Md, GlobalVariable *RuntimeSigGV, Type *IntType, - IRBuilder<> B, BasicBlock &BB); - - void splitBBsAtCalls(Module &Md); - // int countOriginalInstructions(BasicBlock &BB); - CallBase *isCallBB(BasicBlock &BB); - void initializeEntryBlocksMap(Module &Md); - Value *getCondition(Instruction &I); - // void createCFGVerificationBB(BasicBlock &BB, - // std::unordered_map &RandomNumberBBs, - // std::unordered_map &SubRanPrevVals, - // Value &RuntimeSig, Value &RetSig, - // BasicBlock &ErrBB); + // --- UPDATE RETURN VALUE AND CHECK --- + void checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, + GlobalVariable *RuntimeSigGV, + Type *IntType, BasicBlock &ErrBB, + Value *BckupRunSig); + + + // void splitBBsAtCalls(Module &Md); + // CallBase *isCallBB(BasicBlock &BB); + // void initializeEntryBlocksMap(Module &Md); + // Value *getCondition(Instruction &I); public: PreservedAnalyses run(Module &Md, ModuleAnalysisManager &); diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 22a6278..70215d2 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -13,6 +13,7 @@ #define INTRA_FUNCTION_CFC 0 // Default to 0 if not defined #define MARTI_DEBUG true +#define GAMBA_DEBUG true using namespace llvm; @@ -37,7 +38,7 @@ using namespace llvm; 14: if Last Instr. is return instr. and NrIntrBB > 1 then 15: Calculate needed variables 16: return Val ← random number -17: adjust Value ← (compileTimeSigBB + Sum{in%2 = load i32, ptr @signature, align 4 +17: adjust Value ← (compileTimeSigBB + SumIntraInstructions) - 18: return Val 19: Insert signature update before return instr. 20: signature ← signature + adjustValue @@ -51,9 +52,11 @@ using namespace llvm; 27: signature ← signature + adjustValue */ +std::uniform_int_distribution dist32(1, 0x7fffffff); +std::uniform_int_distribution dist64(1, 0xffffffff); +std::mt19937 rng64(0x5EED00); // seed fisso per riproducibilità // --- INITIALIZE BLOCKS RANDOM --- - bool isNotUniqueCompileTimeSig( const uint32_t bb_num, const std::unordered_map &compileTimeSig @@ -81,17 +84,16 @@ bool isNotUnique( void RACFED::initializeBlocksSignatures(Module &Md, Function &Fn) { std::mt19937 rng(0xB00BA5); // seed fisso per riproducibilità - std::uniform_int_distribution dist(1, 0x7fffffff); uint32_t randomBB; uint32_t randomSub; for (BasicBlock &BB : Fn) { do { - randomBB = dist(rng); + randomBB = dist32(rng); } while ( isNotUniqueCompileTimeSig(randomBB, compileTimeSig) ); do { - randomSub = dist(rng); + randomSub = dist32(rng); } while ( isNotUnique( static_cast(randomBB) + randomSub, compileTimeSig, @@ -104,7 +106,6 @@ void RACFED::initializeBlocksSignatures(Module &Md, Function &Fn) { // --- UPDATE SIGNATURE RANDOM --- - void originalInstruction(BasicBlock &BB, std::vector &OrigInstructions) { for (Instruction &I : BB) { if (isa(&I)) continue; // NON è originale @@ -118,7 +119,6 @@ void RACFED::updateCompileSigRandom(Module &Md, Function &Fn, GlobalVariable *RuntimeSigGV, Type *IntType) { std::mt19937 rng(0xC0FFEE); // seed fisso per riproducibilità - std::uniform_int_distribution dist(1, 0x7fffffff); for (auto &BB: Fn){ std::vector OrigInstructions; @@ -126,7 +126,7 @@ void RACFED::updateCompileSigRandom(Module &Md, Function &Fn, if (OrigInstructions.size() <= 2) continue; - uint64_t partial_sum; + uint64_t partial_sum = 0; for (Instruction *I : OrigInstructions) { Instruction *InsertPt = nullptr; @@ -141,95 +141,78 @@ void RACFED::updateCompileSigRandom(Module &Md, Function &Fn, IRBuilder<> B(InsertPt); // signature = signature + randomConstant - uint64_t K = dist(rng); - - try { - partial_sum = K + sumIntraInstruction.at(&BB); - } catch (std::out_of_range &) { - partial_sum = K; - } - - sumIntraInstruction.insert(std::pair(&BB, partial_sum)); - - Value *OldSig = B.CreateLoad(IntType, RuntimeSigGV); - Value *Add = B.CreateAdd(OldSig, ConstantInt::get(IntType, K), "sig_add"); - B.CreateStore(Add, RuntimeSigGV); + uint64_t K = dist32(rng); + partial_sum += K; + #if GAMBA_DEBUG + errs() << "Value of K: " << K << "\n"; + errs() << "Value of partial_sum: " << partial_sum << "\n"; + errs() << "Value of sumIntra: " << sumIntraInstruction[&BB] << "\n"; + #endif + Value *Sig = B.CreateLoad(IntType, RuntimeSigGV); + Value *NewSig = B.CreateAdd(Sig, ConstantInt::get(IntType, K), "sig_add"); + B.CreateStore(NewSig, RuntimeSigGV); + sumIntraInstruction[&BB] = partial_sum; } } - } // --- CHECK BLOCKS AT JUMP END --- -void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn, - GlobalVariable *RuntimeSigGV, Type *IntType) { - - if (Fn.isDeclaration()||Fn.empty()) { - return; - } - BasicBlock *ErrBB = BasicBlock::Create(Fn.getContext(), "ErrBB", &Fn); - IRBuilder<> ErrB(ErrBB); - - IRBuilder<> B(&*(Fn.front().getFirstInsertionPt())); - ErrB.CreateUnreachable(); - std::vector BBs; - - for (BasicBlock &BB : Fn) - BBs.push_back(&BB); - - for (BasicBlock *BBPtr : BBs) { - BasicBlock &BB = *BBPtr; - // in this case BB is not the first Basic Block of the function, so it has - // to update RuntimeSig and check it - if (!BB.isEntryBlock()) { - Instruction *FirstNonPHI = BB.getFirstNonPHI(); - if ((FirstNonPHI && isa(FirstNonPHI)) || - BB.getName().contains_insensitive("verification")) { - if (BB.getFirstInsertionPt() == BB.end()) - continue; // Skip empty/invalid blocks - int randomNumberBB = compileTimeSig.find(&BB)->second; - IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); - BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), - RuntimeSigGV, true); - } else if (!BB.getName().contains_insensitive("errbb")) { - int randomNumberBB = compileTimeSig.find(&BB)->second; - int subRanPrevVal = subRanPrevVals.find(&BB)->second; - BasicBlock *NewBB = BasicBlock::Create( - BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB); - IRBuilder<> BChecker(NewBB); - - // add instructions for the first runtime signature update - Value *InstrRuntimeSig = - BChecker.CreateLoad(IntType, RuntimeSigGV, true); - - Value *RuntimeSignatureVal = BChecker.CreateSub( - InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevVal)); - BChecker.CreateStore(RuntimeSignatureVal, RuntimeSigGV, true); - - // update phi placing them in the new block - while (isa(&BB.front())) { - Instruction *PhiInst = &BB.front(); - PhiInst->removeFromParent(); - PhiInst->insertBefore(&NewBB->front()); - } - - // replace the uses of BB with NewBB - BB.replaceAllUsesWith(NewBB); - - // add instructions for checking the runtime signature - Value *CmpVal = - BChecker.CreateCmp(llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, - llvm::ConstantInt::get(IntType, randomNumberBB)); - BChecker.CreateCondBr(CmpVal, &BB, ErrBB); - - // add NewBB and BB into the NewBBs map - NewBBs.insert(std::pair(NewBB, &BB)); - } +// FIXME: Check this function to comply with the decisions made in design +// +// FIXME: Fix warnings +void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn, BasicBlock &BB, + GlobalVariable *RuntimeSigGV, Type *IntType, + BasicBlock &ErrBB) { + if( BB.isEntryBlock() ) return; + + // in this case BB is not the first Basic Block of the function, so it has + // to update RuntimeSig and check it + Instruction *FirstNonPHI = BB.getFirstNonPHI(); + if ( (FirstNonPHI && isa(FirstNonPHI)) || + BB.getName().contains_insensitive("verification") ) { + + if (BB.getFirstInsertionPt() == BB.end()) return; // Skip empty/invalid blocks + + int randomNumberBB = compileTimeSig.find(&BB)->second; + IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); + BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), RuntimeSigGV, true); + } else if (!BB.getName().contains_insensitive("errbb")) { + int randomNumberBB = compileTimeSig.find(&BB)->second; + int subRanPrevVal = subRanPrevVals.find(&BB)->second; + BasicBlock *NewBB = BasicBlock::Create( + BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB); + IRBuilder<> BChecker(NewBB); + + // add instructions for the first runtime signature update + Value *InstrRuntimeSig = + BChecker.CreateLoad(IntType, RuntimeSigGV, true); + + Value *RuntimeSignatureVal = BChecker.CreateSub( + InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevVal)); + BChecker.CreateStore(RuntimeSignatureVal, RuntimeSigGV, true); + + // update phi placing them in the new block + while (isa(&BB.front())) { + Instruction *PhiInst = &BB.front(); + PhiInst->removeFromParent(); + PhiInst->insertBefore(&NewBB->front()); } + + // replace the uses of BB with NewBB + BB.replaceAllUsesWith(NewBB); + + // add instructions for checking the runtime signature + Value *CmpVal = + BChecker.CreateCmp(llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, + llvm::ConstantInt::get(IntType, randomNumberBB)); + BChecker.CreateCondBr(CmpVal, &BB, &ErrBB); + + // add NewBB and BB into the NewBBs map + NewBBs.insert(std::pair(NewBB, &BB)); } } // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- - ConstantInt* expectedSignature( BasicBlock *Succ, Module &Md, const std::unordered_map &compileTimeSig, @@ -241,9 +224,10 @@ ConstantInt* expectedSignature( return ConstantInt:: get(I32, expected+expectedSub); } -void RACFED::checkBranches(Module &Md, GlobalVariable *RuntimeSigGV, - Type *IntType, IRBuilder<> B, BasicBlock &BB) { +void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, + Type *IntType) { Instruction *Term = BB.getTerminator(); + IRBuilder<> B(&BB); auto *BI = dyn_cast(Term); if (!BI) return; @@ -254,7 +238,7 @@ void RACFED::checkBranches(Module &Md, GlobalVariable *RuntimeSigGV, //define if conditional or unconditional branch //Conditional: expected= CT_succ+subRan_succ //adj = CTB-exp--> new signature = RT -adj - if (BI -> isUnconditional()) { + if ( BI->isUnconditional() ) { BasicBlock *Succ = BI->getSuccessor(0); auto expected = expectedSignature(Succ,Md,compileTimeSig,subRanPrevVals); // adj = expected - current @@ -275,118 +259,91 @@ void RACFED::checkBranches(Module &Md, GlobalVariable *RuntimeSigGV, } } -//Conditional: compute the two adj and the signature that corresponds. -// -// void RACFED::createCFGVerificationBB( -// BasicBlock &BB, std::unordered_map &RandomNumberBBs, -// std::unordered_map &SubRanPrevVals, Value &RuntimeSig, -// Value &RetSig, BasicBlock &ErrBB -// ) { -// -// // checkCompileSigAtJump() NON ENTRY BLOCK -// // compileTimeSig - subRunPrevVal -// // if compileTimeSig != runtime_sig error() -// -// auto *IntType = llvm::Type::getInt64Ty(BB.getContext()); -// -// int randomNumberBB = RandomNumberBBs.find(&BB)->second; -// int subRanPrevVal = SubRanPrevVals.find(&BB)->second; -// -// -// // checkReturnVal() -// // compute returnValue -// // compute adjValue -// // runtime_sig = runtime_sig + adjValue -// -// -// // checkBranchJump() -// // compute adjValue -// // runtime_sig = runtime_sig + adjValue -// -// // update the signature for the successors -// int randomNumberBB_succ; -// int subRanPrevVal_succ; -// -// Instruction *Term = BB.getTerminator(); -// int successors = Term->getNumSuccessors(); -// -// for (int i = 0; i < successors; i++) { -// BasicBlock *Succ = Term->getSuccessor(i); -// if (!Succ->getName().contains_insensitive("errbb")) { -// randomNumberBB_succ = RandomNumberBBs.find(Succ)->second; -// subRanPrevVal_succ = randomNumberBB - randomNumberBB_succ; -// -// // update the map -// if (SubRanPrevVals.find(Succ)->second == 1) { -// SubRanPrevVals.erase(Succ); -// SubRanPrevVals.insert( -// std::pair(Succ, subRanPrevVal_succ)); -// } else { -// // if the successor has already been visited, we have to check if the -// // signature is consistent -// if (SubRanPrevVals.find(Succ)->second != subRanPrevVal_succ) { -// // if not, we have to update the signature -// int diff = subRanPrevVal_succ - SubRanPrevVals.find(Succ)->second; -// IRBuilder<> B(&*BB.getFirstInsertionPt()); -// if (isa(Term) && -// cast(Term)->isConditional()) { -// // if the terminator is a conditional branch, we have to update the -// // signature only if the condition is true or false, depending on -// // the successor -// B.SetInsertPoint(Term); -// } else { -// B.SetInsertPoint(Term); -// } -// -// } -// } -// } -// } -// -// Handle return instructions -// if (isa(Term)) { -// BasicBlock *RetVerificationBB = BasicBlock::Create( -// BB.getContext(), "RACFED_ret_Verification_BB", BB.getParent(), &BB); -// // Move instructions from BB to RetVerificationBB, except the verification -// // logic we just added? No, we want to verify BEFORE return. Actually, the -// // verification block is already added at the beginning of BB. Now we want -// // to update signature before return? RASM updates signature at exit? -// -// -// -// IRBuilder<> BRet(RetVerificationBB); -// Value *InstrRuntimeSig = BRet.CreateLoad(IntType, &RuntimeSig, true); -// Value *InstrRetSig = BRet.CreateLoad(IntType, &RetSig, true); -// -// // In RASM/RACFED, we might check if RuntimeSig matches RetSig (or some -// // derived value) at return. For now, let's just check if they are -// // consistent. But RetSig is initialized to RandomNumberBBs.size() + -// // currSig. + +// --- CHECK RETURN UPDATE VALUE --- +void RACFED::checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, + GlobalVariable *RuntimeSigGV, + Type* IntType, BasicBlock &ErrBB, + Value *BckupRunSig) { +// checkRetVal: // -// // Let's stick to the basic block verification for now. -// } -// } +// 14: if Last Instr. is return instr. and NrIntrBB > 1 then +// 15: Calculate needed variables +// 16: returnVal ← random number +// 17: adjustValue ← (compileTimeSigBB + Sum) - +// 18: returnVal +// 19: Insert signature update before return instr. +// 20: signature ← signature + adjustValue +// 21: if signature != returnVal error() + Instruction *Term = BB.getTerminator(); + if( !isa(Term) ) return; + + std::vector org_instr; + originalInstruction(BB, org_instr); + if( org_instr.size() <= 2 ) return; + + // Splits the BB that contains the return instruction into + // two basic blocks: + // BB will contain the return instruction + // BeforeRetBB will contain all of the instructions before the return one + // + // These two BBs will be linked meaning that BeforeRetBB->successor == BB + BasicBlock *BeforeRetBB = BB.splitBasicBlockBefore(Term); + + // Creating control basic block to insert before + // the return instruction + BasicBlock *ControlBB = BasicBlock::Create( + Md.getContext(), + "RAFCED_ret_verification_BB", + &Fn, + &BB + ); + + // Relinking the basic blocks so that the structure + // results in: BeforeRetBB->ControlBB->BB + BeforeRetBB->getTerminator()->replaceSuccessorWith(&BB, ControlBB); + + // Inserting instructions into ControlBB + IRBuilder<> B(ControlBB); + // 15: Calculate needed variables + // 16: returnVal ← random number + // 17: adjustValue ← (compileTimeSigBB + Sum) - + // 18: returnVal + uint64_t random_ret_value = dist64(rng64); + // This is a 64 bit SIGNED integer (cause a subtraction happens + // and it cannot previously be established that it will be positive) + long int adj_value = compileTimeSig[&BB] + sumIntraInstruction[&BB] + - random_ret_value; + + // 19: Insert signature update before return instr. + // 20: signature ← signature + adjustValue // wrong must be subtracted + // 21: if signature != returnVal error() + Value *Sig = B.CreateLoad(IntType, RuntimeSigGV, true, "checking_sign"); + Value *CmpVal = B.CreateSub(Sig, llvm::ConstantInt::get(IntType, adj_value), "checking_value"); + Value *CmpSig = B.CreateCmp(llvm::CmpInst::ICMP_EQ, CmpVal, + llvm::ConstantInt::get(IntType, random_ret_value)); + + if( !Fn.getName().contains("main") ) B.CreateStore(BckupRunSig, RuntimeSigGV); + B.CreateCondBr(CmpSig, &BB, &ErrBB); +} PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { // mappa: istruzione originale -> random r usato per S = S + r - std::unordered_map InstrUpdates; + // std::unordered_map InstrUpdates; + auto *I64 = llvm::Type::getInt64Ty(Md.getContext()); - auto *I32 = llvm::Type::getInt32Ty(Md.getContext()); - std::unordered_map ErrBBs; - - GlobalVariable *RuntimeSig = Md.getNamedGlobal("signature"); - if (!RuntimeSig) { - RuntimeSig = new GlobalVariable( - Md, - I64, - /*isConstant=*/false, - GlobalValue::ExternalLinkage, - ConstantInt::get(I64, 0), - "signature"); - } - // createFtFuncs(Md); + GlobalVariable *RuntimeSig = new GlobalVariable( + Md, I64, + /*isConstant=*/false, + GlobalValue::ExternalLinkage, + ConstantInt::get(I64, 0), + "signature" + ); + + + createFtFuncs(Md); getFuncAnnotations(Md, FuncAnnotations); LinkageMap linkageMap = mapFunctionLinkageNames((Md)); @@ -396,29 +353,61 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { } for (Function &Fn: Md) { + if (Fn.isDeclaration() || Fn.empty()) continue; updateCompileSigRandom(Md, Fn, RuntimeSig, I64); } for(Function &Fn: Md) { - checkCompileTimeSigAtJump(Md, Fn, RuntimeSig, I64); + if(!shouldCompile(Fn, FuncAnnotations)) continue; + + #if GAMBA_DEBUG + errs() << "Analysing func " << Fn.getName() << "\n"; + #endif + + // Search debug location point + DebugLoc debugLoc; + for (auto &I : Fn.front()) { + if (I.getDebugLoc()) { + debugLoc = I.getDebugLoc(); + break; + } + } + + // Create error basic block + assert(!getLinkageName(linkageMap,"SigMismatch_Handler").empty() + && "Function SigMismatch_Handler is missing!"); + + BasicBlock *ErrBB = BasicBlock::Create(Fn.getContext(), "ErrBB", &Fn); + auto CalleeF = ErrBB->getModule()->getOrInsertFunction( + getLinkageName(linkageMap,"SigMismatch_Handler"), + FunctionType::getVoidTy(Md.getContext()) + ); + + IRBuilder<> ErrIR(ErrBB); + ErrIR.CreateCall(CalleeF)->setDebugLoc(debugLoc); + ErrIR.CreateUnreachable(); + + Value * runtime_sign_bkup; + for (BasicBlock &BB : Fn) { + // TODO: Should the error basic block that is inserted be checked? + + // Backup of compile time sign when entering a function + if( BB.isEntryBlock() ) { + IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); + runtime_sign_bkup = + InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); + InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), + RuntimeSig); + } + + // checkCompileTimeSigAtJump(Md, Fn, BB, RuntimeSig, I64, *ErrBB); + checkReturnValue(Md, Fn, BB, RuntimeSig, I64, *ErrBB, runtime_sign_bkup); + checkBranches(Md, BB, RuntimeSig, I64); + } } - // createCFGVerificationBB(); - // - // for (Function &Fn : Md) { - // if (!shouldCompile(Fn, FuncAnnotations)) - // continue; - // - // if (shouldCompile(Fn, FuncAnnotations)) { - // DebugLoc debugLoc; - // for (auto &I : Fn.front()) { - // if (I.getDebugLoc()) { - // debugLoc = I.getDebugLoc(); - // break; - // } - // } - // } - return PreservedAnalyses::all(); + // There is nothing that this pass preserved + return PreservedAnalyses::none(); } extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK diff --git a/testing/tests/c/multi_instruction/simple.c b/testing/tests/c/multi_instruction/add.c similarity index 98% rename from testing/tests/c/multi_instruction/simple.c rename to testing/tests/c/multi_instruction/add.c index dc623ae..9fc27b7 100644 --- a/testing/tests/c/multi_instruction/simple.c +++ b/testing/tests/c/multi_instruction/add.c @@ -9,4 +9,4 @@ int main() { int c = a + b; printf("c=%d\n", c); return 0; -} \ No newline at end of file +} diff --git a/testing/tests/c/multi_instruction/func_ret.c b/testing/tests/c/multi_instruction/func_ret.c new file mode 100644 index 0000000..d523eb5 --- /dev/null +++ b/testing/tests/c/multi_instruction/func_ret.c @@ -0,0 +1,23 @@ +#include +#include + +void SigMismatch_Handler(void) { + printf("An error occurred and the signature value was different from expected"); + exit(-1); +} + +int foo(); + +int main() { + int a = 10; + int b = 20; + int c = foo(); + printf("foo() %d", c); + return a > b ? a : b; +} + +int foo() { + int c = 12; + int d = 13; + return c + d; +} diff --git a/testing/tests/c/multi_instruction/glob.c b/testing/tests/c/multi_instruction/glob.c new file mode 100644 index 0000000..b70b773 --- /dev/null +++ b/testing/tests/c/multi_instruction/glob.c @@ -0,0 +1,9 @@ +int global = 0; + +int main() { + int a = global + 1; + global += 10; + global += 11; + a += 12; + return a + global; +} diff --git a/testing/tests/c/multi_instruction/ifElse.c b/testing/tests/c/multi_instruction/ifElse.c deleted file mode 100644 index 0d8b183..0000000 --- a/testing/tests/c/multi_instruction/ifElse.c +++ /dev/null @@ -1,19 +0,0 @@ -// -// Created by martina on 28/12/25. -// -#include - - -int main() { - int x = 0; - x = x+1; - if (x<10) { - x = x*10; - printf("valore: %d", x) ; - } - - else - printf("valore: %d", x) ; - return 0; - -} diff --git a/testing/tests/c/multi_instruction/if_then_else.c b/testing/tests/c/multi_instruction/if_then_else.c index 876fef1..312774b 100644 --- a/testing/tests/c/multi_instruction/if_then_else.c +++ b/testing/tests/c/multi_instruction/if_then_else.c @@ -1,22 +1,18 @@ +// +// Created by martina on 28/12/25. +// #include + int main() { - int a = 10; - int b = 20; - int c = a + b; - a = 12; - b = 13; - int d = a + b; - if(c > d) { - a = 15; - b = 2; - d = a + b; - } else { - a = 13; - b = 19; - c = a + b; + int x = 0; + x = x+1; + if (x<10) { + x = x*10; + printf("valore: %d", x) ; } - - printf("c: %d d: %d\n", c, d); + else + printf("valore: %d", x) ; return 0; + } diff --git a/testing/tests/c/multi_instruction/ret.c b/testing/tests/c/multi_instruction/ret.c new file mode 100644 index 0000000..3d11e63 --- /dev/null +++ b/testing/tests/c/multi_instruction/ret.c @@ -0,0 +1,14 @@ +#include +#include + +void SigMismatch_Handler(void) { + printf("An error occurred and the signature value was different from expected"); + exit(-1); +} + +int main() { + int a = 10; + int b = 20; + printf("a + b %d", a+b); + return 0; +} From a92d7f326f51648aa677bbedd4e909bd379151d7 Mon Sep 17 00:00:00 2001 From: martina Date: Sat, 3 Jan 2026 18:12:50 +0100 Subject: [PATCH 16/29] fixes --- passes/ASPIS.h | 2 +- passes/RACFED.cpp | 69 ++++++++++--------- .../tests/c/multi_instruction/if_then_else.c | 7 +- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index c43cff4..fedc2fe 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -182,7 +182,7 @@ class RACFED : public PassInfoMixin { // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- void checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, - Type *IntType); + Type *IntType, BasicBlock &ErrBB); // --- UPDATE RETURN VALUE AND CHECK --- void checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 70215d2..73bc213 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -13,7 +13,7 @@ #define INTRA_FUNCTION_CFC 0 // Default to 0 if not defined #define MARTI_DEBUG true -#define GAMBA_DEBUG true +#define GAMBA_DEBUG false using namespace llvm; @@ -213,46 +213,51 @@ void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn, BasicBlock &BB, } // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- -ConstantInt* expectedSignature( - BasicBlock *Succ, Module &Md, +Constant* expectedSignature( + BasicBlock *Succ, Type *IntType, const std::unordered_map &compileTimeSig, const std::unordered_map &subRanPrevVals ) { const int expected = compileTimeSig.at(Succ); const int expectedSub = subRanPrevVals.at(Succ); - auto *I32 = Type::getInt32Ty(Md.getContext()); - return ConstantInt:: get(I32, expected+expectedSub); + return ConstantInt::get(IntType, expected+expectedSub); } - +/* +* checkJump +23: for all Successor of BB do +24: adjustValue ← (compileTimeSigBB + \Sum{instrMonUpdates}) - +25: (compileTimeSigsuccs + subRanPrevValsuccs) +26: Insert signature update at BB end +27: signature ← signature + adjustValue +*/ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, - Type *IntType) { + Type *IntType, BasicBlock &ErrBB) { Instruction *Term = BB.getTerminator(); IRBuilder<> B(&BB); auto *BI = dyn_cast(Term); if (!BI) return; - //load the current runtimevariable - Value *Current = B.CreateLoad(IntType, RuntimeSigGV, "current"); - Value *Expected = nullptr; -//define if conditional or unconditional branch + //define if conditional or unconditional branch //Conditional: expected= CT_succ+subRan_succ - //adj = CTB-exp--> new signature = RT -adj - if ( BI->isUnconditional() ) { + //adj = CTB-exp--> new signature = RT -adj + if ( BI->isUnconditional() ) { // only one successor + //load the current runtimevariable + Value *Current = B.CreateLoad(IntType, RuntimeSigGV, "current"); BasicBlock *Succ = BI->getSuccessor(0); - auto expected = expectedSignature(Succ,Md,compileTimeSig,subRanPrevVals); - // adj = expected - current - Value *Adj = B.CreateSub(Expected, Current, "racfed.adj"); - Value *NewSig = B.CreateAdd(Current, Adj, "racfed.newsig"); + auto expected = expectedSignature(Succ,IntType,compileTimeSig,subRanPrevVals); + // adj = expected - current + Value *Adj = B.CreateSub(expected, Current, "racfed_adj"); + Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); B.CreateStore(NewSig, RuntimeSigGV); // verify newSig == expected - Value *Ok = B.CreateICmpEQ(NewSig, Expected, "racfed.ok"); + Value *Ok = B.CreateICmpEQ(NewSig, expected, "racfed_ok"); // Replace terminator with condbr(ok, succ, ErrBB) BI->eraseFromParent(); IRBuilder<> BT(&BB); - BT.CreateCondBr(Ok, Succ, nullptr); + BT.CreateCondBr(Ok, Succ, &ErrBB); } else { BasicBlock *SuccT = BI->getSuccessor(0); BasicBlock *SuccF = BI->getSuccessor(1); @@ -261,10 +266,6 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS // --- CHECK RETURN UPDATE VALUE --- -void RACFED::checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, - GlobalVariable *RuntimeSigGV, - Type* IntType, BasicBlock &ErrBB, - Value *BckupRunSig) { // checkRetVal: // // 14: if Last Instr. is return instr. and NrIntrBB > 1 then @@ -275,6 +276,10 @@ void RACFED::checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, // 19: Insert signature update before return instr. // 20: signature ← signature + adjustValue // 21: if signature != returnVal error() +void RACFED::checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, + GlobalVariable *RuntimeSigGV, + Type* IntType, BasicBlock &ErrBB, + Value *BckupRunSig) { Instruction *Term = BB.getTerminator(); if( !isa(Term) ) return; @@ -360,7 +365,7 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { for(Function &Fn: Md) { if(!shouldCompile(Fn, FuncAnnotations)) continue; - #if GAMBA_DEBUG + #if GAMBA_DEBUG || MARTI_DEBUG errs() << "Analysing func " << Fn.getName() << "\n"; #endif @@ -387,22 +392,22 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { ErrIR.CreateCall(CalleeF)->setDebugLoc(debugLoc); ErrIR.CreateUnreachable(); - Value * runtime_sign_bkup; + Value * runtime_sign_bkup = nullptr; for (BasicBlock &BB : Fn) { // TODO: Should the error basic block that is inserted be checked? - // Backup of compile time sign when entering a function if( BB.isEntryBlock() ) { - IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); - runtime_sign_bkup = - InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); - InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), - RuntimeSig); + IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); + runtime_sign_bkup = + InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); + InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), + + RuntimeSig); } // checkCompileTimeSigAtJump(Md, Fn, BB, RuntimeSig, I64, *ErrBB); checkReturnValue(Md, Fn, BB, RuntimeSig, I64, *ErrBB, runtime_sign_bkup); - checkBranches(Md, BB, RuntimeSig, I64); + checkBranches(Md, BB, RuntimeSig, I64, *ErrBB); } } diff --git a/testing/tests/c/multi_instruction/if_then_else.c b/testing/tests/c/multi_instruction/if_then_else.c index 312774b..89c074b 100644 --- a/testing/tests/c/multi_instruction/if_then_else.c +++ b/testing/tests/c/multi_instruction/if_then_else.c @@ -5,14 +5,13 @@ int main() { - int x = 0; + int x = 1000; x = x+1; if (x<10) { x = x*10; - printf("valore: %d", x) ; + printf("valore: %d", x); } else - printf("valore: %d", x) ; + printf("valore: %d", x); return 0; - } From b440a0f1b965f154ed6effe31440f18ebbd2817d Mon Sep 17 00:00:00 2001 From: Gab-San Date: Sat, 3 Jan 2026 20:44:06 +0100 Subject: [PATCH 17/29] Fixed restoring branch signature on return --- passes/RACFED.cpp | 111 +++++++++--------- .../tests/c/multi_instruction/call_less_two.c | 14 +++ 2 files changed, 70 insertions(+), 55 deletions(-) create mode 100644 testing/tests/c/multi_instruction/call_less_two.c diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 73bc213..f0ffedb 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -10,7 +10,6 @@ #define INIT_SIGNATURE \ -0xDEAD // The same value has to be used as initializer for the signatures in // the code -#define INTRA_FUNCTION_CFC 0 // Default to 0 if not defined #define MARTI_DEBUG true #define GAMBA_DEBUG false @@ -54,7 +53,7 @@ using namespace llvm; std::uniform_int_distribution dist32(1, 0x7fffffff); std::uniform_int_distribution dist64(1, 0xffffffff); -std::mt19937 rng64(0x5EED00); // seed fisso per riproducibilità +std::mt19937 rng64(0x5EED00); // constant seed for reproducibility // --- INITIALIZE BLOCKS RANDOM --- bool isNotUniqueCompileTimeSig( @@ -83,7 +82,7 @@ bool isNotUnique( } void RACFED::initializeBlocksSignatures(Module &Md, Function &Fn) { - std::mt19937 rng(0xB00BA5); // seed fisso per riproducibilità + std::mt19937 rng(0xB00BA5); // constant seed for reproducibility uint32_t randomBB; uint32_t randomSub; @@ -286,51 +285,54 @@ void RACFED::checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, std::vector org_instr; originalInstruction(BB, org_instr); - if( org_instr.size() <= 2 ) return; - - // Splits the BB that contains the return instruction into - // two basic blocks: - // BB will contain the return instruction - // BeforeRetBB will contain all of the instructions before the return one - // - // These two BBs will be linked meaning that BeforeRetBB->successor == BB - BasicBlock *BeforeRetBB = BB.splitBasicBlockBefore(Term); - - // Creating control basic block to insert before - // the return instruction - BasicBlock *ControlBB = BasicBlock::Create( - Md.getContext(), - "RAFCED_ret_verification_BB", - &Fn, - &BB - ); + if( org_instr.size() > 2 ) { + + // Splits the BB that contains the return instruction into + // two basic blocks: + // BB will contain the return instruction + // BeforeRetBB will contain all of the instructions before the return one + // + // These two BBs will be linked meaning that BeforeRetBB->successor == BB + BasicBlock *BeforeRetBB = BB.splitBasicBlockBefore(Term); + + // Creating control basic block to insert before + // the return instruction + BasicBlock *ControlBB = BasicBlock::Create( + Md.getContext(), + "RAFCED_ret_verification_BB", + &Fn, + &BB + ); - // Relinking the basic blocks so that the structure - // results in: BeforeRetBB->ControlBB->BB - BeforeRetBB->getTerminator()->replaceSuccessorWith(&BB, ControlBB); - - // Inserting instructions into ControlBB - IRBuilder<> B(ControlBB); - // 15: Calculate needed variables - // 16: returnVal ← random number - // 17: adjustValue ← (compileTimeSigBB + Sum) - - // 18: returnVal - uint64_t random_ret_value = dist64(rng64); - // This is a 64 bit SIGNED integer (cause a subtraction happens - // and it cannot previously be established that it will be positive) - long int adj_value = compileTimeSig[&BB] + sumIntraInstruction[&BB] - - random_ret_value; - - // 19: Insert signature update before return instr. - // 20: signature ← signature + adjustValue // wrong must be subtracted - // 21: if signature != returnVal error() - Value *Sig = B.CreateLoad(IntType, RuntimeSigGV, true, "checking_sign"); - Value *CmpVal = B.CreateSub(Sig, llvm::ConstantInt::get(IntType, adj_value), "checking_value"); - Value *CmpSig = B.CreateCmp(llvm::CmpInst::ICMP_EQ, CmpVal, - llvm::ConstantInt::get(IntType, random_ret_value)); - - if( !Fn.getName().contains("main") ) B.CreateStore(BckupRunSig, RuntimeSigGV); - B.CreateCondBr(CmpSig, &BB, &ErrBB); + // Relinking the basic blocks so that the structure + // results in: BeforeRetBB->ControlBB->BB + BeforeRetBB->getTerminator()->replaceSuccessorWith(&BB, ControlBB); + + // Inserting instructions into ControlBB + IRBuilder<> ControlIR(ControlBB); + // 15: Calculate needed variables + // 16: returnVal ← random number + // 17: adjustValue ← (compileTimeSigBB + Sum) - + // 18: returnVal + uint64_t random_ret_value = dist64(rng64); + // This is a 64 bit SIGNED integer (cause a subtraction happens + // and it cannot previously be established that it will be positive) + long int adj_value = compileTimeSig[&BB] + sumIntraInstruction[&BB] + - random_ret_value; + + // 19: Insert signature update before return instr. + // 20: signature ← signature + adjustValue // wrong must be subtracted + // 21: if signature != returnVal error() + Value *Sig = ControlIR.CreateLoad(IntType, RuntimeSigGV, true, "checking_sign"); + Value *CmpVal = ControlIR.CreateSub(Sig, llvm::ConstantInt::get(IntType, adj_value), "checking_value"); + Value *CmpSig = ControlIR.CreateCmp(llvm::CmpInst::ICMP_EQ, CmpVal, + llvm::ConstantInt::get(IntType, random_ret_value)); + + ControlIR.CreateCondBr(CmpSig, &BB, &ErrBB); + } + + IRBuilder<> RetInstIR(Term); + RetInstIR.CreateStore(BckupRunSig, RuntimeSigGV); } PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { @@ -373,8 +375,8 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { DebugLoc debugLoc; for (auto &I : Fn.front()) { if (I.getDebugLoc()) { - debugLoc = I.getDebugLoc(); - break; + debugLoc = I.getDebugLoc(); + break; } } @@ -397,12 +399,11 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { // TODO: Should the error basic block that is inserted be checked? // Backup of compile time sign when entering a function if( BB.isEntryBlock() ) { - IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); - runtime_sign_bkup = - InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); - InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), - - RuntimeSig); + IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); + runtime_sign_bkup = + InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); + InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), + RuntimeSig); } // checkCompileTimeSigAtJump(Md, Fn, BB, RuntimeSig, I64, *ErrBB); diff --git a/testing/tests/c/multi_instruction/call_less_two.c b/testing/tests/c/multi_instruction/call_less_two.c new file mode 100644 index 0000000..f599d37 --- /dev/null +++ b/testing/tests/c/multi_instruction/call_less_two.c @@ -0,0 +1,14 @@ +#include + +int foo() { + return 0; +} + +int main() { + int sasso_carta = 1; + int filippo_congenito = 2; + for(int i = foo(); i < sasso_carta + filippo_congenito; i++) + filippo_congenito--; + printf("%d", filippo_congenito); + return 0; +} From ff6fe07348aa10d8513c7b68504dd543db85f8f1 Mon Sep 17 00:00:00 2001 From: martina Date: Tue, 6 Jan 2026 09:01:00 +0100 Subject: [PATCH 18/29] checkbranches fix-- to test but it works --- passes/ASPIS.h | 2 + passes/RACFED.cpp | 121 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 110 insertions(+), 13 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index fedc2fe..3661aaa 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -180,6 +180,8 @@ class RACFED : public PassInfoMixin { GlobalVariable *RuntimeSigGV, Type *IntType, BasicBlock &ErrBB); + Value *getCondition(Instruction &I); + // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- void checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType, BasicBlock &ErrBB); diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index f0ffedb..c110d72 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -200,6 +200,20 @@ void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn, BasicBlock &BB, // replace the uses of BB with NewBB BB.replaceAllUsesWith(NewBB); + // Fix PHI nodes in successors + // replaceAllUsesWith updates PHI nodes in successors to point to NewBB, + // but the actual control flow is NewBB -> BB -> Succ, so Succ still sees BB + // as predecessor. + for (BasicBlock *Succ : successors(&BB)) { + for (PHINode &Phi : Succ->phis()) { + for (unsigned i = 0; i < Phi.getNumIncomingValues(); ++i) { + if (Phi.getIncomingBlock(i) == NewBB) { + Phi.setIncomingBlock(i, &BB); + } + } + } + } + // add instructions for checking the runtime signature Value *CmpVal = BChecker.CreateCmp(llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, @@ -208,6 +222,11 @@ void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn, BasicBlock &BB, // add NewBB and BB into the NewBBs map NewBBs.insert(std::pair(NewBB, &BB)); + + // Map NewBB to the same signature requirements as BB so predecessors can + // target it correctly + compileTimeSig[NewBB] = randomNumberBB; + subRanPrevVals[NewBB] = subRanPrevVal; } } @@ -229,41 +248,117 @@ Constant* expectedSignature( 26: Insert signature update at BB end 27: signature ← signature + adjustValue */ +Value *RACFED::getCondition(Instruction &I) { + if (isa(I) && cast(I).isConditional()) { + if (!cast(I).isConditional()) { + return nullptr; + } else { + return cast(I).getCondition(); + } + } else if (isa(I)) { + errs() << "There is a switch!\n"; + abort(); + return cast(I).getCondition(); + } else { + assert(false && "Tried to get a condition on a function that is not a " + "branch or a switch"); + } +} + +static void printSig(Module &Md, IRBuilder<> &B, Value *SigVal, const char *Msg) { + LLVMContext &Ctx = Md.getContext(); + + // int printf(const char*, ...) + FunctionCallee Printf = Md.getOrInsertFunction( + "printf", + FunctionType::get(IntegerType::getInt32Ty(Ctx), + PointerType::getUnqual(Ctx), + true)); + + // Crea stringa globale "Msg: %ld\n" + std::string Fmt = std::string(Msg) + ": %ld\n"; + Value *FmtStr = B.CreateGlobalStringPtr(Fmt); + + + if (SigVal->getType()->isIntegerTy(32)) { + SigVal = B.CreateZExt(SigVal, Type::getInt64Ty(Ctx)); + } + + B.CreateCall(Printf, {FmtStr, SigVal}); +} + void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType, BasicBlock &ErrBB) { Instruction *Term = BB.getTerminator(); IRBuilder<> B(&BB); + B.SetInsertPoint(Term); auto *BI = dyn_cast(Term); if (!BI) return; + //TODO: check this + + // Calculate Source Static Signature: CT_BB + SumIntra + uint64_t SourceStatic = + (uint64_t)compileTimeSig[&BB] + sumIntraInstruction[&BB]; + + Value *Current = B.CreateLoad(IntType, RuntimeSigGV, "current"); + printSig(Md, B, Current, "current"); + + //TODO: until here //define if conditional or unconditional branch //Conditional: expected= CT_succ+subRan_succ //adj = CTB-exp--> new signature = RT -adj - if ( BI->isUnconditional() ) { // only one successor - //load the current runtimevariable - Value *Current = B.CreateLoad(IntType, RuntimeSigGV, "current"); + if ( BI->isUnconditional() ){ // only one successor BasicBlock *Succ = BI->getSuccessor(0); - auto expected = expectedSignature(Succ,IntType,compileTimeSig,subRanPrevVals); + uint64_t Expected = + (uint64_t)compileTimeSig[Succ] + (uint64_t)subRanPrevVals[Succ];; // adj = expected - current - Value *Adj = B.CreateSub(expected, Current, "racfed_adj"); + uint64_t AdjValue = Expected - SourceStatic; + Value *Adj = ConstantInt::get(IntType, AdjValue); Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); B.CreateStore(NewSig, RuntimeSigGV); - + printSig(Md,B, NewSig, "newsig"); // verify newSig == expected - Value *Ok = B.CreateICmpEQ(NewSig, expected, "racfed_ok"); + Value *ExpectedVal = ConstantInt::get(IntType, Expected); + Value *Ok = B.CreateICmpEQ(NewSig, ExpectedVal, "racfed_ok"); - // Replace terminator with condbr(ok, succ, ErrBB) - BI->eraseFromParent(); - IRBuilder<> BT(&BB); - BT.CreateCondBr(Ok, Succ, &ErrBB); - } else { + return; + } + if ( BI-> isConditional()) { BasicBlock *SuccT = BI->getSuccessor(0); BasicBlock *SuccF = BI->getSuccessor(1); + Instruction *Terminator = BB.getTerminator(); + Value *BrCondition = getCondition(*Terminator); + + // Target T + uint64_t expectedT = + (uint64_t)compileTimeSig[SuccT] + (uint64_t)subRanPrevVals[SuccT]; + uint64_t adj1 = expectedT - SourceStatic; + + // Target F + uint64_t expectedF = + (uint64_t)compileTimeSig[SuccF] + (uint64_t)subRanPrevVals[SuccF]; + uint64_t adj2 = expectedF - SourceStatic; + + Value *Adj = B.CreateSelect(BrCondition, ConstantInt::get(IntType, adj1), ConstantInt::get(IntType, adj2)); + Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); + B.CreateStore(NewSig, RuntimeSigGV); + + printSig(Md, B, NewSig, "SIG after cond"); + Value *ExpectedVal = B.CreateSelect( + BrCondition, ConstantInt::get(IntType, expectedT), + ConstantInt::get(IntType, expectedF), "expected_sig"); + Value *Ok = B.CreateICmpEQ(NewSig, ExpectedVal, "racfed_ok"); + + return; + + } } + // --- CHECK RETURN UPDATE VALUE --- // checkRetVal: // @@ -406,7 +501,7 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { RuntimeSig); } - // checkCompileTimeSigAtJump(Md, Fn, BB, RuntimeSig, I64, *ErrBB); + checkCompileTimeSigAtJump(Md, Fn, BB, RuntimeSig, I64, *ErrBB); checkReturnValue(Md, Fn, BB, RuntimeSig, I64, *ErrBB, runtime_sign_bkup); checkBranches(Md, BB, RuntimeSig, I64, *ErrBB); } From 9ebfac690668a855c16ab3ee78c3121b05205944 Mon Sep 17 00:00:00 2001 From: Gab-San Date: Wed, 7 Jan 2026 14:47:26 +0100 Subject: [PATCH 19/29] small-clean --- passes/ASPIS.h | 14 +--- passes/RACFED.cpp | 79 +++++--------------- testing/tests/c/multi_instruction/func_ret.c | 7 +- 3 files changed, 29 insertions(+), 71 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 3661aaa..3698cf8 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -176,9 +176,9 @@ class RACFED : public PassInfoMixin { GlobalVariable *RuntimeSigGV, Type *IntType); // --- CHECK BLOCKS AT JUMP END --- - void checkCompileTimeSigAtJump(Module &Md, Function &Fn, BasicBlock &BB, - GlobalVariable *RuntimeSigGV, Type *IntType, - BasicBlock &ErrBB); + void checkJumpSignature(BasicBlock &BB, + GlobalVariable *RuntimeSigGV, Type *IntType, + BasicBlock &ErrBB); Value *getCondition(Instruction &I); @@ -187,17 +187,11 @@ class RACFED : public PassInfoMixin { Type *IntType, BasicBlock &ErrBB); // --- UPDATE RETURN VALUE AND CHECK --- - void checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, + Instruction *checkReturnValue(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType, BasicBlock &ErrBB, Value *BckupRunSig); - - // void splitBBsAtCalls(Module &Md); - // CallBase *isCallBB(BasicBlock &BB); - // void initializeEntryBlocksMap(Module &Md); - // Value *getCondition(Instruction &I); - public: PreservedAnalyses run(Module &Md, ModuleAnalysisManager &); diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index c110d72..e38649a 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -159,9 +159,9 @@ void RACFED::updateCompileSigRandom(Module &Md, Function &Fn, // FIXME: Check this function to comply with the decisions made in design // // FIXME: Fix warnings -void RACFED::checkCompileTimeSigAtJump(Module &Md, Function &Fn, BasicBlock &BB, - GlobalVariable *RuntimeSigGV, Type *IntType, - BasicBlock &ErrBB) { +void RACFED::checkJumpSignature(BasicBlock &BB, + GlobalVariable *RuntimeSigGV, Type *IntType, + BasicBlock &ErrBB) { if( BB.isEntryBlock() ) return; // in this case BB is not the first Basic Block of the function, so it has @@ -319,6 +319,7 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); B.CreateStore(NewSig, RuntimeSigGV); printSig(Md,B, NewSig, "newsig"); + // FIXME: Should compare neither branch // verify newSig == expected Value *ExpectedVal = ConstantInt::get(IntType, Expected); Value *Ok = B.CreateICmpEQ(NewSig, ExpectedVal, "racfed_ok"); @@ -352,8 +353,6 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS Value *Ok = B.CreateICmpEQ(NewSig, ExpectedVal, "racfed_ok"); return; - - } } @@ -370,13 +369,13 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS // 19: Insert signature update before return instr. // 20: signature ← signature + adjustValue // 21: if signature != returnVal error() -void RACFED::checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, +Instruction *RACFED::checkReturnValue(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type* IntType, BasicBlock &ErrBB, Value *BckupRunSig) { Instruction *Term = BB.getTerminator(); - if( !isa(Term) ) return; + if( !isa(Term) ) return nullptr; std::vector org_instr; originalInstruction(BB, org_instr); @@ -393,9 +392,9 @@ void RACFED::checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, // Creating control basic block to insert before // the return instruction BasicBlock *ControlBB = BasicBlock::Create( - Md.getContext(), + BB.getContext(), "RAFCED_ret_verification_BB", - &Fn, + BB.getParent(), &BB ); @@ -426,8 +425,7 @@ void RACFED::checkReturnValue(Module &Md, Function &Fn, BasicBlock &BB, ControlIR.CreateCondBr(CmpSig, &BB, &ErrBB); } - IRBuilder<> RetInstIR(Term); - RetInstIR.CreateStore(BckupRunSig, RuntimeSigGV); + return Term; } PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { @@ -443,7 +441,7 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { ConstantInt::get(I64, 0), "signature" ); - + Instruction *RetInst = nullptr; createFtFuncs(Md); getFuncAnnotations(Md, FuncAnnotations); @@ -492,6 +490,7 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { Value * runtime_sign_bkup = nullptr; for (BasicBlock &BB : Fn) { // TODO: Should the error basic block that is inserted be checked? + // Backup of compile time sign when entering a function if( BB.isEntryBlock() ) { IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); @@ -501,9 +500,15 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { RuntimeSig); } - checkCompileTimeSigAtJump(Md, Fn, BB, RuntimeSig, I64, *ErrBB); - checkReturnValue(Md, Fn, BB, RuntimeSig, I64, *ErrBB, runtime_sign_bkup); + checkJumpSignature(BB, RuntimeSig, I64, *ErrBB); + RetInst = checkReturnValue(BB, RuntimeSig, I64, *ErrBB, runtime_sign_bkup); checkBranches(Md, BB, RuntimeSig, I64, *ErrBB); + + // Restore signature on return + if( RetInst != nullptr ) { + IRBuilder<> RetInstIR(RetInst); + RetInstIR.CreateStore(runtime_sign_bkup, RuntimeSig); + } } } @@ -527,49 +532,3 @@ llvmGetPassPluginInfo() { }}; } -// -- UNUSED FUNCTIONS -- - -// void RACFED::splitBBsAtCalls(Module &Md) { -// for (Function &Fn : Md) { -// if (shouldCompile(Fn, FuncAnnotations)) { -// std::vector CallInsts; -// for (BasicBlock &BB : Fn) { -// for (Instruction &I : BB) { -// if (isa(&I) && !isa(&I)) { -// CallInsts.push_back(cast(&I)); -// } -// } -// } -// -// for (CallBase *Call : CallInsts) { -// if (Call->getParent()->getTerminator() != Call) { -// SplitBlock(Call->getParent(), Call->getNextNode()); -// } -// } -// } -// } -// } -// -// CallBase *RACFED::isCallBB(BasicBlock &BB) { -// for (Instruction &I : BB) { -// if (isa(&I) && !isa(&I)) { -// return cast(&I); -// } -// } -// return nullptr; -// } -// -// void RACFED::initializeEntryBlocksMap(Module &Md) { -// // Implementation for INTRA_FUNCTION_CFC == 1, left empty for now as we -// // default to 0 -// } -// -// Value *RACFED::getCondition(Instruction &I) { -// // Helper to get condition from terminator if it's a branch -// if (BranchInst *BI = dyn_cast(&I)) { -// if (BI->isConditional()) { -// return BI->getCondition(); -// } -// } -// return nullptr; -// } diff --git a/testing/tests/c/multi_instruction/func_ret.c b/testing/tests/c/multi_instruction/func_ret.c index d523eb5..494adfd 100644 --- a/testing/tests/c/multi_instruction/func_ret.c +++ b/testing/tests/c/multi_instruction/func_ret.c @@ -7,12 +7,13 @@ void SigMismatch_Handler(void) { } int foo(); +void print(int c); int main() { int a = 10; int b = 20; int c = foo(); - printf("foo() %d", c); + print(c); return a > b ? a : b; } @@ -21,3 +22,7 @@ int foo() { int d = 13; return c + d; } + +void print(int c) { + printf("foo() %d\n", c); +} From 34167ffe6eac4fef8a64d215c8f86bec201fe45f Mon Sep 17 00:00:00 2001 From: martina Date: Wed, 7 Jan 2026 16:04:50 +0100 Subject: [PATCH 20/29] fixes and test on phi node --- aspis.sh | 6 +- passes/ASPIS.h | 6 +- passes/RACFED.cpp | 119 ++++++++---------- .../tests/c/multi_instruction/if_then_else.c | 4 +- testing/tests/c/multi_instruction/phi.cpp | 10 ++ 5 files changed, 70 insertions(+), 75 deletions(-) create mode 100644 testing/tests/c/multi_instruction/phi.cpp diff --git a/aspis.sh b/aspis.sh index ec8552b..469a3a5 100755 --- a/aspis.sh +++ b/aspis.sh @@ -368,9 +368,9 @@ run_aspis() { 2) exe $OPT -load-pass-plugin=$DIR/build/passes/libINTER_RASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options ;; -# 3) -# exe $OPT -load-pass-plugin=$DIR/build/passes/libRACFED.so --passes="racfed-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options -# ;; + 3) + exe $OPT -load-pass-plugin=$DIR/build/passes/libRACFED.so --passes="racfed-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options + ;; *) echo -e "\t--no-cfc specified!" esac diff --git a/passes/ASPIS.h b/passes/ASPIS.h index 3698cf8..c799e77 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -170,9 +170,9 @@ class RACFED : public PassInfoMixin { #endif // -- INITIALIZE BLOCKS -- - void initializeBlocksSignatures(Module &Md, Function &Fn); + void initializeBlocksSignatures(Function &Fn); // -- UPDATE COMPILE SIG RANDOM -- - void updateCompileSigRandom(Module &Md, Function &Fn, + void updateCompileSigRandom(Function &Fn, GlobalVariable *RuntimeSigGV, Type *IntType); // --- CHECK BLOCKS AT JUMP END --- @@ -184,7 +184,7 @@ class RACFED : public PassInfoMixin { // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- void checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, - Type *IntType, BasicBlock &ErrBB); + Type *IntType); // --- UPDATE RETURN VALUE AND CHECK --- Instruction *checkReturnValue(BasicBlock &BB, diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index e38649a..ee7fb15 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -12,7 +12,6 @@ // the code #define MARTI_DEBUG true -#define GAMBA_DEBUG false using namespace llvm; @@ -81,7 +80,7 @@ bool isNotUnique( return false; } -void RACFED::initializeBlocksSignatures(Module &Md, Function &Fn) { +void RACFED::initializeBlocksSignatures(Function &Fn) { std::mt19937 rng(0xB00BA5); // constant seed for reproducibility uint32_t randomBB; uint32_t randomSub; @@ -94,7 +93,7 @@ void RACFED::initializeBlocksSignatures(Module &Md, Function &Fn) { do { randomSub = dist32(rng); } while ( isNotUnique( - static_cast(randomBB) + randomSub, + randomBB + randomSub, compileTimeSig, subRanPrevVals) ); @@ -114,7 +113,7 @@ void originalInstruction(BasicBlock &BB, std::vector &OrigInstruct } } -void RACFED::updateCompileSigRandom(Module &Md, Function &Fn, +void RACFED::updateCompileSigRandom(Function &Fn, GlobalVariable *RuntimeSigGV, Type *IntType) { std::mt19937 rng(0xC0FFEE); // seed fisso per riproducibilità @@ -142,11 +141,7 @@ void RACFED::updateCompileSigRandom(Module &Md, Function &Fn, // signature = signature + randomConstant uint64_t K = dist32(rng); partial_sum += K; - #if GAMBA_DEBUG - errs() << "Value of K: " << K << "\n"; - errs() << "Value of partial_sum: " << partial_sum << "\n"; - errs() << "Value of sumIntra: " << sumIntraInstruction[&BB] << "\n"; - #endif + Value *Sig = B.CreateLoad(IntType, RuntimeSigGV); Value *NewSig = B.CreateAdd(Sig, ConstantInt::get(IntType, K), "sig_add"); B.CreateStore(NewSig, RuntimeSigGV); @@ -156,8 +151,6 @@ void RACFED::updateCompileSigRandom(Module &Md, Function &Fn, } // --- CHECK BLOCKS AT JUMP END --- -// FIXME: Check this function to comply with the decisions made in design -// // FIXME: Fix warnings void RACFED::checkJumpSignature(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType, @@ -240,14 +233,7 @@ Constant* expectedSignature( const int expectedSub = subRanPrevVals.at(Succ); return ConstantInt::get(IntType, expected+expectedSub); } -/* -* checkJump -23: for all Successor of BB do -24: adjustValue ← (compileTimeSigBB + \Sum{instrMonUpdates}) - -25: (compileTimeSigsuccs + subRanPrevValsuccs) -26: Insert signature update at BB end -27: signature ← signature + adjustValue -*/ + Value *RACFED::getCondition(Instruction &I) { if (isa(I) && cast(I).isConditional()) { if (!cast(I).isConditional()) { @@ -287,8 +273,16 @@ static void printSig(Module &Md, IRBuilder<> &B, Value *SigVal, const char *Msg) B.CreateCall(Printf, {FmtStr, SigVal}); } +/* +* checkBranches +23: for all Successor of BB do +24: adjustValue ← (compileTimeSigBB + \Sum{instrMonUpdates}) - +25: (compileTimeSigsuccs + subRanPrevValsuccs) +26: Insert signature update at BB end +27: signature ← signature + adjustValue +*/ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, - Type *IntType, BasicBlock &ErrBB) { + Type *IntType) { Instruction *Term = BB.getTerminator(); IRBuilder<> B(&BB); B.SetInsertPoint(Term); @@ -299,7 +293,7 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS // Calculate Source Static Signature: CT_BB + SumIntra uint64_t SourceStatic = - (uint64_t)compileTimeSig[&BB] + sumIntraInstruction[&BB]; + static_cast(compileTimeSig[&BB]) + sumIntraInstruction[&BB]; Value *Current = B.CreateLoad(IntType, RuntimeSigGV, "current"); printSig(Md, B, Current, "current"); @@ -309,50 +303,41 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS //define if conditional or unconditional branch //Conditional: expected= CT_succ+subRan_succ //adj = CTB-exp--> new signature = RT -adj - if ( BI->isUnconditional() ){ // only one successor + if ( BI->isUnconditional() ) { // only one successor BasicBlock *Succ = BI->getSuccessor(0); uint64_t Expected = - (uint64_t)compileTimeSig[Succ] + (uint64_t)subRanPrevVals[Succ];; + static_cast(compileTimeSig[Succ] + subRanPrevVals[Succ]); // adj = expected - current uint64_t AdjValue = Expected - SourceStatic; Value *Adj = ConstantInt::get(IntType, AdjValue); Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); B.CreateStore(NewSig, RuntimeSigGV); printSig(Md,B, NewSig, "newsig"); - // FIXME: Should compare neither branch - // verify newSig == expected - Value *ExpectedVal = ConstantInt::get(IntType, Expected); - Value *Ok = B.CreateICmpEQ(NewSig, ExpectedVal, "racfed_ok"); return; - } - if ( BI-> isConditional()) { - BasicBlock *SuccT = BI->getSuccessor(0); - BasicBlock *SuccF = BI->getSuccessor(1); - Instruction *Terminator = BB.getTerminator(); - Value *BrCondition = getCondition(*Terminator); - - // Target T - uint64_t expectedT = - (uint64_t)compileTimeSig[SuccT] + (uint64_t)subRanPrevVals[SuccT]; - uint64_t adj1 = expectedT - SourceStatic; - - // Target F - uint64_t expectedF = - (uint64_t)compileTimeSig[SuccF] + (uint64_t)subRanPrevVals[SuccF]; - uint64_t adj2 = expectedF - SourceStatic; - - Value *Adj = B.CreateSelect(BrCondition, ConstantInt::get(IntType, adj1), ConstantInt::get(IntType, adj2)); - Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); - B.CreateStore(NewSig, RuntimeSigGV); - - printSig(Md, B, NewSig, "SIG after cond"); - Value *ExpectedVal = B.CreateSelect( - BrCondition, ConstantInt::get(IntType, expectedT), - ConstantInt::get(IntType, expectedF), "expected_sig"); - Value *Ok = B.CreateICmpEQ(NewSig, ExpectedVal, "racfed_ok"); + } - return; + if ( BI-> isConditional()) { + BasicBlock *SuccT = BI->getSuccessor(0); + BasicBlock *SuccF = BI->getSuccessor(1); + Instruction *Terminator = BB.getTerminator(); + Value *BrCondition = getCondition(*Terminator); + + // Target T + uint64_t expectedT = + static_cast(compileTimeSig[SuccT] + subRanPrevVals[SuccT]); + uint64_t adj1 = expectedT - SourceStatic; + + // Target F + uint64_t expectedF = + static_cast(compileTimeSig[SuccF] + subRanPrevVals[SuccF]); + uint64_t adj2 = expectedF - SourceStatic; + + Value *Adj = B.CreateSelect(BrCondition, ConstantInt::get(IntType, adj1), ConstantInt::get(IntType, adj2)); + Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); + B.CreateStore(NewSig, RuntimeSigGV); + + printSig(Md, B, NewSig, "SIG after cond"); } } @@ -449,18 +434,18 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { for (Function &Fn : Md) { if (shouldCompile(Fn, FuncAnnotations)) - initializeBlocksSignatures(Md, Fn); + initializeBlocksSignatures(Fn); } for (Function &Fn: Md) { if (Fn.isDeclaration() || Fn.empty()) continue; - updateCompileSigRandom(Md, Fn, RuntimeSig, I64); + updateCompileSigRandom(Fn, RuntimeSig, I64); } for(Function &Fn: Md) { if(!shouldCompile(Fn, FuncAnnotations)) continue; - #if GAMBA_DEBUG || MARTI_DEBUG + #if MARTI_DEBUG errs() << "Analysing func " << Fn.getName() << "\n"; #endif @@ -468,8 +453,8 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { DebugLoc debugLoc; for (auto &I : Fn.front()) { if (I.getDebugLoc()) { - debugLoc = I.getDebugLoc(); - break; + debugLoc = I.getDebugLoc(); + break; } } @@ -493,21 +478,21 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { // Backup of compile time sign when entering a function if( BB.isEntryBlock() ) { - IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); - runtime_sign_bkup = - InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); - InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), - RuntimeSig); + IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); + runtime_sign_bkup = + InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); + InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), + RuntimeSig); } checkJumpSignature(BB, RuntimeSig, I64, *ErrBB); RetInst = checkReturnValue(BB, RuntimeSig, I64, *ErrBB, runtime_sign_bkup); - checkBranches(Md, BB, RuntimeSig, I64, *ErrBB); + checkBranches(Md, BB, RuntimeSig, I64); // Restore signature on return if( RetInst != nullptr ) { - IRBuilder<> RetInstIR(RetInst); - RetInstIR.CreateStore(runtime_sign_bkup, RuntimeSig); + IRBuilder<> RetInstIR(RetInst); + RetInstIR.CreateStore(runtime_sign_bkup, RuntimeSig); } } } diff --git a/testing/tests/c/multi_instruction/if_then_else.c b/testing/tests/c/multi_instruction/if_then_else.c index 89c074b..95e9cf7 100644 --- a/testing/tests/c/multi_instruction/if_then_else.c +++ b/testing/tests/c/multi_instruction/if_then_else.c @@ -9,9 +9,9 @@ int main() { x = x+1; if (x<10) { x = x*10; - printf("valore: %d", x); + printf("valore: %d\n", x); } else - printf("valore: %d", x); + printf("valore: %d\n", x); return 0; } diff --git a/testing/tests/c/multi_instruction/phi.cpp b/testing/tests/c/multi_instruction/phi.cpp new file mode 100644 index 0000000..4d688c7 --- /dev/null +++ b/testing/tests/c/multi_instruction/phi.cpp @@ -0,0 +1,10 @@ +// +// Created by martina on 07/01/26. +// + +int main() { + int y = 1; + int r = 0; + int a = y || r; + return a; +} \ No newline at end of file From a554ea0d16d5892a9f3e8b008eba29fa822b50ce Mon Sep 17 00:00:00 2001 From: Gab-San Date: Fri, 9 Jan 2026 18:49:03 +0100 Subject: [PATCH 21/29] Added suffix option to aspis.sh Should fix issue #5 --- aspis.sh | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/aspis.sh b/aspis.sh index 469a3a5..f37ce70 100755 --- a/aspis.sh +++ b/aspis.sh @@ -20,6 +20,7 @@ clang_options= eddi_options="-S" cfc_options="-S" llvm_bin=$(dirname "$(which clang)") +suffix="" build_dir="." dup=0 # 0 = eddi, 1 = seddi, 2 = fdsc cfc=0 # 0 = cfcss, 1 = rasm, 2 = inter-rasm @@ -112,12 +113,14 @@ parse_commands() { -o Write the compilation output to . --build-dir Specify the directory where to place all the build files. - --llvm-bin Set the path to the llvm binaries (clang, opt, + --llvm-bin Set the path to the llvm binaries (clang, opt, llvm-link) to . - --exclude Set the files to exclude from the compilation. The + --suffix Set the suffix of the binary to use (clang, opt, + llvm-link) to . + --exclude Set the files to exclude from the compilation. The content of is the list of files to exclude, one for each line (wildcard * allowed). - --asmfiles Defines the set of assembly files required for the + --asmfiles Defines the set of assembly files required for the compilation. The content of is the list of assembly files to pass to the linker at compilation termination, one for each line (wildcard * allowed). @@ -128,12 +131,13 @@ parse_commands() { --eddi (Default) Enable EDDI. --seddi Enable Selective-EDDI. --fdsc Enable Full Duplication with Selective Checking. - --no-dup Completely disable data duplication + --no-dup Completely disable data duplication. --cfcss (Default) Enable CFCSS. --rasm Enable RASM. --inter-rasm Enable inter-RASM with the default signature -0xDEAD. - --no-cfc Completely disable control-flow checking + --racfed Enable RACFED. + --no-cfc Completely disable control-flow checking. Hardening options: --alternate-memmap When set, alternates the definition of original and @@ -155,16 +159,25 @@ EOF if [[ ${#opt} -eq 2 ]]; then parse_state=1; else - output_file=`echo "$opt" | cut -b 2`; + output_file=${opt##"-o"}; fi; ;; --llvm-bin*) + echo ${#opt} if [[ ${#opt} -eq 10 ]]; then parse_state=3; else - llvm_bin=`echo "$opt" | cut -b 10`; + llvm_bin=${opt##"--llvm-bin="}; fi; ;; + --suffix*) + if [[ ${#opt} -eq 8 ]]; then + parse_state=7; + else + suffix='-'; + suffix+=${opt##"--suffix="}; + fi; + ;; --exclude*) if [[ ${#opt} -eq 9 ]]; then parse_state=4; @@ -270,6 +283,10 @@ EOF build_dir="$opt"; parse_state=0; ;; + 7) + suffix="$opt"; + parse_state=0; + ;; esac done @@ -294,9 +311,9 @@ EOF } fi - CLANG="${llvm_bin}/clang" - OPT="${llvm_bin}/opt" - LLVM_LINK="${llvm_bin}/llvm-link" + CLANG="${llvm_bin}/clang${suffix}" + OPT="${llvm_bin}/opt${suffix}" + LLVM_LINK="${llvm_bin}/llvm-link${suffix}" if [[ -n "$config_file" ]]; then CLANG="${CLANG} --config ${config_file}" From fe80d9cf5158092b9b62f6a19ab23d2aa3569a9c Mon Sep 17 00:00:00 2001 From: Gab-San Date: Tue, 13 Jan 2026 10:08:39 +0100 Subject: [PATCH 22/29] Modified test.py Modified test.py in order to be able to run different configuration files making it more manageable. Added --tests-file flag -> use different configuration files Added --suffix flag -> extending support to versioned binaries (aspis modifications compatibility) --- aspis.sh | 2 +- testing/README.md | 29 +++++++++++++++-- testing/config/racfed-tests.toml | 11 +++++++ testing/conftest.py | 31 +++++++++++++++++- testing/test.py | 43 ++++++++++++++----------- testing/tests/c/multi_instruction/add.c | 2 +- 6 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 testing/config/racfed-tests.toml diff --git a/aspis.sh b/aspis.sh index f37ce70..6865298 100755 --- a/aspis.sh +++ b/aspis.sh @@ -284,7 +284,7 @@ EOF parse_state=0; ;; 7) - suffix="$opt"; + suffix="-$opt"; parse_state=0; ;; esac diff --git a/testing/README.md b/testing/README.md index 98051ab..769d18f 100644 --- a/testing/README.md +++ b/testing/README.md @@ -4,12 +4,35 @@ This directory contains utilities and scripts for testing ASPIS. ## Local Testing -For local testing, use the `test.py` script. Configure your tests using `test_config.json`. - +For local testing, use the `test.py` script. Configure your tests using `test_config.toml`. Configure the llvm_bin flag in `llvm_bin.toml`. +Then run: ```bash pytest test.py ``` +### Writing a configuration file + +Test config files must be `.toml` files with the following structure for each test: + +```toml +[[tests]] +test_name = +source_file = +expected_output = +aspis_options = +``` + +> `` will look into `./tests` folder + +### Flags + +It is possible to write different configuration test files. + +Additional flags are: +`--suffix ` : Operates the same way as aspis, searching for binaries versions denoted by ``. +`--tests-file ` : Use the configuration file specified. + + ## Docker Testing You can also test ASPIS using Docker with the `test_docker_pipeline.py` script. This Pytest script uses Docker Compose to manage the container and execute ASPIS. @@ -23,4 +46,4 @@ To set up and run Docker tests: 3. **Run Tests:** Execute the `test_docker_pipeline.py` script: ```bash pytest test_docker_pipeline.py - ``` \ No newline at end of file + ``` diff --git a/testing/config/racfed-tests.toml b/testing/config/racfed-tests.toml new file mode 100644 index 0000000..da35c90 --- /dev/null +++ b/testing/config/racfed-tests.toml @@ -0,0 +1,11 @@ +[[tests]] +test_name = "multiline_add" +source_file = "c/multi_instruction/add.c" +expected_output = "30" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "multiline_func_ret" +source_file = "c/multi_instruction/func_ret.c" +expected_output = "foo() 25" +aspis_options = "--no-dup --racfed" diff --git a/testing/conftest.py b/testing/conftest.py index 6efa9df..f8c36d7 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1,4 +1,5 @@ import pytest +import os def pytest_addoption(parser): parser.addoption( @@ -7,7 +8,35 @@ def pytest_addoption(parser): default=False, help="Run tests inside a container", ) + parser.addoption( + "--tests-file", + action="store", + default="config/tests.toml", + help="Path to the configuration file", + ) + parser.addoption( + "--suffix", + action="store", + help="LLVM version suffix", + ) @pytest.fixture(scope="session") def use_container(pytestconfig): - return pytestconfig.getoption("use_container") \ No newline at end of file + return pytestconfig.getoption("use_container") + +# Optional: Add a check to ensure the file exists before any tests start +def pytest_configure(config): + tests_file = config.getoption("--tests-file") + if not os.path.exists(tests_file): + pytest.exit(f"Config file not found: {tests_file}") + +@pytest.fixture(scope="session") +def aspis_addopt(pytestconfig): + addopt = {} + suffix_opt = pytestconfig.getoption("--suffix") + if suffix_opt is None: + addopt["suffix"] = "" + else: + addopt["suffix"] = "--suffix " + suffix_opt + + return addopt["suffix"] diff --git a/testing/test.py b/testing/test.py index 044b744..65dea00 100644 --- a/testing/test.py +++ b/testing/test.py @@ -16,9 +16,6 @@ def load_config(): assert os.path.exists("../aspis.sh") and "Cannot find aspis.sh, please run the tests from the ASPIS testing directory as `pytest test.py`" with open("config/llvm.toml", "rb") as f: config = tomllib.load(f) - with open("config/tests.toml", "rb") as f: - tests = tomllib.load(f) - config.update(tests) # Merge the dictionaries return config # Utility functions @@ -31,32 +28,44 @@ 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} --build-dir ./{build_dir} --verbose" + command = f"{ASPIS_SCRIPT} --llvm-bin {llvm_bin} {options} {source_file} -o {output_file}.out --build-dir ./{build_dir} --verbose" print(command) stdout, stderr, exit_code = run_command(command) if exit_code != 0: - raise RuntimeError(f"[{test_name}] Compilation failed: {stderr}") + raise RuntimeError(f"[{output_file}] Compilation failed: {stderr}") return stdout -def execute_binary(binary_file): +def execute_binary(local_build_dir, test_name): """Execute the compiled binary and return its output.""" + binary_file = f"./{local_build_dir}/{test_name}.out"; stdout, stderr, exit_code = run_command(binary_file) if exit_code != 0: raise RuntimeError(f"[{test_name}] Execution failed: {stderr}") - return stdout + return stdout.strip() + +def pytest_generate_tests(metafunc): + """Custom hook to parametrize tests based on the CLI --tests-file flag.""" + if "test_data" in metafunc.fixturenames: + # Get the file path from the command line option + file_path = metafunc.config.getoption("--tests-file") + with open(file_path, "rb") as f: + config_data = tomllib.load(f) + # Access the 'tests' list inside the TOML dictionary + test_list = config_data.get("tests", []) + # Use 'test_name' for better output in the terminal + ids = [t.get("test_name", str(i)) for i, t in enumerate(test_list)] + metafunc.parametrize("test_data", test_list, ids=ids) # Tests -@pytest.mark.parametrize("test", load_config()["tests"]) -def test_aspis(test, use_container): +def test_aspis(test_data, use_container, aspis_addopt): """Run a single ASPIS test.""" - global test_name config = load_config() llvm_bin = config["llvm_bin"] - test_name = test["test_name"] - source_file = test["source_file"] - aspis_options = test["aspis_options"] - expected_output = test["expected_output"] + test_name = test_data["test_name"] + source_file = test_data["source_file"] + aspis_options = aspis_addopt + " " + test_data["aspis_options"] + expected_output = test_data["expected_output"] # use docker compose rather than ASPIS if --use-container is set if use_container: ASPIS_SCRIPT = f"docker compose -f {DOCKER_COMPOSE_FILE} run --rm aspis_runner" @@ -67,15 +76,13 @@ def test_aspis(test, use_container): docker_build_dir = "./build/test/"+test_name local_build_dir = "./build/test/"+test_name - - output_file = f"{test_name}.out" source_path = os.path.join(TEST_DIR, source_file) # Compile the source file - compile_with_aspis(source_path, output_file, aspis_options, llvm_bin, docker_build_dir) + compile_with_aspis(source_path, test_name, aspis_options, llvm_bin, docker_build_dir) # Execute the binary and check output - result = execute_binary(f"./{local_build_dir}/{output_file}") + result = execute_binary(local_build_dir, test_name) assert result == expected_output, f"Test {test_name} failed: {result}" if __name__ == "__main__": diff --git a/testing/tests/c/multi_instruction/add.c b/testing/tests/c/multi_instruction/add.c index 9fc27b7..792d416 100644 --- a/testing/tests/c/multi_instruction/add.c +++ b/testing/tests/c/multi_instruction/add.c @@ -7,6 +7,6 @@ int main() { int a = 10; int b = 20; int c = a + b; - printf("c=%d\n", c); + printf("%d\n", c); return 0; } From 53959e1bd90092ef464ebd83391d23befb840340 Mon Sep 17 00:00:00 2001 From: Gab-San Date: Tue, 13 Jan 2026 23:50:28 +0100 Subject: [PATCH 23/29] Tested racfed on c tests Removed some redundant tests Updated testing/README --- passes/RACFED.cpp | 80 ++++++++------- testing/README.md | 10 +- testing/config/racfed-tests.toml | 99 ++++++++++++++++++- testing/tests/c/multi_instruction/add.c | 2 +- testing/tests/c/multi_instruction/func_ret.c | 28 ------ testing/tests/c/multi_instruction/function.c | 27 +++-- testing/tests/c/multi_instruction/glob.c | 9 -- .../tests/c/multi_instruction/if_then_else.c | 4 +- .../c/multi_instruction/{phi.cpp => phi.c} | 6 +- testing/tests/c/multi_instruction/ret.c | 14 --- 10 files changed, 173 insertions(+), 106 deletions(-) delete mode 100644 testing/tests/c/multi_instruction/func_ret.c delete mode 100644 testing/tests/c/multi_instruction/glob.c rename testing/tests/c/multi_instruction/{phi.cpp => phi.c} (64%) delete mode 100644 testing/tests/c/multi_instruction/ret.c diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index ee7fb15..caf1c40 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -11,7 +11,7 @@ -0xDEAD // The same value has to be used as initializer for the signatures in // the code -#define MARTI_DEBUG true +#define MARTI_DEBUG false using namespace llvm; @@ -106,9 +106,9 @@ void RACFED::initializeBlocksSignatures(Function &Fn) { // --- UPDATE SIGNATURE RANDOM --- void originalInstruction(BasicBlock &BB, std::vector &OrigInstructions) { for (Instruction &I : BB) { - if (isa(&I)) continue; // NON è originale - if (I.isTerminator()) continue; // NON è originale - if (isa(&I)) continue; // debug, ignora OrigInstructions.push_back(&I); + if ( isa(&I) ) continue; // NON è originale + if ( I.isTerminator() ) continue; // NON è originale + if ( isa(&I) ) continue; // debug, ignora OrigInstructions.push_back(&I); OrigInstructions.push_back(&I); } } @@ -122,7 +122,7 @@ void RACFED::updateCompileSigRandom(Function &Fn, std::vector OrigInstructions; originalInstruction(BB, OrigInstructions); - if (OrigInstructions.size() <= 2) continue; + if ( OrigInstructions.size() <= 2 ) continue; uint64_t partial_sum = 0; @@ -130,7 +130,7 @@ void RACFED::updateCompileSigRandom(Function &Fn, Instruction *InsertPt = nullptr; // Non puoi inserire "dopo" un terminator: inserisci prima del terminator stesso - if (I->isTerminator()) { + if ( I->isTerminator() ) { InsertPt = I; // insert BEFORE terminator } else { InsertPt = I->getNextNode(); // insert BEFORE next instruction (equivale a "dopo I") @@ -155,7 +155,7 @@ void RACFED::updateCompileSigRandom(Function &Fn, void RACFED::checkJumpSignature(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType, BasicBlock &ErrBB) { - if( BB.isEntryBlock() ) return; + if ( BB.isEntryBlock() ) return; // in this case BB is not the first Basic Block of the function, so it has // to update RuntimeSig and check it @@ -163,12 +163,12 @@ void RACFED::checkJumpSignature(BasicBlock &BB, if ( (FirstNonPHI && isa(FirstNonPHI)) || BB.getName().contains_insensitive("verification") ) { - if (BB.getFirstInsertionPt() == BB.end()) return; // Skip empty/invalid blocks + if ( BB.getFirstInsertionPt() == BB.end() ) return; // Skip empty/invalid blocks int randomNumberBB = compileTimeSig.find(&BB)->second; IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), RuntimeSigGV, true); - } else if (!BB.getName().contains_insensitive("errbb")) { + } else if ( !BB.getName().contains_insensitive("errbb") ) { int randomNumberBB = compileTimeSig.find(&BB)->second; int subRanPrevVal = subRanPrevVals.find(&BB)->second; BasicBlock *NewBB = BasicBlock::Create( @@ -200,7 +200,7 @@ void RACFED::checkJumpSignature(BasicBlock &BB, for (BasicBlock *Succ : successors(&BB)) { for (PHINode &Phi : Succ->phis()) { for (unsigned i = 0; i < Phi.getNumIncomingValues(); ++i) { - if (Phi.getIncomingBlock(i) == NewBB) { + if ( Phi.getIncomingBlock(i) == NewBB ) { Phi.setIncomingBlock(i, &BB); } } @@ -235,13 +235,13 @@ Constant* expectedSignature( } Value *RACFED::getCondition(Instruction &I) { - if (isa(I) && cast(I).isConditional()) { - if (!cast(I).isConditional()) { + if ( isa(I) && cast(I).isConditional() ) { + if ( !cast(I).isConditional() ) { return nullptr; } else { return cast(I).getCondition(); } - } else if (isa(I)) { + } else if ( isa(I) ) { errs() << "There is a switch!\n"; abort(); return cast(I).getCondition(); @@ -263,10 +263,10 @@ static void printSig(Module &Md, IRBuilder<> &B, Value *SigVal, const char *Msg) // Crea stringa globale "Msg: %ld\n" std::string Fmt = std::string(Msg) + ": %ld\n"; - Value *FmtStr = B.CreateGlobalStringPtr(Fmt); + Value *FmtStr = B.CreateGlobalString(Fmt); - if (SigVal->getType()->isIntegerTy(32)) { + if ( SigVal->getType()->isIntegerTy(32) ) { SigVal = B.CreateZExt(SigVal, Type::getInt64Ty(Ctx)); } @@ -287,7 +287,7 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS IRBuilder<> B(&BB); B.SetInsertPoint(Term); auto *BI = dyn_cast(Term); - if (!BI) return; + if ( !BI ) return; //TODO: check this @@ -296,7 +296,9 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS static_cast(compileTimeSig[&BB]) + sumIntraInstruction[&BB]; Value *Current = B.CreateLoad(IntType, RuntimeSigGV, "current"); + #if MARTI_DEBUG printSig(Md, B, Current, "current"); + #endif //TODO: until here @@ -304,17 +306,19 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS //Conditional: expected= CT_succ+subRan_succ //adj = CTB-exp--> new signature = RT -adj if ( BI->isUnconditional() ) { // only one successor - BasicBlock *Succ = BI->getSuccessor(0); - uint64_t Expected = - static_cast(compileTimeSig[Succ] + subRanPrevVals[Succ]); - // adj = expected - current - uint64_t AdjValue = Expected - SourceStatic; - Value *Adj = ConstantInt::get(IntType, AdjValue); - Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); - B.CreateStore(NewSig, RuntimeSigGV); - printSig(Md,B, NewSig, "newsig"); + BasicBlock *Succ = BI->getSuccessor(0); + uint64_t SuccExpected = + static_cast(compileTimeSig[Succ] + subRanPrevVals[Succ]); + // adj = expected - current + uint64_t AdjValue = SuccExpected - SourceStatic; + Value *Adj = ConstantInt::get(IntType, AdjValue); + Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); + B.CreateStore(NewSig, RuntimeSigGV); + #if MARTI_DEBUG + printSig(Md,B, NewSig, "newsig"); + #endif - return; + return; } if ( BI-> isConditional()) { @@ -337,7 +341,9 @@ void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeS Value *NewSig = B.CreateAdd(Current, Adj, "racfed_newsig"); B.CreateStore(NewSig, RuntimeSigGV); + #if MARTI_DEBUG printSig(Md, B, NewSig, "SIG after cond"); + #endif } } @@ -360,11 +366,11 @@ Instruction *RACFED::checkReturnValue(BasicBlock &BB, Value *BckupRunSig) { Instruction *Term = BB.getTerminator(); - if( !isa(Term) ) return nullptr; + if ( !isa(Term) ) return nullptr; std::vector org_instr; originalInstruction(BB, org_instr); - if( org_instr.size() > 2 ) { + if ( org_instr.size() > 2 ) { // Splits the BB that contains the return instruction into // two basic blocks: @@ -443,7 +449,7 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { } for(Function &Fn: Md) { - if(!shouldCompile(Fn, FuncAnnotations)) continue; + if (!shouldCompile(Fn, FuncAnnotations)) continue; #if MARTI_DEBUG errs() << "Analysing func " << Fn.getName() << "\n"; @@ -474,15 +480,15 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { Value * runtime_sign_bkup = nullptr; for (BasicBlock &BB : Fn) { - // TODO: Should the error basic block that is inserted be checked? - // Backup of compile time sign when entering a function - if( BB.isEntryBlock() ) { + if ( BB.isEntryBlock() ) { IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); - runtime_sign_bkup = - InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); - InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), - RuntimeSig); + if ( Fn.getName() != "main" ) { + runtime_sign_bkup = + InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); + } + InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), + RuntimeSig); } checkJumpSignature(BB, RuntimeSig, I64, *ErrBB); @@ -490,7 +496,7 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { checkBranches(Md, BB, RuntimeSig, I64); // Restore signature on return - if( RetInst != nullptr ) { + if ( RetInst != nullptr && Fn.getName() != "main") { IRBuilder<> RetInstIR(RetInst); RetInstIR.CreateStore(runtime_sign_bkup, RuntimeSig); } diff --git a/testing/README.md b/testing/README.md index 769d18f..9c8154b 100644 --- a/testing/README.md +++ b/testing/README.md @@ -4,12 +4,18 @@ This directory contains utilities and scripts for testing ASPIS. ## Local Testing -For local testing, use the `test.py` script. Configure your tests using `test_config.toml`. Configure the llvm_bin flag in `llvm_bin.toml`. +For local testing, use the `test.py` script. Configure your tests using `tests.toml`. Configure the llvm_bin flag in `llvm_bin.toml`. Then run: ```bash pytest test.py ``` +> To run pytest the modules listed in requirements.txt must be installed. +> To install the modules: +> - directly install them globally with `pip install -r requirements.txt` +> - use a tool like conda +> - setup a python environment `python -m venv env` + ### Writing a configuration file Test config files must be `.toml` files with the following structure for each test: @@ -22,7 +28,7 @@ expected_output = aspis_options = ``` -> `` will look into `./tests` folder +> `` is a relative path from `./tests/` folder ### Flags diff --git a/testing/config/racfed-tests.toml b/testing/config/racfed-tests.toml index da35c90..b8b924e 100644 --- a/testing/config/racfed-tests.toml +++ b/testing/config/racfed-tests.toml @@ -1,11 +1,104 @@ +# ml := multiline + [[tests]] -test_name = "multiline_add" +test_name = "racfed_ml_add" source_file = "c/multi_instruction/add.c" expected_output = "30" aspis_options = "--no-dup --racfed" [[tests]] -test_name = "multiline_func_ret" -source_file = "c/multi_instruction/func_ret.c" +test_name = "racfed_ml_function_call" +source_file = "c/multi_instruction/function.c" expected_output = "foo() 25" aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_preserve_runtime_sig" +source_file = "c/multi_instruction/call_less_two.c" +expected_output = "0" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_ml_if_then_else" +source_file = "c/multi_instruction/if_then_else.c" +expected_output = "1001" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_ml_phi_instruction" +source_file = "c/multi_instruction/phi.c" +expected_output = "1" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_function_pointer" +source_file = "c/control_flow/function_pointer.c" +expected_output = "42" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_loop_exit" +source_file = "c/control_flow/loop_exit.c" +expected_output = "2" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_nested-branch" +source_file = "c/control_flow/nested-branch.c" +expected_output = "6" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_simple-branch" +source_file = "c/control_flow/simple-branch.c" +expected_output = "OK" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_switch-case" +source_file = "c/control_flow/switch-case.c" +expected_output = "300" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_data_dep_branches" +source_file = "c/data_duplication_integrity/data_dep_branches.c" +expected_output = "7" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_global_var_across_functions" +source_file = "c/data_duplication_integrity/global_var_across_functions.c" +expected_output = "2" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_misc_data_dup" +source_file = "c/data_duplication_integrity/misc_data_dup.c" +expected_output = "OK" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_volatile_io" +source_file = "c/data_duplication_integrity/volatile_io.c" +expected_output = "42" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_arit_pipeline" +source_file = "c/misc_math/arit_pipeline.c" +expected_output = "3" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_mixed_ops" +source_file = "c/misc_math/mixed_ops.c" +expected_output = "14.5" +aspis_options = "--no-dup --racfed" + +[[tests]] +test_name = "racfed_xor_cypher" +source_file = "c/misc_math/xor_cypher.c" +expected_output = "SUCCESS" +aspis_options = "--no-dup --racfed" + diff --git a/testing/tests/c/multi_instruction/add.c b/testing/tests/c/multi_instruction/add.c index 792d416..5e50264 100644 --- a/testing/tests/c/multi_instruction/add.c +++ b/testing/tests/c/multi_instruction/add.c @@ -1,5 +1,5 @@ // -// Created by Martina Starone on 24/12/25. +// Created by Gabriele Santandrea on 24/12/25. // #include diff --git a/testing/tests/c/multi_instruction/func_ret.c b/testing/tests/c/multi_instruction/func_ret.c deleted file mode 100644 index 494adfd..0000000 --- a/testing/tests/c/multi_instruction/func_ret.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -void SigMismatch_Handler(void) { - printf("An error occurred and the signature value was different from expected"); - exit(-1); -} - -int foo(); -void print(int c); - -int main() { - int a = 10; - int b = 20; - int c = foo(); - print(c); - return a > b ? a : b; -} - -int foo() { - int c = 12; - int d = 13; - return c + d; -} - -void print(int c) { - printf("foo() %d\n", c); -} diff --git a/testing/tests/c/multi_instruction/function.c b/testing/tests/c/multi_instruction/function.c index 7ed50d1..8cc2f9f 100644 --- a/testing/tests/c/multi_instruction/function.c +++ b/testing/tests/c/multi_instruction/function.c @@ -1,14 +1,25 @@ -int max(int a, int b, int c) { - int max = a > b ? a : b; - max = max > c ? max : c; - return max; -} +// +// Created by Gabriele Santandrea +// +#include +int foo(); +void print(int c); int main() { int a = 10; int b = 20; - int c = 30; - max(a, b, c); - return 0; + int c = foo(); + print(c); + return a > b ? 1 : 0; +} + +int foo() { + int c = 12; + int d = 13; + return c + d; +} + +void print(int c) { + printf("foo() %d\n", c); } diff --git a/testing/tests/c/multi_instruction/glob.c b/testing/tests/c/multi_instruction/glob.c deleted file mode 100644 index b70b773..0000000 --- a/testing/tests/c/multi_instruction/glob.c +++ /dev/null @@ -1,9 +0,0 @@ -int global = 0; - -int main() { - int a = global + 1; - global += 10; - global += 11; - a += 12; - return a + global; -} diff --git a/testing/tests/c/multi_instruction/if_then_else.c b/testing/tests/c/multi_instruction/if_then_else.c index 95e9cf7..0a9ab1d 100644 --- a/testing/tests/c/multi_instruction/if_then_else.c +++ b/testing/tests/c/multi_instruction/if_then_else.c @@ -9,9 +9,9 @@ int main() { x = x+1; if (x<10) { x = x*10; - printf("valore: %d\n", x); + printf("%d\n", x); } else - printf("valore: %d\n", x); + printf("%d\n", x); return 0; } diff --git a/testing/tests/c/multi_instruction/phi.cpp b/testing/tests/c/multi_instruction/phi.c similarity index 64% rename from testing/tests/c/multi_instruction/phi.cpp rename to testing/tests/c/multi_instruction/phi.c index 4d688c7..2729b90 100644 --- a/testing/tests/c/multi_instruction/phi.cpp +++ b/testing/tests/c/multi_instruction/phi.c @@ -1,10 +1,12 @@ // // Created by martina on 07/01/26. // +#include int main() { int y = 1; int r = 0; int a = y || r; - return a; -} \ No newline at end of file + printf("%d\n", a); + return 0; +} diff --git a/testing/tests/c/multi_instruction/ret.c b/testing/tests/c/multi_instruction/ret.c deleted file mode 100644 index 3d11e63..0000000 --- a/testing/tests/c/multi_instruction/ret.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -void SigMismatch_Handler(void) { - printf("An error occurred and the signature value was different from expected"); - exit(-1); -} - -int main() { - int a = 10; - int b = 20; - printf("a + b %d", a+b); - return 0; -} From 74a9dace75a8d405222f53a1c00ab90c3a3f1e7c Mon Sep 17 00:00:00 2001 From: Gab-San Date: Wed, 14 Jan 2026 00:41:05 +0100 Subject: [PATCH 24/29] Tested RACFED+EDDI Tested RACFED+EDDI using test.py Issue #11 seems to be related to duplication algorithm since when enabling eddi it works correctly Issue #9 can be closed since it seems to be working correctly --- testing/config/racfed+eddi.toml | 102 ++++++++++++++++++ .../config/{racfed-tests.toml => racfed.toml} | 2 - 2 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 testing/config/racfed+eddi.toml rename testing/config/{racfed-tests.toml => racfed.toml} (99%) diff --git a/testing/config/racfed+eddi.toml b/testing/config/racfed+eddi.toml new file mode 100644 index 0000000..672c2fa --- /dev/null +++ b/testing/config/racfed+eddi.toml @@ -0,0 +1,102 @@ +[[tests]] +test_name = "racfed_ml_add_eddi" +source_file = "c/multi_instruction/add.c" +expected_output = "30" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_ml_function_call_eddi" +source_file = "c/multi_instruction/function.c" +expected_output = "foo() 25" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_preserve_runtime_sig_eddi" +source_file = "c/multi_instruction/call_less_two.c" +expected_output = "0" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_ml_if_then_else_eddi" +source_file = "c/multi_instruction/if_then_else.c" +expected_output = "1001" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_ml_phi_instruction_eddi" +source_file = "c/multi_instruction/phi.c" +expected_output = "1" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_function_pointer_eddi" +source_file = "c/control_flow/function_pointer.c" +expected_output = "42" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_loop_exit_eddi" +source_file = "c/control_flow/loop_exit.c" +expected_output = "2" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_nested-branch_eddi" +source_file = "c/control_flow/nested-branch.c" +expected_output = "6" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_simple-branch_eddi" +source_file = "c/control_flow/simple-branch.c" +expected_output = "OK" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_switch-case_eddi" +source_file = "c/control_flow/switch-case.c" +expected_output = "300" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_data_dep_branches_eddi" +source_file = "c/data_duplication_integrity/data_dep_branches.c" +expected_output = "7" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_global_var_across_functions_eddi" +source_file = "c/data_duplication_integrity/global_var_across_functions.c" +expected_output = "2" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_misc_data_dup_eddi" +source_file = "c/data_duplication_integrity/misc_data_dup.c" +expected_output = "OK" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_volatile_io_eddi" +source_file = "c/data_duplication_integrity/volatile_io.c" +expected_output = "42" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_arit_pipeline_eddi" +source_file = "c/misc_math/arit_pipeline.c" +expected_output = "3" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_mixed_ops_eddi" +source_file = "c/misc_math/mixed_ops.c" +expected_output = "14.5" +aspis_options = "--eddi --racfed" + +[[tests]] +test_name = "racfed_xor_cypher_eddi" +source_file = "c/misc_math/xor_cypher.c" +expected_output = "SUCCESS" +aspis_options = "--eddi --racfed" + diff --git a/testing/config/racfed-tests.toml b/testing/config/racfed.toml similarity index 99% rename from testing/config/racfed-tests.toml rename to testing/config/racfed.toml index b8b924e..f48a5c8 100644 --- a/testing/config/racfed-tests.toml +++ b/testing/config/racfed.toml @@ -1,5 +1,3 @@ -# ml := multiline - [[tests]] test_name = "racfed_ml_add" source_file = "c/multi_instruction/add.c" From 7941f080bf97fa4ee302e2e3749ce3060f750e42 Mon Sep 17 00:00:00 2001 From: Gab-San Date: Wed, 14 Jan 2026 01:23:51 +0100 Subject: [PATCH 25/29] Update README Update to racfed+eddi test names --- README.md | 12 ++++++++++++ testing/config/racfed+eddi.toml | 34 ++++++++++++++++----------------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 0c20a2d..3c651a8 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ The toolchain has been tested with the following versions: - CMake 3.22.1 - LLVM 16.0.0 +> RASM, RACFED and EDDI algorithm are already patched to LLVM 21. +> Patching of the other algorithms will is being done in branch patch-16-to-21. + During the development of ASPIS, done mostly on LLVM 15, we discovered a bug in the [`splitBasicBlock()`](https://llvm.org/doxygen/classllvm_1_1BasicBlock.html#a2bc5caaabd6841e4ab97237ebcaeb86d) procedure. The bug has been fixed in LLVM 16, so we recommend using it rather than applying the patch to the previous versions. ## Building @@ -80,6 +83,9 @@ ASPIS does not compile the annotated function or does not duplicate the annotate ## Built-in compilation pipeline `aspis.sh` is a simple command-line interface that allows users to run the entire compilation pipeline specifying a few command-line arguments. The arguments that are not recognised are passed directly to the front-end, hence all the `clang` arguments are admissible. +> RASM, RACFED and EDDI algorithm are already patched to LLVM 21. +> Patching of the other algorithms will is being done in branch patch-16-to-21. + ### Options - `-h`, `--help`: Display available options. - `-o `: Write the compilation output to ``. @@ -95,6 +101,7 @@ ASPIS does not compile the annotated function or does not duplicate the annotate - `--cfcss`: **(Default)** Enable CFCSS. - `--rasm`: Enable RASM. - `--inter-rasm`: Enable inter-RASM with the default signature `-0xDEAD`. + - `--racfed`: Enable RACFED. ### Example @@ -184,6 +191,11 @@ opt --enable-new-pm=0 -S -load build/passes/libEDDI.so -duplica clang out.ll -o out.elf ``` +> With newer versions of LLVM: +> --enable-new-pm is no longer valid. +> -load has been replaced by -load-pass-plugin=build/passes/lib*.so -passes="passname" + + ## References If you are using this tool in scientific works, please cite the following article: - Davide Baroffio, Federico Reghenzani, and William Fornaciari. 2024. Enhanced Compiler Technology for Software-based Hardware Fault Detection. ACM Trans. Des. Autom. Electron. Syst. 29, 5, Article 91 (September 2024), 23 pages. https://doi.org/10.1145/3660524 diff --git a/testing/config/racfed+eddi.toml b/testing/config/racfed+eddi.toml index 672c2fa..b7da1a9 100644 --- a/testing/config/racfed+eddi.toml +++ b/testing/config/racfed+eddi.toml @@ -1,101 +1,101 @@ [[tests]] -test_name = "racfed_ml_add_eddi" +test_name = "racfed_eddi_ml_add" source_file = "c/multi_instruction/add.c" expected_output = "30" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_ml_function_call_eddi" +test_name = "racfed_eddi_ml_function_call" source_file = "c/multi_instruction/function.c" expected_output = "foo() 25" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_preserve_runtime_sig_eddi" +test_name = "racfed_eddi_preserve_runtime_sig" source_file = "c/multi_instruction/call_less_two.c" expected_output = "0" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_ml_if_then_else_eddi" +test_name = "racfed_eddi_ml_if_then_else" source_file = "c/multi_instruction/if_then_else.c" expected_output = "1001" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_ml_phi_instruction_eddi" +test_name = "racfed_eddi_ml_phi_instruction" source_file = "c/multi_instruction/phi.c" expected_output = "1" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_function_pointer_eddi" +test_name = "racfed_eddi_function_pointer" source_file = "c/control_flow/function_pointer.c" expected_output = "42" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_loop_exit_eddi" +test_name = "racfed_eddi_loop_exit" source_file = "c/control_flow/loop_exit.c" expected_output = "2" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_nested-branch_eddi" +test_name = "racfed_eddi_n-branch_eddi" source_file = "c/control_flow/nested-branch.c" expected_output = "6" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_simple-branch_eddi" +test_name = "racfed_eddi_s-branch_eddi" source_file = "c/control_flow/simple-branch.c" expected_output = "OK" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_switch-case_eddi" +test_name = "racfed_eddi_s-case_eddi" source_file = "c/control_flow/switch-case.c" expected_output = "300" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_data_dep_branches_eddi" +test_name = "racfed_eddi_data_dep_branches" source_file = "c/data_duplication_integrity/data_dep_branches.c" expected_output = "7" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_global_var_across_functions_eddi" +test_name = "racfed_eddi_global_var_across_functions" source_file = "c/data_duplication_integrity/global_var_across_functions.c" expected_output = "2" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_misc_data_dup_eddi" +test_name = "racfed_eddi_misc_data_dup" source_file = "c/data_duplication_integrity/misc_data_dup.c" expected_output = "OK" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_volatile_io_eddi" +test_name = "racfed_eddi_volatile_io" source_file = "c/data_duplication_integrity/volatile_io.c" expected_output = "42" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_arit_pipeline_eddi" +test_name = "racfed_eddi_arit_pipeline" source_file = "c/misc_math/arit_pipeline.c" expected_output = "3" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_mixed_ops_eddi" +test_name = "racfed_eddi_mixed_ops" source_file = "c/misc_math/mixed_ops.c" expected_output = "14.5" aspis_options = "--eddi --racfed" [[tests]] -test_name = "racfed_xor_cypher_eddi" +test_name = "racfed_eddi_xor_cypher" source_file = "c/misc_math/xor_cypher.c" expected_output = "SUCCESS" aspis_options = "--eddi --racfed" From f2c90126e362ee8fba97b11634ff0bfbbcddd4da Mon Sep 17 00:00:00 2001 From: Gab-San Date: Wed, 14 Jan 2026 13:45:15 +0100 Subject: [PATCH 26/29] Adding Documentation Added some documentation. Added CompiledFuncs logic (copied from rasm) --- passes/ASPIS.h | 43 +++++++++--- passes/RACFED.cpp | 171 ++++++++++++++++++++++++++++------------------ 2 files changed, 141 insertions(+), 73 deletions(-) diff --git a/passes/ASPIS.h b/passes/ASPIS.h index c799e77..f1a70d8 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -156,26 +156,53 @@ class RASM : public PassInfoMixin { }; +/** + * @brief Pass implementing RACFED algorithm. + */ class RACFED : public PassInfoMixin { private: std::map FuncAnnotations; - std::map NewBBs; + + /// Compile time signature map. + /// + /// Compile time signatures are unique identifiers for the single basic block. std::unordered_map compileTimeSig; + + /// SubRanPrevVals map. + /// + /// These values are added to compile time signature to identify unique + /// branch jumps. std::unordered_map subRanPrevVals; + + /// Instra instruction sum map. + /// + /// This map contains the sum of all the random values put after instructions. std::unordered_map sumIntraInstruction; -#if (LOG_COMPILED_FUNCS == 1) + #if (LOG_COMPILED_FUNCS == 1) std::set CompiledFuncs; -#endif + #endif - // -- INITIALIZE BLOCKS -- + /** + * Initializes compile time signature and subRanPrevVal, for + * all of the basic blocks, with unique values. + */ void initializeBlocksSignatures(Function &Fn); - // -- UPDATE COMPILE SIG RANDOM -- - void updateCompileSigRandom(Function &Fn, + + /** + * Updates compile time signature with random values intra + * instructions. + */ + void insertIntraInstructionUpdates(Function &Fn, GlobalVariable *RuntimeSigGV, Type *IntType); - // --- CHECK BLOCKS AT JUMP END --- + /** + * Check runtime signature in non entry blocks. + * + * If the runtime signature, after some proper modifications, does not match + * the compile time signature a jump to an error handling block is inserted. + */ void checkJumpSignature(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType, BasicBlock &ErrBB); @@ -183,7 +210,7 @@ class RACFED : public PassInfoMixin { Value *getCondition(Instruction &I); // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- - void checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, + void updateBeforeJump(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType); // --- UPDATE RETURN VALUE AND CHECK --- diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index caf1c40..4062c29 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -1,3 +1,47 @@ +/**************************************************************************************** + * @brief LLVM pass implementing Random Additive Control Flow Error Detection (RACFED). + * Original algorithm by Vankeirsbilck et Al. (DOI: 10.1007/978-3-319-99130-6_15) + * + * @author Martina Starone, Gabriele Santandrea, Politecnico di Milano, Italy + * (martina.starone@mail.polimi.it, gabriele.santandrea@mail.polimi.it) + * + * The RACFED algorithm is reported here. + * It was splitted into sections in order to develop a more readeable code. + * + * initializeBlockSignatures + * 1:for all Basic Block (BB) in CFG do + * 2: repeat compileTimeSig ← random number + * 3: until compileTimeSig is unique + * 4: repeat subRanPrevVal ← random number + * 5: until (compileTimeSig + subRanPrevVal) is unique + * insertIntraInstructionUpdates + * 6:for all BB in CFG do + * 7: if NrInstrBB > 2 then + * 8: for all original instructions insert after + * 9: signature ← signature + random number + * checkJumpSignature + * 10:for all BB in CFG insert at beginning + * 11: signature ← signature − subRanPrevVal + * 12: if signature != compileTimeSig error() + * 13:for all BB in CFG do + * checkRetVal + * 14: if Last Instr. is return instr. and NrIntrBB > 1 then + * 15: Calculate needed variables + * 16: return Val ← random number + * 17: adjust Value ← (compileTimeSigBB + SumIntraInstructions) - + * 18: return Val + * 19: Insert signature update before return instr. + * 20: signature ← signature + adjustValue + * 21: if signature != returnVal error() + * 22: else + * updateBeforeJump + * 23: for all Successor of BB do + * 24: adjustValue ← (compileTimeSigBB + SumIntraInstructions) - + * 25: (compileTimeSigSuccs + subRanPrevValSuccs) + * 26: Insert signature update at BB end + * 27: signature ← signature + adjustValue + *************************************************************************************/ + #include "ASPIS.h" #include "Utils/Utils.h" #include "llvm/IR/IRBuilder.h" @@ -7,54 +51,28 @@ #include -#define INIT_SIGNATURE \ - -0xDEAD // The same value has to be used as initializer for the signatures in - // the code - #define MARTI_DEBUG false using namespace llvm; -/** - * initializeBlockSignatures -1:for all Basic Block (BB) in CFG do -2: repeat compileTimeSig ← random number -3: until compileTimeSig is unique -4: repeat subRanPrevVal ← random number -5: until (compileTimeSig + subRanP revV al) is unique - * updateSignatureRandom -6:for all BB in CFG do -7: if NrInstrBB > 2 then -8: for all original instructions insert after -9: signature ← signature + random number - * checkCompileTimeSigAtJump -10:for all BB in CFG insert at beginning -11: signature ← signature − subRanPrevVal -12: if signature != compileTimeSig error() -13:for all BB in CFG do - * checkRetVal -14: if Last Instr. is return instr. and NrIntrBB > 1 then -15: Calculate needed variables -16: return Val ← random number -17: adjust Value ← (compileTimeSigBB + SumIntraInstructions) - -18: return Val -19: Insert signature update before return instr. -20: signature ← signature + adjustValue -21: if signature != returnVal error() -22: else - * checkJump -23: for all Successor of BB do -24: adjustValue ← (compileTimeSigBB + \Sum{instrMonUpdates}) - -25: (compileTimeSigsuccs + subRanPrevValsuccs) -26: Insert signature update at BB end -27: signature ← signature + adjustValue -*/ - +/// Uniform distribution for 32 bits numbers. +/// +/// In each function using this distribution a different seed will be used. +/// Seeds are chosen to be constant for reproducibility. +/// +/// The range doesn't encapsulate the complete representation of 32 bits unsigned, +/// this was a design choice since multiple 32 bits are sum between each +/// other throughout the algorithm thus no overflow should occur when summing. std::uniform_int_distribution dist32(1, 0x7fffffff); -std::uniform_int_distribution dist64(1, 0xffffffff); -std::mt19937 rng64(0x5EED00); // constant seed for reproducibility -// --- INITIALIZE BLOCKS RANDOM --- +// -------- INITIALIZE BLOCKS SIGNATURES -------- + +/** + * Checks whether the compile time signature is unique. + * + * @param bb_num compile time signature of the current analysed basic block. + * @param compileTimeSig already assigned compile time signatures + */ bool isNotUniqueCompileTimeSig( const uint32_t bb_num, const std::unordered_map &compileTimeSig @@ -65,13 +83,22 @@ bool isNotUniqueCompileTimeSig( return false; } +/** + * Checks whether the compile time signature (already unique) + * + second unique identifier (subRanPrevVal). + * + * @param current_id compileTimeSignature + subRanPrevVal for the + * current basic block. + * @param compileTimeSig already assigned compile time signatures. + * @param subRanPrevVals already assigned subRanPrevVals. + */ bool isNotUnique( const uint32_t current_id, - const std::unordered_map &RandomNumBBs, - const std::unordered_map &SubRanPrevVals + const std::unordered_map &compileTimeSig, + const std::unordered_map &subRanPrevVals ) { - for (const auto &[other_bb, other_bb_num] : RandomNumBBs) { - uint32_t other_id = static_cast(other_bb_num) + SubRanPrevVals.at(other_bb); + for (const auto &[other_bb, other_bb_num] : compileTimeSig) { + uint32_t other_id = static_cast(other_bb_num) + subRanPrevVals.at(other_bb); if ( other_id == current_id ) { return true; } @@ -103,17 +130,22 @@ void RACFED::initializeBlocksSignatures(Function &Fn) { } -// --- UPDATE SIGNATURE RANDOM --- +// --------- INSERT UPDATES AFTER INSTRUCTIONS ----------- + +/** + * Computes the number of original instructions of the intermediate representation. + */ void originalInstruction(BasicBlock &BB, std::vector &OrigInstructions) { for (Instruction &I : BB) { if ( isa(&I) ) continue; // NON è originale if ( I.isTerminator() ) continue; // NON è originale - if ( isa(&I) ) continue; // debug, ignora OrigInstructions.push_back(&I); + // debug, ignora OrigInstructions.push_back(&I); + if ( isa(&I) ) continue; OrigInstructions.push_back(&I); } } -void RACFED::updateCompileSigRandom(Function &Fn, +void RACFED::insertIntraInstructionUpdates(Function &Fn, GlobalVariable *RuntimeSigGV, Type *IntType) { std::mt19937 rng(0xC0FFEE); // seed fisso per riproducibilità @@ -150,7 +182,7 @@ void RACFED::updateCompileSigRandom(Function &Fn, } } -// --- CHECK BLOCKS AT JUMP END --- +// --------- CHECK BLOCKS AT JUMP END --------- // FIXME: Fix warnings void RACFED::checkJumpSignature(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType, @@ -213,9 +245,6 @@ void RACFED::checkJumpSignature(BasicBlock &BB, llvm::ConstantInt::get(IntType, randomNumberBB)); BChecker.CreateCondBr(CmpVal, &BB, &ErrBB); - // add NewBB and BB into the NewBBs map - NewBBs.insert(std::pair(NewBB, &BB)); - // Map NewBB to the same signature requirements as BB so predecessors can // target it correctly compileTimeSig[NewBB] = randomNumberBB; @@ -274,14 +303,14 @@ static void printSig(Module &Md, IRBuilder<> &B, Value *SigVal, const char *Msg) } /* -* checkBranches -23: for all Successor of BB do -24: adjustValue ← (compileTimeSigBB + \Sum{instrMonUpdates}) - -25: (compileTimeSigsuccs + subRanPrevValsuccs) -26: Insert signature update at BB end -27: signature ← signature + adjustValue +* updateBeforeJump +* 23: for all Successor of BB do +* 24: adjustValue ← (compileTimeSigBB + \Sum{instrMonUpdates}) - +* 25: (compileTimeSigsuccs + subRanPrevValsuccs) +* 26: Insert signature update at BB end +* 27: signature ← signature + adjustValue */ -void RACFED::checkBranches(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, +void RACFED::updateBeforeJump(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType) { Instruction *Term = BB.getTerminator(); IRBuilder<> B(&BB); @@ -364,6 +393,12 @@ Instruction *RACFED::checkReturnValue(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type* IntType, BasicBlock &ErrBB, Value *BckupRunSig) { + + // Uniform distribution for 64 bits numbers. + std::uniform_int_distribution dist64(1, 0xffffffff); + // Constant seed for 64 bits + std::mt19937 rng64(0x5EED00); + Instruction *Term = BB.getTerminator(); if ( !isa(Term) ) return nullptr; @@ -420,9 +455,6 @@ Instruction *RACFED::checkReturnValue(BasicBlock &BB, } PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { - // mappa: istruzione originale -> random r usato per S = S + r - // std::unordered_map InstrUpdates; - auto *I64 = llvm::Type::getInt64Ty(Md.getContext()); GlobalVariable *RuntimeSig = new GlobalVariable( @@ -432,6 +464,7 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { ConstantInt::get(I64, 0), "signature" ); + Instruction *RetInst = nullptr; createFtFuncs(Md); @@ -445,7 +478,7 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { for (Function &Fn: Md) { if (Fn.isDeclaration() || Fn.empty()) continue; - updateCompileSigRandom(Fn, RuntimeSig, I64); + insertIntraInstructionUpdates(Fn, RuntimeSig, I64); } for(Function &Fn: Md) { @@ -464,6 +497,10 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { } } + #if (LOG_COMPILED_FUNCS == 1) + CompiledFuncs.insert(&Fn); + #endif + // Create error basic block assert(!getLinkageName(linkageMap,"SigMismatch_Handler").empty() && "Function SigMismatch_Handler is missing!"); @@ -493,7 +530,7 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { checkJumpSignature(BB, RuntimeSig, I64, *ErrBB); RetInst = checkReturnValue(BB, RuntimeSig, I64, *ErrBB, runtime_sign_bkup); - checkBranches(Md, BB, RuntimeSig, I64); + updateBeforeJump(Md, BB, RuntimeSig, I64); // Restore signature on return if ( RetInst != nullptr && Fn.getName() != "main") { @@ -503,6 +540,10 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { } } + #if (LOG_COMPILED_FUNCS == 1) + persistCompiledFunctions(CompiledFuncs, "compiled_racfed_functions.csv"); + #endif + // There is nothing that this pass preserved return PreservedAnalyses::none(); } From 051950f2e9c404c060888250a1e4f3f9a5a11c16 Mon Sep 17 00:00:00 2001 From: Gab-San Date: Wed, 14 Jan 2026 19:23:28 +0100 Subject: [PATCH 27/29] Additional documentation --- README.md | 8 +- passes/ASPIS.h | 48 +++++++---- passes/RACFED.cpp | 209 +++++++++++++++++++++++++++------------------- 3 files changed, 161 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index 3c651a8..acaa837 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The toolchain has been tested with the following versions: - LLVM 16.0.0 > RASM, RACFED and EDDI algorithm are already patched to LLVM 21. -> Patching of the other algorithms will is being done in branch patch-16-to-21. +> Patching of the other algorithms is being done. During the development of ASPIS, done mostly on LLVM 15, we discovered a bug in the [`splitBasicBlock()`](https://llvm.org/doxygen/classllvm_1_1BasicBlock.html#a2bc5caaabd6841e4ab97237ebcaeb86d) procedure. The bug has been fixed in LLVM 16, so we recommend using it rather than applying the patch to the previous versions. @@ -84,7 +84,7 @@ ASPIS does not compile the annotated function or does not duplicate the annotate `aspis.sh` is a simple command-line interface that allows users to run the entire compilation pipeline specifying a few command-line arguments. The arguments that are not recognised are passed directly to the front-end, hence all the `clang` arguments are admissible. > RASM, RACFED and EDDI algorithm are already patched to LLVM 21. -> Patching of the other algorithms will is being done in branch patch-16-to-21. +> Patching of the other algorithms is being done. ### Options - `-h`, `--help`: Display available options. @@ -192,8 +192,8 @@ clang out.ll -o out.elf ``` > With newer versions of LLVM: -> --enable-new-pm is no longer valid. -> -load has been replaced by -load-pass-plugin=build/passes/lib*.so -passes="passname" +> `--enable-new-pm` is no longer valid. +> `-load` has been replaced by `-load-pass-plugin=build/passes/lib*.so -passes="passname"` ## References diff --git a/passes/ASPIS.h b/passes/ASPIS.h index f1a70d8..caa50b6 100644 --- a/passes/ASPIS.h +++ b/passes/ASPIS.h @@ -163,20 +163,26 @@ class RACFED : public PassInfoMixin { private: std::map FuncAnnotations; - /// Compile time signature map. - /// - /// Compile time signatures are unique identifiers for the single basic block. + /** + * Compile time signature map. + * + * Compile time signatures are unique identifiers for the single basic block. + */ std::unordered_map compileTimeSig; - /// SubRanPrevVals map. - /// - /// These values are added to compile time signature to identify unique - /// branch jumps. + /** + * SubRanPrevVals map. + * + * These values are added to compile time signature to identify unique + * branch jumps. + */ std::unordered_map subRanPrevVals; - /// Instra instruction sum map. - /// - /// This map contains the sum of all the random values put after instructions. + /** + * Instra instruction sum map. + * + * This map contains the sum of all the random values put after instructions. + */ std::unordered_map sumIntraInstruction; @@ -191,14 +197,14 @@ class RACFED : public PassInfoMixin { void initializeBlocksSignatures(Function &Fn); /** - * Updates compile time signature with random values intra - * instructions. + * Adds updates to the runtime signature with random values + * after each instruction. */ void insertIntraInstructionUpdates(Function &Fn, GlobalVariable *RuntimeSigGV, Type *IntType); /** - * Check runtime signature in non entry blocks. + * Adds a check on runtime signature at the entrance of non entry blocks. * * If the runtime signature, after some proper modifications, does not match * the compile time signature a jump to an error handling block is inserted. @@ -207,14 +213,24 @@ class RACFED : public PassInfoMixin { GlobalVariable *RuntimeSigGV, Type *IntType, BasicBlock &ErrBB); + // TODO: Add documentation Value *getCondition(Instruction &I); - // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- + /** + * Adds an update of the runtime signature before a branch instruction. + * + * This function works in conjunction with checkJumpSignature(...). + */ void updateBeforeJump(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType); - // --- UPDATE RETURN VALUE AND CHECK --- - Instruction *checkReturnValue(BasicBlock &BB, + /** + * Adds a check on runtime signature before a return instruction. + * + * If the runtime signature, after some proper modifications, does not match + * the compile time signature a jump to an error handling block is inserted. + */ + Instruction *checkOnReturn(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType, BasicBlock &ErrBB, Value *BckupRunSig); diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index 4062c29..abd852f 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -8,7 +8,7 @@ * The RACFED algorithm is reported here. * It was splitted into sections in order to develop a more readeable code. * - * initializeBlockSignatures + * initializeBlocksSignatures * 1:for all Basic Block (BB) in CFG do * 2: repeat compileTimeSig ← random number * 3: until compileTimeSig is unique @@ -24,7 +24,7 @@ * 11: signature ← signature − subRanPrevVal * 12: if signature != compileTimeSig error() * 13:for all BB in CFG do - * checkRetVal + * checkOnReturn * 14: if Last Instr. is return instr. and NrIntrBB > 1 then * 15: Calculate needed variables * 16: return Val ← random number @@ -55,6 +55,12 @@ using namespace llvm; +// TODO: Seeds could be randomised + +// TODO: Check TODOs in updateBeforeJump + +// TODO: Fix warnings in checkJump + /// Uniform distribution for 32 bits numbers. /// /// In each function using this distribution a different seed will be used. @@ -107,6 +113,14 @@ bool isNotUnique( return false; } +/* + * initializeBlocksSignatures + * 1:for all Basic Block (BB) in CFG do + * 2: repeat compileTimeSig ← random number + * 3: until compileTimeSig is unique + * 4: repeat subRanPrevVal ← random number + * 5: until (compileTimeSig + subRanPrevVal) is unique + */ void RACFED::initializeBlocksSignatures(Function &Fn) { std::mt19937 rng(0xB00BA5); // constant seed for reproducibility uint32_t randomBB; @@ -129,7 +143,6 @@ void RACFED::initializeBlocksSignatures(Function &Fn) { } } - // --------- INSERT UPDATES AFTER INSTRUCTIONS ----------- /** @@ -137,62 +150,80 @@ void RACFED::initializeBlocksSignatures(Function &Fn) { */ void originalInstruction(BasicBlock &BB, std::vector &OrigInstructions) { for (Instruction &I : BB) { - if ( isa(&I) ) continue; // NON è originale - if ( I.isTerminator() ) continue; // NON è originale - // debug, ignora OrigInstructions.push_back(&I); + if ( isa(&I) ) continue; // NOT ORIGINAL + if ( I.isTerminator() ) continue; // NOT ORIGINAL if ( isa(&I) ) continue; OrigInstructions.push_back(&I); } } +/* + * insertIntraInstructionUpdates + * 6:for all BB in CFG do + * 7: if NrInstrBB > 2 then + * 8: for all original instructions insert after + * 9: signature ← signature + random number + */ void RACFED::insertIntraInstructionUpdates(Function &Fn, GlobalVariable *RuntimeSigGV, Type *IntType) { - std::mt19937 rng(0xC0FFEE); // seed fisso per riproducibilità + std::mt19937 rng(0xC0FFEE); // fixed seed for reproducibility + // 6: for all BB in CFG do for (auto &BB: Fn){ std::vector OrigInstructions; originalInstruction(BB, OrigInstructions); + // 7: if NrInstrBB > 2 then if ( OrigInstructions.size() <= 2 ) continue; uint64_t partial_sum = 0; + // 8: for all original instructions insert after for (Instruction *I : OrigInstructions) { Instruction *InsertPt = nullptr; - // Non puoi inserire "dopo" un terminator: inserisci prima del terminator stesso if ( I->isTerminator() ) { InsertPt = I; // insert BEFORE terminator } else { - InsertPt = I->getNextNode(); // insert BEFORE next instruction (equivale a "dopo I") + InsertPt = I->getNextNode(); // insert BEFORE next instruction (equivalent to "after I") } - IRBuilder<> B(InsertPt); + IRBuilder<> InstrIR(InsertPt); - // signature = signature + randomConstant + // 9: signature ← signature + random number uint64_t K = dist32(rng); partial_sum += K; - Value *Sig = B.CreateLoad(IntType, RuntimeSigGV); - Value *NewSig = B.CreateAdd(Sig, ConstantInt::get(IntType, K), "sig_add"); - B.CreateStore(NewSig, RuntimeSigGV); - sumIntraInstruction[&BB] = partial_sum; + Value *Sig = InstrIR.CreateLoad(IntType, RuntimeSigGV); + Value *NewSig = InstrIR.CreateAdd(Sig, ConstantInt::get(IntType, K), "sig_add"); + InstrIR.CreateStore(NewSig, RuntimeSigGV); } + // Track total sum + sumIntraInstruction[&BB] = partial_sum; } } // --------- CHECK BLOCKS AT JUMP END --------- -// FIXME: Fix warnings + +/* + * checkJumpSignature + * 10:for all BB in CFG insert at beginning + * 11: signature ← signature − subRanPrevVal + * 12: if signature != compileTimeSig error() + * 13:for all BB in CFG do + */ void RACFED::checkJumpSignature(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType, BasicBlock &ErrBB) { if ( BB.isEntryBlock() ) return; - // in this case BB is not the first Basic Block of the function, so it has - // to update RuntimeSig and check it - Instruction *FirstNonPHI = BB.getFirstNonPHI(); - if ( (FirstNonPHI && isa(FirstNonPHI)) || + // FIXME: Fix warnings + + // In this case BB is not the first Basic Block of the function, + // so it has to update RuntimeSig and check it + auto FirstNonPHI = BB.getFirstNonPHIIt(); + if ( (FirstNonPHI != BB.end() && isa(FirstNonPHI)) || BB.getName().contains_insensitive("verification") ) { if ( BB.getFirstInsertionPt() == BB.end() ) return; // Skip empty/invalid blocks @@ -201,68 +232,66 @@ void RACFED::checkJumpSignature(BasicBlock &BB, IRBuilder<> BChecker(&*BB.getFirstInsertionPt()); BChecker.CreateStore(llvm::ConstantInt::get(IntType, randomNumberBB), RuntimeSigGV, true); } else if ( !BB.getName().contains_insensitive("errbb") ) { - int randomNumberBB = compileTimeSig.find(&BB)->second; - int subRanPrevVal = subRanPrevVals.find(&BB)->second; - BasicBlock *NewBB = BasicBlock::Create( - BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB); - IRBuilder<> BChecker(NewBB); + // Get compile signatures + int compileTimeSigCurrBB = compileTimeSig.find(&BB)->second; + int subRanPrevValCurrBB = subRanPrevVals.find(&BB)->second; + // Create verification basic block + BasicBlock *VerificationBB = BasicBlock::Create( + BB.getContext(), "RACFED_Verification_BB", BB.getParent(), &BB + ); + IRBuilder<> BChecker(VerificationBB); - // add instructions for the first runtime signature update + // Add instructions for the first runtime signature update Value *InstrRuntimeSig = BChecker.CreateLoad(IntType, RuntimeSigGV, true); + // 11: signature ← signature − subRanPrevVal Value *RuntimeSignatureVal = BChecker.CreateSub( - InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevVal)); + InstrRuntimeSig, llvm::ConstantInt::get(IntType, subRanPrevValCurrBB)); BChecker.CreateStore(RuntimeSignatureVal, RuntimeSigGV, true); // update phi placing them in the new block while (isa(&BB.front())) { Instruction *PhiInst = &BB.front(); PhiInst->removeFromParent(); - PhiInst->insertBefore(&NewBB->front()); + PhiInst->insertBefore(&VerificationBB->front()); } - // replace the uses of BB with NewBB - BB.replaceAllUsesWith(NewBB); + // replace the uses of BB with VerificationBB + BB.replaceAllUsesWith(VerificationBB); // Fix PHI nodes in successors - // replaceAllUsesWith updates PHI nodes in successors to point to NewBB, - // but the actual control flow is NewBB -> BB -> Succ, so Succ still sees BB + // replaceAllUsesWith updates PHI nodes in successors to point to VerificationBB, + // but the actual control flow is VerificationBB -> BB -> Succ, so Succ still sees BB // as predecessor. for (BasicBlock *Succ : successors(&BB)) { for (PHINode &Phi : Succ->phis()) { for (unsigned i = 0; i < Phi.getNumIncomingValues(); ++i) { - if ( Phi.getIncomingBlock(i) == NewBB ) { + if ( Phi.getIncomingBlock(i) == VerificationBB ) { Phi.setIncomingBlock(i, &BB); } } } } + // 12: if signature != compileTimeSig error() // add instructions for checking the runtime signature - Value *CmpVal = - BChecker.CreateCmp(llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, - llvm::ConstantInt::get(IntType, randomNumberBB)); + Value *CmpVal = BChecker.CreateCmp( + llvm::CmpInst::ICMP_EQ, RuntimeSignatureVal, + llvm::ConstantInt::get(IntType, compileTimeSigCurrBB) + ); BChecker.CreateCondBr(CmpVal, &BB, &ErrBB); // Map NewBB to the same signature requirements as BB so predecessors can // target it correctly - compileTimeSig[NewBB] = randomNumberBB; - subRanPrevVals[NewBB] = subRanPrevVal; + compileTimeSig[VerificationBB] = compileTimeSigCurrBB; + subRanPrevVals[VerificationBB] = subRanPrevValCurrBB; } } // --- UPDATE BRANCH SIGNATURE BEFORE JUMP --- -Constant* expectedSignature( - BasicBlock *Succ, Type *IntType, - const std::unordered_map &compileTimeSig, - const std::unordered_map &subRanPrevVals -) { - const int expected = compileTimeSig.at(Succ); - const int expectedSub = subRanPrevVals.at(Succ); - return ConstantInt::get(IntType, expected+expectedSub); -} +// TODO: Add documentation in ASPIS.h Value *RACFED::getCondition(Instruction &I) { if ( isa(I) && cast(I).isConditional() ) { if ( !cast(I).isConditional() ) { @@ -280,6 +309,10 @@ Value *RACFED::getCondition(Instruction &I) { } } +#if MARTI_DEBUG +/** + * Adds a call to printf to check the signature + */ static void printSig(Module &Md, IRBuilder<> &B, Value *SigVal, const char *Msg) { LLVMContext &Ctx = Md.getContext(); @@ -301,15 +334,16 @@ static void printSig(Module &Md, IRBuilder<> &B, Value *SigVal, const char *Msg) B.CreateCall(Printf, {FmtStr, SigVal}); } +#endif /* -* updateBeforeJump -* 23: for all Successor of BB do -* 24: adjustValue ← (compileTimeSigBB + \Sum{instrMonUpdates}) - -* 25: (compileTimeSigsuccs + subRanPrevValsuccs) -* 26: Insert signature update at BB end -* 27: signature ← signature + adjustValue -*/ + * updateBeforeJump + * 23: for all Successor of BB do + * 24: adjustValue ← (compileTimeSigBB + SumIntraInstructions) - + * 25: (compileTimeSigSuccs + subRanPrevValSuccs) + * 26: Insert signature update at BB end + * 27: signature ← signature + adjustValue + */ void RACFED::updateBeforeJump(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type *IntType) { Instruction *Term = BB.getTerminator(); @@ -376,27 +410,28 @@ void RACFED::updateBeforeJump(Module &Md, BasicBlock &BB, GlobalVariable *Runti } } +// --- CHECK ON RETURN --- - -// --- CHECK RETURN UPDATE VALUE --- -// checkRetVal: -// -// 14: if Last Instr. is return instr. and NrIntrBB > 1 then -// 15: Calculate needed variables -// 16: returnVal ← random number -// 17: adjustValue ← (compileTimeSigBB + Sum) - -// 18: returnVal -// 19: Insert signature update before return instr. -// 20: signature ← signature + adjustValue -// 21: if signature != returnVal error() -Instruction *RACFED::checkReturnValue(BasicBlock &BB, +/* + * checkOnReturn + * 14: if Last Instr. is return instr. and NrIntrBB > 1 then + * 15: Calculate needed variables + * 16: return Val ← random number + * 17: adjust Value ← (compileTimeSigBB + SumIntraInstructions) - + * 18: return Val + * 19: Insert signature update before return instr. + * 20: signature ← signature + adjustValue + * 21: if signature != returnVal error() + */ +Instruction *RACFED::checkOnReturn(BasicBlock &BB, GlobalVariable *RuntimeSigGV, Type* IntType, BasicBlock &ErrBB, Value *BckupRunSig) { // Uniform distribution for 64 bits numbers. std::uniform_int_distribution dist64(1, 0xffffffff); - // Constant seed for 64 bits + // Constant seed for 64 bits. + // Fixed for reproducibility. std::mt19937 rng64(0x5EED00); Instruction *Term = BB.getTerminator(); @@ -405,7 +440,8 @@ Instruction *RACFED::checkReturnValue(BasicBlock &BB, std::vector org_instr; originalInstruction(BB, org_instr); - if ( org_instr.size() > 2 ) { + // 14: if Last Instr. is return instr. and NrIntrBB > 1 then + if ( org_instr.size() > 1 ) { // Splits the BB that contains the return instruction into // two basic blocks: @@ -430,15 +466,15 @@ Instruction *RACFED::checkReturnValue(BasicBlock &BB, // Inserting instructions into ControlBB IRBuilder<> ControlIR(ControlBB); - // 15: Calculate needed variables // 16: returnVal ← random number + uint64_t random_ret_value = dist64(rng64); // 17: adjustValue ← (compileTimeSigBB + Sum) - // 18: returnVal - uint64_t random_ret_value = dist64(rng64); + // // This is a 64 bit SIGNED integer (cause a subtraction happens // and it cannot previously be established that it will be positive) - long int adj_value = compileTimeSig[&BB] + sumIntraInstruction[&BB] - - random_ret_value; + long int adj_value = static_cast(compileTimeSig[&BB]) + + sumIntraInstruction[&BB] - random_ret_value; // 19: Insert signature update before return instr. // 20: signature ← signature + adjustValue // wrong must be subtracted @@ -457,6 +493,7 @@ Instruction *RACFED::checkReturnValue(BasicBlock &BB, PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { auto *I64 = llvm::Type::getInt64Ty(Md.getContext()); + // Runtime signature defined as a global variable GlobalVariable *RuntimeSig = new GlobalVariable( Md, I64, /*isConstant=*/false, @@ -465,8 +502,6 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { "signature" ); - Instruction *RetInst = nullptr; - createFtFuncs(Md); getFuncAnnotations(Md, FuncAnnotations); LinkageMap linkageMap = mapFunctionLinkageNames((Md)); @@ -501,40 +536,46 @@ PreservedAnalyses RACFED::run(Module &Md, ModuleAnalysisManager &AM) { CompiledFuncs.insert(&Fn); #endif - // Create error basic block assert(!getLinkageName(linkageMap,"SigMismatch_Handler").empty() && "Function SigMismatch_Handler is missing!"); + // Create error basic block BasicBlock *ErrBB = BasicBlock::Create(Fn.getContext(), "ErrBB", &Fn); + // Define instruction call to SigMismatch_Handler auto CalleeF = ErrBB->getModule()->getOrInsertFunction( getLinkageName(linkageMap,"SigMismatch_Handler"), FunctionType::getVoidTy(Md.getContext()) ); IRBuilder<> ErrIR(ErrBB); + // Add call instruction to function SigMismatch_Handler ErrIR.CreateCall(CalleeF)->setDebugLoc(debugLoc); ErrIR.CreateUnreachable(); + + // Initialize runtime signature backup + Value *runtime_sign_bkup = nullptr; + // Initialize return instruction: used to reinstate the runtime signature of the callee + Instruction *ret_inst = nullptr; - Value * runtime_sign_bkup = nullptr; for (BasicBlock &BB : Fn) { // Backup of compile time sign when entering a function if ( BB.isEntryBlock() ) { IRBuilder<> InstrIR(&*BB.getFirstInsertionPt()); - if ( Fn.getName() != "main" ) { - runtime_sign_bkup = - InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); - } + runtime_sign_bkup = + InstrIR.CreateLoad(I64, RuntimeSig, true, "backup_run_sig"); + // Set runtime signature to compile time signature + // of the function's entry block. InstrIR.CreateStore(llvm::ConstantInt::get(I64, compileTimeSig[&BB]), RuntimeSig); } checkJumpSignature(BB, RuntimeSig, I64, *ErrBB); - RetInst = checkReturnValue(BB, RuntimeSig, I64, *ErrBB, runtime_sign_bkup); + ret_inst = checkOnReturn(BB, RuntimeSig, I64, *ErrBB, runtime_sign_bkup); updateBeforeJump(Md, BB, RuntimeSig, I64); // Restore signature on return - if ( RetInst != nullptr && Fn.getName() != "main") { - IRBuilder<> RetInstIR(RetInst); + if ( ret_inst != nullptr ) { + IRBuilder<> RetInstIR(ret_inst); RetInstIR.CreateStore(runtime_sign_bkup, RuntimeSig); } } From 3e48e05474af81a49de47c159b8f92f2e4020acb Mon Sep 17 00:00:00 2001 From: Gab-San Date: Thu, 15 Jan 2026 15:28:07 +0100 Subject: [PATCH 28/29] Added multi_if_then_else.c test In order to close issue #10 test multi_if_then_else has been added Support for multiple test configuration files has been added to flag --tests-file --- testing/README.md | 2 +- testing/config/racfed+eddi.toml | 6 ++++++ testing/config/racfed.toml | 6 ++++++ testing/conftest.py | 8 +++++--- testing/test.py | 18 ++++++++++-------- .../c/multi_instruction/multi_if_then_else.c | 16 ++++++++++++++++ 6 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 testing/tests/c/multi_instruction/multi_if_then_else.c diff --git a/testing/README.md b/testing/README.md index 9c8154b..7858536 100644 --- a/testing/README.md +++ b/testing/README.md @@ -36,7 +36,7 @@ It is possible to write different configuration test files. Additional flags are: `--suffix ` : Operates the same way as aspis, searching for binaries versions denoted by ``. -`--tests-file ` : Use the configuration file specified. +`--tests-file ...` : Use the configuration files specified. ## Docker Testing diff --git a/testing/config/racfed+eddi.toml b/testing/config/racfed+eddi.toml index b7da1a9..c551270 100644 --- a/testing/config/racfed+eddi.toml +++ b/testing/config/racfed+eddi.toml @@ -100,3 +100,9 @@ source_file = "c/misc_math/xor_cypher.c" expected_output = "SUCCESS" aspis_options = "--eddi --racfed" +[[tests]] +test_name = "racfed_ml_multi_if_else" +source_file = "c/multi_instruction/multi_if_then_else.c" +expected_output = "r > 200" +aspis_options = "--eddi --racfed" + diff --git a/testing/config/racfed.toml b/testing/config/racfed.toml index f48a5c8..edc2ad2 100644 --- a/testing/config/racfed.toml +++ b/testing/config/racfed.toml @@ -100,3 +100,9 @@ source_file = "c/misc_math/xor_cypher.c" expected_output = "SUCCESS" aspis_options = "--no-dup --racfed" +[[tests]] +test_name = "racfed_ml_multi_if_else" +source_file = "c/multi_instruction/multi_if_then_else.c" +expected_output = "r > 200" +aspis_options = "--no-dup --racfed" + diff --git a/testing/conftest.py b/testing/conftest.py index f8c36d7..537be87 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -11,6 +11,7 @@ def pytest_addoption(parser): parser.addoption( "--tests-file", action="store", + nargs="*", default="config/tests.toml", help="Path to the configuration file", ) @@ -26,9 +27,10 @@ def use_container(pytestconfig): # Optional: Add a check to ensure the file exists before any tests start def pytest_configure(config): - tests_file = config.getoption("--tests-file") - if not os.path.exists(tests_file): - pytest.exit(f"Config file not found: {tests_file}") + tests_file_paths = config.getoption("--tests-file") + for file_path in tests_file_paths: + if not os.path.exists(file_path): + pytest.exit(f"Config file not found: {file_path}") @pytest.fixture(scope="session") def aspis_addopt(pytestconfig): diff --git a/testing/test.py b/testing/test.py index 65dea00..6c1f571 100644 --- a/testing/test.py +++ b/testing/test.py @@ -46,16 +46,18 @@ def execute_binary(local_build_dir, test_name): def pytest_generate_tests(metafunc): """Custom hook to parametrize tests based on the CLI --tests-file flag.""" if "test_data" in metafunc.fixturenames: - # Get the file path from the command line option - file_path = metafunc.config.getoption("--tests-file") - with open(file_path, "rb") as f: - config_data = tomllib.load(f) + tests_file_paths = metafunc.config.getoption("--tests-file") + test_list = [] + for file_path in tests_file_paths: + with open(file_path, "rb") as f: + config_data = tomllib.load(f) - # Access the 'tests' list inside the TOML dictionary - test_list = config_data.get("tests", []) + # Access the 'tests' list inside the TOML dictionary + test_list.extend(config_data.get("tests", [])) + + # Use 'test_name' for better output in the terminal + ids = [t.get("test_name", str(i)) for i, t in enumerate(test_list)] - # Use 'test_name' for better output in the terminal - ids = [t.get("test_name", str(i)) for i, t in enumerate(test_list)] metafunc.parametrize("test_data", test_list, ids=ids) # Tests def test_aspis(test_data, use_container, aspis_addopt): diff --git a/testing/tests/c/multi_instruction/multi_if_then_else.c b/testing/tests/c/multi_instruction/multi_if_then_else.c new file mode 100644 index 0000000..038f068 --- /dev/null +++ b/testing/tests/c/multi_instruction/multi_if_then_else.c @@ -0,0 +1,16 @@ +#include +#include +#include + +#define MAX 1024 + +int main() { + srand(time(NULL)); + int r = rand() % MAX + 200; + if ( r > 200 ) printf("r > 200\n"); + else if ( r > 100 ) printf("100 < r < 200\n"); + else if ( r > 50 ) printf("50 < r < 100\n"); + else printf("0 < r < 50 \n"); + + return 0; +} From 55ef536b964efc51e9d0bb1514e0cfd5e39c7caa Mon Sep 17 00:00:00 2001 From: Gab-San Date: Thu, 15 Jan 2026 16:31:41 +0100 Subject: [PATCH 29/29] Fixed warnings in checkJumpSignature --- passes/RACFED.cpp | 6 +----- testing/config/racfed+eddi.toml | 2 +- testing/config/racfed.toml | 2 +- testing/tests/c/multi_instruction/phi.c | 7 +++++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/passes/RACFED.cpp b/passes/RACFED.cpp index abd852f..3eca8af 100644 --- a/passes/RACFED.cpp +++ b/passes/RACFED.cpp @@ -59,8 +59,6 @@ using namespace llvm; // TODO: Check TODOs in updateBeforeJump -// TODO: Fix warnings in checkJump - /// Uniform distribution for 32 bits numbers. /// /// In each function using this distribution a different seed will be used. @@ -218,8 +216,6 @@ void RACFED::checkJumpSignature(BasicBlock &BB, BasicBlock &ErrBB) { if ( BB.isEntryBlock() ) return; - // FIXME: Fix warnings - // In this case BB is not the first Basic Block of the function, // so it has to update RuntimeSig and check it auto FirstNonPHI = BB.getFirstNonPHIIt(); @@ -254,7 +250,7 @@ void RACFED::checkJumpSignature(BasicBlock &BB, while (isa(&BB.front())) { Instruction *PhiInst = &BB.front(); PhiInst->removeFromParent(); - PhiInst->insertBefore(&VerificationBB->front()); + PhiInst->insertInto(VerificationBB, VerificationBB->getFirstInsertionPt()); } // replace the uses of BB with VerificationBB diff --git a/testing/config/racfed+eddi.toml b/testing/config/racfed+eddi.toml index c551270..ce3d34e 100644 --- a/testing/config/racfed+eddi.toml +++ b/testing/config/racfed+eddi.toml @@ -25,7 +25,7 @@ aspis_options = "--eddi --racfed" [[tests]] test_name = "racfed_eddi_ml_phi_instruction" source_file = "c/multi_instruction/phi.c" -expected_output = "1" +expected_output = "SUCCESS" aspis_options = "--eddi --racfed" [[tests]] diff --git a/testing/config/racfed.toml b/testing/config/racfed.toml index edc2ad2..5129d1f 100644 --- a/testing/config/racfed.toml +++ b/testing/config/racfed.toml @@ -25,7 +25,7 @@ aspis_options = "--no-dup --racfed" [[tests]] test_name = "racfed_ml_phi_instruction" source_file = "c/multi_instruction/phi.c" -expected_output = "1" +expected_output = "SUCCESS" aspis_options = "--no-dup --racfed" [[tests]] diff --git a/testing/tests/c/multi_instruction/phi.c b/testing/tests/c/multi_instruction/phi.c index 2729b90..5839bed 100644 --- a/testing/tests/c/multi_instruction/phi.c +++ b/testing/tests/c/multi_instruction/phi.c @@ -2,11 +2,14 @@ // Created by martina on 07/01/26. // #include +#include +#include int main() { - int y = 1; + srand(time(NULL)); + int y = rand() % 2; int r = 0; int a = y || r; - printf("%d\n", a); + printf("SUCCESS\n"); return 0; }