Boost logo

Boost-Commit :

From: chris_at_[hidden]
Date: 2008-03-12 09:26:41


Author: chris_kohlhoff
Date: 2008-03-12 09:26:41 EDT (Wed, 12 Mar 2008)
New Revision: 43570
URL: http://svn.boost.org/trac/boost/changeset/43570

Log:
Use unions to fix a sockaddr_storage aliasing problem that shows up with
g++ 4.3.0.

Text files modified:
   trunk/boost/asio/detail/socket_ops.hpp | 60 ++++++++++----------
   trunk/boost/asio/ip/basic_endpoint.hpp | 116 +++++++++++++++------------------------
   2 files changed, 73 insertions(+), 103 deletions(-)

Modified: trunk/boost/asio/detail/socket_ops.hpp
==============================================================================
--- trunk/boost/asio/detail/socket_ops.hpp (original)
+++ trunk/boost/asio/detail/socket_ops.hpp 2008-03-12 09:26:41 EDT (Wed, 12 Mar 2008)
@@ -699,40 +699,40 @@
     return 0;
   }
 
- sockaddr_storage_type address;
+ union
+ {
+ socket_addr_type base;
+ sockaddr_storage_type storage;
+ sockaddr_in4_type v4;
+ sockaddr_in6_type v6;
+ } address;
   DWORD address_length;
   if (af == AF_INET)
   {
     address_length = sizeof(sockaddr_in4_type);
- sockaddr_in4_type* ipv4_address =
- reinterpret_cast<sockaddr_in4_type*>(&address);
- ipv4_address->sin_family = AF_INET;
- ipv4_address->sin_port = 0;
- memcpy(&ipv4_address->sin_addr, src, sizeof(in4_addr_type));
+ address.v4.sin_family = AF_INET;
+ address.v4.sin_port = 0;
+ memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
   }
   else // AF_INET6
   {
     address_length = sizeof(sockaddr_in6_type);
- sockaddr_in6_type* ipv6_address =
- reinterpret_cast<sockaddr_in6_type*>(&address);
- ipv6_address->sin6_family = AF_INET6;
- ipv6_address->sin6_port = 0;
- ipv6_address->sin6_flowinfo = 0;
- ipv6_address->sin6_scope_id = scope_id;
- memcpy(&ipv6_address->sin6_addr, src, sizeof(in6_addr_type));
+ address.v6.sin6_family = AF_INET6;
+ address.v6.sin6_port = 0;
+ address.v6.sin6_flowinfo = 0;
+ address.v6.sin6_scope_id = scope_id;
+ memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
   }
 
   DWORD string_length = static_cast<DWORD>(length);
 #if defined(BOOST_NO_ANSI_APIS)
   LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
- int result = error_wrapper(::WSAAddressToStringW(
- reinterpret_cast<sockaddr*>(&address),
+ int result = error_wrapper(::WSAAddressToStringW(&address.base,
         address_length, 0, string_buffer, &string_length), ec);
   ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0);
 #else
   int result = error_wrapper(::WSAAddressToStringA(
- reinterpret_cast<sockaddr*>(&address),
- address_length, 0, dest, &string_length), ec);
+ &address.base, address_length, 0, dest, &string_length), ec);
 #endif
 
   // Windows may set error code on success.
@@ -775,30 +775,30 @@
     return -1;
   }
 
- sockaddr_storage_type address;
+ union
+ {
+ socket_addr_type base;
+ sockaddr_storage_type storage;
+ sockaddr_in4_type v4;
+ sockaddr_in6_type v6;
+ } address;
   int address_length = sizeof(sockaddr_storage_type);
 #if defined(BOOST_NO_ANSI_APIS)
   int num_wide_chars = strlen(src) + 1;
   LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
   ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
   int result = error_wrapper(::WSAStringToAddressW(
- wide_buffer, af, 0,
- reinterpret_cast<sockaddr*>(&address),
- &address_length), ec);
+ wide_buffer, af, 0, &address.base, &address_length), ec);
 #else
   int result = error_wrapper(::WSAStringToAddressA(
- const_cast<char*>(src), af, 0,
- reinterpret_cast<sockaddr*>(&address),
- &address_length), ec);
+ const_cast<char*>(src), af, 0, &address.base, &address_length), ec);
 #endif
 
   if (af == AF_INET)
   {
     if (result != socket_error_retval)
     {
- sockaddr_in4_type* ipv4_address =
- reinterpret_cast<sockaddr_in4_type*>(&address);
- memcpy(dest, &ipv4_address->sin_addr, sizeof(in4_addr_type));
+ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
       clear_error(ec);
     }
     else if (strcmp(src, "255.255.255.255") == 0)
@@ -811,11 +811,9 @@
   {
     if (result != socket_error_retval)
     {
- sockaddr_in6_type* ipv6_address =
- reinterpret_cast<sockaddr_in6_type*>(&address);
- memcpy(dest, &ipv6_address->sin6_addr, sizeof(in6_addr_type));
+ memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
       if (scope_id)
- *scope_id = ipv6_address->sin6_scope_id;
+ *scope_id = address.v6.sin6_scope_id;
       clear_error(ec);
     }
   }

Modified: trunk/boost/asio/ip/basic_endpoint.hpp
==============================================================================
--- trunk/boost/asio/ip/basic_endpoint.hpp (original)
+++ trunk/boost/asio/ip/basic_endpoint.hpp 2008-03-12 09:26:41 EDT (Wed, 12 Mar 2008)
@@ -66,11 +66,9 @@
   basic_endpoint()
     : data_()
   {
- boost::asio::detail::sockaddr_in4_type& data
- = reinterpret_cast<boost::asio::detail::sockaddr_in4_type&>(data_);
- data.sin_family = AF_INET;
- data.sin_port = 0;
- data.sin_addr.s_addr = INADDR_ANY;
+ data_.v4.sin_family = AF_INET;
+ data_.v4.sin_port = 0;
+ data_.v4.sin_addr.s_addr = INADDR_ANY;
   }
 
   /// Construct an endpoint using a port number, specified in the host's byte
@@ -95,24 +93,20 @@
     using namespace std; // For memcpy.
     if (protocol.family() == PF_INET)
     {
- boost::asio::detail::sockaddr_in4_type& data
- = reinterpret_cast<boost::asio::detail::sockaddr_in4_type&>(data_);
- data.sin_family = AF_INET;
- data.sin_port =
+ data_.v4.sin_family = AF_INET;
+ data_.v4.sin_port =
         boost::asio::detail::socket_ops::host_to_network_short(port_num);
- data.sin_addr.s_addr = INADDR_ANY;
+ data_.v4.sin_addr.s_addr = INADDR_ANY;
     }
     else
     {
- boost::asio::detail::sockaddr_in6_type& data
- = reinterpret_cast<boost::asio::detail::sockaddr_in6_type&>(data_);
- data.sin6_family = AF_INET6;
- data.sin6_port =
+ data_.v6.sin6_family = AF_INET6;
+ data_.v6.sin6_port =
         boost::asio::detail::socket_ops::host_to_network_short(port_num);
- data.sin6_flowinfo = 0;
+ data_.v6.sin6_flowinfo = 0;
       boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT;
- data.sin6_addr = tmp_addr;
- data.sin6_scope_id = 0;
+ data_.v6.sin6_addr = tmp_addr;
+ data_.v6.sin6_scope_id = 0;
     }
   }
 
@@ -125,27 +119,23 @@
     using namespace std; // For memcpy.
     if (addr.is_v4())
     {
- boost::asio::detail::sockaddr_in4_type& data
- = reinterpret_cast<boost::asio::detail::sockaddr_in4_type&>(data_);
- data.sin_family = AF_INET;
- data.sin_port =
+ data_.v4.sin_family = AF_INET;
+ data_.v4.sin_port =
         boost::asio::detail::socket_ops::host_to_network_short(port_num);
- data.sin_addr.s_addr =
+ data_.v4.sin_addr.s_addr =
         boost::asio::detail::socket_ops::host_to_network_long(
             addr.to_v4().to_ulong());
     }
     else
     {
- boost::asio::detail::sockaddr_in6_type& data
- = reinterpret_cast<boost::asio::detail::sockaddr_in6_type&>(data_);
- data.sin6_family = AF_INET6;
- data.sin6_port =
+ data_.v6.sin6_family = AF_INET6;
+ data_.v6.sin6_port =
         boost::asio::detail::socket_ops::host_to_network_short(port_num);
- data.sin6_flowinfo = 0;
+ data_.v6.sin6_flowinfo = 0;
       boost::asio::ip::address_v6 v6_addr = addr.to_v6();
       boost::asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes();
- memcpy(data.sin6_addr.s6_addr, bytes.elems, 16);
- data.sin6_scope_id = v6_addr.scope_id();
+ memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16);
+ data_.v6.sin6_scope_id = v6_addr.scope_id();
     }
   }
 
@@ -165,7 +155,7 @@
   /// The protocol associated with the endpoint.
   protocol_type protocol() const
   {
- if (is_v4(data_))
+ if (is_v4())
       return InternetProtocol::v4();
     return InternetProtocol::v6();
   }
@@ -173,19 +163,19 @@
   /// Get the underlying endpoint in the native type.
   data_type* data()
   {
- return reinterpret_cast<data_type*>(&data_);
+ return &data_.base;
   }
 
   /// Get the underlying endpoint in the native type.
   const data_type* data() const
   {
- return reinterpret_cast<const data_type*>(&data_);
+ return &data_.base;
   }
 
   /// Get the underlying size of the endpoint in the native type.
   std::size_t size() const
   {
- if (is_v4(data_))
+ if (is_v4())
       return sizeof(boost::asio::detail::sockaddr_in4_type);
     else
       return sizeof(boost::asio::detail::sockaddr_in6_type);
@@ -194,7 +184,7 @@
   /// Set the underlying size of the endpoint in the native type.
   void resize(std::size_t size)
   {
- if (size > sizeof(data_))
+ if (size > sizeof(boost::asio::detail::sockaddr_storage_type))
     {
       boost::system::system_error e(boost::asio::error::invalid_argument);
       boost::throw_exception(e);
@@ -204,24 +194,22 @@
   /// Get the capacity of the endpoint in the native type.
   std::size_t capacity() const
   {
- return sizeof(data_);
+ return sizeof(boost::asio::detail::sockaddr_storage_type);
   }
 
   /// Get the port associated with the endpoint. The port number is always in
   /// the host's byte order.
   unsigned short port() const
   {
- if (is_v4(data_))
+ if (is_v4())
     {
       return boost::asio::detail::socket_ops::network_to_host_short(
- reinterpret_cast<const boost::asio::detail::sockaddr_in4_type&>(
- data_).sin_port);
+ data_.v4.sin_port);
     }
     else
     {
       return boost::asio::detail::socket_ops::network_to_host_short(
- reinterpret_cast<const boost::asio::detail::sockaddr_in6_type&>(
- data_).sin6_port);
+ data_.v6.sin6_port);
     }
   }
 
@@ -229,14 +217,14 @@
   /// the host's byte order.
   void port(unsigned short port_num)
   {
- if (is_v4(data_))
+ if (is_v4())
     {
- reinterpret_cast<boost::asio::detail::sockaddr_in4_type&>(data_).sin_port
+ data_.v4.sin_port
         = boost::asio::detail::socket_ops::host_to_network_short(port_num);
     }
     else
     {
- reinterpret_cast<boost::asio::detail::sockaddr_in6_type&>(data_).sin6_port
+ data_.v6.sin_port
         = boost::asio::detail::socket_ops::host_to_network_short(port_num);
     }
   }
@@ -245,23 +233,17 @@
   boost::asio::ip::address address() const
   {
     using namespace std; // For memcpy.
- if (is_v4(data_))
+ if (is_v4())
     {
- const boost::asio::detail::sockaddr_in4_type& data
- = reinterpret_cast<const boost::asio::detail::sockaddr_in4_type&>(
- data_);
       return boost::asio::ip::address_v4(
           boost::asio::detail::socket_ops::network_to_host_long(
- data.sin_addr.s_addr));
+ data_.v4.sin_addr.s_addr));
     }
     else
     {
- const boost::asio::detail::sockaddr_in6_type& data
- = reinterpret_cast<const boost::asio::detail::sockaddr_in6_type&>(
- data_);
       boost::asio::ip::address_v6::bytes_type bytes;
- memcpy(bytes.elems, data.sin6_addr.s6_addr, 16);
- return boost::asio::ip::address_v6(bytes, data.sin6_scope_id);
+ memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16);
+ return boost::asio::ip::address_v6(bytes, data_.v6.sin6_scope_id);
     }
   }
 
@@ -299,29 +281,19 @@
 
 private:
   // Helper function to determine whether the endpoint is IPv4.
-#if defined(_AIX)
- template <typename T, unsigned char (T::*)> struct is_v4_helper {};
-
- template <typename T>
- static bool is_v4(const T& ss, is_v4_helper<T, &T::ss_family>* = 0)
+ bool is_v4() const
   {
- return ss.ss_family == AF_INET;
+ return data_.base.sa_family == AF_INET;
   }
 
- template <typename T>
- static bool is_v4(const T& ss, is_v4_helper<T, &T::__ss_family>* = 0)
- {
- return ss.__ss_family == AF_INET;
- }
-#else
- static bool is_v4(const boost::asio::detail::sockaddr_storage_type& ss)
- {
- return ss.ss_family == AF_INET;
- }
-#endif
-
   // The underlying IP socket address.
- boost::asio::detail::sockaddr_storage_type data_;
+ union data_union
+ {
+ boost::asio::detail::socket_addr_type base;
+ boost::asio::detail::sockaddr_storage_type storage;
+ boost::asio::detail::sockaddr_in4_type v4;
+ boost::asio::detail::sockaddr_in6_type v6;
+ } data_;
 };
 
 /// Output an endpoint as a string.


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk