[Bug ipa/105682] [12/13 Regression] Both `-Wsuggest-attribute=pure` and `-Wsuggest-attribute=const` on same function since r12-5177-g494bdadf28d0fb35
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105682 --- Comment #8 from sagebar at web dot de --- (In reply to Jan Hubicka from comment #6) > I think the conlcusion here is correct. callee has pure attribute and that > means that it has no side effects except for reading global memory. So > whatever volatile assembly does has to satisfy this. > > Now since assembly is not declared as reading memory, GCC concludes that the > function has no side effects and does not read global memory and this can be > uprgraded to const. This assumes that reading memory is the only thing inline assembly can do to access (part of) the global state. But consider the following example where the ARM FPU control word is read: ``` #include // HINT: this is arm assembly //#define _FPU_GETCW(cw) __asm__ __volatile__("vmrs %0, fpscr" : "=r" (cw)) //#define _FPU_SETCW(cw) __asm__ __volatile__("vmsr fpscr, %0" : : "r" (cw)) __attribute__((pure)) fpu_control_t getcw() { fpu_control_t result; _FPU_GETCW(result); return result; } int main() { fpu_control_t before, after; before = getcw(); _FPU_SETCW(0x1234); after = getcw() printf("oldcw: %d\n", before); printf("newcw: %d\n", after); } ``` If you're saying that a `__asm__ __volatile__` that doesn't access memory should be considered as `const`, then gcc should be allowed to remove the first `getcw()` and simply assign the same value to `before` and `after` (since a `const` function's return value only depends on its arguments, meaning it calls can be removed and re-ordered however gcc pleases). I think you can see how that would be a problem in the above. However: I would understand gcc doing this if `_FPU_GETCW` was implemented using `__asm__` instead of `__asm__ __volatile__`. (If I'm misunderstanding how `pure` is meant to work, please correct me. But as far as I understand it, the above is a correct usage examle)
[Bug c/105676] New: Bogus `-Wsuggest-attribute=pure` on function marked `__attribute__((const))`
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105676 Bug ID: 105676 Summary: Bogus `-Wsuggest-attribute=pure` on function marked `__attribute__((const))` Product: gcc Version: 12.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: sagebar at web dot de Target Milestone: --- When compiling with `-Wsuggest-attribute=pure`, gcc warns about missing `__attribute__((pure))` on functions declared as `__attribute__((const))`. It is common knowledge that any function marked as `__attribute__((const))` also implicitly has the behavior of a function marked as `__attribute__((pure))` (const implies pure). Therefor, it stands to reason that such a warning is bogus (also: earlier version of gcc didn't emit a warning in this case; know: gcc-9 already supported these warnings, but didn't emit `-Wsuggest-attribute=pure` on a `__attribute__((const))` function). Example (`gcc -Wsuggest-attribute=pure -c -O2 input.c`): ``` __attribute__((const)) extern int do_expensive_calculation(void); __attribute__((const)) int getval(void) { static int cache = -1; if (cache == -1) cache = do_expensive_calculation(); return cache; } ``` >test.c: In function 'getval': >test.c:5:5: warning: function might be candidate for attribute 'pure' >>[-Wsuggest-attribute=pure] >5 | int getval(void) { > | ^~ When trying to declare as both pure+const: >test.c:5:1: warning: ignoring attribute 'const' because it conflicts with >attribute 'pure' [-Wattributes] >5 | int getval(void) { > | ^~~ Explaination of why using `__attribute__((const))` is valid here I see why gcc might think that `getval()` is *only* `pure`, but there is nothing wrong with the `__attribute__((const))` annotation since we don't "read global memory" (emphasis on the "global"), and thus don't depend on the global state (also: what counts as "global" vs. "non-global" isn't something that can be quantified. - It depends on the application and how memory is used). As such, the use of `__attribute__((const))` is very much valid (and gcc might even consider suggesting `__attribute__((const))` instead of `__attribute__((pure))`, since because `cache` is scoped-static, it not being used outside of `getval()` can actually be proven, though that isn't what this bug report is about...). However, so-long as it believes that the function is pure, there is no reason to ever emit a about that fact so-long as `getval()` remains annotated as `__attribute__((const))`. End of Explaination
[Bug c/105682] New: Both `-Wsuggest-attribute=pure` and `-Wsuggest-attribute=const` on same function
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105682 Bug ID: 105682 Summary: Both `-Wsuggest-attribute=pure` and `-Wsuggest-attribute=const` on same function Product: gcc Version: 12.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: sagebar at web dot de Target Milestone: --- The following example causes both a `-Wsuggest-attribute=pure` and `-Wsuggest-attribute=const` warning for the same function. Additionally, in this example, only `-Wsuggest-attribute=pure` would be correct (the `-Wsuggest-attribute=const` is completely bogus): Compile with `gcc -c -O2 -Wsuggest-attribute=const -Wsuggest-attribute=pure input.c`: ``` __attribute__((pure)) int callee(int x) { unsigned int a; __asm__ __volatile__(""); __asm__ __volatile__("" : "=X" (a)); x &= 1; if (a & 2) __asm__ __volatile__("" : "=m" (x)); return x & 4; } int caller(int x) { return callee(x); } ``` Output (gcc-12.1.0): >input.c: In function 'caller': >input.c:12:5: warning: function might be candidate for attribute 'pure' >[-Wsuggest-attribute=pure] > 12 | int caller(int x) { > | ^~ >input.c:12:5: warning: function might be candidate for attribute 'const' >[-Wsuggest-attribute=const] Output (gcc-11.2.0; expected behavior): >input.c: In function 'caller': >input.c:12:5: warning: function might be candidate for attribute 'pure' >[-Wsuggest-attribute=pure] > 12 | int caller(int x) { > | ^~ === After adding `__attribute__((pure))` to `caller` === ``` __attribute__((pure)) int caller(int x) { return callee(x); } ``` gcc-12.1.0 (bogus warning: `caller()` has no right to be const; it calls a pure function, and that function even contains inline assembly): >infile.c: In function 'caller': >infile.c:13:5: warning: function might be candidate for attribute 'const' >[-Wsuggest-attribute=const] > 13 | int caller(int x) { > | ^~ gcc-11.2.0 (expected behavior): > (No warnings) === NOTES: - Not only does gcc suggest to add both pure & const to the same function, the later wouldn't even make any sense in this scenario (though suggesting `pure` is correct). - The strange-looking body of `callee()` is required to reproduce the bug. - Trying to further simplify it tends to make the warning go away, suggesting a problem with some kind of heuristic. - I know I also just reported https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105676, but that one is about a bogus `-Wsuggest-attribute=pure` warning, while this one is about a bogus `-Wsuggest-attribute=const` warning. The two bugs may be related, but simply suppressing `-Wsuggest-attribute=pure` on const-functions wouldn't be enough to fix the bug addressed in this report.
[Bug c/105684] New: Bogus `-Warray-bounds` in partially allocated struct
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105684 Bug ID: 105684 Summary: Bogus `-Warray-bounds` in partially allocated struct Product: gcc Version: 12.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: sagebar at web dot de Target Milestone: --- Accessing the fields of a partially allocated struct results in `-Warray-bounds`, even when all accessed fields lie within the allocated portion of the struct (a fact that can be proven to be known to gcc by asking it for `__builtin_object_size()`) Example (compile with `gcc -c infile.c -O2 -Warray-bounds -S -o -`): ``` struct obj { unsigned long long kind; union { struct { unsigned long long a; } data0; struct { unsigned long long a; unsigned long long b; } data1; }; }; extern __attribute__((alloc_size(1))) void *my_malloc(unsigned long); #define offsetafter(s, m) (__builtin_offsetof(s, m) + sizeof(((s *)0)->m)) struct obj *create_object_kind_0(void) { struct obj *result; result = (struct obj *)my_malloc(offsetafter(struct obj, data0)); __asm__ __volatile__("# Object size is: %p0" : : "X" (__builtin_object_size(result, 0))); result->kind= 0; result->data0.a = 1; return result; } ``` Real-world use-case & rationale: the idea is that access to `data1` vs. `data0` is governed by the value of `kind` (`obj` is a "typed variant"), and by allocating only the relevant portion of the object, we can save memory, and create an environment where buggy code that wrongfully accesses (e.g.) certain fields of `data1` of a `kind=0` object might cause the program to crash (rather than remain unnoticed as would be the case when simply using `sizeof(struct obj)` as allocation size). Expected behavior: no warnings should be generated == Actual behavior (Truncated) === >[stderr]infile.c: In function 'create_object_kind_0': >[stderr]infile.c:22:15: warning: array subscript 'struct obj[0]' is partly >outside array bounds of 'unsigned char[16]' [-Warray-bounds] >[stderr] 21 | result->kind= 0; >[stderr] | ^~ >[stderr]infile.c:20:32: note: object of size 16 allocated by 'my_malloc' >[stderr] 19 | result = (struct obj *)my_malloc(offsetafter(struct >obj, data0)); >[stderr] | >^ >[stderr]infile.c:23:15: warning: array subscript 'struct obj[0]' is partly >outside array bounds of 'unsigned char[16]' [-Warray-bounds] >[stderr] 22 | result->data0.a = 1; >[stderr] | ^~ >[stderr]infile.c:20:32: note: object of size 16 allocated by 'my_malloc' >[stderr] 19 | result = (struct obj *)my_malloc(offsetafter(struct >obj, data0)); >[stderr] | >^ >[stdout][...] >[stdout]/ 22 "infile.c" 1 >[stdout]# Object size is: 16 >[stdout]/ 0 "" 2 >[stdout]/NO_APP >[stdout]movl$0, (%eax) >[stdout]movl$0, 4(%eax) >[stdout]movl$1, 8(%eax) >[stdout]movl$0, 12(%eax) >[stdout]leave >[stdout]ret >[stdout][...] As can be seen by `# Object size is: 16` (and repeated in warning messages), gcc knows that the allocated size of the object is 16 bytes, and as can be seen by the offsets used by the `movl` instructions, this limit is never exceeded. Judging by what the warnings state (and confirmed by replacing `offsetafter(struct obj, data0)` with `sizeof(struct obj)`), the `-Warray-bounds` warning will always be generated for any accessed field (irregardless of that field's offset) so-long as `__builtin_object_size(result, 0) < sizeof(struct obj)`. I am uncertain about the intended semantics of `-Warray-bounds`, and technically speaking, the warning is stating the truth: "'struct obj[0]' is partly outside array bounds" (emphasis on the "partly"). However, as it stands right now, warning about this situation is less than useful (a warning might arguably be useful when passing `result` -- or a pointer to one of its members -- to some other function, but even in that situation a warning would probably be a false positive). So in my opinion, at `-Warray-bounds[=1]`, a warning should only be generated exactly in those cases where an out-of-bounds access *actually* happens (*possible* out-of-bounds warnings may appear at `-Warray-bounds=2`, but definitely shouldn't at `-Warray-bounds=1`). == Additionally, after making the following changes to the above code (causing `sizeof(struct obj) == offsetafter(struct obj, data0)`): ``` @@ -6,7 +6,7 @@ } data0;
[Bug ipa/105685] New: Still Bogus `-Wsuggest-attribute=cold` on function already marked as `__attribute__((cold))`
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105685 Bug ID: 105685 Summary: Still Bogus `-Wsuggest-attribute=cold` on function already marked as `__attribute__((cold))` Product: gcc Version: 12.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: ipa Assignee: unassigned at gcc dot gnu.org Reporter: sagebar at web dot de CC: marxin at gcc dot gnu.org Target Milestone: --- I would re-open https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93087, but I don't think I can so a new bug report it is... - Anyways: while my test-case from back then remains fixed, the same problem still happens for the following code: Run (`gcc -c -O2 -Wsuggest-attribute=cold infile.c`) ``` extern void external_fun(char *, char const *, int); __attribute__((cold)) char *my_cold_fun(int x) { static char b[42]; external_fun(b, "Without me, the warning disappears?", x); return b; } __attribute__((cold)) char *my_other_cold_fun(int x) { return my_cold_fun(x); } ``` Output >infile.c: In function 'my_other_cold_fun': >infile.c:9:29: warning: function might be candidate for attribute 'cold' >[-Wsuggest-attribute=cold] >9 | __attribute__((cold)) char *my_other_cold_fun(int x) { > | ^ Output (Expected) >
[Bug c/105689] New: Bogus `-Wstringop-overflow=` after accessing field, then containing struct (wrong "region size")
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105689 Bug ID: 105689 Summary: Bogus `-Wstringop-overflow=` after accessing field, then containing struct (wrong "region size") Product: gcc Version: 12.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: sagebar at web dot de Target Milestone: --- The following code wrongly produces a warning `[-Wstringop-overflow=`: Compile (using `gcc -c -O2 infile.c`) ``` struct subobject { int field1; int field2; }; struct myobject { struct subobject sub; }; extern void access_1(int *a); extern __attribute__((access(read_write, 1))) void access_2(struct subobject *); void myfunc(struct myobject *me) { // { void *p __attribute__((unused)) = &me->sub; } access_1(&me->sub.field1); access_2(&me->sub); } ``` === Output (gcc-12) === >infile.c: In function 'myfunc': >infile.c:16:9: warning: 'access_2' accessing 8 bytes in a region of size 4 >[-Wstringop-overflow=] > 16 | access_2(&me->sub); > | ^~ >infile.c:11:52: note: in a call to function 'access_2' declared with attribute >'access (read_write, 1)' > 11 | extern __attribute__((access(read_write, 1))) void access_2(struct > subobject *); > |^~~~ === Output (expected) === > === Notes === - By uncommenting the line `{ void *p __attribute__((unused)) = &me->sub; }`, the warning goes away, even though that line literally does nothing. (see Theory below) - I was able to observe this bug in gcc-12.1.0 and gcc-11.2.0 === Theory === It seems that this has got something to do with some internal, hidden attribute (relating to the "region size") attached to some field-expression the first time that field is accessed, only that when accessing `me->sub.field1` (where `offsetof(field1) == 0`) before `me->sub`, that "region size" attribute wrongfully also gets attached to `me->sub`. Then, when an access to `me->sub` actually happens, gcc seems to think that the "region size" of `me->sub` as a whole matches the size of the previously accessed field (`me->sub.field1`). This seems further compounded by the fact that this only happens when `field1` is the first field of `subobject` (i.e. has offset 0). If we insert another field `int field0;` before it, the warning also disappears (so something in gcc's logic appears to make it think that `region_size_of() == region_size_of()`)
[Bug tree-optimization/105684] Bogus `-Warray-bounds` in partially allocated struct
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105684 --- Comment #3 from sagebar at web dot de --- >The issue is that 'result->data0.a' is (*result).data0.a, and so to GCC you are >accessing an object of type 'obj' for which there isn't enough allocated space. Technically true, and yes: not dereferencing `result` while it's still a `struct obj` makes the warning go away: ``` - result->kind= 0; - result->data0.a = 1; + *(unsigned long long *)((char *)result + __builtin_offsetof(struct obj, kind)) = 0; + *(unsigned long long *)((char *)result + __builtin_offsetof(struct obj, data0.a)) = 1; ``` But that's like saying `int x = obj->field;` is the same as `int x = ({ typeof(*obj) c = *obj; c.field; })` (i.e. accessing 1 field is like accessing _all_ fields) -- They're just not the same: accessing a single field simply doesn't cause the rest of the containing struct to also be loaded (if there's some weird arch where it does ???, fine; but then this should be an arch-specific warning). >A workaround might be to declare 'obj' as > >struct obj { > unsigned long long kind; > unsigned long long data[]; >}; > >if in your case all data is really uniform 'unsigned long long'. There's >no way to union several different typed flexarrays though. It would for the demo-code, but that's not the context where I encountered this problem in the real world. For reference, the following is the "typed variant"-style struct which lead me to create this bug report: https://github.com/GrieferAtWork/KOSmk4/blob/master/kos/src/kernel/moddbx/include/ctype.h#L193 I simply crafted the minimal viable code that still causes the warning for the sake of making this bug report.
[Bug debug/111080] New: restrict qualifier leaks debug info
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111080 Bug ID: 111080 Summary: restrict qualifier leaks debug info Product: gcc Version: 12.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: debug Assignee: unassigned at gcc dot gnu.org Reporter: sagebar at web dot de Target Milestone: --- The the following code example, debug information is retained for `struct foo` even though that structure doesn't end up used: Compile as `gcc -g -S -o - in.c | grep field_number` ``` struct foo { int field_number_1; int field_number_2; int field_number_3; int field_number_4; int field_number_5; }; typedef int fun_t(struct foo *restrict); int main() { return 0; } ``` Output: gcc -g -S -o - test.c | grep field_number .ascii "field_number_1\0" .ascii "field_number_2\0" .ascii "field_number_3\0" .ascii "field_number_4\0" .ascii "field_number_5\0" When removing the `restrict` qualifier in the parameter of `funptr_t`, debug information is not included in the produced assembly (as one would expect). Here is a list of different declarations and where `struct foo` is leaked in gcc 12.1.0: > typedef int fun_t(struct foo *restrict);// Leak > typedef int fun_t(struct foo *);// No leak > typedef int (*fun_t)(struct foo *restrict); // Leak > typedef int (*fun_t)(struct foo *); // No leak > extern int fun_t(struct foo *restrict); // No leak > extern int fun_t(struct foo *); // No leak > extern int (*fun_t)(struct foo *restrict); // Leak > extern int (*fun_t)(struct foo *); // No leak > static int fun_t(struct foo *restrict); // No leak > static int fun_t(struct foo *); // No leak > static int (*fun_t)(struct foo *restrict); // Leak > static int (*fun_t)(struct foo *); // Leak (even w/o restrict!) > int fun_t(struct foo *restrict);// No leak > int fun_t(struct foo *);// No leak > int (*fun_t)(struct foo *restrict); // Leak > int (*fun_t)(struct foo *); // Leak (even w/o restrict!) There is no difference when using `__restrict` or `__restrict__` instead.
[Bug debug/111080] [11/12/13/14 Regression] restrict qualifier causes extra debug info to happen
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111080 --- Comment #2 from sagebar at web dot de --- @Andrew Pinski Of course: yes. I did make a mistake there, but only for this case: > int (*fun_t)(struct foo *); // Leak (even w/o restrict!) asm: ... .globl fun_t .section.bss .align 4 .type fun_t, @object .size fun_t, 4 fun_t: .zero 4 ... In the other case: > static int (*fun_t)(struct foo *); // Leak (even w/o restrict!) asm: ... # No data-symbol is generated for `fun_t` ... Gcc actually doesn't generate a .bss-symbol for the static variable (since it's unused), but it still generates debug inforation for `struct foo`. So I guess strike `int (*fun_t)(struct foo *);` from the list, but keep `static int (*fun_t)(struct foo *);` which still leaks
[Bug driver/110607] New: Makefile.in build broken build-tools when CXXFLAGS is defined
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110607 Bug ID: 110607 Summary: Makefile.in build broken build-tools when CXXFLAGS is defined Product: gcc Version: 12.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: driver Assignee: unassigned at gcc dot gnu.org Reporter: sagebar at web dot de Target Milestone: --- This part in the main makefile: > 177 # These variables must be set on the make command line for directories > 178 # built for the build system to override those in BASE_FLAGS_TO_PASS. > 179 EXTRA_BUILD_FLAGS = \ > 180 CFLAGS="$(CFLAGS_FOR_BUILD)" \ > 181 LDFLAGS="$(LDFLAGS_FOR_BUILD)" Should instead be: > 177 # These variables must be set on the make command line for directories > 178 # built for the build system to override those in BASE_FLAGS_TO_PASS. > 179 EXTRA_BUILD_FLAGS = \ > 180 CFLAGS="$(CFLAGS_FOR_BUILD)" \ > 181 CXXFLAGS="$(CXXFLAGS_FOR_BUILD)" \ > 182 LDFLAGS="$(LDFLAGS_FOR_BUILD)" Since some components of the build system are compiled as c++, if one wants to define custom CXX-flags in cross-compilation situations, these flags then also get used when building build-tools (which causes breakage)
[Bug bootstrap/110607] Makefile.in builds broken build-tools when CXXFLAGS is defined
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110607 --- Comment #2 from sagebar at web dot de --- @Andrew Pinski Sorry if this is a known bug. I simply checked the current gcc master (https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=Makefile.tpl;h=d0fe7e2fb778b3c3fa2cc8742e06cf1f78fdc5f2;hb=HEAD#l183), which is still affected. I was not aware that a fix was already pending but not yet merged.