[SLOF] [PATCH] libnet: Fix compiler warnings with GCC 9
Alexey Kardashevskiy
aik at ozlabs.ru
Mon Sep 23 16:44:13 AEST 2019
On 23/09/2019 16:16, Thomas Huth wrote:
> On 23/09/2019 04.21, Alexey Kardashevskiy wrote:
>>
>>
>> On 20/09/2019 03:48, Thomas Huth wrote:
>>> When compiling the libnet code with GCC 9, there are some new
>>> compiler warnings popping up now:
>>>
>>> ipv6.c: In function ‘handle_ipv6’:
>>> ipv6.c:152:21: warning: taking address of packed member of ‘struct ip6hdr’
>>> may result in an unaligned pointer value [-Waddress-of-packed-member]
>>> 152 | if (! find_ip6addr(&(ip6->dst)))
>>> | ^~~~~~~~~~~
>>> ipv6.c: In function ‘ip6_checksum’:
>>> ipv6.c:455:2: warning: converting a packed ‘struct ip6hdr’ pointer
>>> (alignment 1) to a ‘short unsigned int’ pointer (alignment 2) may result
>>> in an unaligned pointer value [-Waddress-of-packed-member]
>>> 455 | pip6h = (unsigned short *) &pseudo_ip6h;
>>> | ^~~~~
>>> In file included from ipv6.c:21:
>>> ipv6.h:86:8: note: defined here
>>> 86 | struct ip6hdr {
>>> | ^~~~~~
>>> ipv6.c:522:8: warning: converting a packed ‘struct icmp6hdr’ pointer
>>> (alignment 1) to a ‘short unsigned int’ pointer (alignment 2) may result
>>> in an unaligned pointer value [-Waddress-of-packed-member]
>>> 522 | ip6h->pl >> 1);
>>> | ^~~~
>>> In file included from ipv6.c:22:
>>> icmpv6.h:123:8: note: defined here
>>> 123 | struct icmp6hdr {
>>> | ^~~~~~~~
>>> etc.
>>>
>>> The entries in struct ip6hdr are naturally aligned, so we can simply
>>> drop the __attribute__ ((packed)) here and use a _Static_assert() for
>>> the correct size instead.
>>> icmp6hdr is a more complex struct since it contains a union of
>>> packed structs, but the entries before the union are naturally aligned,
>>> too, so we can silence the compiler warning by dropping the "packed"
>>> attribute from the struct icmp6hdr and just asserting that the union
>>> is at the correct offset.
>>>
>>> Signed-off-by: Thomas Huth <thuth at redhat.com>
>>> ---
>>> lib/libnet/icmpv6.h | 4 +++-
>>> lib/libnet/ipv6.h | 3 ++-
>>> 2 files changed, 5 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/lib/libnet/icmpv6.h b/lib/libnet/icmpv6.h
>>> index 41b0c70..ba51524 100644
>>> --- a/lib/libnet/icmpv6.h
>>> +++ b/lib/libnet/icmpv6.h
>>> @@ -130,6 +130,8 @@ struct icmp6hdr {
>>> struct router_solicitation router_solicit;
>>> struct router_advertisement ra;
>>> } icmp6body;
>>> -} __attribute((packed));
>>> +};
>>> +_Static_assert((long)&(((struct icmp6hdr *)NULL)->icmp6body) == 4,
>>> + "unexpected padding in icmp6hdr");
>>>
>>> #endif
>>> diff --git a/lib/libnet/ipv6.h b/lib/libnet/ipv6.h
>>> index 7b71b50..5fb718e 100644
>>> --- a/lib/libnet/ipv6.h
>>> +++ b/lib/libnet/ipv6.h
>>> @@ -90,7 +90,8 @@ struct ip6hdr {
>>> uint8_t hl; /**< Hop limit */
>>> ip6_addr_t src; /**< IPv6 source address */
>>> ip6_addr_t dst; /**< IPv6 destination address */
>>> -} __attribute((packed));
>>
>>
>> The (packed) rather explicitly says it is a binary format which is a
>> good thing.
>
> It's ok for architectures where you know that the CPU can do unaligned
> memory accesses. But it's ugly in generic code that should be compilable
> on any architecture, then these packed structs are often rather a
> nuisance - we've had this problems in the QEMU sources a couple of times
> already. So I rather prefer to write code *without* the "packed"
> attribute nowadays.
It is a binary format, just a different scope, how is this a nuisance?
They have to be packed anyway.
>>> +};
>>> +_Static_assert(sizeof(struct ip6hdr) == 40, "unexpected padding in ip6hdr");
>>
>> This hurts my eyes.
>
> Really? Would it be better if it was wrapped in a nice macro?
This one at least checks the whole struct size but the other one was
checking an offset, that one did hurt. A programming language should
provide guarantees of this kind of alignments and (packed) does exactly
this.
>> I propose this approach (gcc8 compile tested only, I still to compile my
>> own gcc9):
>>
>> https://github.com/aik/SLOF/commit/2cdb340ac5026d0478eb873c0ad57bd6dc0a289f
>>
>> Does this work? Basically instead of passing "unaligned" pointers, do
>> the right thing and pass values instead, we are not that much restricted
>> in SLOF to save bytes.
>
> That approach looks fine at a first glance to me, too -- at least for
> the libnet code.
>
> But your patch didn't fix all warnings yet. These are left:
Sure, I have not tried to fix that, this is just a direction, you are
welcome to finish the task :) Or I can do that when I get time to
compile gcc9, recover my ipv6 setup for testing and try myself.
>
> lib/libnet/ipv6.c: In function ‘ip6_checksum’:
> lib/libnet/ipv6.c:452:2: warning: converting a packed ‘struct ip6hdr’
> pointer (alignment 1) to a ‘short unsigned int’ pointer (alignment 2)
> may result in an unaligned pointer value [-Waddress-of-packed-member]
> 452 | pip6h = (unsigned short *) &pseudo_ip6h;
> | ^~~~~
> In file included from lib/libnet/ipv6.c:21:
> lib/libnet/ipv6.h:86:8: note: defined here
> 86 | struct ip6hdr {
> | ^~~~~~
> CC pc-bios/s390-ccw/ndp.o
> lib/libnet/ipv6.c: In function ‘send_ipv6’:
> lib/libnet/ipv6.c:519:8: warning: converting a packed ‘struct icmp6hdr’
> pointer (alignment 1) to a ‘short unsigned int’ pointer (alignment 2)
> may result in an unaligned pointer value [-Waddress-of-packed-member]
> 519 | ip6h->pl >> 1);
> | ^~~~
> In file included from lib/libnet/ipv6.c:22:
> lib/libnet/icmpv6.h:123:8: note: defined here
> 123 | struct icmp6hdr {
> | ^~~~~~~~
> lib/libnet/ipv6.c:527:32: warning: taking address of packed member of
> ‘struct ip6hdr’ may result in an unaligned pointer value
> [-Waddress-of-packed-member]
> 527 | gw = ipv6_get_default_router(&ip6h->src);
> | ^~~~~~~~~~
> lib/libnet/icmpv6.c: In function ‘handle_ra’:
> lib/libnet/icmpv6.c:171:11: warning: taking address of packed member of
> ‘struct ip6hdr’ may result in an unaligned pointer value
> [-Waddress-of-packed-member]
> 171 | rtr_ip = (ip6_addr_t *) &ip6h->src;
> | ^~~~~~~~~~~~~~~~~~~~~~~~~
>
> At least the ip6_checksum()-related warnings can not be silenced that
> easily with your approach of passing parameters by value instead of
> pointer...
Then use unions:
https://github.com/aik/SLOF/commit/db37446ad
ip6_checksum() is weird btw.
>> Or disable this particular warning. What exactly
>> does it protect against?
> If I've googled it right, assigning an unaligned pointer value is
> undefined behavior according to the C standard. So the compiler could do
> weird stuff if we simply ignore it.
Huh. Well. There we go - no taking references of struct members.
--
Alexey
More information about the SLOF
mailing list