PR libstdc++/86861 Meet precondition for Solaris memalign

Message ID 20180807161051.GA25459@redhat.com
State New
Headers show
Series
  • PR libstdc++/86861 Meet precondition for Solaris memalign
Related show

Commit Message

Jonathan Wakely Aug. 7, 2018, 4:10 p.m.
Solaris memalign requires alignment to be at least sizeof(int), so
increase it as needed.

Also move the check for valid alignments from the fallback
implementation of aligned_alloc into operator new, as it's required for
all of aligned_alloc, memalign, posix_memalign and __aligned_malloc.
This adds a branch to check for undefined behaviour which we could just
ignore, so the check could just be removed. It should certainly be
removed if PR 86878 is implemented to issue a warning about calls with
invalid alignments.

	PR libstdc++/86861
	* libsupc++/new_opa.cc [_GLIBCXX_HAVE_MEMALIGN] (aligned_alloc):
	Replace macro with inline function.
	[__sun]: Increase alignment to meet memalign precondition.
	[!HAVE__ALIGNED_MALLOC && !HAVE_POSIX_MEMALIGN && !HAVE_MEMALIGN]
	(aligned_alloc): Move check for valid alignment to operator new.
	Remove redundant check for non-zero size, it's enforced by the caller.
	(operator new): Move check for valid alignment here. Use
	__builtin_expect on check for zero size.

Tested powerpc64le-linux, committed to trunk.
commit 926a15251b85d0b1a8b6bd08a138ad90ec9c83df
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Aug 6 15:43:43 2018 +0100

    PR libstdc++/86861 Meet precondition for Solaris memalign
    
    Solaris memalign requires alignment to be at least sizeof(int), so
    increase it as needed.
    
    Also move the check for valid alignments from the fallback
    implementation of aligned_alloc into operator new, as it's required for
    all of aligned_alloc, memalign, posix_memalign and __aligned_malloc.
    This adds a branch to check for undefined behaviour which we could just
    ignore, so the check could just be removed. It should certainly be
    removed if PR 86878 is implemented to issue a warning about calls with
    invalid alignments.
    
            PR libstdc++/86861
            * libsupc++/new_opa.cc [_GLIBCXX_HAVE_MEMALIGN] (aligned_alloc):
            Replace macro with inline function.
            [__sun]: Increase alignment to meet memalign precondition.
            [!HAVE__ALIGNED_MALLOC && !HAVE_POSIX_MEMALIGN && !HAVE_MEMALIGN]
            (aligned_alloc): Move check for valid alignment to operator new.
            Remove redundant check for non-zero size, it's enforced by the caller.
            (operator new): Move check for valid alignment here. Use
            __builtin_expect on check for zero size.

Patch

diff --git a/libstdc++-v3/libsupc++/new_opa.cc b/libstdc++-v3/libsupc++/new_opa.cc
index 7c4bb79cdab..5be0cc2ca65 100644
--- a/libstdc++-v3/libsupc++/new_opa.cc
+++ b/libstdc++-v3/libsupc++/new_opa.cc
@@ -39,6 +39,7 @@  static inline void*
 aligned_alloc (std::size_t al, std::size_t sz)
 {
   void *ptr;
+  // posix_memalign has additional requirement, not present on aligned_alloc:
   // The value of alignment shall be a power of two multiple of sizeof(void *).
   if (al < sizeof(void*))
     al = sizeof(void*);
@@ -53,20 +54,24 @@  aligned_alloc (std::size_t al, std::size_t sz)
 #else
 extern "C" void *memalign(std::size_t boundary, std::size_t size);
 #endif
-#define aligned_alloc memalign
-#else
+static inline void*
+aligned_alloc (std::size_t al, std::size_t sz)
+{
+#ifdef __sun
+  // Solaris 10 memalign requires that alignment is greater than or equal to
+  // the size of a word.
+  if (al < sizeof(int))
+    al = sizeof(int);
+#endif
+  return memalign (al, sz);
+}
+#else // !HAVE__ALIGNED_MALLOC && !HAVE_POSIX_MEMALIGN && !HAVE_MEMALIGN
 #include <stdint.h>
 // The C library doesn't provide any aligned allocation functions, define one.
 // This is a modified version of code from gcc/config/i386/gmm_malloc.h
 static inline void*
 aligned_alloc (std::size_t al, std::size_t sz)
 {
-  // Alignment must be a power of two.
-  if (al & (al - 1))
-    return nullptr;
-  else if (!sz)
-    return nullptr;
-
   // We need extra bytes to store the original value returned by malloc.
   if (al < sizeof(void*))
     al = sizeof(void*);
@@ -90,8 +95,13 @@  operator new (std::size_t sz, std::align_val_t al)
   void *p;
   std::size_t align = (std::size_t)al;
 
+  /* Alignment must be a power of two.  */
+  /* XXX This should be checked by the compiler (PR 86878).  */
+  if (__builtin_expect (align & (align - 1), false))
+    _GLIBCXX_THROW_OR_ABORT(bad_alloc());
+
   /* malloc (0) is unpredictable; avoid it.  */
-  if (sz == 0)
+  if (__builtin_expect (sz == 0, false))
     sz = 1;
 
 #if _GLIBCXX_HAVE_ALIGNED_ALLOC