From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 4DD8C38930E0 for ; Mon, 26 Apr 2021 20:20:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 4DD8C38930E0 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-400-gEeQ7OFGM7i0bXIBbd1OXQ-1; Mon, 26 Apr 2021 16:20:42 -0400 X-MC-Unique: gEeQ7OFGM7i0bXIBbd1OXQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 19E6183DD28; Mon, 26 Apr 2021 20:20:42 +0000 (UTC) Received: from localhost (unknown [10.33.36.164]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8E12E17C5F; Mon, 26 Apr 2021 20:20:41 +0000 (UTC) Date: Mon, 26 Apr 2021 21:20:40 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed 1/2] libstdc++: Fix socket option classes Message-ID: MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: multipart/mixed; boundary="FKrAUbDDlbiPgLWw" Content-Disposition: inline X-Spam-Status: No, score=-14.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 26 Apr 2021 20:20:49 -0000 --FKrAUbDDlbiPgLWw Content-Type: text/plain; charset=us-ascii Content-Disposition: inline This fixes some flaws in the socket option types defined in net::socket_base: - The constructors were not noexcept. - The __sockopt_base::value() member function was present unconditionally (so was defined for socket_base::linger which is incorrect). - The __socket_crtp::operator=(T) assignment operator was not noexcept, and was hidden in the derived classes. Also: - Use class instead of struct for the socket option types. - Define the _S_level and _S_name constants as private. - Declare the __socket_crtp base as a friend. libstdc++-v3/ChangeLog: * include/experimental/bits/net.h (__socket_base): Add bool template parameter to allow BooleanSocketOption and IntegerSocketOption to have different __socket_base base classes. (__socket_base): Adjust base class. (__socket_base): Add partial specialization. (__socket_crtp::operator=(_Tp)): Add noexcept-specifier. * include/experimental/socket (socket_base::broadcast) (socket_base::debug, socket_base::do_not_route) (socket_base::keep_alive, socket_base::linger) (socket_base::out_of_band_inline) (socket_base::receive_buffer_size) (socket_base::receive_low_watermark) (socket_base::reuse_address, socket_base::send_buffer_size) (socket_base::send_low_watermark): Add using-declaration for __socket_crtp::operator=(_Tp). * testsuite/experimental/net/socket/socket_base.cc: Check properties of socket option types. Tested powerpc64le-linux and powerpc-aix. Committed to trunk. --FKrAUbDDlbiPgLWw Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="patch.txt" commit 06c86a4f210c76a157512a2963e6c31302d161cb Author: Jonathan Wakely Date: Mon Apr 26 21:16:21 2021 libstdc++: Fix socket option classes This fixes some flaws in the socket option types defined in net::socket_base: - The constructors were not noexcept. - The __sockopt_base::value() member function was present unconditionally (so was defined for socket_base::linger which is incorrect). - The __socket_crtp::operator=(T) assignment operator was not noexcept, and was hidden in the derived classes. Also: - Use class instead of struct for the socket option types. - Define the _S_level and _S_name constants as private. - Declare the __socket_crtp base as a friend. libstdc++-v3/ChangeLog: * include/experimental/bits/net.h (__socket_base): Add bool template parameter to allow BooleanSocketOption and IntegerSocketOption to have different __socket_base base classes. (__socket_base): Adjust base class. (__socket_base): Add partial specialization. (__socket_crtp::operator=(_Tp)): Add noexcept-specifier. * include/experimental/socket (socket_base::broadcast) (socket_base::debug, socket_base::do_not_route) (socket_base::keep_alive, socket_base::linger) (socket_base::out_of_band_inline) (socket_base::receive_buffer_size) (socket_base::receive_low_watermark) (socket_base::reuse_address, socket_base::send_buffer_size) (socket_base::send_low_watermark): Add using-declaration for __socket_crtp::operator=(_Tp). * testsuite/experimental/net/socket/socket_base.cc: Check properties of socket option types. diff --git a/libstdc++-v3/include/experimental/bits/net.h b/libstdc++-v3/include/experimental/bits/net.h index 0ac9ca7ddc6..3087f8957da 100644 --- a/libstdc++-v3/include/experimental/bits/net.h +++ b/libstdc++-v3/include/experimental/bits/net.h @@ -95,15 +95,20 @@ inline namespace v1 /// @endcond - // Base class for types meeting IntegerSocketOption requirements. - template + // Base class for types meeting both GettableSocketOption and + // SettableSocketOption requirements. + // The bool parameter allows __sockopt_base to have a + // __sockopt_base base class (so that its _M_value is an int) + // but to have that be a distinct type from __sockopt_base. + template struct __sockopt_base { __sockopt_base() = default; - explicit __sockopt_base(int __val) : _M_value(__val) { } - - int value() const noexcept { return _M_value; } + explicit + __sockopt_base(_Tp __val) noexcept(noexcept(_Tp(std::declval<_Tp&>()))) + : _M_value(__val) + { } template void* @@ -134,24 +139,36 @@ inline namespace v1 // Base class for types meeting BooleanSocketOption requirements. template<> - struct __sockopt_base : __sockopt_base + struct __sockopt_base : __sockopt_base { __sockopt_base() = default; - explicit __sockopt_base(bool __val) : __sockopt_base(__val) { } + explicit + __sockopt_base(bool __val) noexcept + : __sockopt_base(__val) + { } - bool value() const noexcept { return __sockopt_base::_M_value; } + bool value() const noexcept { return this->_M_value; } explicit operator bool() const noexcept { return value(); } bool operator!() const noexcept { return !value(); } }; + // Base class for types meeting IntegerSocketOption requirements. + template<> + struct __sockopt_base : __sockopt_base + { + using __sockopt_base::__sockopt_base; + + int value() const noexcept { return this->_M_value; } + }; + template struct __sockopt_crtp : __sockopt_base<_Tp> { using __sockopt_base<_Tp>::__sockopt_base; _Derived& - operator=(_Tp __value) + operator=(_Tp __value) noexcept(noexcept(__value = __value)) { __sockopt_base<_Tp>::_M_value = __value; return static_cast<_Derived&>(*this); diff --git a/libstdc++-v3/include/experimental/socket b/libstdc++-v3/include/experimental/socket index 09c3b729607..538dc78e72c 100644 --- a/libstdc++-v3/include/experimental/socket +++ b/libstdc++-v3/include/experimental/socket @@ -138,41 +138,59 @@ inline namespace v1 { public: #ifdef _GLIBCXX_HAVE_SYS_SOCKET_H - struct broadcast : __sockopt_crtp + class broadcast : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_BROADCAST; }; - struct debug : __sockopt_crtp + class debug : public __sockopt_crtp { + public: + friend __sockopt_crtp; using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: static const int _S_level = SOL_SOCKET; static const int _S_name = SO_DEBUG; }; - struct do_not_route : __sockopt_crtp + class do_not_route : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_DONTROUTE; }; - struct keep_alive : __sockopt_crtp + class keep_alive : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_KEEPALIVE; }; - struct linger : __sockopt_crtp + class linger : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; linger() noexcept = default; @@ -198,54 +216,80 @@ inline namespace v1 timeout(chrono::seconds __t) noexcept { _M_value.l_linger = __t.count(); } + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_LINGER; }; - struct out_of_band_inline : __sockopt_crtp + class out_of_band_inline : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_OOBINLINE; }; - struct receive_buffer_size : __sockopt_crtp + class receive_buffer_size : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_RCVBUF; }; - struct receive_low_watermark : __sockopt_crtp + class receive_low_watermark : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_RCVLOWAT; }; - struct reuse_address : __sockopt_crtp + class reuse_address : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_REUSEADDR; }; - struct send_buffer_size : __sockopt_crtp + class send_buffer_size : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_SNDBUF; }; - struct send_low_watermark : __sockopt_crtp + class send_low_watermark : public __sockopt_crtp { + public: using __sockopt_crtp::__sockopt_crtp; + using __sockopt_crtp::operator=; + private: + friend __sockopt_crtp; static const int _S_level = SOL_SOCKET; static const int _S_name = SO_SNDLOWAT; }; diff --git a/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc b/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc index b0b02b4e560..95cd8151840 100644 --- a/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc +++ b/libstdc++-v3/testsuite/experimental/net/socket/socket_base.cc @@ -15,14 +15,156 @@ // with this library; see the file COPYING3. If not see // . -// { dg-do compile { target c++14 } } +// { dg-do run { target c++14 } } #include #include +#include using S = std::experimental::net::socket_base; using namespace std; +// Dummy protocol +struct P +{ + struct endpoint + { + using protocol_type = P; + P protocol() const; + }; +}; + +static_assert( ! is_default_constructible(), "" ); +static_assert( ! is_destructible(), "" ); + +template +void check_gettable_sockopt() +{ + P p; + static_assert( is_same().level(p)), int>(), "" ); + static_assert( noexcept(declval().level(p)), "" ); + + static_assert( is_same().name(p)), int>(), "" ); + static_assert( noexcept(declval().name(p)), "" ); + + static_assert( is_same().data(p)), void*>(), "" ); + static_assert( noexcept(declval().data(p)), "" ); + + static_assert( is_same().size(p)), size_t>(), "" ); + static_assert( noexcept(declval().size(p)), "" ); + + static_assert( is_same().resize(p, 0)), void>(), "" ); + static_assert( ! noexcept(declval().resize(p, 0)), "" ); + + C opt; + VERIFY(opt.size(p) == sizeof(T)); +} + +template +void check_settable_sockopt() +{ + P p; + static_assert( is_same().level(p)), int>(), "" ); + static_assert( noexcept(declval().level(p)), "" ); + + static_assert( is_same().name(p)), int>(), "" ); + static_assert( noexcept(declval().name(p)), "" ); + + static_assert( is_same().data(p)), const void*>(), "" ); + static_assert( noexcept(declval().data(p)), "" ); + + static_assert( is_same().size(p)), size_t>(), "" ); + static_assert( noexcept(declval().size(p)), "" ); + + C opt; + VERIFY(opt.size(p) == sizeof(T)); +} + +template +void check_boolean_sockopt() +{ + check_gettable_sockopt(); + check_settable_sockopt(); + + static_assert( is_destructible(), "" ); + static_assert( is_nothrow_default_constructible(), "" ); + static_assert( is_nothrow_copy_constructible(), "" ); + static_assert( is_nothrow_copy_assignable(), "" ); + + static_assert( is_nothrow_constructible(), "" ); + static_assert( is_nothrow_assignable(), "" ); + + static_assert( is_same().value()), bool>(), "" ); + static_assert( noexcept(declval().value()), "" ); + + static_assert( is_same(declval())), bool>(), "" ); + static_assert( noexcept(static_cast(declval())), "" ); + + static_assert( is_same()), bool>(), "" ); + static_assert( noexcept(!declval()), "" ); +} + +template +void check_integer_sockopt() +{ + check_gettable_sockopt(); + check_settable_sockopt(); + + static_assert( is_destructible(), "" ); + static_assert( is_nothrow_default_constructible(), "" ); + static_assert( is_nothrow_copy_constructible(), "" ); + static_assert( is_nothrow_copy_assignable(), "" ); + + static_assert( is_nothrow_constructible(), "" ); + static_assert( is_nothrow_assignable(), "" ); + + static_assert( is_same().value()), int>(), "" ); + static_assert( noexcept(declval().value()), "" ); +} + +void test_option_types() +{ + check_boolean_sockopt(); + + check_boolean_sockopt(); + + check_boolean_sockopt(); + + check_boolean_sockopt(); + + check_gettable_sockopt(); + check_settable_sockopt(); + static_assert( is_destructible(), "" ); + static_assert( is_nothrow_default_constructible(), "" ); + static_assert( is_nothrow_copy_constructible(), "" ); + static_assert( is_nothrow_copy_assignable(), "" ); + static_assert( is_nothrow_constructible(), "" ); + + static_assert( is_same().enabled()), bool>(), "" ); + static_assert( noexcept(declval().enabled()), "" ); + + static_assert( is_void().enabled(true))>(), "" ); + static_assert( noexcept(declval().enabled(true)), "" ); + + static_assert( is_same().timeout()), chrono::seconds>(), "" ); + static_assert( noexcept(declval().timeout()), "" ); + + static_assert( is_void().timeout(chrono::seconds()))>(), "" ); + static_assert( noexcept(declval().timeout(chrono::seconds())), "" ); + + check_boolean_sockopt(); + + check_integer_sockopt(); + + check_integer_sockopt(); + + check_boolean_sockopt(); + + check_integer_sockopt(); + + check_integer_sockopt(); +} + void test_constants() { static_assert( is_enum::value, "" ); @@ -43,3 +185,7 @@ void test_constants() static_assert( is_same::value, "" ); } +int main() +{ + test_option_types(); +} --FKrAUbDDlbiPgLWw--