EricWF created this revision.
EricWF added reviewers: vsapsai, mclow.lists.
Herald added a subscriber: christof.

Currently libc++ silently ignores over-aligned allocation requests
made through __libcpp_allocate when aligned new/delete is not available.

      

This patch uses the `diagnose_if` attribute to generate a warning in that
case instead of being silent.

      

The change required converting __is_overaligned_for_new to a macro
so that the diagnose_if condition is still a potential constant expression in 
C++03.


Repository:
  rCXX libc++

https://reviews.llvm.org/D45013

Files:
  include/memory
  include/new
  
test/libcxx/utilities/memory/default.allocation/allocator.members/overaligned_new_not_supported.fail.cpp

Index: test/libcxx/utilities/memory/default.allocation/allocator.members/overaligned_new_not_supported.fail.cpp
===================================================================
--- /dev/null
+++ test/libcxx/utilities/memory/default.allocation/allocator.members/overaligned_new_not_supported.fail.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: diagnose-if-support, verify-support
+
+// <memory>
+
+// allocator:
+// pointer allocate(size_type n, allocator<void>::const_pointer hint=0);
+
+// Test that a warning is generated when aligned allocation is not supported
+// but an over-aligned allocation is requested.
+
+#include <memory>
+
+#include "test_macros.h"
+
+#ifndef TEST_HAS_NO_ALIGNED_ALLOCATION
+// expected-no-diagnostics
+#endif
+
+
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+static const size_t MaxAligned = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+#else
+static const size_t MaxAligned = std::alignment_of<std::max_align_t>::value;
+#endif
+
+static const size_t OverAligned = MaxAligned * 2;
+
+
+template <size_t Align>
+struct TEST_ALIGNAS(Align) AlignedType {
+  char data;
+  AlignedType() { }
+  AlignedType(AlignedType const&) { }
+  ~AlignedType() {}
+};
+
+
+void test_builtin_new() {
+  {
+    typedef AlignedType<MaxAligned> T;
+    void* ptr = std::__libcpp_allocate(sizeof(T), __alignof(T));
+    std::__libcpp_deallocate(ptr, __alignof(T));
+  }
+  {
+#if defined(TEST_HAS_NO_ALIGNED_ALLOCATION)
+    // expected-warning@+3 1 {{over-aligned allocation using 'operator new' is not supported}}
+#endif
+    typedef AlignedType<OverAligned> T;
+    void* ptr = std::__libcpp_allocate(sizeof(T), __alignof(T));
+    std::__libcpp_deallocate(ptr, __alignof(T));
+  }
+}
+
+void test_std_allocator() {
+  {
+    typedef AlignedType<MaxAligned> T;
+    std::allocator<T> a;
+    T* ptr = a.allocate(1); // OK
+    a.deallocate(ptr, 1);
+  }
+  {
+#if defined(TEST_HAS_NO_ALIGNED_ALLOCATION)
+    // expected-warning@memory:* 1 {{over-aligned allocation using 'operator new' is not supported}}
+    // expected-note@+4  {{requested here}}
+#endif
+    typedef AlignedType<OverAligned> T;
+    std::allocator<T> a;
+    T* ptr = a.allocate(1);
+    a.deallocate(ptr, 1);
+  }
+}
+
+int main() {
+  test_std_allocator();
+  test_builtin_new();
+}
Index: include/new
===================================================================
--- include/new
+++ include/new
@@ -232,17 +232,20 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-_LIBCPP_CONSTEXPR inline _LIBCPP_INLINE_VISIBILITY bool __is_overaligned_for_new(size_t __align) _NOEXCEPT {
 #ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
-  return __align > __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+#define _LIBCPP_IS_OVERALIGNED_FOR_NEW(__align) __align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
 #else
-  return __align > alignment_of<max_align_t>::value;
+#define _LIBCPP_ISOVERALIGNED_FOR_NEW(__align) __align > _VSTD::alignment_of<_VSTD::max_align_t>::value
 #endif
-}
 
-inline _LIBCPP_INLINE_VISIBILITY void *__libcpp_allocate(size_t __size, size_t __align) {
+inline _LIBCPP_INLINE_VISIBILITY void *__libcpp_allocate(size_t __size, size_t __align)
+#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
+_LIBCPP_DIAGNOSE_WARNING(_LIBCPP_IS_OVERALIGNED_FOR_NEW(__align),
+  "over-aligned allocation using 'operator new' is not supported")
+#endif
+{
 #ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
-  if (__is_overaligned_for_new(__align)) {
+  if (_LIBCPP_IS_OVERALIGNED_FOR_NEW(__align)) {
     const align_val_t __align_val = static_cast<align_val_t>(__align);
 # ifdef _LIBCPP_HAS_NO_BUILTIN_ALIGNED_OPERATOR_NEW_DELETE
     return ::operator new(__size, __align_val);
@@ -262,7 +265,7 @@
 
 inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __align) {
 #ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
-  if (__is_overaligned_for_new(__align)) {
+  if (_LIBCPP_IS_OVERALIGNED_FOR_NEW(__align)) {
     const align_val_t __align_val = static_cast<align_val_t>(__align);
 # ifdef _LIBCPP_HAS_NO_BUILTIN_ALIGNED_OPERATOR_NEW_DELETE
     return ::operator delete(__ptr, __align_val);
Index: include/memory
===================================================================
--- include/memory
+++ include/memory
@@ -2016,7 +2016,7 @@
     while (__n > 0)
     {
 #if !defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
-    if (__is_overaligned_for_new(__alignof(_Tp)))
+    if (_LIBCPP_IS_OVERALIGNED_FOR_NEW(__alignof(_Tp)))
         {
             std::align_val_t __al =
                 std::align_val_t(std::alignment_of<_Tp>::value);
@@ -2027,7 +2027,7 @@
                 __n * sizeof(_Tp), nothrow));
         }
 #else
-    if (__is_overaligned_for_new(__alignof(_Tp)))
+    if (_LIBCPP_IS_OVERALIGNED_FOR_NEW(__alignof(_Tp)))
         {
             // Since aligned operator new is unavailable, return an empty
             // buffer rather than one with invalid alignment.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to