<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><span class="">I checked in </span><span class=""></span><span class="">r</span><span class="">304486 to try and address the issue.</span><div class=""><br class=""></div><div class="">thanks,</div><div class="">vedant</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jun 1, 2017, at 3:21 PM, Vedant Kumar via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" class="">cfe-commits@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=us-ascii" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Taking a look.<div class=""><br class=""></div><div class="">vedant</div><div class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jun 1, 2017, at 2:45 PM, Galina Kistanova <<a href="mailto:gkistanova@gmail.com" class="">gkistanova@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class=""><div class="">Hello Vedant,<br class=""><br class="">This commit broke tests on some of our builders:<br class=""><br class="">Failing Tests (1):<br class=""> Clang :: CodeGen/ubsan-pointer-overflow.m<br class=""><br class=""><a href="http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/2865/steps/test-check-all/logs/stdio" class="">http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/2865/steps/test-check-all/logs/stdio</a><br class=""><a href="http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/10259" class="">http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/10259</a><br class=""><a href="http://lab.llvm.org:8011/builders/clang-with-lto-ubuntu/builds/3097" class="">http://lab.llvm.org:8011/builders/clang-with-lto-ubuntu/builds/3097</a><br class=""></div><div class="">etc<br class=""></div><div class=""><br class=""></div>Thanks<br class=""><br class=""></div>Galina<br class=""></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Thu, Jun 1, 2017 at 12:22 PM, Vedant Kumar via cfe-commits <span dir="ltr" class=""><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank" class="">cfe-commits@lists.llvm.org</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: vedantk<br class="">
Date: Thu Jun 1 14:22:18 2017<br class="">
New Revision: 304459<br class="">
<br class="">
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=304459&view=rev" rel="noreferrer" target="_blank" class="">http://llvm.org/viewvc/llvm-<wbr class="">project?rev=304459&view=rev</a><br class="">
Log:<br class="">
[ubsan] Add a check for pointer overflow UB<br class="">
<br class="">
Check pointer arithmetic for overflow.<br class="">
<br class="">
For some more background on this check, see:<br class="">
<br class="">
<a href="https://wdtz.org/catching-pointer-overflow-bugs.html" rel="noreferrer" target="_blank" class="">https://wdtz.org/catching-<wbr class="">pointer-overflow-bugs.html</a><br class="">
<a href="https://reviews.llvm.org/D20322" rel="noreferrer" target="_blank" class="">https://reviews.llvm.org/<wbr class="">D20322</a><br class="">
<br class="">
Patch by Will Dietz and John Regehr!<br class="">
<br class="">
This version of the patch is different from the original in a few ways:<br class="">
<br class="">
- It introduces the EmitCheckedInBoundsGEP utility which inserts<br class="">
checks when the pointer overflow check is enabled.<br class="">
<br class="">
- It does some constant-folding to reduce instrumentation overhead.<br class="">
<br class="">
- It does not check some GEPs in CGExprCXX. I'm not sure that<br class="">
inserting checks here, or in CGClass, would catch many bugs.<br class="">
<br class="">
Possible future directions for this check:<br class="">
<br class="">
- Introduce CGF.EmitCheckedStructGEP, to detect overflows when<br class="">
accessing structures.<br class="">
<br class="">
Testing: Apart from the added lit test, I ran check-llvm and check-clang<br class="">
with a stage2, ubsan-instrumented clang. Will and John have also done<br class="">
extensive testing on numerous open source projects.<br class="">
<br class="">
Differential Revision: <a href="https://reviews.llvm.org/D33305" rel="noreferrer" target="_blank" class="">https://reviews.llvm.org/<wbr class="">D33305</a><br class="">
<br class="">
Added:<br class="">
cfe/trunk/test/CodeGen/ubsan-<wbr class="">pointer-overflow.m<br class="">
Modified:<br class="">
cfe/trunk/docs/<wbr class="">UndefinedBehaviorSanitizer.rst<br class="">
cfe/trunk/include/clang/Basic/<wbr class="">Sanitizers.def<br class="">
cfe/trunk/lib/CodeGen/CGExpr.<wbr class="">cpp<br class="">
cfe/trunk/lib/CodeGen/<wbr class="">CGExprScalar.cpp<br class="">
cfe/trunk/lib/CodeGen/<wbr class="">CodeGenFunction.h<br class="">
cfe/trunk/test/Driver/<wbr class="">fsanitize.c<br class="">
<br class="">
Modified: cfe/trunk/docs/<wbr class="">UndefinedBehaviorSanitizer.rst<br class="">
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/UndefinedBehaviorSanitizer.rst?rev=304459&r1=304458&r2=304459&view=diff" rel="noreferrer" target="_blank" class="">http://llvm.org/viewvc/llvm-<wbr class="">project/cfe/trunk/docs/<wbr class="">UndefinedBehaviorSanitizer.<wbr class="">rst?rev=304459&r1=304458&r2=<wbr class="">304459&view=diff</a><br class="">
==============================<wbr class="">==============================<wbr class="">==================<br class="">
--- cfe/trunk/docs/<wbr class="">UndefinedBehaviorSanitizer.rst (original)<br class="">
+++ cfe/trunk/docs/<wbr class="">UndefinedBehaviorSanitizer.rst Thu Jun 1 14:22:18 2017<br class="">
@@ -106,6 +106,8 @@ Available checks are:<br class="">
invalid pointers. These checks are made in terms of<br class="">
``__builtin_object_size``, and consequently may be able to detect more<br class="">
problems at higher optimization levels.<br class="">
+ - ``-fsanitize=pointer-overflow`<wbr class="">`: Performing pointer arithmetic which<br class="">
+ overflows.<br class="">
- ``-fsanitize=return``: In C++, reaching the end of a<br class="">
value-returning function without returning a value.<br class="">
- ``-fsanitize=returns-nonnull-<wbr class="">attribute``: Returning null pointer<br class="">
<br class="">
Modified: cfe/trunk/include/clang/Basic/<wbr class="">Sanitizers.def<br class="">
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Sanitizers.def?rev=304459&r1=304458&r2=304459&view=diff" rel="noreferrer" target="_blank" class="">http://llvm.org/viewvc/llvm-<wbr class="">project/cfe/trunk/include/<wbr class="">clang/Basic/Sanitizers.def?<wbr class="">rev=304459&r1=304458&r2=<wbr class="">304459&view=diff</a><br class="">
==============================<wbr class="">==============================<wbr class="">==================<br class="">
--- cfe/trunk/include/clang/Basic/<wbr class="">Sanitizers.def (original)<br class="">
+++ cfe/trunk/include/clang/Basic/<wbr class="">Sanitizers.def Thu Jun 1 14:22:18 2017<br class="">
@@ -73,6 +73,7 @@ SANITIZER("nullability-return"<wbr class="">, Nullabil<br class="">
SANITIZER_GROUP("nullability", Nullability,<br class="">
NullabilityArg | NullabilityAssign | NullabilityReturn)<br class="">
SANITIZER("object-size", ObjectSize)<br class="">
+SANITIZER("pointer-overflow", PointerOverflow)<br class="">
SANITIZER("return", Return)<br class="">
SANITIZER("returns-nonnull-<wbr class="">attribute", ReturnsNonnullAttribute)<br class="">
SANITIZER("shift-base", ShiftBase)<br class="">
@@ -108,9 +109,9 @@ SANITIZER("safe-stack", SafeStack)<br class="">
SANITIZER_GROUP("undefined", Undefined,<br class="">
Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |<br class="">
FloatDivideByZero | IntegerDivideByZero | NonnullAttribute |<br class="">
- Null | ObjectSize | Return | ReturnsNonnullAttribute |<br class="">
- Shift | SignedIntegerOverflow | Unreachable | VLABound |<br class="">
- Function | Vptr)<br class="">
+ Null | ObjectSize | PointerOverflow | Return |<br class="">
+ ReturnsNonnullAttribute | Shift | SignedIntegerOverflow |<br class="">
+ Unreachable | VLABound | Function | Vptr)<br class="">
<br class="">
// -fsanitize=undefined-trap is an alias for -fsanitize=undefined.<br class="">
SANITIZER_GROUP("undefined-<wbr class="">trap", UndefinedTrap, Undefined)<br class="">
<br class="">
Modified: cfe/trunk/lib/CodeGen/CGExpr.<wbr class="">cpp<br class="">
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=304459&r1=304458&r2=304459&view=diff" rel="noreferrer" target="_blank" class="">http://llvm.org/viewvc/llvm-<wbr class="">project/cfe/trunk/lib/CodeGen/<wbr class="">CGExpr.cpp?rev=304459&r1=<wbr class="">304458&r2=304459&view=diff</a><br class="">
==============================<wbr class="">==============================<wbr class="">==================<br class="">
--- cfe/trunk/lib/CodeGen/CGExpr.<wbr class="">cpp (original)<br class="">
+++ cfe/trunk/lib/CodeGen/CGExpr.<wbr class="">cpp Thu Jun 1 14:22:18 2017<br class="">
@@ -3002,9 +3002,10 @@ static llvm::Value *emitArraySubscriptGE<br class="">
llvm::Value *ptr,<br class="">
ArrayRef<llvm::Value*> indices,<br class="">
bool inbounds,<br class="">
+ SourceLocation loc,<br class="">
const llvm::Twine &name = "arrayidx") {<br class="">
if (inbounds) {<br class="">
- return CGF.Builder.CreateInBoundsGEP(<wbr class="">ptr, indices, name);<br class="">
+ return CGF.EmitCheckedInBoundsGEP(<wbr class="">ptr, indices, loc, name);<br class="">
} else {<br class="">
return CGF.Builder.CreateGEP(ptr, indices, name);<br class="">
}<br class="">
@@ -3035,8 +3036,9 @@ static QualType getFixedSizeElementType(<br class="">
}<br class="">
<br class="">
static Address emitArraySubscriptGEP(<wbr class="">CodeGenFunction &CGF, Address addr,<br class="">
- ArrayRef<llvm::Value*> indices,<br class="">
+ ArrayRef<llvm::Value *> indices,<br class="">
QualType eltType, bool inbounds,<br class="">
+ SourceLocation loc,<br class="">
const llvm::Twine &name = "arrayidx") {<br class="">
// All the indices except that last must be zero.<br class="">
#ifndef NDEBUG<br class="">
@@ -3057,7 +3059,7 @@ static Address emitArraySubscriptGEP(Cod<br class="">
getArrayElementAlign(addr.<wbr class="">getAlignment(), indices.back(), eltSize);<br class="">
<br class="">
llvm::Value *eltPtr =<br class="">
- emitArraySubscriptGEP(CGF, addr.getPointer(), indices, inbounds, name);<br class="">
+ emitArraySubscriptGEP(CGF, addr.getPointer(), indices, inbounds, loc, name);<br class="">
return Address(eltPtr, eltAlign);<br class="">
}<br class="">
<br class="">
@@ -3110,7 +3112,8 @@ LValue CodeGenFunction::<wbr class="">EmitArraySubscri<br class="">
Address Addr = EmitExtVectorElementLValue(LV)<wbr class="">;<br class="">
<br class="">
QualType EltType = LV.getType()->castAs<<wbr class="">VectorType>()->getElementType(<wbr class="">);<br class="">
- Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true);<br class="">
+ Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true,<br class="">
+ E->getExprLoc());<br class="">
return MakeAddrLValue(Addr, EltType, LV.getBaseInfo());<br class="">
}<br class="">
<br class="">
@@ -3138,7 +3141,8 @@ LValue CodeGenFunction::<wbr class="">EmitArraySubscri<br class="">
}<br class="">
<br class="">
Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(),<br class="">
- !getLangOpts().<wbr class="">isSignedOverflowDefined());<br class="">
+ !getLangOpts().<wbr class="">isSignedOverflowDefined(),<br class="">
+ E->getExprLoc());<br class="">
<br class="">
} else if (const ObjCObjectType *OIT = E->getType()->getAs<<wbr class="">ObjCObjectType>()){<br class="">
// Indexing over an interface, as in "NSString *P; P[4];"<br class="">
@@ -3163,8 +3167,8 @@ LValue CodeGenFunction::<wbr class="">EmitArraySubscri<br class="">
// Do the GEP.<br class="">
CharUnits EltAlign =<br class="">
getArrayElementAlign(Addr.<wbr class="">getAlignment(), Idx, InterfaceSize);<br class="">
- llvm::Value *EltPtr =<br class="">
- emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false);<br class="">
+ llvm::Value *EltPtr = emitArraySubscriptGEP(<br class="">
+ *this, Addr.getPointer(), ScaledIdx, false, E->getExprLoc());<br class="">
Addr = Address(EltPtr, EltAlign);<br class="">
<br class="">
// Cast back.<br class="">
@@ -3189,14 +3193,16 @@ LValue CodeGenFunction::<wbr class="">EmitArraySubscri<br class="">
Addr = emitArraySubscriptGEP(*this, ArrayLV.getAddress(),<br class="">
{CGM.getSize(CharUnits::Zero()<wbr class="">), Idx},<br class="">
E->getType(),<br class="">
- !getLangOpts().<wbr class="">isSignedOverflowDefined());<br class="">
+ !getLangOpts().<wbr class="">isSignedOverflowDefined(),<br class="">
+ E->getExprLoc());<br class="">
BaseInfo = ArrayLV.getBaseInfo();<br class="">
} else {<br class="">
// The base must be a pointer; emit it with an estimate of its alignment.<br class="">
Addr = EmitPointerWithAlignment(E-><wbr class="">getBase(), &BaseInfo);<br class="">
auto *Idx = EmitIdxAfterBase(/*Promote*/<wbr class="">true);<br class="">
Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),<br class="">
- !getLangOpts().<wbr class="">isSignedOverflowDefined());<br class="">
+ !getLangOpts().<wbr class="">isSignedOverflowDefined(),<br class="">
+ E->getExprLoc());<br class="">
}<br class="">
<br class="">
LValue LV = MakeAddrLValue(Addr, E->getType(), BaseInfo);<br class="">
@@ -3368,7 +3374,8 @@ LValue CodeGenFunction::<wbr class="">EmitOMPArraySect<br class="">
else<br class="">
Idx = Builder.CreateNSWMul(Idx, NumElements);<br class="">
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(),<br class="">
- !getLangOpts().<wbr class="">isSignedOverflowDefined());<br class="">
+ !getLangOpts().<wbr class="">isSignedOverflowDefined(),<br class="">
+ E->getExprLoc());<br class="">
} else if (const Expr *Array = isSimpleArrayDecayOperand(E-><wbr class="">getBase())) {<br class="">
// If this is A[i] where A is an array, the frontend will have decayed the<br class="">
// base to be a ArrayToPointerDecay implicit cast. While correct, it is<br class="">
@@ -3387,13 +3394,15 @@ LValue CodeGenFunction::<wbr class="">EmitOMPArraySect<br class="">
// Propagate the alignment from the array itself to the result.<br class="">
EltPtr = emitArraySubscriptGEP(<br class="">
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()<wbr class="">), Idx},<br class="">
- ResultExprTy, !getLangOpts().<wbr class="">isSignedOverflowDefined());<br class="">
+ ResultExprTy, !getLangOpts().<wbr class="">isSignedOverflowDefined(),<br class="">
+ E->getExprLoc());<br class="">
BaseInfo = ArrayLV.getBaseInfo();<br class="">
} else {<br class="">
Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo,<br class="">
BaseTy, ResultExprTy, IsLowerBound);<br class="">
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy,<br class="">
- !getLangOpts().<wbr class="">isSignedOverflowDefined());<br class="">
+ !getLangOpts().<wbr class="">isSignedOverflowDefined(),<br class="">
+ E->getExprLoc());<br class="">
}<br class="">
<br class="">
return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo);<br class="">
<br class="">
Modified: cfe/trunk/lib/CodeGen/<wbr class="">CGExprScalar.cpp<br class="">
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=304459&r1=304458&r2=304459&view=diff" rel="noreferrer" target="_blank" class="">http://llvm.org/viewvc/llvm-<wbr class="">project/cfe/trunk/lib/CodeGen/<wbr class="">CGExprScalar.cpp?rev=304459&<wbr class="">r1=304458&r2=304459&view=diff</a><br class="">
==============================<wbr class="">==============================<wbr class="">==================<br class="">
--- cfe/trunk/lib/CodeGen/<wbr class="">CGExprScalar.cpp (original)<br class="">
+++ cfe/trunk/lib/CodeGen/<wbr class="">CGExprScalar.cpp Thu Jun 1 14:22:18 2017<br class="">
@@ -30,6 +30,7 @@<br class="">
#include "llvm/IR/Constants.h"<br class="">
#include "llvm/IR/DataLayout.h"<br class="">
#include "llvm/IR/Function.h"<br class="">
+#include "llvm/IR/<wbr class="">GetElementPtrTypeIterator.h"<br class="">
#include "llvm/IR/GlobalVariable.h"<br class="">
#include "llvm/IR/Intrinsics.h"<br class="">
#include "llvm/IR/Module.h"<br class="">
@@ -44,6 +45,43 @@ using llvm::Value;<br class="">
//===-------------------------<wbr class="">------------------------------<wbr class="">---------------===//<br class="">
<br class="">
namespace {<br class="">
+<br class="">
+/// Determine whether the given binary operation may overflow.<br class="">
+/// Sets \p Result to the value of the operation for BO_Add, BO_Sub, BO_Mul,<br class="">
+/// and signed BO_{Div,Rem}. For these opcodes, and for unsigned BO_{Div,Rem},<br class="">
+/// the returned overflow check is precise. The returned value is 'true' for<br class="">
+/// all other opcodes, to be conservative.<br class="">
+bool mayHaveIntegerOverflow(llvm::<wbr class="">ConstantInt *LHS, llvm::ConstantInt *RHS,<br class="">
+ BinaryOperator::Opcode Opcode, bool Signed,<br class="">
+ llvm::APInt &Result) {<br class="">
+ // Assume overflow is possible, unless we can prove otherwise.<br class="">
+ bool Overflow = true;<br class="">
+ const auto &LHSAP = LHS->getValue();<br class="">
+ const auto &RHSAP = RHS->getValue();<br class="">
+ if (Opcode == BO_Add) {<br class="">
+ if (Signed)<br class="">
+ Result = LHSAP.sadd_ov(RHSAP, Overflow);<br class="">
+ else<br class="">
+ Result = LHSAP.uadd_ov(RHSAP, Overflow);<br class="">
+ } else if (Opcode == BO_Sub) {<br class="">
+ if (Signed)<br class="">
+ Result = LHSAP.ssub_ov(RHSAP, Overflow);<br class="">
+ else<br class="">
+ Result = LHSAP.usub_ov(RHSAP, Overflow);<br class="">
+ } else if (Opcode == BO_Mul) {<br class="">
+ if (Signed)<br class="">
+ Result = LHSAP.smul_ov(RHSAP, Overflow);<br class="">
+ else<br class="">
+ Result = LHSAP.umul_ov(RHSAP, Overflow);<br class="">
+ } else if (Opcode == BO_Div || Opcode == BO_Rem) {<br class="">
+ if (Signed && !RHS->isZero())<br class="">
+ Result = LHSAP.sdiv_ov(RHSAP, Overflow);<br class="">
+ else<br class="">
+ return false;<br class="">
+ }<br class="">
+ return Overflow;<br class="">
+}<br class="">
+<br class="">
struct BinOpInfo {<br class="">
Value *LHS;<br class="">
Value *RHS;<br class="">
@@ -55,37 +93,14 @@ struct BinOpInfo {<br class="">
/// Check if the binop can result in integer overflow.<br class="">
bool mayHaveIntegerOverflow() const {<br class="">
// Without constant input, we can't rule out overflow.<br class="">
- const auto *LHSCI = dyn_cast<llvm::ConstantInt>(<wbr class="">LHS);<br class="">
- const auto *RHSCI = dyn_cast<llvm::ConstantInt>(<wbr class="">RHS);<br class="">
+ auto *LHSCI = dyn_cast<llvm::ConstantInt>(<wbr class="">LHS);<br class="">
+ auto *RHSCI = dyn_cast<llvm::ConstantInt>(<wbr class="">RHS);<br class="">
if (!LHSCI || !RHSCI)<br class="">
return true;<br class="">
<br class="">
- // Assume overflow is possible, unless we can prove otherwise.<br class="">
- bool Overflow = true;<br class="">
- const auto &LHSAP = LHSCI->getValue();<br class="">
- const auto &RHSAP = RHSCI->getValue();<br class="">
- if (Opcode == BO_Add) {<br class="">
- if (Ty-><wbr class="">hasSignedIntegerRepresentation<wbr class="">())<br class="">
- (void)LHSAP.sadd_ov(RHSAP, Overflow);<br class="">
- else<br class="">
- (void)LHSAP.uadd_ov(RHSAP, Overflow);<br class="">
- } else if (Opcode == BO_Sub) {<br class="">
- if (Ty-><wbr class="">hasSignedIntegerRepresentation<wbr class="">())<br class="">
- (void)LHSAP.ssub_ov(RHSAP, Overflow);<br class="">
- else<br class="">
- (void)LHSAP.usub_ov(RHSAP, Overflow);<br class="">
- } else if (Opcode == BO_Mul) {<br class="">
- if (Ty-><wbr class="">hasSignedIntegerRepresentation<wbr class="">())<br class="">
- (void)LHSAP.smul_ov(RHSAP, Overflow);<br class="">
- else<br class="">
- (void)LHSAP.umul_ov(RHSAP, Overflow);<br class="">
- } else if (Opcode == BO_Div || Opcode == BO_Rem) {<br class="">
- if (Ty-><wbr class="">hasSignedIntegerRepresentation<wbr class="">() && !RHSCI->isZero())<br class="">
- (void)LHSAP.sdiv_ov(RHSAP, Overflow);<br class="">
- else<br class="">
- return false;<br class="">
- }<br class="">
- return Overflow;<br class="">
+ llvm::APInt Result;<br class="">
+ return ::mayHaveIntegerOverflow(<br class="">
+ LHSCI, RHSCI, Opcode, Ty-><wbr class="">hasSignedIntegerRepresentation<wbr class="">(), Result);<br class="">
}<br class="">
<br class="">
/// Check if the binop computes a division or a remainder.<br class="">
@@ -1925,7 +1940,8 @@ ScalarExprEmitter::<wbr class="">EmitScalarPrePostIncD<br class="">
if (CGF.getLangOpts().<wbr class="">isSignedOverflowDefined())<br class="">
value = Builder.CreateGEP(value, numElts, "vla.inc");<br class="">
else<br class="">
- value = Builder.CreateInBoundsGEP(<wbr class="">value, numElts, "vla.inc");<br class="">
+ value = CGF.EmitCheckedInBoundsGEP(<wbr class="">value, numElts, E->getExprLoc(),<br class="">
+ "vla.inc");<br class="">
<br class="">
// Arithmetic on function pointers (!) is just +-1.<br class="">
} else if (type->isFunctionType()) {<br class="">
@@ -1935,7 +1951,8 @@ ScalarExprEmitter::<wbr class="">EmitScalarPrePostIncD<br class="">
if (CGF.getLangOpts().<wbr class="">isSignedOverflowDefined())<br class="">
value = Builder.CreateGEP(value, amt, "incdec.funcptr");<br class="">
else<br class="">
- value = Builder.CreateInBoundsGEP(<wbr class="">value, amt, "incdec.funcptr");<br class="">
+ value = CGF.EmitCheckedInBoundsGEP(<wbr class="">value, amt, E->getExprLoc(),<br class="">
+ "incdec.funcptr");<br class="">
value = Builder.CreateBitCast(value, input->getType());<br class="">
<br class="">
// For everything else, we can just do a simple increment.<br class="">
@@ -1944,7 +1961,8 @@ ScalarExprEmitter::<wbr class="">EmitScalarPrePostIncD<br class="">
if (CGF.getLangOpts().<wbr class="">isSignedOverflowDefined())<br class="">
value = Builder.CreateGEP(value, amt, "incdec.ptr");<br class="">
else<br class="">
- value = Builder.CreateInBoundsGEP(<wbr class="">value, amt, "incdec.ptr");<br class="">
+ value = CGF.EmitCheckedInBoundsGEP(<wbr class="">value, amt, E->getExprLoc(),<br class="">
+ "incdec.ptr");<br class="">
}<br class="">
<br class="">
// Vector increment/decrement.<br class="">
@@ -2025,7 +2043,8 @@ ScalarExprEmitter::<wbr class="">EmitScalarPrePostIncD<br class="">
if (CGF.getLangOpts().<wbr class="">isSignedOverflowDefined())<br class="">
value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");<br class="">
else<br class="">
- value = Builder.CreateInBoundsGEP(<wbr class="">value, sizeValue, "incdec.objptr");<br class="">
+ value = CGF.EmitCheckedInBoundsGEP(<wbr class="">value, sizeValue, E->getExprLoc(),<br class="">
+ "incdec.objptr");<br class="">
value = Builder.CreateBitCast(value, input->getType());<br class="">
}<br class="">
<br class="">
@@ -2692,7 +2711,8 @@ static Value *emitPointerArithmetic(Code<br class="">
pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr");<br class="">
} else {<br class="">
index = CGF.Builder.CreateNSWMul(<wbr class="">index, numElements, "vla.index");<br class="">
- pointer = CGF.Builder.CreateInBoundsGEP(<wbr class="">pointer, index, "add.ptr");<br class="">
+ pointer = CGF.EmitCheckedInBoundsGEP(<wbr class="">pointer, index, op.E->getExprLoc(),<br class="">
+ "add.ptr");<br class="">
}<br class="">
return pointer;<br class="">
}<br class="">
@@ -2709,7 +2729,8 @@ static Value *emitPointerArithmetic(Code<br class="">
if (CGF.getLangOpts().<wbr class="">isSignedOverflowDefined())<br class="">
return CGF.Builder.CreateGEP(pointer, index, "add.ptr");<br class="">
<br class="">
- return CGF.Builder.CreateInBoundsGEP(<wbr class="">pointer, index, "add.ptr");<br class="">
+ return CGF.EmitCheckedInBoundsGEP(<wbr class="">pointer, index, op.E->getExprLoc(),<br class="">
+ "add.ptr");<br class="">
}<br class="">
<br class="">
// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and<br class="">
@@ -3824,3 +3845,124 @@ LValue CodeGenFunction::<wbr class="">EmitCompoundAssi<br class="">
<br class="">
llvm_unreachable("Unhandled compound assignment operator");<br class="">
}<br class="">
+<br class="">
+Value *CodeGenFunction::<wbr class="">EmitCheckedInBoundsGEP(Value *Ptr,<br class="">
+ ArrayRef<Value *> IdxList,<br class="">
+ SourceLocation Loc,<br class="">
+ const Twine &Name) {<br class="">
+ Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);<br class="">
+<br class="">
+ // If the pointer overflow sanitizer isn't enabled, do nothing.<br class="">
+ if (!SanOpts.has(SanitizerKind::<wbr class="">PointerOverflow))<br class="">
+ return GEPVal;<br class="">
+<br class="">
+ // If the GEP has already been reduced to a constant, leave it be.<br class="">
+ if (isa<llvm::Constant>(GEPVal))<br class="">
+ return GEPVal;<br class="">
+<br class="">
+ // Only check for overflows in the default address space.<br class="">
+ if (GEPVal->getType()-><wbr class="">getPointerAddressSpace())<br class="">
+ return GEPVal;<br class="">
+<br class="">
+ auto *GEP = cast<llvm::GEPOperator>(<wbr class="">GEPVal);<br class="">
+ assert(GEP->isInBounds() && "Expected inbounds GEP");<br class="">
+<br class="">
+ SanitizerScope SanScope(this);<br class="">
+ auto &VMContext = getLLVMContext();<br class="">
+ const auto &DL = CGM.getDataLayout();<br class="">
+ auto *IntPtrTy = DL.getIntPtrType(GEP-><wbr class="">getPointerOperandType());<br class="">
+<br class="">
+ // Grab references to the signed add/mul overflow intrinsics for intptr_t.<br class="">
+ auto *Zero = llvm::ConstantInt::<wbr class="">getNullValue(IntPtrTy);<br class="">
+ auto *SAddIntrinsic =<br class="">
+ CGM.getIntrinsic(llvm::<wbr class="">Intrinsic::sadd_with_overflow, IntPtrTy);<br class="">
+ auto *SMulIntrinsic =<br class="">
+ CGM.getIntrinsic(llvm::<wbr class="">Intrinsic::smul_with_overflow, IntPtrTy);<br class="">
+<br class="">
+ // The total (signed) byte offset for the GEP.<br class="">
+ llvm::Value *TotalOffset = nullptr;<br class="">
+ // The offset overflow flag - true if the total offset overflows.<br class="">
+ llvm::Value *OffsetOverflows = Builder.getFalse();<br class="">
+<br class="">
+ /// Return the result of the given binary operation.<br class="">
+ auto eval = [&](BinaryOperator::Opcode Opcode, llvm::Value *LHS,<br class="">
+ llvm::Value *RHS) -> llvm::Value * {<br class="">
+ assert(Opcode == BO_Add || Opcode == BO_Mul && "Can't eval binop");<br class="">
+<br class="">
+ // If the operands are constants, return a constant result.<br class="">
+ if (auto *LHSCI = dyn_cast<llvm::ConstantInt>(<wbr class="">LHS)) {<br class="">
+ if (auto *RHSCI = dyn_cast<llvm::ConstantInt>(<wbr class="">RHS)) {<br class="">
+ llvm::APInt N;<br class="">
+ bool HasOverflow = mayHaveIntegerOverflow(LHSCI, RHSCI, Opcode,<br class="">
+ /*Signed=*/true, N);<br class="">
+ if (HasOverflow)<br class="">
+ OffsetOverflows = Builder.getTrue();<br class="">
+ return llvm::ConstantInt::get(<wbr class="">VMContext, N);<br class="">
+ }<br class="">
+ }<br class="">
+<br class="">
+ // Otherwise, compute the result with checked arithmetic.<br class="">
+ auto *ResultAndOverflow = Builder.CreateCall(<br class="">
+ (Opcode == BO_Add) ? SAddIntrinsic : SMulIntrinsic, {LHS, RHS});<br class="">
+ OffsetOverflows = Builder.CreateOr(<br class="">
+ OffsetOverflows, Builder.CreateExtractValue(<wbr class="">ResultAndOverflow, 1));<br class="">
+ return Builder.CreateExtractValue(<wbr class="">ResultAndOverflow, 0);<br class="">
+ };<br class="">
+<br class="">
+ // Determine the total byte offset by looking at each GEP operand.<br class="">
+ for (auto GTI = llvm::gep_type_begin(GEP), GTE = llvm::gep_type_end(GEP);<br class="">
+ GTI != GTE; ++GTI) {<br class="">
+ llvm::Value *LocalOffset;<br class="">
+ auto *Index = GTI.getOperand();<br class="">
+ // Compute the local offset contributed by this indexing step:<br class="">
+ if (auto *STy = GTI.getStructTypeOrNull()) {<br class="">
+ // For struct indexing, the local offset is the byte position of the<br class="">
+ // specified field.<br class="">
+ unsigned FieldNo = cast<llvm::ConstantInt>(Index)<wbr class="">->getZExtValue();<br class="">
+ LocalOffset = llvm::ConstantInt::get(<br class="">
+ IntPtrTy, DL.getStructLayout(STy)-><wbr class="">getElementOffset(FieldNo));<br class="">
+ } else {<br class="">
+ // Otherwise this is array-like indexing. The local offset is the index<br class="">
+ // multiplied by the element size.<br class="">
+ auto *ElementSize = llvm::ConstantInt::get(<br class="">
+ IntPtrTy, DL.getTypeAllocSize(GTI.<wbr class="">getIndexedType()));<br class="">
+ auto *IndexS = Builder.CreateIntCast(Index, IntPtrTy, /*isSigned=*/true);<br class="">
+ LocalOffset = eval(BO_Mul, ElementSize, IndexS);<br class="">
+ }<br class="">
+<br class="">
+ // If this is the first offset, set it as the total offset. Otherwise, add<br class="">
+ // the local offset into the running total.<br class="">
+ if (!TotalOffset || TotalOffset == Zero)<br class="">
+ TotalOffset = LocalOffset;<br class="">
+ else<br class="">
+ TotalOffset = eval(BO_Add, TotalOffset, LocalOffset);<br class="">
+ }<br class="">
+<br class="">
+ // Common case: if the total offset is zero, don't emit a check.<br class="">
+ if (TotalOffset == Zero)<br class="">
+ return GEPVal;<br class="">
+<br class="">
+ // Now that we've computed the total offset, add it to the base pointer (with<br class="">
+ // wrapping semantics).<br class="">
+ auto *IntPtr = Builder.CreatePtrToInt(GEP-><wbr class="">getPointerOperand(), IntPtrTy);<br class="">
+ auto *ComputedGEP = Builder.CreateAdd(IntPtr, TotalOffset);<br class="">
+<br class="">
+ // The GEP is valid if:<br class="">
+ // 1) The total offset doesn't overflow, and<br class="">
+ // 2) The sign of the difference between the computed address and the base<br class="">
+ // pointer matches the sign of the total offset.<br class="">
+ llvm::Value *PosOrZeroValid = Builder.CreateICmpUGE(<wbr class="">ComputedGEP, IntPtr);<br class="">
+ llvm::Value *NegValid = Builder.CreateICmpULT(<wbr class="">ComputedGEP, IntPtr);<br class="">
+ auto *PosOrZeroOffset = Builder.CreateICmpSGE(<wbr class="">TotalOffset, Zero);<br class="">
+ llvm::Value *ValidGEP = Builder.CreateAnd(<br class="">
+ Builder.CreateNot(<wbr class="">OffsetOverflows),<br class="">
+ Builder.CreateSelect(<wbr class="">PosOrZeroOffset, PosOrZeroValid, NegValid));<br class="">
+<br class="">
+ llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)}<wbr class="">;<br class="">
+ // Pass the computed GEP to the runtime to avoid emitting poisoned arguments.<br class="">
+ llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};<br class="">
+ EmitCheck(std::make_pair(<wbr class="">ValidGEP, SanitizerKind::<wbr class="">PointerOverflow),<br class="">
+ SanitizerHandler::<wbr class="">PointerOverflow, StaticArgs, DynamicArgs);<br class="">
+<br class="">
+ return GEPVal;<br class="">
+}<br class="">
<br class="">
Modified: cfe/trunk/lib/CodeGen/<wbr class="">CodeGenFunction.h<br class="">
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=304459&r1=304458&r2=304459&view=diff" rel="noreferrer" target="_blank" class="">http://llvm.org/viewvc/llvm-<wbr class="">project/cfe/trunk/lib/CodeGen/<wbr class="">CodeGenFunction.h?rev=304459&<wbr class="">r1=304458&r2=304459&view=diff</a><br class="">
==============================<wbr class="">==============================<wbr class="">==================<br class="">
--- cfe/trunk/lib/CodeGen/<wbr class="">CodeGenFunction.h (original)<br class="">
+++ cfe/trunk/lib/CodeGen/<wbr class="">CodeGenFunction.h Thu Jun 1 14:22:18 2017<br class="">
@@ -120,6 +120,7 @@ enum TypeEvaluationKind {<br class="">
SANITIZER_CHECK(NonnullArg, nonnull_arg, 0) \<br class="">
SANITIZER_CHECK(NonnullReturn, nonnull_return, 0) \<br class="">
SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0) \<br class="">
+ SANITIZER_CHECK(<wbr class="">PointerOverflow, pointer_overflow, 0) \<br class="">
SANITIZER_CHECK(<wbr class="">ShiftOutOfBounds, shift_out_of_bounds, 0) \<br class="">
SANITIZER_CHECK(SubOverflow, sub_overflow, 0) \<br class="">
SANITIZER_CHECK(TypeMismatch, type_mismatch, 1) \<br class="">
@@ -3551,6 +3552,13 @@ public:<br class="">
/// nonnull, if \p LHS is marked _Nonnull.<br class="">
void EmitNullabilityCheck(LValue LHS, llvm::Value *RHS, SourceLocation Loc);<br class="">
<br class="">
+ /// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to<br class="">
+ /// detect undefined behavior when the pointer overflow sanitizer is enabled.<br class="">
+ llvm::Value *EmitCheckedInBoundsGEP(llvm::<wbr class="">Value *Ptr,<br class="">
+ ArrayRef<llvm::Value *> IdxList,<br class="">
+ SourceLocation Loc,<br class="">
+ const Twine &Name = "");<br class="">
+<br class="">
/// \brief Emit a description of a type in a format suitable for passing to<br class="">
/// a runtime sanitizer handler.<br class="">
llvm::Constant *EmitCheckTypeDescriptor(<wbr class="">QualType T);<br class="">
<br class="">
Added: cfe/trunk/test/CodeGen/ubsan-<wbr class="">pointer-overflow.m<br class="">
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/ubsan-pointer-overflow.m?rev=304459&view=auto" rel="noreferrer" target="_blank" class="">http://llvm.org/viewvc/llvm-<wbr class="">project/cfe/trunk/test/<wbr class="">CodeGen/ubsan-pointer-<wbr class="">overflow.m?rev=304459&view=<wbr class="">auto</a><br class="">
==============================<wbr class="">==============================<wbr class="">==================<br class="">
--- cfe/trunk/test/CodeGen/ubsan-<wbr class="">pointer-overflow.m (added)<br class="">
+++ cfe/trunk/test/CodeGen/ubsan-<wbr class="">pointer-overflow.m Thu Jun 1 14:22:18 2017<br class="">
@@ -0,0 +1,171 @@<br class="">
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -w -emit-llvm -o - %s -fsanitize=pointer-overflow | FileCheck %s<br class="">
+<br class="">
+// CHECK-LABEL: define void @unary_arith<br class="">
+void unary_arith(char *p) {<br class="">
+ // CHECK: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize<br class="">
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 1, !nosanitize<br class="">
+ // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize<br class="">
+ // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize<br class="">
+ // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 true, i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize<br class="">
+ // CHECK-NEXT: [[VALID:%.*]] = and i1 true, [[DIFFVALID]], !nosanitize<br class="">
+ // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize<br class="">
+ ++p;<br class="">
+<br class="">
+ // CHECK: ptrtoint i8* {{.*}} to i64, !nosanitize<br class="">
+ // CHECK-NEXT: add i64 {{.*}}, -1, !nosanitize<br class="">
+ // CHECK: select i1 false{{.*}}, !nosanitize<br class="">
+ // CHECK-NEXT: and i1 true{{.*}}, !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+ --p;<br class="">
+<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+ p++;<br class="">
+<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+ p--;<br class="">
+}<br class="">
+<br class="">
+// CHECK-LABEL: define void @binary_arith<br class="">
+void binary_arith(char *p, int i) {<br class="">
+ // CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(<wbr class="">i64 1, i64 %{{.*}}), !nosanitize<br class="">
+ // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize<br class="">
+ // CHECK-NEXT: [[OFFSETOFLOW:%.*]] = or i1 false, [[SMULOFLOW]], !nosanitize<br class="">
+ // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize<br class="">
+ // CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize<br class="">
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize<br class="">
+ // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize<br class="">
+ // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize<br class="">
+ // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize<br class="">
+ // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[OFFSETOFLOW]], true, !nosanitize<br class="">
+ // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize<br class="">
+ // CHECK-NEXT: [[VALID:%.*]] = and i1 [[OFFSETVALID]], [[DIFFVALID]], !nosanitize<br class="">
+ // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize<br class="">
+ p + i;<br class="">
+<br class="">
+ // CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}}<br class="">
+ // CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]]<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+ p - i;<br class="">
+}<br class="">
+<br class="">
+// CHECK-LABEL: define void @fixed_len_array<br class="">
+void fixed_len_array(int k) {<br class="">
+ // CHECK: getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]* [[ARR:%.*]], i64 0, i64 [[IDXPROM:%.*]]<br class="">
+ // CHECK-NEXT: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(<wbr class="">i64 40, i64 [[IDXPROM]]), !nosanitize<br class="">
+ // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize<br class="">
+ // CHECK-NEXT: [[OFFSETOFLOW:%.*]] = or i1 false, [[SMULOFLOW]], !nosanitize<br class="">
+ // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize<br class="">
+ // CHECK-NEXT: [[BASE:%.*]] = ptrtoint [10 x [10 x i32]]* [[ARR]] to i64, !nosanitize<br class="">
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize<br class="">
+ // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize<br class="">
+ // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize<br class="">
+ // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize<br class="">
+ // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[OFFSETOFLOW]], true, !nosanitize<br class="">
+ // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize<br class="">
+ // CHECK-NEXT: [[VALID:%.*]] = and i1 [[OFFSETVALID]], [[DIFFVALID]], !nosanitize<br class="">
+ // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize<br class="">
+<br class="">
+ // CHECK: getelementptr inbounds [10 x i32], [10 x i32]* {{.*}}, i64 0, i64 [[IDXPROM1:%.*]]<br class="">
+ // CHECK-NEXT: @llvm.smul.with.overflow.i64(<wbr class="">i64 4, i64 [[IDXPROM1]]), !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+<br class="">
+ int arr[10][10];<br class="">
+ arr[k][k];<br class="">
+}<br class="">
+<br class="">
+// CHECK-LABEL: define void @variable_len_array<br class="">
+void variable_len_array(int n, int k) {<br class="">
+ // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]]<br class="">
+ // CHECK-NEXT: @llvm.smul.with.overflow.i64(<wbr class="">i64 4, i64 [[IDXPROM]]), !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+<br class="">
+ // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM1:%.*]]<br class="">
+ // CHECK-NEXT: @llvm.smul.with.overflow.i64(<wbr class="">i64 4, i64 [[IDXPROM1]]), !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+<br class="">
+ int arr[n][n];<br class="">
+ arr[k][k];<br class="">
+}<br class="">
+<br class="">
+// CHECK-LABEL: define void @pointer_array<br class="">
+void pointer_array(int **arr, int k) {<br class="">
+ // CHECK: @llvm.smul.with.overflow.i64(<wbr class="">i64 8, i64 {{.*}}), !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+<br class="">
+ // CHECK: @llvm.smul.with.overflow.i64(<wbr class="">i64 4, i64 {{.*}}), !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+<br class="">
+ arr[k][k];<br class="">
+}<br class="">
+<br class="">
+struct S1 {<br class="">
+ int pad1;<br class="">
+ union {<br class="">
+ char leaf;<br class="">
+ struct S1 *link;<br class="">
+ } u;<br class="">
+ struct S1 *arr;<br class="">
+};<br class="">
+<br class="">
+// TODO: Currently, structure GEPs are not checked, so there are several<br class="">
+// potentially unsafe GEPs here which we don't instrument.<br class="">
+//<br class="">
+// CHECK-LABEL: define void @struct_index<br class="">
+void struct_index(struct S1 *p) {<br class="">
+ // CHECK: getelementptr inbounds %struct.S1, %struct.S1* [[P:%.*]], i64 10<br class="">
+ // CHECK-NEXT: [[BASE:%.*]] = ptrtoint %struct.S1* [[P]] to i64, !nosanitize<br class="">
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 240, !nosanitize<br class="">
+ // CHECK: @__ubsan_handle_pointer_<wbr class="">overflow{{.*}} i64 [[BASE]], i64 [[COMPGEP]]) {{.*}}, !nosanitize<br class="">
+<br class="">
+ // CHECK-NOT: @__ubsan_handle_pointer_<wbr class="">overflow<br class="">
+<br class="">
+ p->arr[10].u.link->u.leaf;<br class="">
+}<br class="">
+<br class="">
+typedef void (*funcptr_t)(void);<br class="">
+<br class="">
+// CHECK-LABEL: define void @function_pointer_arith<br class="">
+void function_pointer_arith(<wbr class="">funcptr_t *p, int k) {<br class="">
+ // CHECK: add i64 {{.*}}, 8, !nosanitize<br class="">
+ // CHECK: @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+ ++p;<br class="">
+<br class="">
+ // CHECK: @llvm.smul.with.overflow.i64(<wbr class="">i64 8, i64 {{.*}}), !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+ p + k;<br class="">
+}<br class="">
+<br class="">
+// CHECK-LABEL: define void @variable_len_array_arith<br class="">
+void variable_len_array_arith(int n, int k) {<br class="">
+ int vla[n];<br class="">
+ int (*p)[n] = &vla;<br class="">
+<br class="">
+ // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[INC:%.*]]<br class="">
+ // CHECK: @llvm.smul.with.overflow.i64(<wbr class="">i64 4, i64 [[INC]]), !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+ ++p;<br class="">
+<br class="">
+ // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]]<br class="">
+ // CHECK: @llvm.smul.with.overflow.i64(<wbr class="">i64 4, i64 [[IDXPROM]]), !nosanitize<br class="">
+ // CHECK: call void @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+ p + k;<br class="">
+}<br class="">
+<br class="">
+// CHECK-LABEL: define void @objc_id<br class="">
+void objc_id(id *p) {<br class="">
+ // CHECK: add i64 {{.*}}, 8, !nosanitize<br class="">
+ // CHECK: @__ubsan_handle_pointer_<wbr class="">overflow{{.*}}<br class="">
+ p++;<br class="">
+}<br class="">
+<br class="">
+// CHECK-LABEL: define void @dont_emit_checks_for_no_op_<wbr class="">GEPs<br class="">
+// CHECK-NOT: __ubsan_handle_pointer_<wbr class="">overflow<br class="">
+void dont_emit_checks_for_no_op_<wbr class="">GEPs(char *p) {<br class="">
+ &p[0];<br class="">
+<br class="">
+ int arr[10][10];<br class="">
+ &arr[0][0];<br class="">
+}<br class="">
<br class="">
Modified: cfe/trunk/test/Driver/<wbr class="">fsanitize.c<br class="">
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/fsanitize.c?rev=304459&r1=304458&r2=304459&view=diff" rel="noreferrer" target="_blank" class="">http://llvm.org/viewvc/llvm-<wbr class="">project/cfe/trunk/test/Driver/<wbr class="">fsanitize.c?rev=304459&r1=<wbr class="">304458&r2=304459&view=diff</a><br class="">
==============================<wbr class="">==============================<wbr class="">==================<br class="">
--- cfe/trunk/test/Driver/<wbr class="">fsanitize.c (original)<br class="">
+++ cfe/trunk/test/Driver/<wbr class="">fsanitize.c Thu Jun 1 14:22:18 2017<br class="">
@@ -3,18 +3,18 @@<br class="">
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-undefined-trap-on-<wbr class="">error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-<wbr class="">UNDEFINED-TRAP<br class="">
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap -fsanitize-undefined-trap-on-<wbr class="">error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-<wbr class="">UNDEFINED-TRAP<br class="">
// RUN: %clang -target x86_64-linux-gnu -fsanitize-undefined-trap-on-<wbr class="">error -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-<wbr class="">UNDEFINED-TRAP<br class="">
-// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|shift-base|shift-<wbr class="">exponent|unreachable|return|<wbr class="">vla-bound|alignment|null|<wbr class="">object-size|float-cast-<wbr class="">overflow|array-bounds|enum|<wbr class="">bool|returns-nonnull-<wbr class="">attribute|nonnull-attribute|<wbr class="">function),?){18}"}}<br class="">
-// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,<wbr class="">array-bounds,bool,enum,float-<wbr class="">cast-overflow,float-divide-by-<wbr class="">zero,function,integer-divide-<wbr class="">by-zero,nonnull-attribute,<wbr class="">null,object-size,return,<wbr class="">returns-nonnull-attribute,<wbr class="">shift-base,shift-exponent,<wbr class="">signed-integer-overflow,<wbr class="">unreachable,vla-bound"<br class="">
-// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,<wbr class="">array-bounds,bool,enum,float-<wbr class="">cast-overflow,float-divide-by-<wbr class="">zero,function,integer-divide-<wbr class="">by-zero,nonnull-attribute,<wbr class="">null,object-size,return,<wbr class="">returns-nonnull-attribute,<wbr class="">shift-base,shift-exponent,<wbr class="">unreachable,vla-bound"<br class="">
+// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|shift-base|shift-<wbr class="">exponent|unreachable|return|<wbr class="">vla-bound|alignment|null|<wbr class="">object-size|pointer-overflow|<wbr class="">float-cast-overflow|array-<wbr class="">bounds|enum|bool|returns-<wbr class="">nonnull-attribute|nonnull-<wbr class="">attribute|function),?){19}"}}<br class="">
+// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,<wbr class="">array-bounds,bool,enum,float-<wbr class="">cast-overflow,float-divide-by-<wbr class="">zero,function,integer-divide-<wbr class="">by-zero,nonnull-attribute,<wbr class="">null,object-size,pointer-<wbr class="">overflow,return,returns-<wbr class="">nonnull-attribute,shift-base,<wbr class="">shift-exponent,signed-integer-<wbr class="">overflow,unreachable,vla-<wbr class="">bound"<br class="">
+// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,<wbr class="">array-bounds,bool,enum,float-<wbr class="">cast-overflow,float-divide-by-<wbr class="">zero,function,integer-divide-<wbr class="">by-zero,nonnull-attribute,<wbr class="">null,object-size,pointer-<wbr class="">overflow,return,returns-<wbr class="">nonnull-attribute,shift-base,<wbr class="">shift-exponent,unreachable,<wbr class="">vla-bound"<br class="">
<br class="">
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED<br class="">
-// CHECK-UNDEFINED: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|function|shift-base|<wbr class="">shift-exponent|unreachable|<wbr class="">return|vla-bound|alignment|<wbr class="">null|vptr|object-size|float-<wbr class="">cast-overflow|array-bounds|<wbr class="">enum|bool|returns-nonnull-<wbr class="">attribute|nonnull-attribute),?<wbr class="">){19}"}}<br class="">
+// CHECK-UNDEFINED: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|function|shift-base|<wbr class="">shift-exponent|unreachable|<wbr class="">return|vla-bound|alignment|<wbr class="">null|vptr|object-size|pointer-<wbr class="">overflow|float-cast-overflow|<wbr class="">array-bounds|enum|bool|<wbr class="">returns-nonnull-attribute|<wbr class="">nonnull-attribute),?){20}"}}<br class="">
<br class="">
// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-<wbr class="">UNDEFINED-DARWIN<br class="">
-// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|shift-base|shift-<wbr class="">exponent|unreachable|return|<wbr class="">vla-bound|alignment|null|<wbr class="">object-size|float-cast-<wbr class="">overflow|array-bounds|enum|<wbr class="">bool|returns-nonnull-<wbr class="">attribute|nonnull-attribute),?<wbr class="">){17}"}}<br class="">
+// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|shift-base|shift-<wbr class="">exponent|unreachable|return|<wbr class="">vla-bound|alignment|null|<wbr class="">object-size|pointer-overflow|<wbr class="">float-cast-overflow|array-<wbr class="">bounds|enum|bool|returns-<wbr class="">nonnull-attribute|nonnull-<wbr class="">attribute),?){18}"}}<br class="">
<br class="">
// RUN: %clang -target i386-unknown-openbsd -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-<wbr class="">UNDEFINED-OPENBSD<br class="">
-// CHECK-UNDEFINED-OPENBSD: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|shift-base|shift-<wbr class="">exponent|unreachable|return|<wbr class="">vla-bound|alignment|null|<wbr class="">object-size|float-cast-<wbr class="">overflow|array-bounds|enum|<wbr class="">bool|returns-nonnull-<wbr class="">attribute|nonnull-attribute),?<wbr class="">){17}"}}<br class="">
+// CHECK-UNDEFINED-OPENBSD: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|shift-base|shift-<wbr class="">exponent|unreachable|return|<wbr class="">vla-bound|alignment|null|<wbr class="">object-size|pointer-overflow|<wbr class="">float-cast-overflow|array-<wbr class="">bounds|enum|bool|returns-<wbr class="">nonnull-attribute|nonnull-<wbr class="">attribute),?){18}"}}<br class="">
<br class="">
// RUN: %clang -target i386-pc-win32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-<wbr class="">UNDEFINED-WIN --check-prefix=CHECK-<wbr class="">UNDEFINED-WIN32<br class="">
// RUN: %clang -target i386-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-<wbr class="">UNDEFINED-WIN --check-prefix=CHECK-<wbr class="">UNDEFINED-WIN32 --check-prefix=CHECK-<wbr class="">UNDEFINED-WIN-CXX<br class="">
@@ -23,7 +23,7 @@<br class="">
// CHECK-UNDEFINED-WIN32: "--dependent-lib={{[^"]*}}<wbr class="">ubsan_standalone-i386.lib"<br class="">
// CHECK-UNDEFINED-WIN64: "--dependent-lib={{[^"]*}}<wbr class="">ubsan_standalone-x86_64.lib"<br class="">
// CHECK-UNDEFINED-WIN-CXX: "--dependent-lib={{[^"]*}}<wbr class="">ubsan_standalone_cxx{{[^"]*}}.<wbr class="">lib"<br class="">
-// CHECK-UNDEFINED-WIN-SAME: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|shift-base|shift-<wbr class="">exponent|unreachable|return|<wbr class="">vla-bound|alignment|null|<wbr class="">object-size|float-cast-<wbr class="">overflow|array-bounds|enum|<wbr class="">bool|returns-nonnull-<wbr class="">attribute|nonnull-attribute),?<wbr class="">){17}"}}<br class="">
+// CHECK-UNDEFINED-WIN-SAME: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|shift-base|shift-<wbr class="">exponent|unreachable|return|<wbr class="">vla-bound|alignment|null|<wbr class="">object-size|pointer-overflow|<wbr class="">float-cast-overflow|array-<wbr class="">bounds|enum|bool|returns-<wbr class="">nonnull-attribute|nonnull-<wbr class="">attribute),?){18}"}}<br class="">
<br class="">
// RUN: %clang -target i386-pc-win32 -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-COVERAGE-<wbr class="">WIN32<br class="">
// CHECK-COVERAGE-WIN32: "--dependent-lib={{[^"]*}}<wbr class="">ubsan_standalone-i386.lib"<br class="">
@@ -43,7 +43,7 @@<br class="">
// CHECK-FNO-SANITIZE-ALL: "-fsanitize=thread"<br class="">
<br class="">
// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-sanitize=thread -fno-sanitize=float-cast-<wbr class="">overflow,vptr,bool,enum %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-<wbr class="">UNDEFINED<br class="">
-// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|function|shift-base|<wbr class="">shift-exponent|unreachable|<wbr class="">return|vla-bound|alignment|<wbr class="">null|object-size|array-bounds|<wbr class="">returns-nonnull-attribute|<wbr class="">nonnull-attribute),?){15}"}}<br class="">
+// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-<wbr class="">integer-overflow|integer-<wbr class="">divide-by-zero|float-divide-<wbr class="">by-zero|function|shift-base|<wbr class="">shift-exponent|unreachable|<wbr class="">return|vla-bound|alignment|<wbr class="">null|object-size|pointer-<wbr class="">overflow|array-bounds|returns-<wbr class="">nonnull-attribute|nonnull-<wbr class="">attribute),?){16}"}}<br class="">
<br class="">
// RUN: %clang -target x86_64-linux-gnu -fsanitize=shift -fno-sanitize=shift-base %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-<wbr class="">FSANITIZE-SHIFT-PARTIAL<br class="">
// CHECK-FSANITIZE-SHIFT-PARTIAL: "-fsanitize=shift-exponent"<br class="">
@@ -217,7 +217,7 @@<br class="">
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=<wbr class="">undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-<wbr class="">RECOVER-UBSAN<br class="">
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=thread -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-<wbr class="">RECOVER-UBSAN<br class="">
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=all -fno-sanitize-recover=<wbr class="">undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-<wbr class="">RECOVER-UBSAN<br class="">
-// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((<wbr class="">signed-integer-overflow|<wbr class="">integer-divide-by-zero|float-<wbr class="">divide-by-zero|function|shift-<wbr class="">base|shift-exponent|vla-bound|<wbr class="">alignment|null|vptr|object-<wbr class="">size|float-cast-overflow|<wbr class="">array-bounds|enum|bool|<wbr class="">returns-nonnull-attribute|<wbr class="">nonnull-attribute),?){17}"}}<br class="">
+// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((<wbr class="">signed-integer-overflow|<wbr class="">integer-divide-by-zero|float-<wbr class="">divide-by-zero|function|shift-<wbr class="">base|shift-exponent|vla-bound|<wbr class="">alignment|null|vptr|object-<wbr class="">size|pointer-overflow|float-<wbr class="">cast-overflow|array-bounds|<wbr class="">enum|bool|returns-nonnull-<wbr class="">attribute|nonnull-attribute),?<wbr class="">){18}"}}<br class="">
// CHECK-NO-RECOVER-UBSAN-NOT: sanitize-recover<br class="">
<br class="">
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=object-<wbr class="">size,shift-base -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-<wbr class="">RECOVER<br class="">
<br class="">
<br class="">
______________________________<wbr class="">_________________<br class="">
cfe-commits mailing list<br class="">
<a href="mailto:cfe-commits@lists.llvm.org" class="">cfe-commits@lists.llvm.org</a><br class="">
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank" class="">http://lists.llvm.org/cgi-bin/<wbr class="">mailman/listinfo/cfe-commits</a><br class="">
</blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></div></div>_______________________________________________<br class="">cfe-commits mailing list<br class=""><a href="mailto:cfe-commits@lists.llvm.org" class="">cfe-commits@lists.llvm.org</a><br class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits<br class=""></div></blockquote></div><br class=""></div></body></html>