On 22/12/2024 10:44, Matthias Andree via Dnsmasq-discuss wrote:
Am 20.12.24 um 22:16 schrieb Simon Kelley:
On 12/20/24 12:27, Matthias Andree via Dnsmasq-discuss wrote:
Simon,
I cannot compile v2.91test1 on FreeBSD 14.2, errors below. (Neither
tarball nor Git compile.) (2nd to last shown errors). Patch attached,
should be fine with git-am.
Patch applied, thanks.
Adding multiple unions with variable size into some other aggregate
(union or struct) isn't portable, first shown warning below, might be
an error on other or strictly set compilers. This needs fixing not
covered by my patch.
If I've understood this right, then
https://thekelleys.org.uk/gitweb/?
p=dnsmasq.git;a=commit;h=4902807879c9b39db46c32e3e082a33266836d24
should fix it.
Thanks, but it's not sufficient, and my wording was unclear, sorry for
that.
I am attaching an incremental git-am ready patch to go on top your Git
HEAD,
to fix all sorts of issues and make this conforming C99 with default
options set,
and fix another load of warnings you receive when setting the compiler
to pick the nits,
-pedantic-errors -std=c99 (or c11, c18, c2x).
It changes many void * to uint8_t * to make the "increment by bytes"
explicit.
You can't do:
void *foo;
// ...
foo += 2.
Understood. There are few more instances of this in Linux-only code.
I'll see to those too.
IMPORTANT: please review the char data[1] in my patch, whether you want
to increase the size.
I see the six header warnings show below for practically all source
files compiled, and regarding the log message:
The warning is from FreeBSD 14.2's clang 18.1.6 compiler, not GCC, which
only shows them under -pedantic (I used GCC 13.3):
The root cause for these warnings appears to be the VLA char data[]
inside union all_addr's struct datablock, see line 342 of src/dnsmasq.h:
336 /* for arbitrary RR record small enough to go in addr.
337 NOTE: rrblock and rrdata are discriminated by the
F_KEYTAG bit
338 in the cache flags. */
339 struct datablock {
340 unsigned short rrtype;
341 unsigned char datalen; /* also length of SOA in negative
records. */
342 char data[];
343 } rrdata;
344 };
Declaring this as char data[1] or data[16] or whatever is suitable
should fix the warnings. data[0] is non-conforming and won't work either.
I don't know what's a good size here, as I haven't read enough context
code to judge that. My patch sets it 1 because that's the minimum in
order not to bloat the structure.
data[1] will, I think, work fine.
The plan here is to to have a union tag that stores the rrtype and a
small length field and uses the rest of the space in the union to store
RR data when that's small enough. The size of the union is at least 16
bytes, because it can store an IPv6 address, and I don't want it to get
any larger than that.
The line
#define RR_IMDATALEN (sizeof(union all_addr) - offsetof(struct
datablock, data))
calculates how much data will fit and is used in the code. This is
always 13 bytes at the moment. Sadly, the chicken-and-egg problem
prevents the use of that expression in the declaration of data[]
Declaring data[1] and then writing bytes up to data[12] clearly works
whilst struct rrdata is part of a union of size 16, but I wonder if it
will trip over array-overflow checking?
Maybe we should stop being clever,
#define RR_IMDATALEN 13
and declare data[RR_IMDATALEN];
That at least stays away from language definition areas I don't claim to
understand.
Also note that many of the *_addr types you define are
memory-inefficient because you often have short types before pointer
types, which have alignment requirements almost everywhere, and
something like:
struct {
unsigned short rrtype;
unsigned short datalen;
struct blockdata *rrdata;
} rrblock;
will incur 4 bytes of padding between datalen and rrdata so the pointer
is aligned at 64-bit boundaries. The standing recommendation is to sort
members by descending order of alignment requirement and size. I. e.
pointers and longs first, then ints, then shorts.
For this particular example, you could write:
struct {
struct blockdata *rrdata;
unsigned short rrtype;
unsigned short datalen;
} rrblock;
The reason for doing this is that it allows code to find the value of
rrtype from a strut rrblock OR struct rrdata all_addr without doing
different code path for each. No space is wasted in rrblock since the
all_addr union is 16 bytes to store an IPv6 address, and the struct as
defined fits that. It's important to have the rrtype at the start of
struct rrdata to maximise the size of the data field.
to fix that. IMPORTANT: my patch does not address this!
In many cases, size-definite types (such as uint16_t) are a good choice
if you really know the value range, say, from IETF standards and RFCs,
but would require lots of printf-style format adjustments, too.
./dnsmasq.h:350:18: warning: field 'addr' with variable sized type
'union all_addr' not at the end of a struct or class is a GNU
extension [-Wgnu-variable-sized-type-not-at-end]
350 | union all_addr addr;
| ^
./dnsmasq.h:416:18: warning: field 'addr' with variable sized type
'union all_addr' not at the end of a struct or class is a GNU
extension [-Wgnu-variable-sized-type-not-at-end]
416 | union all_addr addr;
| ^
./dnsmasq.h:483:18: warning: field 'addr' with variable sized type
'union all_addr' not at the end of a struct or class is a GNU
extension [-Wgnu-variable-sized-type-not-at-end]
483 | union all_addr addr;
| ^
./dnsmasq.h:782:20: warning: field 'dest' with variable sized type
'union all_addr' not at the end of a struct or class is a GNU
extension [-Wgnu-variable-sized-type-not-at-end]
782 | union all_addr dest;
| ^
./dnsmasq.h:787:5: warning: field 'frec_src' with variable sized type
'struct frec_src' not at the end of a struct or class is a GNU
extension [-Wgnu-variable-sized-type-not-at-end]
787 | } frec_src;
| ^
./dnsmasq.h:1108:18: warning: field 'source' with variable sized type
'union all_addr' not at the end of a struct or class is a GNU
extension [-Wgnu-variable-sized-type-not-at-end]
1108 | union all_addr source;
| ^
GCC shows such warnings in stricter modes (for instance, -pedantic),
clang already does with default options.
There is also this char * vs. void * complaint:
bpf.c: In function 'arp_enumerate':
bpf.c:94:40: warning: passing argument 2 of 'callback.af_unspec' from
incompatible pointer type [-Wincompatible-pointer-types]
94 | if (!callback.af_unspec(AF_INET, &sin2->sin_addr,
LLADDR(sdl), sdl->sdl_alen, parm))
| ^~~~~~~~~~~~~~~
| |
| struct in_addr *
bpf.c:94:40: note: expected 'char *' but argument is of type 'struct
in_addr *'
A simple fix for this one is changing the inf (*af_unspec)...
declaration to make void *addrp instead of char *addrp.
_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss
_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss