Avoid undefined behavior in struct sockaddr
Problem noted by Philipp Stephani in: http://lists.gnu.org/archive/html/emacs-devel/2017-05/msg00391.html * src/conf_post.h (ATTRIBUTE_MAY_ALIAS, DECLARE_POINTER_ALIAS): New macros. * src/process.c (conv_sockaddr_to_lisp, conv_lisp_to_sockaddr) (connect_network_socket, network_interface_info) (server_accept_connection): Use it when aliasing non-char objects.
This commit is contained in:
parent
184d74ce00
commit
e54a3b4fde
2 changed files with 31 additions and 14 deletions
|
@ -263,6 +263,20 @@ extern int emacs_setenv_TZ (char const *);
|
|||
#define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST
|
||||
#define ATTRIBUTE_UNUSED _GL_UNUSED
|
||||
|
||||
#if GNUC_PREREQ (3, 3, 0)
|
||||
# define ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__))
|
||||
#else
|
||||
# define ATTRIBUTE_MAY_ALIAS
|
||||
#endif
|
||||
|
||||
/* Declare NAME to be a pointer to an object of type TYPE, initialized
|
||||
to the address ADDR, which may be of a different type. Accesses
|
||||
via NAME may alias with other accesses with the traditional
|
||||
behavior, even if options like gcc -fstrict-aliasing are used. */
|
||||
|
||||
#define DECLARE_POINTER_ALIAS(name, type, addr) \
|
||||
type ATTRIBUTE_MAY_ALIAS *name = (type *) (addr)
|
||||
|
||||
#if 3 <= __GNUC__
|
||||
# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
|
||||
#else
|
||||
|
|
|
@ -2476,7 +2476,7 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len)
|
|||
{
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
|
||||
DECLARE_POINTER_ALIAS (sin, struct sockaddr_in, sa);
|
||||
len = sizeof (sin->sin_addr) + 1;
|
||||
address = Fmake_vector (make_number (len), Qnil);
|
||||
p = XVECTOR (address);
|
||||
|
@ -2487,8 +2487,8 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len)
|
|||
#ifdef AF_INET6
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
|
||||
uint16_t *ip6 = (uint16_t *) &sin6->sin6_addr;
|
||||
DECLARE_POINTER_ALIAS (sin6, struct sockaddr_in6, sa);
|
||||
DECLARE_POINTER_ALIAS (ip6, uint16_t, &sin6->sin6_addr);
|
||||
len = sizeof (sin6->sin6_addr) / 2 + 1;
|
||||
address = Fmake_vector (make_number (len), Qnil);
|
||||
p = XVECTOR (address);
|
||||
|
@ -2501,7 +2501,7 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len)
|
|||
#ifdef HAVE_LOCAL_SOCKETS
|
||||
case AF_LOCAL:
|
||||
{
|
||||
struct sockaddr_un *sockun = (struct sockaddr_un *) sa;
|
||||
DECLARE_POINTER_ALIAS (sockun, struct sockaddr_un, sa);
|
||||
ptrdiff_t name_length = len - offsetof (struct sockaddr_un, sun_path);
|
||||
/* If the first byte is NUL, the name is a Linux abstract
|
||||
socket name, and the name can contain embedded NULs. If
|
||||
|
@ -2612,7 +2612,7 @@ conv_lisp_to_sockaddr (int family, Lisp_Object address, struct sockaddr *sa, int
|
|||
p = XVECTOR (address);
|
||||
if (family == AF_INET)
|
||||
{
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
|
||||
DECLARE_POINTER_ALIAS (sin, struct sockaddr_in, sa);
|
||||
len = sizeof (sin->sin_addr) + 1;
|
||||
hostport = XINT (p->contents[--len]);
|
||||
sin->sin_port = htons (hostport);
|
||||
|
@ -2622,8 +2622,8 @@ conv_lisp_to_sockaddr (int family, Lisp_Object address, struct sockaddr *sa, int
|
|||
#ifdef AF_INET6
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
|
||||
uint16_t *ip6 = (uint16_t *)&sin6->sin6_addr;
|
||||
DECLARE_POINTER_ALIAS (sin6, struct sockaddr_in6, sa);
|
||||
DECLARE_POINTER_ALIAS (ip6, uint16_t, &sin6->sin6_addr);
|
||||
len = sizeof (sin6->sin6_addr) / 2 + 1;
|
||||
hostport = XINT (p->contents[--len]);
|
||||
sin6->sin6_port = htons (hostport);
|
||||
|
@ -2645,7 +2645,7 @@ conv_lisp_to_sockaddr (int family, Lisp_Object address, struct sockaddr *sa, int
|
|||
#ifdef HAVE_LOCAL_SOCKETS
|
||||
if (family == AF_LOCAL)
|
||||
{
|
||||
struct sockaddr_un *sockun = (struct sockaddr_un *) sa;
|
||||
DECLARE_POINTER_ALIAS (sockun, struct sockaddr_un, sa);
|
||||
cp = SDATA (address);
|
||||
for (i = 0; i < sizeof (sockun->sun_path) && *cp; i++)
|
||||
sockun->sun_path[i] = *cp++;
|
||||
|
@ -3436,13 +3436,15 @@ connect_network_socket (Lisp_Object proc, Lisp_Object addrinfos,
|
|||
== offsetof (struct sockaddr_in6, sin6_port))
|
||||
&& sizeof (sa1.sin_port) == sizeof (sa6.sin6_port));
|
||||
#endif
|
||||
if (getsockname (s, (struct sockaddr *)&sa1, &len1) == 0)
|
||||
DECLARE_POINTER_ALIAS (psa1, struct sockaddr, &sa1);
|
||||
if (getsockname (s, psa1, &len1) == 0)
|
||||
{
|
||||
Lisp_Object service = make_number (ntohs (sa1.sin_port));
|
||||
contact = Fplist_put (contact, QCservice, service);
|
||||
/* Save the port number so that we can stash it in
|
||||
the process object later. */
|
||||
((struct sockaddr_in *) sa)->sin_port = sa1.sin_port;
|
||||
DECLARE_POINTER_ALIAS (psa, struct sockaddr_in, sa);
|
||||
psa->sin_port = sa1.sin_port;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -3550,9 +3552,10 @@ connect_network_socket (Lisp_Object proc, Lisp_Object addrinfos,
|
|||
{
|
||||
struct sockaddr_storage sa1;
|
||||
socklen_t len1 = sizeof (sa1);
|
||||
if (getsockname (s, (struct sockaddr *)&sa1, &len1) == 0)
|
||||
DECLARE_POINTER_ALIAS (psa1, struct sockaddr, &sa1);
|
||||
if (getsockname (s, psa1, &len1) == 0)
|
||||
contact = Fplist_put (contact, QClocal,
|
||||
conv_sockaddr_to_lisp ((struct sockaddr *)&sa1, len1));
|
||||
conv_sockaddr_to_lisp (psa1, len1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -4401,7 +4404,7 @@ network_interface_info (Lisp_Object ifname)
|
|||
|
||||
for (it = ifap; it != NULL; it = it->ifa_next)
|
||||
{
|
||||
struct sockaddr_dl *sdl = (struct sockaddr_dl *) it->ifa_addr;
|
||||
DECLARE_POINTER_ALIAS (sdl, struct sockaddr_dl, it->ifa_addr);
|
||||
unsigned char linkaddr[6];
|
||||
int n;
|
||||
|
||||
|
@ -4722,7 +4725,7 @@ server_accept_connection (Lisp_Object server, int channel)
|
|||
{
|
||||
args[nargs++] = procname_format_in6;
|
||||
nargs++;
|
||||
uint16_t *ip6 = (uint16_t *)&saddr.in6.sin6_addr;
|
||||
DECLARE_POINTER_ALIAS (ip6, uint16_t, &saddr.in6.sin6_addr);
|
||||
service = make_number (ntohs (saddr.in.sin_port));
|
||||
for (int i = 0; i < 8; i++)
|
||||
args[nargs++] = make_number (ip6[i]);
|
||||
|
|
Loading…
Add table
Reference in a new issue