r199452 - Issue a warning if a throwing operator new or operator new[] returns a null
Richard Smith
richard-llvm at metafoo.co.uk
Thu Jan 16 18:09:33 PST 2014
Author: rsmith
Date: Thu Jan 16 20:09:33 2014
New Revision: 199452
URL: http://llvm.org/viewvc/llvm-project?rev=199452&view=rev
Log:
Issue a warning if a throwing operator new or operator new[] returns a null
pointer, since this invokes undefined behavior. Based on a patch by Artyom
Skrobov! Handling of dependent exception specifications and some additional
testcases by me.
Added:
cfe/trunk/test/SemaCXX/new-null.cpp
Modified:
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/test/SemaCXX/new-delete.cpp
cfe/trunk/test/SemaCXX/warn-new-overaligned.cpp
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=199452&r1=199451&r2=199452&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Thu Jan 16 20:09:33 2014
@@ -3036,15 +3036,10 @@ public:
return 0;
return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[1];
}
- bool isNothrow(const ASTContext &Ctx) const {
- ExceptionSpecificationType EST = getExceptionSpecType();
- assert(EST != EST_Unevaluated && EST != EST_Uninstantiated);
- if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
- return true;
- if (EST != EST_ComputedNoexcept)
- return false;
- return getNoexceptSpec(Ctx) == NR_Nothrow;
- }
+ /// \brief Determine whether this function type has a non-throwing exception
+ /// specification. If this depends on template arguments, returns
+ /// \c ResultIfDependent.
+ bool isNothrow(const ASTContext &Ctx, bool ResultIfDependent = false) const;
bool isVariadic() const { return Variadic; }
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=199452&r1=199451&r2=199452&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Thu Jan 16 20:09:33 2014
@@ -226,6 +226,7 @@ def : DiagGroup<"overflow">;
def ForwardClassReceiver : DiagGroup<"receiver-forward-class">;
def MethodAccess : DiagGroup<"objc-method-access">;
def ObjCReceiver : DiagGroup<"receiver-expr">;
+def OperatorNewReturnsNull : DiagGroup<"new-returns-null">;
def OverlengthStrings : DiagGroup<"overlength-strings">;
def OverloadedVirtual : DiagGroup<"overloaded-virtual">;
def PrivateExtern : DiagGroup<"private-extern">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=199452&r1=199451&r2=199452&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 16 20:09:33 2014
@@ -5996,6 +5996,9 @@ def err_operator_new_delete_too_few_para
"%0 must have at least one parameter">;
def err_operator_new_delete_template_too_few_parameters : Error<
"%0 template must have at least two parameters">;
+def warn_operator_new_returns_null : Warning<
+ "%0 should not return a null pointer unless it is declared 'throw()'"
+ "%select{| or 'noexcept'}1">, InGroup<OperatorNewReturnsNull>;
def err_operator_new_dependent_param_type : Error<
"%0 cannot take a dependent type as first parameter; "
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=199452&r1=199451&r2=199452&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Thu Jan 16 20:09:33 2014
@@ -1689,6 +1689,31 @@ FunctionProtoType::getNoexceptSpec(const
return value.getBoolValue() ? NR_Nothrow : NR_Throw;
}
+bool FunctionProtoType::isNothrow(const ASTContext &Ctx,
+ bool ResultIfDependent) const {
+ ExceptionSpecificationType EST = getExceptionSpecType();
+ assert(EST != EST_Unevaluated && EST != EST_Uninstantiated);
+ if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
+ return true;
+
+ if (EST == EST_Dynamic && ResultIfDependent == true) {
+ // A dynamic exception specification is throwing unless every exception
+ // type is an (unexpanded) pack expansion type.
+ for (unsigned I = 0, N = NumExceptions; I != N; ++I)
+ if (!getExceptionType(I)->getAs<PackExpansionType>())
+ return false;
+ return ResultIfDependent;
+ }
+
+ if (EST != EST_ComputedNoexcept)
+ return false;
+
+ NoexceptResult NR = getNoexceptSpec(Ctx);
+ if (NR == NR_Dependent)
+ return ResultIfDependent;
+ return NR == NR_Nothrow;
+}
+
bool FunctionProtoType::isTemplateVariadic() const {
for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx)
if (isa<PackExpansionType>(getArgType(ArgIdx - 1)))
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=199452&r1=199451&r2=199452&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu Jan 16 20:09:33 2014
@@ -2936,6 +2936,28 @@ Sema::ActOnReturnStmt(SourceLocation Ret
}
CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+
+ // C++11 [basic.stc.dynamic.allocation]p4:
+ // If an allocation function declared with a non-throwing
+ // exception-specification fails to allocate storage, it shall return
+ // a null pointer. Any other allocation function that fails to allocate
+ // storage shall indicate failure only by throwing an exception [...]
+ if (const FunctionDecl *FD = getCurFunctionDecl()) {
+ OverloadedOperatorKind Op = FD->getOverloadedOperator();
+ if (Op == OO_New || Op == OO_Array_New) {
+ const FunctionProtoType *Proto
+ = FD->getType()->castAs<FunctionProtoType>();
+ bool ReturnValueNonNull;
+
+ if (!Proto->isNothrow(Context, /*ResultIfDependent*/true) &&
+ !RetValExp->isValueDependent() &&
+ RetValExp->EvaluateAsBooleanCondition(ReturnValueNonNull,
+ Context) &&
+ !ReturnValueNonNull)
+ Diag(ReturnLoc, diag::warn_operator_new_returns_null)
+ << FD << getLangOpts().CPlusPlus11;
+ }
+ }
}
if (RetValExp) {
Modified: cfe/trunk/test/SemaCXX/new-delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/new-delete.cpp?rev=199452&r1=199451&r2=199452&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/new-delete.cpp (original)
+++ cfe/trunk/test/SemaCXX/new-delete.cpp Thu Jan 16 20:09:33 2014
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -Wno-new-returns-null
#include <stddef.h>
Added: cfe/trunk/test/SemaCXX/new-null.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/new-null.cpp?rev=199452&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/new-null.cpp (added)
+++ cfe/trunk/test/SemaCXX/new-null.cpp Thu Jan 16 20:09:33 2014
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+
+typedef __SIZE_TYPE__ size_t;
+
+#if __cplusplus >= 201103L
+struct S1 {
+ void *operator new(size_t n) {
+ return nullptr; // expected-warning {{'operator new' should not return a null pointer unless it is declared 'throw()' or 'noexcept'}}
+ }
+ void *operator new[](size_t n) noexcept {
+ return __null;
+ }
+};
+#endif
+
+struct S2 {
+ static size_t x;
+ void *operator new(size_t n) throw() {
+ return 0;
+ }
+ void *operator new[](size_t n) {
+ return (void*)0;
+#if __cplusplus >= 201103L
+ // expected-warning at -2 {{'operator new[]' should not return a null pointer unless it is declared 'throw()' or 'noexcept'}}
+#else
+ // expected-warning-re at -4 {{'operator new[]' should not return a null pointer unless it is declared 'throw()'{{$}}}}
+#endif
+ }
+};
+
+struct S3 {
+ void *operator new(size_t n) {
+ return 1-1;
+#if __cplusplus >= 201103L
+ // expected-error at -2 {{cannot initialize return object of type 'void *' with an rvalue of type 'int'}}
+#else
+ // expected-warning at -4 {{expression which evaluates to zero treated as a null pointer constant of type 'void *'}}
+ // expected-warning at -5 {{'operator new' should not return a null pointer unless it is declared 'throw()'}}
+#endif
+ }
+ void *operator new[](size_t n) {
+ return (void*)(1-1); // expected-warning {{'operator new[]' should not return a null pointer unless it is declared 'throw()'}}
+ }
+};
+
+#if __cplusplus >= 201103L
+template<bool B> struct S4 {
+ void *operator new(size_t n) noexcept(B) {
+ return 0; // expected-warning {{'operator new' should not return a null pointer}}
+ }
+};
+template struct S4<true>;
+template struct S4<false>; // expected-note {{in instantiation of}}
+#endif
+
+template<typename ...T> struct S5 { // expected-warning 0-1{{extension}}
+ void *operator new(size_t n) throw(T...) {
+ return 0; // expected-warning {{'operator new' should not return a null pointer}}
+ }
+};
+template struct S5<>;
+template struct S5<int>; // expected-note {{in instantiation of}}
Modified: cfe/trunk/test/SemaCXX/warn-new-overaligned.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-new-overaligned.cpp?rev=199452&r1=199451&r2=199452&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-new-overaligned.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-new-overaligned.cpp Thu Jan 16 20:09:33 2014
@@ -38,7 +38,7 @@ struct Test {
} __attribute__((aligned(256)));
void* operator new(unsigned long) {
- return 0;
+ return 0; // expected-warning {{'operator new' should not return a null pointer unless it is declared 'throw()'}}
}
SeparateCacheLines<int> high_contention_data[10];
@@ -59,7 +59,7 @@ struct Test {
} __attribute__((aligned(256)));
void* operator new[](unsigned long) {
- return 0;
+ return 0; // expected-warning {{'operator new[]' should not return a null pointer unless it is declared 'throw()'}}
}
SeparateCacheLines<int> high_contention_data[10];
More information about the cfe-commits
mailing list