From a5a760b8c5d54d5d941f4dc3fcfb0ec245d977ca Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 21 Aug 2026 10:53:08 -0400 Subject: [PATCH 01/16] resolve-toolchain.cmake: Adding '-fno-omit-frame-pointer' flag to RESOLVE_DEBUG_FLAGS. --- toolchains/resolve-toolchain.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchains/resolve-toolchain.cmake b/toolchains/resolve-toolchain.cmake index d458aa6b0..98dac2a83 100644 --- a/toolchains/resolve-toolchain.cmake +++ b/toolchains/resolve-toolchain.cmake @@ -17,7 +17,7 @@ set(RESOLVE_INTRINSICS_FLAGS # Keep basic debug info to make it eaiser to lookup function names and files for inlined functions set(RESOLVE_DEBUG_INFO_FLAGS - "-g1" + "-g1 -fno-omit-frame-pointer" ) set(CMAKE_C_FLAGS_INIT "${CMAKE_C_FLAGS} ${RESOLVE_PLUGINS} ${RESOLVE_INTRINSICS_FLAGS} ${RESOLVE_DEBUG_INFO_FLAGS}" CACHE STRING "c flags") From 31b5022a2c03507b8d18c66853f0ce24ed2eac1b Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 3 Aug 2026 11:38:50 -0400 Subject: [PATCH 02/16] ArithmeticSanitizer.cpp: WIP adding continue strategy to divide by zero sanitizer. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 106 +++++++++++------- 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 5b0b8430e..5b7e67815 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -126,13 +126,13 @@ void sanitizeDivideByZero(Function *F, } // Loop over each instruction in the list - for (auto *binaryOp : worklist) { + for (auto *binaryInst : worklist) { Value *dividend; Value *divisor; Value *isZero; - BasicBlock *checkMapEntryBB = binaryOp->getParent(); - BasicBlock *joinResultBB = checkMapEntryBB->splitBasicBlock(binaryOp); + BasicBlock *checkMapEntryBB = binaryInst->getParent(); + BasicBlock *joinResultBB = checkMapEntryBB->splitBasicBlock(binaryInst); BasicBlock *checkZeroBB = BasicBlock::Create(Ctx, "check.zero", F); BasicBlock *preserveDivBB = BasicBlock::Create(Ctx, "safe.div", F, joinResultBB); @@ -147,10 +147,10 @@ void sanitizeDivideByZero(Function *F, builder.SetInsertPoint(checkZeroBB); // Extract dividend and divisor - dividend = binaryOp->getOperand(0); - divisor = binaryOp->getOperand(1); + dividend = binaryInst->getOperand(0); + divisor = binaryInst->getOperand(1); - switch (binaryOp->getOpcode()) { + switch (binaryInst->getOpcode()) { case Instruction::SDiv: case Instruction::UDiv: case Instruction::SRem: @@ -168,6 +168,26 @@ void sanitizeDivideByZero(Function *F, builder.CreateCondBr(isZero, remedDivBB, preserveDivBB); builder.SetInsertPoint(remedDivBB); + builder.CreateCall(getOrCreateResolveReportSanitizerTriggered(M)); + + // TODO: Implement continue strategy for div-zero + Constant *recoveryValue = nullptr; + if (strategy == Vulnerability::RemediationStrategies::CONTINUE) { + + Type *type = binary_inst->getType(); + unsigned bitWidth = type->getIntegerBitWidth(); + + if (binaryInst->getOpcode() == Instruction::SDiv) { + recoveryValue = + ConstantInt::get(type, APInt::getSignedMaxValue(bitWidth)); + + } else { + recoveryValue = ConstantInt::get(type, APInt::getMaxValue(bitWidth)); + } + + builder.CreateRet(recoveryValue); + } + if (Function *fn = getOrCreateRemediationBehavior(M, strategy)) { builder.CreateCall(fn); } @@ -175,7 +195,7 @@ void sanitizeDivideByZero(Function *F, Value *safeIntDivisor; Value *safeFpDivisor; - switch (binaryOp->getOpcode()) { + switch (binaryInst->getOpcode()) { case Instruction::UDiv: safeIntDivisor = ConstantInt::get(divisor->getType(), 1); safeDiv = builder.CreateUDiv(dividend, safeIntDivisor); @@ -187,7 +207,7 @@ void sanitizeDivideByZero(Function *F, break; case Instruction::FDiv: - safeFpDivisor = ConstantFP::get(binaryOp->getType(), 1.0); + safeFpDivisor = ConstantFP::get(binaryInst->getType(), 1.0); safeDiv = builder.CreateFDiv(dividend, safeFpDivisor); break; @@ -211,7 +231,7 @@ void sanitizeDivideByZero(Function *F, builder.SetInsertPoint(preserveDivBB); Value *normalResult = nullptr; - switch (binaryOp->getOpcode()) { + switch (binaryInst->getOpcode()) { case Instruction::SDiv: normalResult = builder.CreateSDiv(dividend, divisor); builder.CreateBr(joinResultBB); @@ -244,12 +264,12 @@ void sanitizeDivideByZero(Function *F, } builder.SetInsertPoint(&*joinResultBB->begin()); - PHINode *phi = builder.CreatePHI(binaryOp->getType(), 2); + PHINode *phi = builder.CreatePHI(binaryInst->getType(), 2); phi->addIncoming(safeDiv, remedDivBB); phi->addIncoming(normalResult, preserveDivBB); - binaryOp->replaceAllUsesWith(phi); - binaryOp->eraseFromParent(); + binaryInst->replaceAllUsesWith(phi); + binaryInst->eraseFromParent(); } } @@ -293,29 +313,29 @@ void sanitizeIntOverflow(Function *F, Value *op1; Value *op2; - for (auto *binaryOp : worklist) { - if (!binaryOp->hasNoSignedWrap() && !binaryOp->hasNoUnsignedWrap()) { + for (auto *binaryInst : worklist) { + if (!binaryInst->hasNoSignedWrap() && !binaryInst->hasNoUnsignedWrap()) { continue; } - op1 = binaryOp->getOperand(0); - op2 = binaryOp->getOperand(1); + op1 = binaryInst->getOperand(0); + op2 = binaryInst->getOperand(1); - builder.SetInsertPoint(binaryOp); + builder.SetInsertPoint(binaryInst); auto insertSafeOp = [&builder, - M](Instruction *binaryOp, Value *op1, + M](Instruction *binaryInst, Value *op1, Value *op2) -> std::pair { Intrinsic::ID intrinsic_id; - Type *BinOpType = binaryOp->getType(); + Type *BinOpType = binaryInst->getType(); bool isUnsigned = false; // Heuristic: If instruction has NUW but not NSW then, treat as unsigned - if (binaryOp->hasNoUnsignedWrap() && !binaryOp->hasNoSignedWrap()) { + if (binaryInst->hasNoUnsignedWrap() && !binaryInst->hasNoSignedWrap()) { isUnsigned = true; } - switch (binaryOp->getOpcode()) { + switch (binaryInst->getOpcode()) { case Instruction::Add: intrinsic_id = isUnsigned ? Intrinsic::uadd_with_overflow : Intrinsic::sadd_with_overflow; @@ -343,17 +363,17 @@ void sanitizeIntOverflow(Function *F, return {result, isOverflow}; }; - auto insertSatOp = [&builder, M](Instruction *binaryOp, Value *op1, + auto insertSatOp = [&builder, M](Instruction *binaryInst, Value *op1, Value *op2) -> Instruction * { Intrinsic::ID intrinsic_id; - Type *BinOpType = binaryOp->getType(); + Type *BinOpType = binaryInst->getType(); bool isUnsigned = false; - if (binaryOp->hasNoUnsignedWrap() && !binaryOp->hasNoSignedWrap()) { + if (binaryInst->hasNoUnsignedWrap() && !binaryInst->hasNoSignedWrap()) { isUnsigned = true; } - switch (binaryOp->getOpcode()) { + switch (binaryInst->getOpcode()) { case Instruction::Add: intrinsic_id = isUnsigned ? Intrinsic::uadd_sat : Intrinsic::sadd_sat; break; @@ -378,7 +398,7 @@ void sanitizeIntOverflow(Function *F, // Add fracBits parameter for saturated multiplication operations // LLVM LangRef: // https://llvm.org/docs/LangRef.html#fixed-point-arithmetic-intrinsics - if (binaryOp->getOpcode() == Instruction::Mul) { + if (binaryInst->getOpcode() == Instruction::Mul) { Value *fracBits = ConstantInt::get(BinOpType, 0); return builder.CreateCall(satOp, {op1, op2, fracBits}); @@ -387,11 +407,11 @@ void sanitizeIntOverflow(Function *F, } }; - auto [safeResult, isOverflow] = insertSafeOp(binaryOp, op1, op2); - auto satResult = insertSatOp(binaryOp, op1, op2); + auto [safeResult, isOverflow] = insertSafeOp(binaryInst, op1, op2); + auto satResult = insertSatOp(binaryInst, op1, op2); - BasicBlock *checkMapEntryBB = binaryOp->getParent(); - BasicBlock *joinResultBB = checkMapEntryBB->splitBasicBlock(binaryOp); + BasicBlock *checkMapEntryBB = binaryInst->getParent(); + BasicBlock *joinResultBB = checkMapEntryBB->splitBasicBlock(binaryInst); BasicBlock *checkOverflowBB = BasicBlock::Create(Ctx, "check.overflow", F); BasicBlock *remedOverflowBB = BasicBlock::Create(Ctx, "sanitize.overflow", F, joinResultBB); @@ -412,12 +432,12 @@ void sanitizeIntOverflow(Function *F, builder.SetInsertPoint(&*joinResultBB->begin()); if (strategy == Vulnerability::RemediationStrategies::SAT) { - binaryOp->replaceAllUsesWith(satResult); + binaryInst->replaceAllUsesWith(satResult); } else { - binaryOp->replaceAllUsesWith(safeResult); + binaryInst->replaceAllUsesWith(safeResult); } - binaryOp->eraseFromParent(); + binaryInst->eraseFromParent(); } } @@ -457,13 +477,13 @@ void sanitizeBitShift(Function *F, } } - for (auto *binaryOp : worklist) { + for (auto *binaryInst : worklist) { Value *isNegative; Value *isGreaterThanBitwidth; Value *CheckShiftAmtCond; - BasicBlock *checkMapEntryBB = binaryOp->getParent(); - BasicBlock *joinResultBB = checkMapEntryBB->splitBasicBlock(binaryOp); + BasicBlock *checkMapEntryBB = binaryInst->getParent(); + BasicBlock *joinResultBB = checkMapEntryBB->splitBasicBlock(binaryInst); BasicBlock *checkShiftBB = BasicBlock::Create(Ctx, "check.zero", F); BasicBlock *preserveShiftBB = BasicBlock::Create(Ctx, "safe.shift", F, joinResultBB); @@ -476,8 +496,8 @@ void sanitizeBitShift(Function *F, preserveShiftBB, checkShiftBB); builder.SetInsertPoint(checkShiftBB); - Value *shifted_value = binaryOp->getOperand(0); - Value *bit_pos = binaryOp->getOperand(1); + Value *shifted_value = binaryInst->getOperand(0); + Value *bit_pos = binaryInst->getOperand(1); unsigned BitWidth = shifted_value->getType()->getIntegerBitWidth(); isNegative = @@ -494,7 +514,7 @@ void sanitizeBitShift(Function *F, Value *safeShift = nullptr; Value *safeBitPos; - switch (binaryOp->getOpcode()) { + switch (binaryInst->getOpcode()) { case Instruction::Shl: safeBitPos = ConstantInt::get(bit_pos->getType(), 0); safeShift = builder.CreateShl(shifted_value, safeBitPos); @@ -515,7 +535,7 @@ void sanitizeBitShift(Function *F, builder.SetInsertPoint(preserveShiftBB); Value *normalResult = nullptr; - switch (binaryOp->getOpcode()) { + switch (binaryInst->getOpcode()) { case Instruction::Shl: normalResult = builder.CreateShl(shifted_value, bit_pos); builder.CreateBr(joinResultBB); @@ -533,11 +553,11 @@ void sanitizeBitShift(Function *F, } builder.SetInsertPoint(&*joinResultBB->begin()); - PHINode *phi = builder.CreatePHI(binaryOp->getType(), 2); + PHINode *phi = builder.CreatePHI(binaryInst->getType(), 2); phi->addIncoming(safeShift, remedShiftBB); phi->addIncoming(normalResult, preserveShiftBB); - binaryOp->replaceAllUsesWith(phi); - binaryOp->eraseFromParent(); + binaryInst->replaceAllUsesWith(phi); + binaryInst->eraseFromParent(); } } From 600376c18091ce72226d70721f1a312c331d0b7d Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 3 Aug 2026 11:44:21 -0400 Subject: [PATCH 03/16] ArithmeticSanitizer.cpp: Fixing compilation issue. changed variable name to binaryInst. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 5b7e67815..7cb0546ea 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -174,7 +174,7 @@ void sanitizeDivideByZero(Function *F, Constant *recoveryValue = nullptr; if (strategy == Vulnerability::RemediationStrategies::CONTINUE) { - Type *type = binary_inst->getType(); + Type *type = binaryInst->getType(); unsigned bitWidth = type->getIntegerBitWidth(); if (binaryInst->getOpcode() == Instruction::SDiv) { From 48d9e3ed26569b35234663bd54ab481978677cd4 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 3 Aug 2026 11:45:51 -0400 Subject: [PATCH 04/16] ArithmeticSanitizer.cpp: Include llvm::APInt header. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 7cb0546ea..0f7b5da59 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -3,6 +3,7 @@ * LGPL-3; See LICENSE.txt in the repo root for details. */ +#include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Twine.h" #include "llvm/AsmParser/Parser.h" From 32d1aaecd6ac211678234f3a5e768b24ea24fde1 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 7 Aug 2026 09:35:54 -0400 Subject: [PATCH 05/16] ArithmeticSanitizer.cpp: Adding support for the CONTINUE strategy for the divide by zero sanitizer. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 120 ++++++++---------- 1 file changed, 56 insertions(+), 64 deletions(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 0f7b5da59..88f82eed0 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -19,6 +19,7 @@ #include "Vulnerability.hpp" #include +#include #include #include #include @@ -26,6 +27,33 @@ using namespace llvm; +Constant *getContinueValue(Instruction *I) { + Type *Ty = I->getType(); + + if (Ty->isIntegerTy()) { + unsigned bitwidth = Ty->getIntegerBitWidth(); + + switch (I->getOpcode()) { + case Instruction::SDiv: + case Instruction::SRem: + return ConstantInt::get(Ty, APInt::getSignedMaxValue(bitwidth)); + + case Instruction::UDiv: + case Instruction::URem: + return ConstantInt::get(Ty, APInt::getMaxValue(bitwidth)); + + default: + llvm_unreachable("[CVEAssert] Unsupported integer operation"); + } + } + + if (Ty->isFloatTy()) + return ConstantFP::get(Ty, APFloat(std::numeric_limits::max())); + + if (Ty->isDoubleTy()) + return ConstantFP::get(Ty, APFloat(std::numeric_limits::max())); +} + static void widenIntOverflow(Function *F) { // Basic algorithm: // Find the pattern of overflowing op -> sext @@ -136,7 +164,7 @@ void sanitizeDivideByZero(Function *F, BasicBlock *joinResultBB = checkMapEntryBB->splitBasicBlock(binaryInst); BasicBlock *checkZeroBB = BasicBlock::Create(Ctx, "check.zero", F); BasicBlock *preserveDivBB = - BasicBlock::Create(Ctx, "safe.div", F, joinResultBB); + BasicBlock::Create(Ctx, "perform.div", F, joinResultBB); BasicBlock *remedDivBB = BasicBlock::Create(Ctx, "sanitize.div", F, joinResultBB); @@ -172,102 +200,66 @@ void sanitizeDivideByZero(Function *F, builder.CreateCall(getOrCreateResolveReportSanitizerTriggered(M)); // TODO: Implement continue strategy for div-zero - Constant *recoveryValue = nullptr; - if (strategy == Vulnerability::RemediationStrategies::CONTINUE) { - - Type *type = binaryInst->getType(); - unsigned bitWidth = type->getIntegerBitWidth(); - - if (binaryInst->getOpcode() == Instruction::SDiv) { - recoveryValue = - ConstantInt::get(type, APInt::getSignedMaxValue(bitWidth)); - - } else { - recoveryValue = ConstantInt::get(type, APInt::getMaxValue(bitWidth)); - } - - builder.CreateRet(recoveryValue); - } - - if (Function *fn = getOrCreateRemediationBehavior(M, strategy)) { - builder.CreateCall(fn); - } - Value *safeDiv = nullptr; - Value *safeIntDivisor; - Value *safeFpDivisor; - - switch (binaryInst->getOpcode()) { - case Instruction::UDiv: - safeIntDivisor = ConstantInt::get(divisor->getType(), 1); - safeDiv = builder.CreateUDiv(dividend, safeIntDivisor); - break; - - case Instruction::SDiv: - safeIntDivisor = ConstantInt::get(divisor->getType(), 1); - safeDiv = builder.CreateSDiv(dividend, safeIntDivisor); - break; - - case Instruction::FDiv: - safeFpDivisor = ConstantFP::get(binaryInst->getType(), 1.0); - safeDiv = builder.CreateFDiv(dividend, safeFpDivisor); - break; + Value *remedValue = nullptr; - case Instruction::URem: - safeIntDivisor = ConstantInt::get(divisor->getType(), 1); - safeDiv = builder.CreateURem(dividend, safeIntDivisor); + switch (strategy) { + case Vulnerability::RemediationStrategies::CONTINUE: + remedValue = getContinueValue(binaryInst); + builder.CreateBr(joinResultBB); break; - case Instruction::SRem: - safeIntDivisor = ConstantInt::get(divisor->getType(), 1); - safeDiv = builder.CreateSRem(dividend, safeIntDivisor); - break; + case Vulnerability::RemediationStrategies::EXIT: + case Vulnerability::RemediationStrategies::RECOVER: + builder.CreateCall(getOrCreateRemediationBehavior(M, strategy)); - case Instruction::FRem: - safeFpDivisor = ConstantFP::get(divisor->getType(), 1.0); - safeDiv = builder.CreateFRem(dividend, safeFpDivisor); + // EXIT/RECOVER transfer control elsewhere + builder.CreateUnreachable(); break; } - builder.CreateBr(joinResultBB); builder.SetInsertPoint(preserveDivBB); - Value *normalResult = nullptr; + // Perform the division operation with the given operands. + Value *divOp = nullptr; switch (binaryInst->getOpcode()) { case Instruction::SDiv: - normalResult = builder.CreateSDiv(dividend, divisor); + divOp = builder.CreateSDiv(dividend, divisor); builder.CreateBr(joinResultBB); break; - case Instruction::UDiv: - normalResult = builder.CreateUDiv(dividend, divisor); + case Instruction::SRem: + divOp = builder.CreateSRem(dividend, divisor); builder.CreateBr(joinResultBB); break; - case Instruction::FDiv: - normalResult = builder.CreateFDiv(dividend, divisor); + case Instruction::UDiv: + divOp = builder.CreateUDiv(dividend, divisor); builder.CreateBr(joinResultBB); break; - case Instruction::SRem: - normalResult = builder.CreateSRem(dividend, divisor); + case Instruction::URem: + divOp = builder.CreateURem(dividend, divisor); builder.CreateBr(joinResultBB); break; - case Instruction::URem: - normalResult = builder.CreateURem(dividend, divisor); + case Instruction::FDiv: + divOp = builder.CreateFDiv(dividend, divisor); builder.CreateBr(joinResultBB); break; case Instruction::FRem: - normalResult = builder.CreateFRem(dividend, divisor); + divOp = builder.CreateFRem(dividend, divisor); builder.CreateBr(joinResultBB); break; } builder.SetInsertPoint(&*joinResultBB->begin()); PHINode *phi = builder.CreatePHI(binaryInst->getType(), 2); - phi->addIncoming(safeDiv, remedDivBB); - phi->addIncoming(normalResult, preserveDivBB); + phi->addIncoming(divOp, preserveDivBB); + + if (strategy == Vulnerability::RemediationStrategies::CONTINUE) { + phi->addIncoming(remedValue, remedDivBB); + } binaryInst->replaceAllUsesWith(phi); binaryInst->eraseFromParent(); From b1fd8d866bec766446ed46b71bce0987cab9ef09 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 7 Aug 2026 10:12:49 -0400 Subject: [PATCH 06/16] ArithmeticSanitizer.cpp: Adding static qualifier on helper function and cleaning up some comments. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 88f82eed0..0d49050cd 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -27,7 +27,7 @@ using namespace llvm; -Constant *getContinueValue(Instruction *I) { +static Constant *getContinueValue(Instruction *I) { Type *Ty = I->getType(); if (Ty->isIntegerTy()) { @@ -199,9 +199,7 @@ void sanitizeDivideByZero(Function *F, builder.SetInsertPoint(remedDivBB); builder.CreateCall(getOrCreateResolveReportSanitizerTriggered(M)); - // TODO: Implement continue strategy for div-zero Value *remedValue = nullptr; - switch (strategy) { case Vulnerability::RemediationStrategies::CONTINUE: remedValue = getContinueValue(binaryInst); @@ -219,7 +217,6 @@ void sanitizeDivideByZero(Function *F, builder.SetInsertPoint(preserveDivBB); - // Perform the division operation with the given operands. Value *divOp = nullptr; switch (binaryInst->getOpcode()) { case Instruction::SDiv: From f05e03a9444c3dc46cc6fb6031d3b4c228bec723 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 7 Aug 2026 14:02:55 -0400 Subject: [PATCH 07/16] ArithmeticSanitizer.cpp: Removing 'CVEAssert' from llvm_unreachable. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 0d49050cd..d9588c623 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -43,7 +43,7 @@ static Constant *getContinueValue(Instruction *I) { return ConstantInt::get(Ty, APInt::getMaxValue(bitwidth)); default: - llvm_unreachable("[CVEAssert] Unsupported integer operation"); + llvm_unreachable("Unsupported integer operation"); } } From d14bd94befa3385d96b03990bda18cd80936b80a Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 18 Aug 2026 11:51:35 -0400 Subject: [PATCH 08/16] IRUtils.cpp: Adding LLVM 'noreturn' attribute to __cve_exit and __cve_recover because they do not return. This can help LLVM optimize CFGs. --- resolve-cveassert/src/IRUtils.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/resolve-cveassert/src/IRUtils.cpp b/resolve-cveassert/src/IRUtils.cpp index 5d9cb9146..ca29f9d96 100644 --- a/resolve-cveassert/src/IRUtils.cpp +++ b/resolve-cveassert/src/IRUtils.cpp @@ -498,8 +498,13 @@ getOrCreateRemediationBehavior(Module *M, return fn; } - BasicBlock *entryBB = BasicBlock::Create(Ctx, "entry", fn); - IRBuilder<> builder(entryBB); + AttrBuilder FnAttrs(Ctx); + FnAttrs.addAttribute(Attribute::NoReturn); + AttributeList attrs = + AttributeList::get(Ctx, AttributeList::FunctionIndex, FnAttrs); + + BasicBlock *BB = BasicBlock::Create(Ctx, "entry", fn); + IRBuilder<> builder(BB); switch (strategy) { case Vulnerability::RemediationStrategies::EXIT: { From 99cbe37ca8dc30b45214e15d9dd4e68b1c79493d Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 20 Aug 2026 17:13:02 -0400 Subject: [PATCH 09/16] IRUtils.cpp: Fixing variable BB. It should be entryBB. --- resolve-cveassert/src/IRUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resolve-cveassert/src/IRUtils.cpp b/resolve-cveassert/src/IRUtils.cpp index ca29f9d96..09ce63ae6 100644 --- a/resolve-cveassert/src/IRUtils.cpp +++ b/resolve-cveassert/src/IRUtils.cpp @@ -503,8 +503,8 @@ getOrCreateRemediationBehavior(Module *M, AttributeList attrs = AttributeList::get(Ctx, AttributeList::FunctionIndex, FnAttrs); - BasicBlock *BB = BasicBlock::Create(Ctx, "entry", fn); - IRBuilder<> builder(BB); + BasicBlock *entryBB = BasicBlock::Create(Ctx, "entry", fn); + IRBuilder<> builder(entryBB); switch (strategy) { case Vulnerability::RemediationStrategies::EXIT: { From 0d2373182cb6e5f6e65fb74e541e59730afcb358 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 20 Aug 2026 17:19:01 -0400 Subject: [PATCH 10/16] ArithmeticSanitizer.cpp: Removing getOrCreateREsolveReportSanitizerTriggered. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index d9588c623..1438aeba1 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -197,7 +197,6 @@ void sanitizeDivideByZero(Function *F, builder.CreateCondBr(isZero, remedDivBB, preserveDivBB); builder.SetInsertPoint(remedDivBB); - builder.CreateCall(getOrCreateResolveReportSanitizerTriggered(M)); Value *remedValue = nullptr; switch (strategy) { From dd956376ba58c5352320607d55b4f721323baa55 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 20 Aug 2026 17:46:06 -0400 Subject: [PATCH 11/16] ArithmeticSanitizer.cpp: Modified getContinueValue logic to generate the largest floating point value from LLVM's point of view. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 1438aeba1..9fcbf96c8 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -3,6 +3,7 @@ * LGPL-3; See LICENSE.txt in the repo root for details. */ +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Twine.h" @@ -47,11 +48,9 @@ static Constant *getContinueValue(Instruction *I) { } } - if (Ty->isFloatTy()) - return ConstantFP::get(Ty, APFloat(std::numeric_limits::max())); - - if (Ty->isDoubleTy()) - return ConstantFP::get(Ty, APFloat(std::numeric_limits::max())); + if (Ty->isFloatTy()) { + return ConstantFP::get(Ty, APFloat::getLargest(Ty->getFltSemantics())); + } } static void widenIntOverflow(Function *F) { From 5ddba08aa359babd944b0264a2020989bc2b6a30 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 25 Aug 2026 10:09:19 -0400 Subject: [PATCH 12/16] ArithmeticSanitizer.cpp: Changing from isFloatTy to isFloatingPointTy(). --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 9fcbf96c8..dce6015a0 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -48,7 +48,7 @@ static Constant *getContinueValue(Instruction *I) { } } - if (Ty->isFloatTy()) { + if (Ty->isFloatingPointTy()) { return ConstantFP::get(Ty, APFloat::getLargest(Ty->getFltSemantics())); } } From 567471fdcb413de29f68ded79ed7ae9cbf4a1be9 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 25 Aug 2026 10:29:18 -0400 Subject: [PATCH 13/16] Adding comment and default case to include strategies that are considered incompatible with this sanitizer. This also quiets clang-tidy complaint. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index dce6015a0..7f41266d2 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -211,6 +211,14 @@ void sanitizeDivideByZero(Function *F, // EXIT/RECOVER transfer control elsewhere builder.CreateUnreachable(); break; + + // The only remediation policies that work with this sanitizer + // are CONTINUE, EXIT, and RECOVER. + // This default case should never be triggered because + // the beginning of the function checks for the correct + // sanitizer-policy combination + default: + break; } builder.SetInsertPoint(preserveDivBB); From 94cd8a57461af4a0e8106d4b92f26d345df433b2 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 25 Aug 2026 10:37:27 -0400 Subject: [PATCH 14/16] ArithmeticSanitizer.cpp: Adding llvm_unreachable. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 7f41266d2..02c262898 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -218,7 +218,7 @@ void sanitizeDivideByZero(Function *F, // the beginning of the function checks for the correct // sanitizer-policy combination default: - break; + llvm_unreachable(); } builder.SetInsertPoint(preserveDivBB); From 7ad669e9754ce757eff30a2a658d255d88cedc61 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 25 Aug 2026 10:45:08 -0400 Subject: [PATCH 15/16] ArithmeticSanitzer.cpp: Adding brackets around llvm_unreachable() --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 02c262898..95ad5956f 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -217,9 +217,10 @@ void sanitizeDivideByZero(Function *F, // This default case should never be triggered because // the beginning of the function checks for the correct // sanitizer-policy combination - default: + default: { llvm_unreachable(); } + } builder.SetInsertPoint(preserveDivBB); From 2da691e736b787c9e17afb9f2b9687afd2bf01bd Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 25 Aug 2026 10:50:16 -0400 Subject: [PATCH 16/16] ArithmeticSanitizer.cpp: Note to self, add empty string to llvm_unreachable() or it will throw compilation error. --- resolve-cveassert/src/ArithmeticSanitizer.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/resolve-cveassert/src/ArithmeticSanitizer.cpp b/resolve-cveassert/src/ArithmeticSanitizer.cpp index 95ad5956f..974ba57fe 100644 --- a/resolve-cveassert/src/ArithmeticSanitizer.cpp +++ b/resolve-cveassert/src/ArithmeticSanitizer.cpp @@ -217,9 +217,8 @@ void sanitizeDivideByZero(Function *F, // This default case should never be triggered because // the beginning of the function checks for the correct // sanitizer-policy combination - default: { - llvm_unreachable(); - } + default: + llvm_unreachable(""); } builder.SetInsertPoint(preserveDivBB);