From patchwork Wed May 22 20:40:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1103658 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-501470-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="Gbs4qLul"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 458Pdz5lG1z9s3Z for ; Thu, 23 May 2019 06:40:21 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=CUktpaDKXiWJJL3GOTR8nuOTuAsCgNScYOA0LwfhSSEkZQ+SGFecw WapEqFScauiNoCt2SRjwfSKgjPs05/5ziII3JR9c+e9dK77ofnsJnkeTZWgIDk7p fsOzTintXzTHWmggPJ67mgXhKRnQ46AsxxgfFBJoHvB4dFNtvscbi4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=/QZvIms3r/J/jAtS2rHcd9orNkE=; b=Gbs4qLulcKWQNCRShgGD zKmCMaXrAEwTd0Un3ktQ5koXGUgWsGEOxGPfDY4pTpuSoxKChGHiXTpQL7sT6YdT p29FZDh9yvpFQ4843fxm7xlT3rhSxz32FNeBDHeh5kmZ27lAY2HrKTQUyzycDS2d T88pV1gj0pTHCB8FL0ES1zM= Received: (qmail 51846 invoked by alias); 22 May 2019 20:40:10 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 51627 invoked by uid 89); 22 May 2019 20:40:09 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-15.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=bytes_allocated, __gnu_cxx X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 22 May 2019 20:40:07 +0000 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9CECF3087926; Wed, 22 May 2019 20:40:06 +0000 (UTC) Received: from localhost (unknown [10.33.36.15]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2748A6685C; Wed, 22 May 2019 20:40:06 +0000 (UTC) Date: Wed, 22 May 2019 21:40:05 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] PR libstdc++/77691 fix resource_adaptor failures due to max_align_t bugs Message-ID: <20190522204005.GA30214@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.11.3 (2019-02-01) Remove the hardcoded whitelist of allocators expected to return memory aligned to alignof(max_align_t), because that doesn't work when the platform's malloc() and GCC's max_align_t do not agree what the largest fundamental alignment is. It's also sub-optimal for user-defined allocators that return memory suitable for any fundamental alignment. Instead use a hardcoded list of alignments that are definitely supported by the platform malloc, and use a copy of the allocator rebound to a POD type with the requested alignment. Only allocate an oversized buffer to use with std::align for alignments larger than any of the hardcoded values. For 32-bit Solaris x86 do not include alignof(max_align_t) in the hardcoded values. PR libstdc++/77691 * include/experimental/memory_resource: Add system header pragma. (__resource_adaptor_common::__guaranteed_alignment): Remove. (__resource_adaptor_common::_Types) (__resource_adaptor_common::__new_list) (__resource_adaptor_common::_New_list) (__resource_adaptor_common::_Alignments) (__resource_adaptor_common::_Fund_align_types): New utilities for creating a list of types with fundamental alignments. (__resource_adaptor_imp::do_allocate): Call new _M_allocate function. (__resource_adaptor_imp::do_deallocate): Call new _M_deallocate function. (__resource_adaptor_imp::_M_allocate): New function that first tries to use an allocator rebound to a type with a fundamental alignment. (__resource_adaptor_imp::_M_deallocate): Likewise for deallocation. * testsuite/experimental/memory_resource/new_delete_resource.cc: Adjust expected allocation sizes. * testsuite/experimental/memory_resource/resource_adaptor.cc: Remove xfail. Tested x86_64-linux, committed to trunk. commit 5a14390cba4480685ef98c97a88a1ea965679c6a Author: Jonathan Wakely Date: Wed May 22 21:06:25 2019 +0100 PR libstdc++/77691 fix resource_adaptor failures due to max_align_t bugs Remove the hardcoded whitelist of allocators expected to return memory aligned to alignof(max_align_t), because that doesn't work when the platform's malloc() and GCC's max_align_t do not agree what the largest fundamental alignment is. It's also sub-optimal for user-defined allocators that return memory suitable for any fundamental alignment. Instead use a hardcoded list of alignments that are definitely supported by the platform malloc, and use a copy of the allocator rebound to a POD type with the requested alignment. Only allocate an oversized buffer to use with std::align for alignments larger than any of the hardcoded values. For 32-bit Solaris x86 do not include alignof(max_align_t) in the hardcoded values. PR libstdc++/77691 * include/experimental/memory_resource: Add system header pragma. (__resource_adaptor_common::__guaranteed_alignment): Remove. (__resource_adaptor_common::_Types) (__resource_adaptor_common::__new_list) (__resource_adaptor_common::_New_list) (__resource_adaptor_common::_Alignments) (__resource_adaptor_common::_Fund_align_types): New utilities for creating a list of types with fundamental alignments. (__resource_adaptor_imp::do_allocate): Call new _M_allocate function. (__resource_adaptor_imp::do_deallocate): Call new _M_deallocate function. (__resource_adaptor_imp::_M_allocate): New function that first tries to use an allocator rebound to a type with a fundamental alignment. (__resource_adaptor_imp::_M_deallocate): Likewise for deallocation. * testsuite/experimental/memory_resource/new_delete_resource.cc: Adjust expected allocation sizes. * testsuite/experimental/memory_resource/resource_adaptor.cc: Remove xfail. diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource index a0b30632154..dde3753fab7 100644 --- a/libstdc++-v3/include/experimental/memory_resource +++ b/libstdc++-v3/include/experimental/memory_resource @@ -30,6 +30,10 @@ #ifndef _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE #define _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 1 +#pragma GCC system_header + +#if __cplusplus >= 201402L + #include // align, uses_allocator, __uses_alloc #include // pair, experimental::erased_type #include // atomic @@ -358,23 +362,6 @@ namespace pmr { return __val; } }; - - template - struct __guaranteed_alignment : std::integral_constant { }; - - template - struct __guaranteed_alignment<__gnu_cxx::new_allocator<_Tp>> - : std::alignment_of::type { }; - - template - struct __guaranteed_alignment<__gnu_cxx::malloc_allocator<_Tp>> - : std::alignment_of::type { }; - -#if _GLIBCXX_USE_ALLOCATOR_NEW - template - struct __guaranteed_alignment> - : std::alignment_of::type { }; -#endif }; /// @endcond @@ -425,14 +412,22 @@ namespace pmr { virtual void* do_allocate(size_t __bytes, size_t __alignment) override { - if (__alignment <= __guaranteed_alignment<_Alloc>::value) + // Cannot use max_align_t on 32-bit Solaris x86, see PR libstdc++/77691 +#if ! (defined __sun__ && defined __i386__) + if (__alignment == alignof(max_align_t)) + return _M_allocate(__bytes); +#endif + switch (__alignment) { - if (__bytes < __alignment) - __bytes = __alignment; + case 1: return _M_alloc.allocate(__bytes); + case 2: + return _M_allocate<2>(__bytes); + case 4: + return _M_allocate<4>(__bytes); + case 8: + return _M_allocate<8>(__bytes); } - - const _AlignMgr __mgr(__bytes, __alignment); // Assume _M_alloc returns 1-byte aligned memory, so allocate enough // space to fit a block of the right size and alignment, plus some @@ -441,21 +436,28 @@ namespace pmr { } virtual void - do_deallocate(void* __p, size_t __bytes, size_t __alignment) noexcept + do_deallocate(void* __ptr, size_t __bytes, size_t __alignment) noexcept override { - auto __ptr = static_cast(__p); - if (__alignment <= __guaranteed_alignment<_Alloc>::value) +#if ! (defined __sun__ && defined __i386__) + if (__alignment == alignof(max_align_t)) + return (void) _M_deallocate(__ptr, __bytes); +#endif + switch (__alignment) { - if (__bytes < __alignment) - __bytes = __alignment; - _M_alloc.deallocate(__ptr, __bytes); - return; + case 1: + return (void) _M_alloc.deallocate((char*)__ptr, __bytes); + case 2: + return (void) _M_deallocate<2>(__ptr, __bytes); + case 4: + return (void) _M_deallocate<4>(__ptr, __bytes); + case 8: + return (void) _M_deallocate<8>(__ptr, __bytes); } - const _AlignMgr __mgr(__bytes, __alignment); - // Use the stored token to retrieve the original pointer to deallocate. - _M_alloc.deallocate(__mgr._M_unadjust(__ptr), __mgr._M_alloc_size()); + // Use the stored token to retrieve the original pointer. + _M_alloc.deallocate(__mgr._M_unadjust((char*)__ptr), + __mgr._M_alloc_size()); } virtual bool @@ -467,6 +469,31 @@ namespace pmr { } private: + template + struct _Aligned_type { alignas(_Num) char __c[_Num]; }; + + // Rebind the allocator to the specified type and use it to allocate. + template> + void* + _M_allocate(size_t __bytes) + { + typename allocator_traits<_Alloc>::template + rebind_alloc<_Tp> __a2(_M_alloc); + const size_t __n = (__bytes + _Num - 1) / _Num; + return __a2.allocate(__n); + } + + // Rebind the allocator to the specified type and use it to deallocate. + template> + void + _M_deallocate(void* __ptr, size_t __bytes) noexcept + { + typename allocator_traits<_Alloc>::template + rebind_alloc<_Tp> __a2(_M_alloc); + const size_t __n = (__bytes + _Num - 1) / _Num; + __a2.deallocate((_Tp*)__ptr, __n); + } + _Alloc _M_alloc{}; }; @@ -537,4 +564,5 @@ namespace pmr { _GLIBCXX_END_NAMESPACE_VERSION } // namespace std +#endif // C++14 #endif // _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE diff --git a/libstdc++-v3/testsuite/experimental/memory_resource/new_delete_resource.cc b/libstdc++-v3/testsuite/experimental/memory_resource/new_delete_resource.cc index 41232b6fc67..7dcb408f3f7 100644 --- a/libstdc++-v3/testsuite/experimental/memory_resource/new_delete_resource.cc +++ b/libstdc++-v3/testsuite/experimental/memory_resource/new_delete_resource.cc @@ -23,6 +23,11 @@ #include #include +#if defined __sun__ && defined __i386__ +// See PR libstdc++/77691 +# define BAD_MAX_ALIGN_T 1 +#endif + bool new_called = false; bool delete_called = false; std::size_t bytes_allocated = 0; @@ -38,14 +43,14 @@ void* operator new(std::size_t n) throw std::bad_alloc(); } -void operator delete(void* p) +void operator delete(void* p) noexcept { delete_called = true; std::free(p); bytes_allocated = 0; // assume everything getting deleted } -void operator delete(void* p, std::size_t n) +void operator delete(void* p, std::size_t n) noexcept { delete_called = true; std::free(p); @@ -55,9 +60,7 @@ void operator delete(void* p, std::size_t n) template bool aligned(void* p) - { - return (reinterpret_cast(p) % A) == 0; - } + { return (reinterpret_cast(p) % A) == 0; } template bool aligned(void* p) @@ -108,13 +111,17 @@ test03() using std::size_t; void* p = nullptr; - auto max = [](int n, int a) { return n > a ? n : a; }; + auto round = [](size_t n, size_t a) { return n % a ? n + a - (n % a) : n; }; bytes_allocated = 0; memory_resource* r1 = new_delete_resource(); p = r1->allocate(1); // uses alignment = alignof(max_align_t) - VERIFY( bytes_allocated <= alignof(max_align_t) ); +#ifdef BAD_MAX_ALIGN_T + VERIFY( bytes_allocated != 0 ); +#else + VERIFY( bytes_allocated == alignof(max_align_t) ); +#endif VERIFY( aligned(p) ); r1->deallocate(p, 1); VERIFY( bytes_allocated == 0 ); @@ -123,17 +130,16 @@ test03() VERIFY( bytes_allocated == 2 ); VERIFY( aligned(p) ); r1->deallocate(p, 2, alignof(char)); - __builtin_printf("%d\n", (int)bytes_allocated); VERIFY( bytes_allocated == 0 ); p = r1->allocate(3, alignof(short)); - VERIFY( bytes_allocated == max(3, alignof(short)) ); + VERIFY( bytes_allocated == round(3, alignof(short)) ); VERIFY( aligned(p) ); r1->deallocate(p, 3, alignof(short)); VERIFY( bytes_allocated == 0 ); p = r1->allocate(4, alignof(long)); - VERIFY( bytes_allocated == max(4, alignof(long)) ); + VERIFY( bytes_allocated == round(4, alignof(long)) ); VERIFY( aligned(p) ); r1->deallocate(p, 4, alignof(long)); VERIFY( bytes_allocated == 0 ); diff --git a/libstdc++-v3/testsuite/experimental/memory_resource/resource_adaptor.cc b/libstdc++-v3/testsuite/experimental/memory_resource/resource_adaptor.cc index 27ee1078dd4..56c8ffa2803 100644 --- a/libstdc++-v3/testsuite/experimental/memory_resource/resource_adaptor.cc +++ b/libstdc++-v3/testsuite/experimental/memory_resource/resource_adaptor.cc @@ -1,6 +1,5 @@ // { dg-do run { target c++14 } } // { dg-require-cstdint "" } -// { dg-xfail-run-if "PR libstdc++/77691" { { i?86-*-solaris2.* x86_64-*-solaris2.* } && ilp32 } } // Copyright (C) 2016-2019 Free Software Foundation, Inc. //