diff options
author | Philip Withnall <philip.withnall@collabora.co.uk> | 2013-12-17 09:27:58 +0000 |
---|---|---|
committer | Olivier Crête <olivier.crete@collabora.com> | 2013-12-18 17:50:33 -0500 |
commit | 63e74d8efac70b92df008da8a27d72720216b937 (patch) | |
tree | 13301091104a90abce05445ee582f6419882d30d /agent/pseudotcp.c | |
parent | 71fa5bb8716ea311fc3a1d9cc845a123eb8cd4cc (diff) | |
download | libnice-63e74d8efac70b92df008da8a27d72720216b937.tar.gz |
Fix strict aliasing of sockaddr structures
Casting from one struct sockaddr type to another breaks C’s strict
aliasing rules (variables of different types cannot alias). Fix this
cleanly by using unions of struct sockaddrs to convert between the
types (i.e. type-punning).
I wish sockaddr didn’t have to be this painful.
See:
http://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Optimize-Options.html#Type_002dpunning
Diffstat (limited to 'agent/pseudotcp.c')
-rw-r--r-- | agent/pseudotcp.c | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/agent/pseudotcp.c b/agent/pseudotcp.c index 632eb28..fe8dcc1 100644 --- a/agent/pseudotcp.c +++ b/agent/pseudotcp.c @@ -794,32 +794,36 @@ packet(PseudoTcpSocket *self, guint32 seq, guint8 flags, { PseudoTcpSocketPrivate *priv = self->priv; guint32 now = get_current_time(); - guint8 buffer[MAX_PACKET]; + union { + guint8 u8[MAX_PACKET]; + guint16 u16[MAX_PACKET / 2]; + guint32 u32[MAX_PACKET / 4]; + } buffer; PseudoTcpWriteResult wres = WR_SUCCESS; g_assert(HEADER_SIZE + len <= MAX_PACKET); - *((guint32 *) buffer) = htonl(priv->conv); - *((guint32 *) (buffer + 4)) = htonl(seq); - *((guint32 *) (buffer + 8)) = htonl(priv->rcv_nxt); - buffer[12] = 0; - buffer[13] = flags; - *((guint16 *) (buffer + 14)) = htons((guint16)priv->rcv_wnd); + *buffer.u32 = htonl(priv->conv); + *(buffer.u32 + 1) = htonl(seq); + *(buffer.u32 + 2) = htonl(priv->rcv_nxt); + buffer.u8[12] = 0; + buffer.u8[13] = flags; + *(buffer.u16 + 7) = htons((guint16)priv->rcv_wnd); // Timestamp computations - *((guint32 *) (buffer + 16)) = htonl(now); - *((guint32 *) (buffer + 20)) = htonl(priv->ts_recent); + *(buffer.u32 + 4) = htonl(now); + *(buffer.u32 + 5) = htonl(priv->ts_recent); priv->ts_lastack = priv->rcv_nxt; if (data != NULL) - memcpy(buffer + HEADER_SIZE, data, len); + memcpy(buffer.u8 + HEADER_SIZE, data, len); DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "<-- <CONV=%d><FLG=%d><SEQ=%d:%d><ACK=%d>" "<WND=%d><TS=%d><TSR=%d><LEN=%d>", priv->conv, (unsigned)flags, seq, seq + len, priv->rcv_nxt, priv->rcv_wnd, now % 10000, priv->ts_recent % 10000, len); - wres = priv->callbacks.WritePacket(self, (gchar *) buffer, len + HEADER_SIZE, + wres = priv->callbacks.WritePacket(self, (gchar *) buffer.u8, len + HEADER_SIZE, priv->callbacks.user_data); /* Note: When data is NULL, this is an ACK packet. We don't read the return value for those, and thus we won't retry. So go ahead and treat @@ -839,23 +843,31 @@ packet(PseudoTcpSocket *self, guint32 seq, guint8 flags, } static gboolean -parse(PseudoTcpSocket *self, const guint8 * buffer, guint32 size) +parse(PseudoTcpSocket *self, const guint8 * _buffer, guint32 size) { Segment seg; + union { + const guint8 *u8; + const guint16 *u16; + const guint32 *u32; + } buffer; + + buffer.u8 = _buffer; + if (size < 12) return FALSE; - seg.conv = ntohl(*(guint32 *)buffer); - seg.seq = ntohl(*(guint32 *)(buffer + 4)); - seg.ack = ntohl(*(guint32 *)(buffer + 8)); - seg.flags = buffer[13]; - seg.wnd = ntohs(*(guint16 *)(buffer + 14)); + seg.conv = ntohl(*buffer.u32); + seg.seq = ntohl(*(buffer.u32 + 1)); + seg.ack = ntohl(*(buffer.u32 + 2)); + seg.flags = buffer.u8[13]; + seg.wnd = ntohs(*(buffer.u16 + 7)); - seg.tsval = ntohl(*(guint32 *)(buffer + 16)); - seg.tsecr = ntohl(*(guint32 *)(buffer + 20)); + seg.tsval = ntohl(*(buffer.u32 + 4)); + seg.tsecr = ntohl(*(buffer.u32 + 5)); - seg.data = ((gchar *)buffer) + HEADER_SIZE; + seg.data = ((gchar *)buffer.u8) + HEADER_SIZE; seg.len = size - HEADER_SIZE; DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "--> <CONV=%d><FLG=%d><SEQ=%d:%d><ACK=%d>" |