From d8fe926ba4e799f7b1bd6b0b4464920443bedea9 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 21 Dec 2017 17:46:24 +0000 Subject: [PATCH] Fix various strict aliasing problems with sockaddr Fix various strict aliasing problems caused by casting between (struct sockaddr *) and (struct sockaddr_storage *): the correct code here is to keep the two in a union. Signed-off-by: Philip Withnall https://bugzilla.gnome.org/show_bug.cgi?id=791622 --- gio/gnativesocketaddress.c | 9 ++++--- gio/gsocket.c | 51 ++++++++++++++++++++++++-------------- glib/gmessages.c | 13 ++++++---- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/gio/gnativesocketaddress.c b/gio/gnativesocketaddress.c index 60d81e641..21106348f 100644 --- a/gio/gnativesocketaddress.c +++ b/gio/gnativesocketaddress.c @@ -47,7 +47,10 @@ struct _GNativeSocketAddressPrivate { struct sockaddr *sockaddr; - struct sockaddr_storage storage; + union { + struct sockaddr_storage storage; + struct sockaddr sa; + } storage; gsize sockaddr_len; }; @@ -58,7 +61,7 @@ g_native_socket_address_dispose (GObject *object) { GNativeSocketAddress *address = G_NATIVE_SOCKET_ADDRESS (object); - if (address->priv->sockaddr != (struct sockaddr *)&address->priv->storage) + if (address->priv->sockaddr != &address->priv->storage.sa) g_free (address->priv->sockaddr); G_OBJECT_CLASS (g_native_socket_address_parent_class)->dispose (object); @@ -150,7 +153,7 @@ g_native_socket_address_new (gpointer native, addr = g_object_new (G_TYPE_NATIVE_SOCKET_ADDRESS, NULL); if (len <= sizeof(addr->priv->storage)) - addr->priv->sockaddr = (struct sockaddr*)&addr->priv->storage; + addr->priv->sockaddr = &addr->priv->storage.sa; else addr->priv->sockaddr = g_malloc (len); diff --git a/gio/gsocket.c b/gio/gsocket.c index 567b4802e..06042d8a8 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -421,7 +421,10 @@ check_timeout (GSocket *socket, static void g_socket_details_from_fd (GSocket *socket) { - struct sockaddr_storage address; + union { + struct sockaddr_storage storage; + struct sockaddr sa; + } address; gint fd; guint addrlen; int value, family; @@ -454,7 +457,7 @@ g_socket_details_from_fd (GSocket *socket) } addrlen = sizeof address; - if (getsockname (fd, (struct sockaddr *) &address, &addrlen) != 0) + if (getsockname (fd, &address.sa, &addrlen) != 0) { errsv = get_socket_errno (); goto err; @@ -463,8 +466,8 @@ g_socket_details_from_fd (GSocket *socket) if (addrlen > 0) { g_assert (G_STRUCT_OFFSET (struct sockaddr, sa_family) + - sizeof address.ss_family <= addrlen); - family = address.ss_family; + sizeof address.storage.ss_family <= addrlen); + family = address.storage.ss_family; } else { @@ -488,7 +491,7 @@ g_socket_details_from_fd (GSocket *socket) { case G_SOCKET_FAMILY_IPV4: case G_SOCKET_FAMILY_IPV6: - socket->priv->family = address.ss_family; + socket->priv->family = address.storage.ss_family; switch (socket->priv->type) { case G_SOCKET_TYPE_STREAM: @@ -521,7 +524,7 @@ g_socket_details_from_fd (GSocket *socket) if (socket->priv->family != G_SOCKET_FAMILY_INVALID) { addrlen = sizeof address; - if (getpeername (fd, (struct sockaddr *) &address, &addrlen) >= 0) + if (getpeername (fd, &address.sa, &addrlen) >= 0) { socket->priv->connected_read = TRUE; socket->priv->connected_write = TRUE; @@ -1936,12 +1939,15 @@ GSocketAddress * g_socket_get_local_address (GSocket *socket, GError **error) { - struct sockaddr_storage buffer; + union { + struct sockaddr_storage storage; + struct sockaddr sa; + } buffer; guint len = sizeof (buffer); g_return_val_if_fail (G_IS_SOCKET (socket), NULL); - if (getsockname (socket->priv->fd, (struct sockaddr *) &buffer, &len) < 0) + if (getsockname (socket->priv->fd, &buffer.sa, &len) < 0) { int errsv = get_socket_errno (); g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), @@ -1949,7 +1955,7 @@ g_socket_get_local_address (GSocket *socket, return NULL; } - return g_socket_address_new_from_native (&buffer, len); + return g_socket_address_new_from_native (&buffer.storage, len); } /** @@ -1969,7 +1975,10 @@ GSocketAddress * g_socket_get_remote_address (GSocket *socket, GError **error) { - struct sockaddr_storage buffer; + union { + struct sockaddr_storage storage; + struct sockaddr sa; + } buffer; guint len = sizeof (buffer); g_return_val_if_fail (G_IS_SOCKET (socket), NULL); @@ -1984,7 +1993,7 @@ g_socket_get_remote_address (GSocket *socket, if (!socket->priv->remote_address) { - if (getpeername (socket->priv->fd, (struct sockaddr *) &buffer, &len) < 0) + if (getpeername (socket->priv->fd, &buffer.sa, &len) < 0) { int errsv = get_socket_errno (); g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), @@ -1992,7 +2001,7 @@ g_socket_get_remote_address (GSocket *socket, return NULL; } - socket->priv->remote_address = g_socket_address_new_from_native (&buffer, len); + socket->priv->remote_address = g_socket_address_new_from_native (&buffer.storage, len); } return g_object_ref (socket->priv->remote_address); @@ -2104,7 +2113,10 @@ g_socket_bind (GSocket *socket, gboolean reuse_address, GError **error) { - struct sockaddr_storage addr; + union { + struct sockaddr_storage storage; + struct sockaddr sa; + } addr; gboolean so_reuseaddr; #ifdef SO_REUSEPORT gboolean so_reuseport; @@ -2115,7 +2127,7 @@ g_socket_bind (GSocket *socket, if (!check_socket (socket, error)) return FALSE; - if (!g_socket_address_to_native (address, &addr, sizeof addr, error)) + if (!g_socket_address_to_native (address, &addr.storage, sizeof addr, error)) return FALSE; /* On Windows, SO_REUSEADDR has the semantics we want for UDP @@ -2147,7 +2159,7 @@ g_socket_bind (GSocket *socket, g_socket_set_option (socket, SOL_SOCKET, SO_REUSEPORT, so_reuseport, NULL); #endif - if (bind (socket->priv->fd, (struct sockaddr *) &addr, + if (bind (socket->priv->fd, &addr.sa, g_socket_address_get_native_size (address)) < 0) { int errsv = get_socket_errno (); @@ -2793,14 +2805,17 @@ g_socket_connect (GSocket *socket, GCancellable *cancellable, GError **error) { - struct sockaddr_storage buffer; + union { + struct sockaddr_storage storage; + struct sockaddr sa; + } buffer; g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE); if (!check_socket (socket, error)) return FALSE; - if (!g_socket_address_to_native (address, &buffer, sizeof buffer, error)) + if (!g_socket_address_to_native (address, &buffer.storage, sizeof buffer, error)) return FALSE; if (socket->priv->remote_address) @@ -2811,7 +2826,7 @@ g_socket_connect (GSocket *socket, { win32_unset_event_mask (socket, FD_CONNECT); - if (connect (socket->priv->fd, (struct sockaddr *) &buffer, + if (connect (socket->priv->fd, &buffer.sa, g_socket_address_get_native_size (address)) < 0) { int errsv = get_socket_errno (); diff --git a/glib/gmessages.c b/glib/gmessages.c index cb2abd5fd..8c78568b5 100644 --- a/glib/gmessages.c +++ b/glib/gmessages.c @@ -2167,12 +2167,15 @@ g_log_writer_is_journald (gint output_fd) if (g_once_init_enter (&initialized)) { - struct sockaddr_storage addr; + union { + struct sockaddr_storage storage; + struct sockaddr sa; + struct sockaddr_un un; + } addr; socklen_t addr_len = sizeof(addr); - int err = getpeername (output_fd, (struct sockaddr *) &addr, &addr_len); - if (err == 0 && addr.ss_family == AF_UNIX) - fd_is_journal = g_str_has_prefix (((struct sockaddr_un *)&addr)->sun_path, - "/run/systemd/journal/"); + int err = getpeername (output_fd, &addr.sa, &addr_len); + if (err == 0 && addr.storage.ss_family == AF_UNIX) + fd_is_journal = g_str_has_prefix (addr.un.sun_path, "/run/systemd/journal/"); g_once_init_leave (&initialized, TRUE); }