Il 14/10/2014 03:25, Mark R. Tuttle ha scritto:
Thanks, Luca.  Can you estimate how complete your branch is for the
overflow instrinsics?  Is this something I could complete with a bit of
advice from you?  -Mark

On Mon, Oct 13, 2014 at 6:00 PM, Luca Dariz <[email protected]
<mailto:[email protected]>> wrote:

    Il 13/10/2014 23:47, Mark R. Tuttle ha scritto:

        *Can KLEE check for integer overflow?*

        Since KLEE is based on STP and STP is based on a theory of bit
        vectors,
        I had hoped it might be easy for KLEE to check for an overflow
        bit.Since
        CLANG has -fsanitize=unsigned-integer-__overflow and
        -fsanitize=integer I
        had hoped it would be easy to compile with these flags and run
        KLEE, but
        KLEE does not appear to support the LLVM arithmetic with overflow
        intrinsics like llvm.uadd.with.overflow.* that CLANG inserts.


    Hi Mark,
    the implementation of these intrinsics is just incomplete, I started
    to expand it to detect unsigned integer overflow in this branch
    https://github.com/luckyluke/__klee/tree/detect-overflow
    <https://github.com/luckyluke/klee/tree/detect-overflow>.

    Best Regards,
    Luca Dariz



Hi Mark,

for now only the checks related to -fsanitize=unsigned-integer-overflow are tested, I started working on -fsanitize=signed-integer-overflow but it is not complete yet. I attach the temporary patch based on my detect-overflow branch, if you want to try it or enhance. Please note that signed multiplication overflow still does not work, and divrem is missing.

As an advice, in order to consider all the possible corner cases, I found useful to have a look at the LLVM compiler-rt library, which contains the code that expand the llvm.*.with.overflow intrinsics, just in case you want to add some additional checks.

I re-add klee-dev since somehow I left it out of this thread.

Hope this helps,
Luca Dariz

diff --git a/lib/Core/SpecialFunctionHandler.cpp b/lib/Core/SpecialFunctionHandler.cpp
index e36d180..97a8cdf 100644
--- a/lib/Core/SpecialFunctionHandler.cpp
+++ b/lib/Core/SpecialFunctionHandler.cpp
@@ -112,6 +112,7 @@ static SpecialFunctionHandler::HandlerInfo handlerInfo[] = {
   add("__ubsan_handle_add_overflow", handleAddOverflow, false),
   add("__ubsan_handle_sub_overflow", handleSubOverflow, false),
   add("__ubsan_handle_mul_overflow", handleMulOverflow, false),
+  add("__ubsan_handle_divrem_overflow", handleDivRemOverflow, false),
 
 #undef addDNR
 #undef add  
@@ -765,3 +766,11 @@ void SpecialFunctionHandler::handleMulOverflow(ExecutionState &state,
                                  "overflow on unsigned multiplication",
                                  "overflow.err");
 }
+
+void SpecialFunctionHandler::handleDivRemOverflow(ExecutionState &state,
+                                               KInstruction *target,
+                                               std::vector<ref<Expr> > &arguments) {
+  executor.terminateStateOnError(state,
+                                 "overflow on division or remainder",
+                                 "overflow.err");
+}
diff --git a/lib/Core/SpecialFunctionHandler.h b/lib/Core/SpecialFunctionHandler.h
index 601b149..d52b8fc 100644
--- a/lib/Core/SpecialFunctionHandler.h
+++ b/lib/Core/SpecialFunctionHandler.h
@@ -135,6 +135,7 @@ namespace klee {
     HANDLER(handleAddOverflow);
     HANDLER(handleMulOverflow);
     HANDLER(handleSubOverflow);
+    HANDLER(handleDivRemOverflow);
 #undef HANDLER
   };
 } // End klee namespace
diff --git a/lib/Module/IntrinsicCleaner.cpp b/lib/Module/IntrinsicCleaner.cpp
index 9d4f0fe..b8a3339 100644
--- a/lib/Module/IntrinsicCleaner.cpp
+++ b/lib/Module/IntrinsicCleaner.cpp
@@ -6,7 +6,7 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-
+#include <iostream>
 #include "Passes.h"
 
 #include "klee/Config/Version.h"
@@ -118,10 +118,14 @@ bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b, Module &M) {
         break;
       }
 
+      case Intrinsic::sadd_with_overflow:
+      case Intrinsic::ssub_with_overflow:
+      case Intrinsic::smul_with_overflow:
       case Intrinsic::uadd_with_overflow:
       case Intrinsic::usub_with_overflow:
       case Intrinsic::umul_with_overflow: {
         IRBuilder<> builder(ii->getParent(), ii);
+
         Function *F = builder.GetInsertBlock()->getParent();
 
         Value *op1 = ii->getArgOperand(0);
@@ -169,7 +173,143 @@ bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b, Module &M) {
           result = builder.CreateMul(op1, op2);
           overflow = phi_of;
           block_split = true;
-        }
+
+        } else if (ii->getIntrinsicID() == Intrinsic::sadd_with_overflow){
+          result = builder.CreateAdd(op1, op2);
+          // overflow if ((op2 >= 0) && (result < op1))
+          Value *op2ge0 =
+            builder.CreateICmpSGE(op2,
+                                  ConstantInt::getSigned(op2->getType(), 0));
+          Value *cond_ge0 =
+            builder.CreateAnd(op2ge0, builder.CreateICmpSLT(result, op1));
+          // overflow if ((op2 < 0) && (result >= op1))
+          Value *op2lt0 =
+            builder.CreateICmpSLT(op2,
+                                  ConstantInt::getSigned(op2->getType(), 0));
+          Value *cond_lt0 =
+            builder.CreateAnd(op2lt0, builder.CreateICmpSGE(result, op1));
+          overflow = builder.CreateOr(cond_ge0, cond_lt0);
+        } else if (ii->getIntrinsicID() == Intrinsic::ssub_with_overflow){
+          result = builder.CreateSub(op1, op2);
+		  // overflow if ((op2 >= 0) && (result > op1))
+		  Value *op2ge0 =
+            builder.CreateICmpSGE(op2,
+                                  ConstantInt::getSigned(op2->getType(), 0));
+		  Value *cond_ge0 =
+            builder.CreateAnd(op2ge0, builder.CreateICmpSGT(result, op1));
+		  // overflow if ((op2 < 0) && (result <= op1))
+		  Value *op2lt0 =
+            builder.CreateICmpSLT(op2,
+                                  ConstantInt::getSigned(op2->getType(), 0));
+		  Value *cond_lt0 =
+            builder.CreateAnd(op2lt0, builder.CreateICmpSLE(result, op1));
+		  overflow = builder.CreateOr(cond_ge0, cond_lt0);
+		} else if (ii->getIntrinsicID() == Intrinsic::smul_with_overflow){
+          uint64_t bit_width = op1->getType()->getPrimitiveSizeInBits();
+          Value *int_min = ConstantInt::get(op1->getType(),
+                                           APInt::getSignedMinValue(bit_width));
+          Value *int_max = ConstantInt::get(op1->getType(),
+                                           APInt::getSignedMaxValue(bit_width));
+
+          //          std::cerr << int_min << " " << int_max << "\n";
+
+          // overflow if (op1 == int_min) && ((op2 != 0) || (op2 != 1))
+          Value *op1_min = builder.CreateICmpEQ(op1, int_min);
+          Value *op2_eq0 =
+            builder.CreateICmpNE(op2, ConstantInt::getSigned(op2->getType(), 0));
+          Value *op2_eq1 =
+            builder.CreateICmpNE(op2, ConstantInt::getSigned(op2->getType(), 1));
+          Value *overflow_1 =
+            builder.CreateAnd(op1_min, builder.CreateAnd(op2_eq0, op2_eq1));
+
+          // overflow if (op2 == int_min) && ((op1 != 0) || (op1 != 1))
+          Value *op2_min = builder.CreateICmpEQ(op2, int_min);
+          Value *op1_eq0 =
+            builder.CreateICmpNE(op1, ConstantInt::getSigned(op1->getType(), 0));
+          Value *op1_eq1 =
+            builder.CreateICmpNE(op1, ConstantInt::getSigned(op1->getType(), 1));
+          Value *overflow_2 =
+            builder.CreateAnd(op2_min, builder.CreateAnd(op1_eq0, op1_eq1));
+
+          // branch if overflow is detected
+          BasicBlock *entry = builder.GetInsertBlock();
+          entry->setName(Twine(entry->getName(), "_smul_start"));
+          BasicBlock *end_of = entry->splitBasicBlock(builder.GetInsertPoint(),
+                                                       "smul_end");
+          BasicBlock *check_abs = BasicBlock::Create(builder.getContext(),
+                                                     "smul_check_abs",
+                                                     F, end_of);
+          BasicBlock *check_sign = BasicBlock::Create(builder.getContext(),
+                                                     "smul_check_sign",
+                                                      F, end_of);
+          BasicBlock *check_sequal = BasicBlock::Create(builder.getContext(),
+                                                        "smul_check_same_sign",
+                                                        F, end_of);
+          BasicBlock *check_sdiff = BasicBlock::Create(builder.getContext(),
+                                                       "smul_check_diff_sign",
+                                                       F, end_of);
+
+          entry->getTerminator()->eraseFromParent();
+          builder.SetInsertPoint(entry);
+          Value *overflow_on_min = builder.CreateOr(overflow_1, overflow_2);
+          builder.CreateCondBr(overflow_on_min, end_of, check_abs);
+
+          // no overflow if (|op1| < 2) && (|op2| < 2),
+          // otherwise perform a check depending on the sign of the operands
+
+          // compute absolute values
+          builder.SetInsertPoint(check_abs);
+          Value *op1_neg = builder.CreateNeg(op1);
+          Value *op1_isneg =
+            builder.CreateICmpSLT(op1, Constant::getNullValue(op1->getType()));
+          Value *op1_abs = builder.CreateSelect(op1_isneg, op1_neg, op1);
+          Value *op2_neg = builder.CreateNeg(op2);
+          Value *op2_isneg =
+            builder.CreateICmpSLT(op2, Constant::getNullValue(op2->getType()));
+          Value *op2_abs = builder.CreateSelect(op2_isneg, op2_neg, op2);
+
+          // check if (|op1| < 2) && (|op2| < 2)
+          Value *op1_g1 =
+            builder.CreateICmpSGT(op1_abs,
+                                  ConstantInt::getSigned(op1->getType(), 2));
+          Value *op2_g1 =
+            builder.CreateICmpSGT(op2_abs,
+                                  ConstantInt::getSigned(op2->getType(), 2));
+          Value *overflow_no_abs = builder.CreateAnd(op1_g1, op2_g1);
+          builder.CreateCondBr(overflow_no_abs, end_of, check_sign);
+          
+          // check sign
+          builder.SetInsertPoint(check_sign);
+          Value *different_sign = builder.CreateXor(op1_isneg, op2_isneg);
+          builder.CreateCondBr(different_sign, check_sequal, check_sdiff);
+
+          // operands have same sign
+          builder.SetInsertPoint(check_sequal);
+          Value *div_sequal = builder.CreateSDiv(int_max, op2_abs);
+          Value *overflow_sequal = builder.CreateICmpSGT(op1_abs, div_sequal);
+          builder.CreateBr(end_of);
+
+          // operands have different sign
+          builder.SetInsertPoint(check_sdiff);
+          Value *div_sdiff = builder.CreateSDiv(int_min,
+                                                builder.CreateNeg(op2_abs));
+          Value *overflow_sdiff = builder.CreateICmpSGT(op1_abs, div_sdiff);
+          builder.CreateBr(end_of);
+
+          // merge overflow values
+          builder.SetInsertPoint(end_of, end_of->begin());
+          PHINode *phi_of = builder.CreatePHI(overflow_on_min->getType(), 4);
+          phi_of->addIncoming(overflow_on_min, entry);
+          phi_of->addIncoming(overflow_no_abs, check_abs);
+          phi_of->addIncoming(overflow_sequal, check_sequal);
+          phi_of->addIncoming(overflow_sdiff, check_sdiff);
+
+          result = builder.CreateMul(op1, op2);
+          overflow = phi_of;
+          block_split = true;
+
+          F->viewCFG();
+		}
 
         Value *resultStruct =
           builder.CreateInsertValue(UndefValue::get(ii->getType()), result, 0);
diff --git a/tools/klee/main.cpp b/tools/klee/main.cpp
index fe80994..23eff17 100644
--- a/tools/klee/main.cpp
+++ b/tools/klee/main.cpp
@@ -786,6 +786,7 @@ static const char *modelledExternals[] = {
   "__ubsan_handle_add_overflow",
   "__ubsan_handle_sub_overflow",
   "__ubsan_handle_mul_overflow",
+  "__ubsan_handle_divrem_overflow",
 };
 // Symbols we aren't going to warn about
 static const char *dontCareExternals[] = {
_______________________________________________
klee-dev mailing list
[email protected]
https://mailman.ic.ac.uk/mailman/listinfo/klee-dev

Reply via email to