[compiler-rt] r217389 - Implement nonnull-attribute sanitizer

Alexey Samsonov vonosmas at gmail.com
Mon Sep 8 10:22:45 PDT 2014


Author: samsonov
Date: Mon Sep  8 12:22:45 2014
New Revision: 217389

URL: http://llvm.org/viewvc/llvm-project?rev=217389&view=rev
Log:
Implement nonnull-attribute sanitizer

Summary:
This patch implements a new UBSan check, which verifies
that function arguments declared to be nonnull with __attribute__((nonnull))
are actually nonnull in runtime.

To implement this check, we pass FunctionDecl to CodeGenFunction::EmitCallArgs
(where applicable) and if function declaration has nonnull attribute specified
for a certain formal parameter, we compare the corresponding RValue to null as
soon as it's calculated.

Test Plan: regression test suite

Reviewers: rsmith

Reviewed By: rsmith

Subscribers: cfe-commits, rnk

Differential Revision: http://reviews.llvm.org/D5082

Added:
    compiler-rt/trunk/test/ubsan/TestCases/Misc/nonnull-arg.cpp
Modified:
    compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
    compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
    compiler-rt/trunk/lib/ubsan/ubsan_handlers.h

Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.cc?rev=217389&r1=217388&r2=217389&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.cc Mon Sep  8 12:22:45 2014
@@ -296,9 +296,9 @@ Diag::~Diag() {
 
   Printf("%s\n", Decor.Default());
 
-  if (Loc.isMemoryLocation())
+  /*if (Loc.isMemoryLocation())
     renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
-                        NumRanges, Args);
+                        NumRanges, Args);*/
 }
 
 ScopedReport::ScopedReport(ReportOptions Opts) : Opts(Opts) {

Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc?rev=217389&r1=217388&r2=217389&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc Mon Sep  8 12:22:45 2014
@@ -331,7 +331,7 @@ void __ubsan::__ubsan_handle_function_ty
   handleFunctionTypeMismatch(Data, Function, Opts);
 }
 
-static void handleNonnullReturn(NonNullReturnData *Data, ReportOptions Opts) {
+static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
   if (Loc.isDisabled())
     return;
@@ -344,10 +344,33 @@ static void handleNonnullReturn(NonNullR
 
 void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
   GET_REPORT_OPTIONS(false);
-  handleNonnullReturn(Data, Opts);
+  handleNonNullReturn(Data, Opts);
 }
 
 void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
   GET_REPORT_OPTIONS(true);
-  handleNonnullReturn(Data, Opts);
+  handleNonNullReturn(Data, Opts);
+}
+
+static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
+  SourceLocation Loc = Data->Loc.acquire();
+  if (Loc.isDisabled())
+    return;
+
+  ScopedReport R(Opts);
+
+  Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
+       "never be null") << Data->ArgIndex;
+  if (!Data->AttrLoc.isInvalid())
+    Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here");
+}
+
+void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
+  GET_REPORT_OPTIONS(false);
+  handleNonNullArg(Data, Opts);
+}
+
+void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
+  GET_REPORT_OPTIONS(true);
+  handleNonNullArg(Data, Opts);
 }

Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers.h?rev=217389&r1=217388&r2=217389&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers.h (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers.h Mon Sep  8 12:22:45 2014
@@ -130,6 +130,15 @@ struct NonNullReturnData {
 /// \brief Handle returning null from function with returns_nonnull attribute.
 RECOVERABLE(nonnull_return, NonNullReturnData *Data)
 
+struct NonNullArgData {
+  SourceLocation Loc;
+  SourceLocation AttrLoc;
+  int ArgIndex;
+};
+
+/// \brief Handle passing null pointer to function with nonnull attribute.
+RECOVERABLE(nonnull_arg, NonNullArgData *Data);
+
 }
 
 #endif // UBSAN_HANDLERS_H

Added: compiler-rt/trunk/test/ubsan/TestCases/Misc/nonnull-arg.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/ubsan/TestCases/Misc/nonnull-arg.cpp?rev=217389&view=auto
==============================================================================
--- compiler-rt/trunk/test/ubsan/TestCases/Misc/nonnull-arg.cpp (added)
+++ compiler-rt/trunk/test/ubsan/TestCases/Misc/nonnull-arg.cpp Mon Sep  8 12:22:45 2014
@@ -0,0 +1,58 @@
+// RUN: %clangxx -fsanitize=nonnull-attribute -fno-sanitize-recover %s -O3 -o %t
+// RUN: %run %t nc
+// RUN: %run %t nm
+// RUN: %run %t nf
+// RUN: %run %t nv
+// RUN: not %run %t 0c 2>&1 | FileCheck %s --check-prefix=CTOR
+// RUN: not %run %t 0m 2>&1 | FileCheck %s --check-prefix=METHOD
+// RUN: not %run %t 0f 2>&1 | FileCheck %s --check-prefix=FUNC
+// RUN: not %run %t 0v 2>&1 | FileCheck %s --check-prefix=VARIADIC
+
+class C {
+  int *null_;
+  int *nonnull_;
+
+public:
+  C(int *null, __attribute__((nonnull)) int *nonnull)
+      : null_(null), nonnull_(nonnull) {}
+  int value() { return *nonnull_; }
+  int method(int *nonnull, int *null) __attribute__((nonnull(2))) {
+    return *nonnull_ + *nonnull;
+  }
+};
+
+__attribute__((nonnull)) int func(int *nonnull) { return *nonnull; }
+
+#include <stdarg.h>
+__attribute__((nonnull)) int variadic(int x, ...) {
+  va_list args;
+  va_start(args, x);
+  int *nonnull = va_arg(args, int*);
+  int res = *nonnull;
+  va_end(args);
+  return res;
+}
+
+int main(int argc, char *argv[]) {
+  int local = 0;
+  int *arg = (argv[1][0] == '0') ? 0x0 : &local;
+  switch (argv[1][1]) {
+    case 'c':
+      return C(0x0, arg).value();
+      // CTOR: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:21: runtime error: null pointer passed as argument 2, which is declared to never be null
+      // CTOR-NEXT: {{.*}}nonnull-arg.cpp:16:31: note: nonnull attribute specified here
+    case 'm':
+      return C(0x0, &local).method(arg, 0x0);
+      // METHOD: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:36: runtime error: null pointer passed as argument 1, which is declared to never be null
+      // METHOD-NEXT: {{.*}}nonnull-arg.cpp:19:54: note: nonnull attribute specified here
+    case 'f':
+      return func(arg);
+      // FUNC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:19: runtime error: null pointer passed as argument 1, which is declared to never be null
+      // FUNC-NEXT: {{.*}}nonnull-arg.cpp:24:16: note: nonnull attribute specified here
+    case 'v':
+      return variadic(42, arg);
+    // VARIADIC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:27: runtime error: null pointer passed as argument 2, which is declared to never be null
+    // VARIADIC-NEXT: {{.*}}nonnull-arg.cpp:27:16: note: nonnull attribute specified here
+  }
+  return 0;
+}





More information about the llvm-commits mailing list