[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