From 714dc22ccb12efdc203e8ce92d6e546ca9ffb157 Mon Sep 17 00:00:00 2001 From: Luca Dariz Date: Thu, 20 Nov 2014 12:41:12 +0100 Subject: refactor integer overflow detection, add signed int Instead of checking for every possible casse which result in overflow, it is much simpler to perform the operation using integers with bigger dimension and check if the result overflow --- lib/Core/SpecialFunctionHandler.cpp | 9 +++ lib/Core/SpecialFunctionHandler.h | 1 + lib/Module/IntrinsicCleaner.cpp | 106 ++++++++++++++++++++++-------------- test/Feature/ubsan_add_overflow.c | 19 ------- test/Feature/ubsan_mul_overflow.c | 22 -------- test/Feature/ubsan_sadd_overflow.c | 19 +++++++ test/Feature/ubsan_smul_overflow.c | 19 +++++++ test/Feature/ubsan_ssub_overflow.c | 19 +++++++ test/Feature/ubsan_sub_overflow.c | 19 ------- test/Feature/ubsan_uadd_overflow.c | 19 +++++++ test/Feature/ubsan_umul_overflow.c | 22 ++++++++ test/Feature/ubsan_usub_overflow.c | 19 +++++++ tools/klee/main.cpp | 1 + 13 files changed, 193 insertions(+), 101 deletions(-) delete mode 100644 test/Feature/ubsan_add_overflow.c delete mode 100644 test/Feature/ubsan_mul_overflow.c create mode 100644 test/Feature/ubsan_sadd_overflow.c create mode 100644 test/Feature/ubsan_smul_overflow.c create mode 100644 test/Feature/ubsan_ssub_overflow.c delete mode 100644 test/Feature/ubsan_sub_overflow.c create mode 100644 test/Feature/ubsan_uadd_overflow.c create mode 100644 test/Feature/ubsan_umul_overflow.c create mode 100644 test/Feature/ubsan_usub_overflow.c diff --git a/lib/Core/SpecialFunctionHandler.cpp b/lib/Core/SpecialFunctionHandler.cpp index 04a82cf7..f06ae4f5 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 @@ -736,3 +737,11 @@ void SpecialFunctionHandler::handleMulOverflow(ExecutionState &state, "overflow on unsigned multiplication", "overflow.err"); } + +void SpecialFunctionHandler::handleDivRemOverflow(ExecutionState &state, + KInstruction *target, + std::vector > &arguments) { + executor.terminateStateOnError(state, + "overflow on division or remainder", + "overflow.err"); +} diff --git a/lib/Core/SpecialFunctionHandler.h b/lib/Core/SpecialFunctionHandler.h index 601b149b..d52b8fc5 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 9d4f0fec..da97621a 100644 --- a/lib/Module/IntrinsicCleaner.cpp +++ b/lib/Module/IntrinsicCleaner.cpp @@ -118,59 +118,83 @@ 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); Value *op2 = ii->getArgOperand(1); Value *result = 0; + Value *result_ext = 0; Value *overflow = 0; - if (ii->getIntrinsicID() == Intrinsic::uadd_with_overflow){ - result = builder.CreateAdd(op1, op2); - overflow = builder.CreateICmpULT(result, op1); - } else if (ii->getIntrinsicID() == Intrinsic::usub_with_overflow){ - result = builder.CreateSub(op1, op2); - overflow = builder.CreateICmpUGT(result, op1); - } else if (ii->getIntrinsicID() == Intrinsic::umul_with_overflow){ - BasicBlock *entry = builder.GetInsertBlock(); - entry->setName(Twine(entry->getName(), "_umul_start")); - BasicBlock *cont_of = entry->splitBasicBlock(builder.GetInsertPoint(), - "umul_end"); - BasicBlock *on_of = BasicBlock::Create(builder.getContext(), - "umul_overflow", F, cont_of); - - // remove the branch inserted by splitBasicBlock, we'll add our own - entry->getTerminator()->eraseFromParent(); - builder.SetInsertPoint(entry); - Value *no_overflow = builder.getFalse(); - Value *one = ConstantInt::getSigned(op1->getType(), 1); - Value *op1_g1 = builder.CreateICmpUGT(op1, one); - Value *op2_g1 = builder.CreateICmpUGT(op2, one); - Value *may_of = builder.CreateAnd(op1_g1, op2_g1); - builder.CreateCondBr(may_of, on_of, cont_of); - - builder.SetInsertPoint(on_of); - uint64_t bit_size = op1->getType()->getPrimitiveSizeInBits(); - Value *uint_max = ConstantInt::get(op1->getType(), - APInt::getMaxValue(bit_size)); - Value *div1 = builder.CreateUDiv(uint_max, op1); - Value *overflow1 = builder.CreateICmpUGT(op2, div1); - builder.CreateBr(cont_of); - - builder.SetInsertPoint(cont_of, cont_of->begin()); - PHINode *phi_of = builder.CreatePHI(no_overflow->getType(), 2); - phi_of->addIncoming(overflow1, on_of); - phi_of->addIncoming(no_overflow, entry); - - result = builder.CreateMul(op1, op2); - overflow = phi_of; - block_split = true; + + unsigned int bw = op1->getType()->getPrimitiveSizeInBits(); + unsigned int bw2 = op1->getType()->getPrimitiveSizeInBits()*2; + + if ((ii->getIntrinsicID() == Intrinsic::uadd_with_overflow) || + (ii->getIntrinsicID() == Intrinsic::usub_with_overflow) || + (ii->getIntrinsicID() == Intrinsic::umul_with_overflow)) { + + Value *op1ext = + builder.CreateZExt(op1, IntegerType::get(M.getContext(), bw2)); + Value *op2ext = + builder.CreateZExt(op2, IntegerType::get(M.getContext(), bw2)); + Value *int_max_s = + ConstantInt::get(op1->getType(), APInt::getMaxValue(bw)); + Value *int_max = + builder.CreateZExt(int_max_s, IntegerType::get(M.getContext(), bw2)); + + if (ii->getIntrinsicID() == Intrinsic::uadd_with_overflow){ + result_ext = builder.CreateAdd(op1ext, op2ext); + } else if (ii->getIntrinsicID() == Intrinsic::usub_with_overflow){ + result_ext = builder.CreateSub(op1ext, op2ext); + } else if (ii->getIntrinsicID() == Intrinsic::umul_with_overflow){ + result_ext = builder.CreateMul(op1ext, op2ext); + } + overflow = builder.CreateICmpUGT(result_ext, int_max); + + } else if ((ii->getIntrinsicID() == Intrinsic::sadd_with_overflow) || + (ii->getIntrinsicID() == Intrinsic::ssub_with_overflow) || + (ii->getIntrinsicID() == Intrinsic::smul_with_overflow)) { + + Value *op1ext = + builder.CreateSExt(op1, IntegerType::get(M.getContext(), bw2)); + Value *op2ext = + builder.CreateSExt(op2, IntegerType::get(M.getContext(), bw2)); + Value *int_max_s = + ConstantInt::get(op1->getType(), APInt::getSignedMaxValue(bw)); + Value *int_min_s = + ConstantInt::get(op1->getType(), APInt::getSignedMinValue(bw)); + Value *int_max = + builder.CreateSExt(int_max_s, IntegerType::get(M.getContext(), bw2)); + Value *int_min = + builder.CreateSExt(int_min_s, IntegerType::get(M.getContext(), bw2)); + + if (ii->getIntrinsicID() == Intrinsic::sadd_with_overflow){ + result_ext = builder.CreateAdd(op1ext, op2ext); + } else if (ii->getIntrinsicID() == Intrinsic::ssub_with_overflow){ + result_ext = builder.CreateSub(op1ext, op2ext); + } else if (ii->getIntrinsicID() == Intrinsic::smul_with_overflow){ + result_ext = builder.CreateMul(op1ext, op2ext); + } + overflow = builder.CreateOr(builder.CreateICmpSGT(result_ext, int_max), + builder.CreateICmpSLT(result_ext, int_min)); } + // This trunc cound be replaced by a more general trunc replacement + // that allows to detect also undefined behavior in assignments or + // overflow in operation with integers whose dimension is smaller than + // int's dimension, e.g. + // uint8_t = uint8_t + uint8_t; + // if one desires the wrapping should write + // uint8_t = (uint8_t + uint8_t) & 0xFF; + // before this, must check if it has side effects on other operations + result = builder.CreateTrunc(result_ext, op1->getType()); Value *resultStruct = builder.CreateInsertValue(UndefValue::get(ii->getType()), result, 0); resultStruct = builder.CreateInsertValue(resultStruct, overflow, 1); diff --git a/test/Feature/ubsan_add_overflow.c b/test/Feature/ubsan_add_overflow.c deleted file mode 100644 index 87701029..00000000 --- a/test/Feature/ubsan_add_overflow.c +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %llvmgcc %s -fsanitize=unsigned-integer-overflow -emit-llvm -g -O0 -c -o %t.bc -// RUN: %klee %t.bc 2> %t.log -// RUN: grep -c "overflow on unsigned addition" %t.log -// RUN: grep -c "ubsan_add_overflow.c:16: overflow" %t.log - -#include "klee/klee.h" - -int main() -{ - unsigned int x; - unsigned int y; - volatile unsigned int result; - - klee_make_symbolic(&x, sizeof(x), "unsigned add 1"); - klee_make_symbolic(&y, sizeof(y), "unsigned add 2"); - result = x + y; - - return 0; -} diff --git a/test/Feature/ubsan_mul_overflow.c b/test/Feature/ubsan_mul_overflow.c deleted file mode 100644 index 12300b05..00000000 --- a/test/Feature/ubsan_mul_overflow.c +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: %llvmgcc %s -fsanitize=unsigned-integer-overflow -emit-llvm -g -O0 -c -o %t.bc -// RUN: %klee %t.bc 2> %t.log -// RUN: grep -c "overflow on unsigned multiplication" %t.log -// RUN: grep -c "ubsan_mul_overflow.c:18: overflow" %t.log -// RUN: grep -c "ubsan_mul_overflow.c:19: overflow" %t.log - -#include "klee/klee.h" - -int main() -{ - unsigned int x; - unsigned int y; - uint32_t x2=3147483648, y2=3727483648; - volatile unsigned int result; - - klee_make_symbolic(&x, sizeof(x), "unsigned add 1"); - klee_make_symbolic(&y, sizeof(y), "unsigned add 2"); - result = x * y; - result = x2 * y2; - - return 0; -} diff --git a/test/Feature/ubsan_sadd_overflow.c b/test/Feature/ubsan_sadd_overflow.c new file mode 100644 index 00000000..6ab3c3ab --- /dev/null +++ b/test/Feature/ubsan_sadd_overflow.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -fsanitize=signed-integer-overflow -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee %t.bc 2> %t.log +// RUN: grep -c "overflow on unsigned addition" %t.log +// RUN: grep -c "ubsan_sadd_overflow.c:16: overflow" %t.log + +#include "klee/klee.h" + +int main() +{ + signed int x; + signed int y; + volatile signed int result; + + klee_make_symbolic(&x, sizeof(x), "signed add 1"); + klee_make_symbolic(&y, sizeof(y), "signed add 2"); + result = x + y; + + return 0; +} diff --git a/test/Feature/ubsan_smul_overflow.c b/test/Feature/ubsan_smul_overflow.c new file mode 100644 index 00000000..21a796cb --- /dev/null +++ b/test/Feature/ubsan_smul_overflow.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -fsanitize=signed-integer-overflow -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee %t.bc 2> %t.log +// RUN: grep -c "overflow on unsigned multiplication" %t.log +// RUN: grep -c "ubsan_smul_overflow.c:16: overflow" %t.log + +#include "klee/klee.h" + +int main() +{ + int x; + int y; + volatile int result; + + klee_make_symbolic(&x, sizeof(x), "signed mul 1"); + klee_make_symbolic(&y, sizeof(y), "signed mul 2"); + result = x * y; + + return 0; +} diff --git a/test/Feature/ubsan_ssub_overflow.c b/test/Feature/ubsan_ssub_overflow.c new file mode 100644 index 00000000..5ba62567 --- /dev/null +++ b/test/Feature/ubsan_ssub_overflow.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -fsanitize=signed-integer-overflow -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee %t.bc 2> %t.log +// RUN: grep -c "overflow on unsigned subtraction" %t.log +// RUN: grep -c "ubsan_ssub_overflow.c:16: overflow" %t.log + +#include "klee/klee.h" + +int main() +{ + signed int x; + signed int y; + volatile signed int result; + + klee_make_symbolic(&x, sizeof(x), "signed sub 1"); + klee_make_symbolic(&y, sizeof(y), "signed sub 2"); + result = x - y; + + return 0; +} diff --git a/test/Feature/ubsan_sub_overflow.c b/test/Feature/ubsan_sub_overflow.c deleted file mode 100644 index 37a251bc..00000000 --- a/test/Feature/ubsan_sub_overflow.c +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %llvmgcc %s -fsanitize=unsigned-integer-overflow -emit-llvm -g -O0 -c -o %t.bc -// RUN: %klee %t.bc 2> %t.log -// RUN: grep -c "overflow on unsigned subtraction" %t.log -// RUN: grep -c "ubsan_sub_overflow.c:16: overflow" %t.log - -#include "klee/klee.h" - -int main() -{ - unsigned int x; - unsigned int y; - volatile unsigned int result; - - klee_make_symbolic(&x, sizeof(x), "unsigned add 1"); - klee_make_symbolic(&y, sizeof(y), "unsigned add 2"); - result = x - y; - - return 0; -} diff --git a/test/Feature/ubsan_uadd_overflow.c b/test/Feature/ubsan_uadd_overflow.c new file mode 100644 index 00000000..9dc6832d --- /dev/null +++ b/test/Feature/ubsan_uadd_overflow.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -fsanitize=unsigned-integer-overflow -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee %t.bc 2> %t.log +// RUN: grep -c "overflow on unsigned addition" %t.log +// RUN: grep -c "ubsan_uadd_overflow.c:16: overflow" %t.log + +#include "klee/klee.h" + +int main() +{ + unsigned int x; + unsigned int y; + volatile unsigned int result; + + klee_make_symbolic(&x, sizeof(x), "unsigned add 1"); + klee_make_symbolic(&y, sizeof(y), "unsigned add 2"); + result = x + y; + + return 0; +} diff --git a/test/Feature/ubsan_umul_overflow.c b/test/Feature/ubsan_umul_overflow.c new file mode 100644 index 00000000..2525a5e0 --- /dev/null +++ b/test/Feature/ubsan_umul_overflow.c @@ -0,0 +1,22 @@ +// RUN: %llvmgcc %s -fsanitize=unsigned-integer-overflow -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee %t.bc 2> %t.log +// RUN: grep -c "overflow on unsigned multiplication" %t.log +// RUN: grep -c "ubsan_umul_overflow.c:18: overflow" %t.log +// RUN: grep -c "ubsan_umul_overflow.c:19: overflow" %t.log + +#include "klee/klee.h" + +int main() +{ + unsigned int x; + unsigned int y; + uint32_t x2=3147483648, y2=3727483648; + volatile unsigned int result; + + klee_make_symbolic(&x, sizeof(x), "unsigned mul 1"); + klee_make_symbolic(&y, sizeof(y), "unsigned mul 2"); + result = x * y; + result = x2 * y2; + + return 0; +} diff --git a/test/Feature/ubsan_usub_overflow.c b/test/Feature/ubsan_usub_overflow.c new file mode 100644 index 00000000..bfd94e3c --- /dev/null +++ b/test/Feature/ubsan_usub_overflow.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -fsanitize=unsigned-integer-overflow -emit-llvm -g -O0 -c -o %t.bc +// RUN: %klee %t.bc 2> %t.log +// RUN: grep -c "overflow on unsigned subtraction" %t.log +// RUN: grep -c "ubsan_usub_overflow.c:16: overflow" %t.log + +#include "klee/klee.h" + +int main() +{ + unsigned int x; + unsigned int y; + volatile unsigned int result; + + klee_make_symbolic(&x, sizeof(x), "unsigned sub 1"); + klee_make_symbolic(&y, sizeof(y), "unsigned sub 2"); + result = x - y; + + return 0; +} diff --git a/tools/klee/main.cpp b/tools/klee/main.cpp index decf586d..8a246685 100644 --- a/tools/klee/main.cpp +++ b/tools/klee/main.cpp @@ -768,6 +768,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[] = { -- cgit 1.4.1