From 203193e93e75c77840b01c56da7e9265f2b69da1 Mon Sep 17 00:00:00 2001
From: Will Dietz <w@wdtz.org>
Date: Wed, 7 Nov 2012 15:42:54 -0800
Subject: [PATCH 1/2] Add "unsigned-integer-overflow" sanitizer.

---
 include/clang/Basic/Sanitizers.def |    3 ++
 lib/CodeGen/CGExprScalar.cpp       |   56 +++++++++++++++++++++++++++++-------
 2 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def
index 085ca16..8832e38 100644
--- a/include/clang/Basic/Sanitizers.def
+++ b/include/clang/Basic/Sanitizers.def
@@ -57,6 +57,9 @@ SANITIZER("vptr", Vptr)
 SANITIZER("object-size", ObjectSize)
 SANITIZER("float-cast-overflow", FloatCastOverflow)
 
+// IntegerSanitizer
+SANITIZER("unsigned-integer-overflow", UnsignedIntegerOverflow)
+
 // -fsanitize=undefined (and its alias -fcatch-undefined-behavior). This should
 // include all the sanitizers which have low overhead, no ABI or address space
 // layout implications, and only catch undefined behavior.
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index b429b1d..6857082 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -414,6 +414,11 @@ public:
       }
     }
 
+    if (Ops.Ty->isUnsignedIntegerType() &&
+        CGF.getLangOpts().SanitizeUnsignedIntegerOverflow) {
+      return EmitOverflowCheckedBinOp(Ops);
+    }
+
     if (Ops.LHS->getType()->isFPOrFPVectorTy())
       return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
     return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
@@ -1472,11 +1477,23 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
 
     // Note that signed integer inc/dec with width less than int can't
     // overflow because of promotion rules; we're just eliding a few steps here.
-    if (type->isSignedIntegerOrEnumerationType() &&
-        value->getType()->getPrimitiveSizeInBits() >=
-            CGF.IntTy->getBitWidth())
-      value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
-    else
+    if (value->getType()->getPrimitiveSizeInBits() >=
+            CGF.IntTy->getBitWidth() &&
+        type->isSignedIntegerOrEnumerationType()) {
+        value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
+    } else if (value->getType()->getPrimitiveSizeInBits() >=
+               CGF.IntTy->getBitWidth() &&
+               type->isUnsignedIntegerType() &&
+               CGF.getLangOpts().SanitizeUnsignedIntegerOverflow) {
+      BinOpInfo BinOp;
+      BinOp.LHS = value;
+      BinOp.RHS = llvm::ConstantInt::get(value->getType(), 1, false);
+      BinOp.Ty = E->getType();
+      BinOp.Opcode = isInc ? BO_Add : BO_Sub;
+      BinOp.FPContractable = false;
+      BinOp.E = E;
+      value = EmitOverflowCheckedBinOp(BinOp);
+    } else
       value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
   
   // Next most common: pointer increment.
@@ -1995,27 +2012,33 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
   unsigned IID;
   unsigned OpID = 0;
 
+  bool isSigned = Ops.Ty->isSignedIntegerOrEnumerationType();
   switch (Ops.Opcode) {
   case BO_Add:
   case BO_AddAssign:
     OpID = 1;
-    IID = llvm::Intrinsic::sadd_with_overflow;
+    IID = isSigned ? llvm::Intrinsic::sadd_with_overflow :
+                     llvm::Intrinsic::uadd_with_overflow;
     break;
   case BO_Sub:
   case BO_SubAssign:
     OpID = 2;
-    IID = llvm::Intrinsic::ssub_with_overflow;
+    IID = isSigned ? llvm::Intrinsic::ssub_with_overflow :
+                     llvm::Intrinsic::usub_with_overflow;
     break;
   case BO_Mul:
   case BO_MulAssign:
     OpID = 3;
     IID = llvm::Intrinsic::smul_with_overflow;
+    IID = isSigned ? llvm::Intrinsic::smul_with_overflow :
+                     llvm::Intrinsic::umul_with_overflow;
     break;
   default:
     llvm_unreachable("Unsupported operation for overflow detection");
   }
   OpID <<= 1;
-  OpID |= 1;
+  if (isSigned)
+    OpID |= 1;
 
   llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
 
@@ -2031,7 +2054,8 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
   if (handlerName->empty()) {
     // If the signed-integer-overflow sanitizer is enabled, emit a call to its
     // runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
-    if (CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+    if (CGF.getLangOpts().SanitizeSignedIntegerOverflow ||
+        CGF.getLangOpts().SanitizeUnsignedIntegerOverflow)
       EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
     else
       CGF.EmitTrapvCheck(Builder.CreateNot(overflow));
@@ -2256,7 +2280,12 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
       return EmitOverflowCheckedBinOp(op);
     }
   }
-    
+
+  if (op.Ty->isUnsignedIntegerType() &&
+      CGF.getLangOpts().SanitizeUnsignedIntegerOverflow) {
+    return EmitOverflowCheckedBinOp(op);
+  }
+
   if (op.LHS->getType()->isFPOrFPVectorTy()) {
     // Try to form an fmuladd.
     if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
@@ -2283,7 +2312,12 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
         return EmitOverflowCheckedBinOp(op);
       }
     }
-    
+
+    if (op.Ty->isUnsignedIntegerType() &&
+        CGF.getLangOpts().SanitizeUnsignedIntegerOverflow) {
+      return EmitOverflowCheckedBinOp(op);
+    }
+
     if (op.LHS->getType()->isFPOrFPVectorTy()) {
       // Try to form an fmuladd.
       if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
-- 
1.7.1

