Renamed the -fsanitize= flag value to "-fsanitize=returns-nonnull-attribute" 
and added the documentation.
Addressed reviewer's comments.

http://reviews.llvm.org/D4849

Files:
  projects/compiler-rt/lib/ubsan/ubsan_handlers.cc
  projects/compiler-rt/lib/ubsan/ubsan_handlers.h
  projects/compiler-rt/test/ubsan/TestCases/Misc/nonnull.cpp
  tools/clang/docs/UsersManual.rst
  tools/clang/include/clang/Basic/Sanitizers.def
  tools/clang/lib/CodeGen/CGCall.cpp
  tools/clang/test/CodeGen/catch-undef-behavior.c
  tools/clang/test/Driver/fsanitize.c
Index: tools/clang/test/Driver/fsanitize.c
===================================================================
--- tools/clang/test/Driver/fsanitize.c
+++ tools/clang/test/Driver/fsanitize.c
@@ -1,22 +1,22 @@
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
 // RUN: %clang -target x86_64-linux-gnu -fsanitize-undefined-trap-on-error -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
-// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool),?){14}"}}
+// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute),?){15}"}}
 // CHECK-UNDEFINED-TRAP: "-fsanitize-undefined-trap-on-error"
 
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
-// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool),?){16}"}}
+// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute),?){17}"}}
 
 // RUN: %clang -target x86_64-apple-darwin10 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-DARWIN
-// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool),?){15}"}}
+// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute),?){16}"}}
 
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER
 // CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|unsigned-integer-overflow|integer-divide-by-zero|shift),?){4}"}}
 
 // RUN: %clang -fsanitize=bounds -### -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=CHECK-BOUNDS
 // CHECK-BOUNDS: "-fsanitize={{((array-bounds|local-bounds),?){2}"}}
 
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-sanitize=thread -fno-sanitize=float-cast-overflow,vptr,bool,enum %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
-// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|object-size|array-bounds),?){12}"}}
+// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift|unreachable|return|vla-bound|alignment|null|object-size|array-bounds|returns-nonnull-attribute),?){13}"}}
 
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP-ON-ERROR-UNDEF
 // CHECK-UNDEFINED-TRAP-ON-ERROR-UNDEF: '-fsanitize=undefined' not allowed with '-fsanitize-undefined-trap-on-error'
Index: tools/clang/test/CodeGen/catch-undef-behavior.c
===================================================================
--- tools/clang/test/CodeGen/catch-undef-behavior.c
+++ tools/clang/test/CodeGen/catch-undef-behavior.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
-// RUN: %clang_cc1 -fsanitize-undefined-trap-on-error -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-TRAP
+// RUN: %clang_cc1 -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -fsanitize-undefined-trap-on-error -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool,returns-nonnull-attribute -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-TRAP
 // RUN: %clang_cc1 -fsanitize=null -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-NULL
 // RUN: %clang_cc1 -fsanitize=signed-integer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-OVERFLOW
 
@@ -432,6 +432,20 @@
   return *p;
 }
 
+// CHECK-LABEL: @ret_nonnull
+__attribute__((returns_nonnull))
+int *ret_nonnull(int *a) {
+  // CHECK: [[OK:%.*]] = icmp ne i32* {{.*}}, null
+  // CHECK: br i1 [[OK]]
+  // CHECK: call void @__ubsan_handle_nonnull_return
+
+  // CHECK-TRAP: [[OK:%.*]] = icmp ne i32* {{.*}}, null
+  // CHECK-TRAP: br i1 [[OK]]
+  // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+  // CHECK-TRAP: unreachable
+  return a;
+}
+
 // CHECK: ![[WEIGHT_MD]] = metadata !{metadata !"branch_weights", i32 1048575, i32 1}
 
 // CHECK-TRAP: attributes [[NR_NUW]] = { noreturn nounwind }
Index: tools/clang/include/clang/Basic/Sanitizers.def
===================================================================
--- tools/clang/include/clang/Basic/Sanitizers.def
+++ tools/clang/include/clang/Basic/Sanitizers.def
@@ -62,6 +62,7 @@
 SANITIZER("null", Null)
 SANITIZER("object-size", ObjectSize)
 SANITIZER("return", Return)
+SANITIZER("returns-nonnull-attribute", ReturnsNonnullAttribute)
 SANITIZER("shift", Shift)
 SANITIZER("signed-integer-overflow", SignedIntegerOverflow)
 SANITIZER("unreachable", Unreachable)
@@ -78,19 +79,19 @@
 // ABI or address space layout implications, and only catch undefined behavior.
 SANITIZER_GROUP("undefined", Undefined,
                 Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
-                FloatDivideByZero | Function | IntegerDivideByZero | Null |
-                ObjectSize | Return | Shift | SignedIntegerOverflow |
-                Unreachable | VLABound | Vptr)
+                    FloatDivideByZero | Function | IntegerDivideByZero | Null |
+                    ObjectSize | Return | ReturnsNonnullAttribute | Shift |
+                    SignedIntegerOverflow | Unreachable | VLABound | Vptr)
 
 // -fsanitize=undefined-trap includes
 // all sanitizers included by -fsanitize=undefined, except those that require
 // runtime support.  This group is generally used in conjunction with the
 // -fsanitize-undefined-trap-on-error flag.
 SANITIZER_GROUP("undefined-trap", UndefinedTrap,
                 Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
-                FloatDivideByZero | IntegerDivideByZero | Null | ObjectSize |
-                Return | Shift | SignedIntegerOverflow | Unreachable |
-                VLABound)
+                    FloatDivideByZero | IntegerDivideByZero | Null |
+                    ObjectSize | Return | ReturnsNonnullAttribute | Shift |
+                    SignedIntegerOverflow | Unreachable | VLABound)
 
 SANITIZER_GROUP("integer", Integer,
                 SignedIntegerOverflow | UnsignedIntegerOverflow | Shift |
Index: tools/clang/docs/UsersManual.rst
===================================================================
--- tools/clang/docs/UsersManual.rst
+++ tools/clang/docs/UsersManual.rst
@@ -986,6 +986,8 @@
       more problems at higher optimization levels.
    -  ``-fsanitize=return``: In C++, reaching the end of a
       value-returning function without returning a value.
+   -  ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
+      from a function which is declared to never return null.
    -  ``-fsanitize=shift``: Shift operators where the amount shifted is
       greater or equal to the promoted bit-width of the left hand side
       or less than zero, or where the left hand side is negative. For a
Index: tools/clang/lib/CodeGen/CGCall.cpp
===================================================================
--- tools/clang/lib/CodeGen/CGCall.cpp
+++ tools/clang/lib/CodeGen/CGCall.cpp
@@ -1998,7 +1998,24 @@
     llvm_unreachable("Invalid ABI kind for return argument");
   }
 
-  llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
+  llvm::Instruction *Ret;
+  if (RV) {
+    if (SanOpts->ReturnsNonnullAttribute &&
+        CurGD.getDecl()->hasAttr<ReturnsNonNullAttr>()) {
+      SanitizerScope SanScope(this);
+      llvm::Value *Cond =
+          Builder.CreateICmpNE(RV, llvm::Constant::getNullValue(RV->getType()));
+      llvm::Constant *StaticData[] = {
+        EmitCheckSourceLocation(EndLoc)
+      };
+      EmitCheck(Cond, "nonnull_return", StaticData, ArrayRef<llvm::Value *>(),
+                CRK_Recoverable);
+    }
+    Ret = Builder.CreateRet(RV);
+  } else {
+    Ret = Builder.CreateRetVoid();
+  }
+
   if (!RetDbgLoc.isUnknown())
     Ret->setDebugLoc(RetDbgLoc);
 }
Index: projects/compiler-rt/lib/ubsan/ubsan_handlers.h
===================================================================
--- projects/compiler-rt/lib/ubsan/ubsan_handlers.h
+++ projects/compiler-rt/lib/ubsan/ubsan_handlers.h
@@ -121,6 +121,13 @@
             FunctionTypeMismatchData *Data,
             ValueHandle Val)
 
+struct NonNullReturnData {
+  SourceLocation Loc;
+};
+
+/// \brief Handle returning null from function with returns_nonnull attribute.
+RECOVERABLE(nonnull_return, NonNullReturnData *Data)
+
 }
 
 #endif // UBSAN_HANDLERS_H
Index: projects/compiler-rt/lib/ubsan/ubsan_handlers.cc
===================================================================
--- projects/compiler-rt/lib/ubsan/ubsan_handlers.cc
+++ projects/compiler-rt/lib/ubsan/ubsan_handlers.cc
@@ -308,3 +308,22 @@
     FunctionTypeMismatchData *Data, ValueHandle Function) {
   handleFunctionTypeMismatch(Data, Function, true);
 }
+
+static void handleNonnullReturn(NonNullReturnData *Data, bool Abort) {
+  SourceLocation Loc = Data->Loc.acquire();
+  if (Loc.isDisabled())
+    return;
+
+  ScopedReport R(Abort);
+
+  Diag(Loc, DL_Error, "null pointer returned from function declared to never "
+                      "return null");
+}
+
+void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
+  handleNonnullReturn(Data, false);
+}
+
+void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
+  handleNonnullReturn(Data, true);
+}
Index: projects/compiler-rt/test/ubsan/TestCases/Misc/nonnull.cpp
===================================================================
--- /dev/null
+++ projects/compiler-rt/test/ubsan/TestCases/Misc/nonnull.cpp
@@ -0,0 +1,13 @@
+// RUN: %clangxx -fsanitize=returns-nonnull-attribute %s -O3 -o %t
+// RUN: %run %t foo
+// RUN: %run %t 2>&1 | FileCheck %s
+
+__attribute__((returns_nonnull))
+char *foo(char *a) {
+  return a;
+  // CHECK: nonnull.cpp:[[@LINE+1]]:1: runtime error: null pointer returned from function declared to never return null
+}
+
+int main(int argc, char **argv) {
+  return foo(argv[1]) == 0;
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to