Merge remote-tracking branch 'origin/swift-4.0-branch' into stable
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index 6ffffae..4e025a8 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -38,7 +38,7 @@
const char *TypeCheckKinds[] = {
"load of", "store to", "reference binding to", "member access within",
"member call on", "constructor call on", "downcast of", "downcast of",
- "upcast of", "cast to virtual base of"};
+ "upcast of", "cast to virtual base of", "_Nonnull binding to"};
}
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
@@ -472,7 +472,8 @@
Die();
}
-static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
+static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts,
+ bool IsAttr) {
SourceLocation Loc = Data->Loc.acquire();
ErrorType ET = ErrorType::InvalidNullReturn;
@@ -484,21 +485,35 @@
Diag(Loc, DL_Error, "null pointer returned from function declared to never "
"return null");
if (!Data->AttrLoc.isInvalid())
- Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here");
+ Diag(Data->AttrLoc, DL_Note, "%0 specified here")
+ << (IsAttr ? "returns_nonnull attribute"
+ : "_Nonnull return type annotation");
}
void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
GET_REPORT_OPTIONS(false);
- handleNonNullReturn(Data, Opts);
+ handleNonNullReturn(Data, Opts, true);
}
void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
GET_REPORT_OPTIONS(true);
- handleNonNullReturn(Data, Opts);
+ handleNonNullReturn(Data, Opts, true);
Die();
}
-static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
+void __ubsan::__ubsan_handle_nullability_return(NonNullReturnData *Data) {
+ GET_REPORT_OPTIONS(false);
+ handleNonNullReturn(Data, Opts, false);
+}
+
+void __ubsan::__ubsan_handle_nullability_return_abort(NonNullReturnData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleNonNullReturn(Data, Opts, false);
+ Die();
+}
+
+static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,
+ bool IsAttr) {
SourceLocation Loc = Data->Loc.acquire();
ErrorType ET = ErrorType::InvalidNullArgument;
@@ -507,20 +522,34 @@
ScopedReport R(Opts, Loc, ET);
- Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
- "never be null") << Data->ArgIndex;
+ 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");
+ Diag(Data->AttrLoc, DL_Note, "%0 specified here")
+ << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation");
}
void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
GET_REPORT_OPTIONS(false);
- handleNonNullArg(Data, Opts);
+ handleNonNullArg(Data, Opts, true);
}
void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
GET_REPORT_OPTIONS(true);
- handleNonNullArg(Data, Opts);
+ handleNonNullArg(Data, Opts, true);
+ Die();
+}
+
+void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) {
+ GET_REPORT_OPTIONS(false);
+ handleNonNullArg(Data, Opts, false);
+}
+
+void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleNonNullArg(Data, Opts, false);
Die();
}
diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h
index 350eb91..5857bc2 100644
--- a/lib/ubsan/ubsan_handlers.h
+++ b/lib/ubsan/ubsan_handlers.h
@@ -136,8 +136,10 @@
SourceLocation AttrLoc;
};
-/// \brief Handle returning null from function with returns_nonnull attribute.
+/// \brief Handle returning null from function with the returns_nonnull
+/// attribute, or a return type annotated with _Nonnull.
RECOVERABLE(nonnull_return, NonNullReturnData *Data)
+RECOVERABLE(nullability_return, NonNullReturnData *Data)
struct NonNullArgData {
SourceLocation Loc;
@@ -145,8 +147,10 @@
int ArgIndex;
};
-/// \brief Handle passing null pointer to function with nonnull attribute.
+/// \brief Handle passing null pointer to a function parameter with the nonnull
+/// attribute, or a _Nonnull type annotation.
RECOVERABLE(nonnull_arg, NonNullArgData *Data)
+RECOVERABLE(nullability_arg, NonNullArgData *Data)
/// \brief Known CFI check kinds.
/// Keep in sync with the enum of the same name in CodeGenFunction.h
diff --git a/test/ubsan/TestCases/Misc/nullability.c b/test/ubsan/TestCases/Misc/nullability.c
new file mode 100644
index 0000000..37b8ddc
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/nullability.c
@@ -0,0 +1,64 @@
+// RUN: %clang -w -fsanitize=nullability-arg,nullability-assign,nullability-return %s -O3 -o %t
+// RUN: %run %t foo 2>&1 | count 0
+// RUN: %run %t 2>&1 | FileCheck %s
+
+// CHECK: nullability.c:[[@LINE+2]]:51: runtime error: null pointer returned from function declared to never return null
+// CHECK-NEXT: nullability.c:[[@LINE+1]]:6: note: _Nonnull return type annotation specified here
+int *_Nonnull nonnull_retval1(int *p) { return p; }
+
+// CHECK: nullability.c:1001:19: runtime error: null pointer passed as argument 1, which is declared to never be null
+// CHECK-NEXT: nullability.c:[[@LINE+3]]:36: note: _Nonnull type annotation specified here
+// CHECK: nullability.c:1001:22: runtime error: null pointer passed as argument 2, which is declared to never be null
+// CHECK-NEXT: nullability.c:[[@LINE+1]]:56: note: _Nonnull type annotation specified here
+int *_Nonnull nonnull_retval2(int *_Nonnull arg1, int *_Nonnull arg2,
+ int *_Nullable arg3, int *arg4, int arg5, ...) {
+ return arg1;
+}
+
+// CHECK: nullability.c:1002:15: runtime error: null pointer passed as argument 1, which is declared to never be null
+// CHECK-NEXT: nullability.c:[[@LINE+1]]:23: note: _Nonnull type annotation specified here
+void nonnull_arg(int *_Nonnull p) {}
+
+void nonnull_assign1(int *p) {
+ int *_Nonnull local;
+// CHECK: nullability.c:[[@LINE+1]]:9: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+ local = p;
+}
+
+void nonnull_assign2(int *p) {
+ int *_Nonnull arr[1];
+ // CHECK: nullability.c:[[@LINE+1]]:10: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+ arr[0] = p;
+}
+
+struct S1 {
+ int *_Nonnull mptr;
+};
+
+void nonnull_assign3(int *p) {
+ struct S1 s;
+ // CHECK: nullability.c:[[@LINE+1]]:10: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+ s.mptr = p;
+}
+
+// CHECK: nullability.c:[[@LINE+1]]:52: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+void nonnull_init1(int *p) { int *_Nonnull local = p; }
+
+// CHECK: nullability.c:[[@LINE+2]]:53: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+// CHECK: nullability.c:[[@LINE+1]]:56: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+void nonnull_init2(int *p) { int *_Nonnull arr[] = {p, p}; }
+
+int main(int argc, char **argv) {
+ int *p = (argc > 1) ? &argc : ((int *)0);
+
+#line 1000
+ nonnull_retval1(p);
+ nonnull_retval2(p, p, p, p, 0, 0, 0, 0);
+ nonnull_arg(p);
+ nonnull_assign1(p);
+ nonnull_assign2(p);
+ nonnull_assign3(p);
+ nonnull_init1(p);
+ nonnull_init2(p);
+ return 0;
+}