Hi all, I just noticed that a build for SLES12 threw the following warning: gcc -DHAVE_CONFIG_H -I. -I.. -DCONFDIR='"/etc"' -fmessage-length=0 -grecord-gcc-switches -fstack-protector -O2 -Wall -D_FORTIFY_SOURCE=2 -funwind-tables -fasynchronous-unwind-tables -g -c -o pdnsd-list.o `test -f 'list.c' || echo './'`list.c list.c: In function 'dlist_grow': list.c:113:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] *((size_t *)&a->data[a->last])=a->lastsz; ^ While when build for SLES15, with similar CFLAGS="-fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -g" it does not warn. The code is like: 109 size_t sz=0, allocsz=0, szincr, newsz; 110 if(a) { 111 sz=a->last+a->lastsz; 112 allocsz = (sz+DLISTCHUNKSIZEMASK)&(~DLISTCHUNKSIZEMASK); 113 *((size_t *)&a->data[a->last])=a->lastsz; 114 } I was just starting to patch this, then I noticed that I could not even get the warning to show on newer distributions. (My OBS instance does not have factory available easily, so I just tested OBS build on SLES12 and SLES15, but the warning does not trigger on current Tumbleweed, too, even with "-Wstrict-aliasing" added to the CFLAGS mix. What has changed? The rpmlint check said "this will break with future compilers" in SLES12. Is it now broken or have the compilers been fixed? -- Stefan Seyfried "For a successful technology, reality must take precedence over public relations, for nature cannot be fooled." -- Richard Feynman
Am 24.02.21 um 10:39 schrieb Stefan Seyfried:
*((size_t *)&a->data[a->last])=a->lastsz;
Can you provide the types of the relevant members of *a? Especially "data" would be interesting. I have tried struct { size_t last, lastsz; int* data; } a; which would make it a strict aliasing violation in my reading of the standard ([1], 6.5p7, here we have a 64-bit system with 32-bit int), but I can't get the warning to trigger for any version of GCC in the compiler explorer (godbolt.org), even with -O2 (in case it's a middle end warning). Though I remember that -Wstrict-aliasing used to be too strict in the past and was relaxed significantly, but I can't give you any details about that. The kind of aliasing we see here is (assuming the types are indeed as above) is technically illegal but no relevant compiler uses that for optimization since it's entirely local and the aliasing is transparent. Best regards, Aaron [1] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
Uh, nevermind, just saw your conversation on the other post. I should probably read the remaining posts before replying the next time. With char* it should of course be fine and the warning was just a bug. Am 25.02.21 um 00:57 schrieb Aaron Puchert:
Am 24.02.21 um 10:39 schrieb Stefan Seyfried:
*((size_t *)&a->data[a->last])=a->lastsz;
Can you provide the types of the relevant members of *a? Especially "data" would be interesting. I have tried
struct { size_t last, lastsz; int* data; } a;
which would make it a strict aliasing violation in my reading of the standard ([1], 6.5p7, here we have a 64-bit system with 32-bit int), but I can't get the warning to trigger for any version of GCC in the compiler explorer (godbolt.org), even with -O2 (in case it's a middle end warning).
Though I remember that -Wstrict-aliasing used to be too strict in the past and was relaxed significantly, but I can't give you any details about that. The kind of aliasing we see here is (assuming the types are indeed as above) is technically illegal but no relevant compiler uses that for optimization since it's entirely local and the aliasing is transparent.
Best regards, Aaron
[1] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
Wait, I think it's actually not allowed by the standard: it's allowed to access a size_t through a char* ("by an lvalue expression that has [...] a character type") but not the other way around. Though GCC might be smart enough to support it both ways, or maybe the aliasing tracker doesn't care about the "actual" type and just decides based on the access types if memory operations can alias, which means one type being char* is fine either way. But it shouldn't be aliased as another type ∉ {char, size_t} then. Best regards, Aaron Am 25.02.21 um 01:07 schrieb Aaron Puchert:
Uh, nevermind, just saw your conversation on the other post. I should probably read the remaining posts before replying the next time.
With char* it should of course be fine and the warning was just a bug.
Am 25.02.21 um 00:57 schrieb Aaron Puchert:
Am 24.02.21 um 10:39 schrieb Stefan Seyfried:
*((size_t *)&a->data[a->last])=a->lastsz;
Can you provide the types of the relevant members of *a? Especially "data" would be interesting. I have tried
struct { size_t last, lastsz; int* data; } a;
which would make it a strict aliasing violation in my reading of the standard ([1], 6.5p7, here we have a 64-bit system with 32-bit int), but I can't get the warning to trigger for any version of GCC in the compiler explorer (godbolt.org), even with -O2 (in case it's a middle end warning).
Though I remember that -Wstrict-aliasing used to be too strict in the past and was relaxed significantly, but I can't give you any details about that. The kind of aliasing we see here is (assuming the types are indeed as above) is technically illegal but no relevant compiler uses that for optimization since it's entirely local and the aliasing is transparent.
Best regards, Aaron
[1] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
On Thu, 25 Feb 2021, Aaron Puchert wrote:
Wait, I think it's actually not allowed by the standard: it's allowed to access a size_t through a char* ("by an lvalue expression that has [...] a character type") but not the other way around.
Indeed.
Though GCC might be smart enough to support it both ways, or maybe the aliasing tracker doesn't care about the "actual" type and just decides based on the access types if memory operations can alias, which means one type being char* is fine either way. But it shouldn't be aliased as another type ∉ {char, size_t} then.
Yes, GCC supports it both ways with some restrictions. The unfortunate fact is that this idiom is used quite often and recent C++ standards even bless it - you can construct arbitrary objects into such "storage" via placement new - yay! :( Now there can still be bugs but the -Wstrict-aliasing machinery only looks at a single expression and the bugs are inconsistencies between multiple expressions accessing the same storage. Richard.
Best regards, Aaron
Am 25.02.21 um 01:07 schrieb Aaron Puchert:
Uh, nevermind, just saw your conversation on the other post. I should probably read the remaining posts before replying the next time.
With char* it should of course be fine and the warning was just a bug.
Am 25.02.21 um 00:57 schrieb Aaron Puchert:
Am 24.02.21 um 10:39 schrieb Stefan Seyfried:
*((size_t *)&a->data[a->last])=a->lastsz;
Can you provide the types of the relevant members of *a? Especially "data" would be interesting. I have tried
struct { size_t last, lastsz; int* data; } a;
which would make it a strict aliasing violation in my reading of the standard ([1], 6.5p7, here we have a 64-bit system with 32-bit int), but I can't get the warning to trigger for any version of GCC in the compiler explorer (godbolt.org), even with -O2 (in case it's a middle end warning).
Though I remember that -Wstrict-aliasing used to be too strict in the past and was relaxed significantly, but I can't give you any details about that. The kind of aliasing we see here is (assuming the types are indeed as above) is technically illegal but no relevant compiler uses that for optimization since it's entirely local and the aliasing is transparent.
Best regards, Aaron
[1] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
-- Richard Biener <rguenther@suse.de> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
participants (3)
-
Aaron Puchert
-
Richard Biener
-
Stefan Seyfried