From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id E80DE383F859; Mon, 4 Jan 2021 22:43:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E80DE383F859 From: "w at 1wt dot eu" To: gcc-bugs@gcc.gnu.org Subject: [Bug c/98503] [11 regression] -Warray-bounds false positive with global variables at -O2 since r11-3306-g3f9a497d1b0dd9da Date: Mon, 04 Jan 2021 22:43:51 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c X-Bugzilla-Version: 11.0 X-Bugzilla-Keywords: diagnostic X-Bugzilla-Severity: normal X-Bugzilla-Who: w at 1wt dot eu X-Bugzilla-Status: REOPENED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: 11.0 X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: resolution bug_status Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: gcc-bugs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-bugs mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Jan 2021 22:43:52 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D98503 Willy Tarreau changed: What |Removed |Added ---------------------------------------------------------------------------- Resolution|INVALID |--- Status|RESOLVED |REOPENED --- Comment #7 from Willy Tarreau --- It's not easy because as often with optimizations, depending on the code mo= ves I'm doing, the issue appears and disappears. The closest looking one is bel= ow. The general idea is that we're having a function that is called to dump a certain number of elements to a buffer and return when the buffer is full, = to give back control to other parts of the code, then it's called again from t= he last list element where the dump was started. A common practice with such interruptible processing of list consists in starting from the head and let= ting the dump function iterate. This would roughly look like this (still simplif= ied quite a bit to grasp the principle). The code below manages to trigger the warning. If you're interested in the original code (I doubt it), it's on th= is line: https://github.com/haproxy/haproxy/blob/master/src/ssl_sock.c#L6366 a= nd the initial call is made here: https://github.com/haproxy/haproxy/blob/master/src/ssl_sock.c#L6437 #include #define container_of(ptr, type, member) ({ \ void *__mptr =3D (void *)(ptr); \ ((type *)(__mptr - __builtin_offsetof(type, member))); }) // returns number of bytes emitted or 0 if it failed to dump. extern int try_dump_string(const char *name); struct list { struct list *n; struct list *p; }; static struct list head; struct ref { struct list list; char *filename; }; static struct ref *last_dumped; /* try to dump one ref, returns 0 on failure */ static inline int try_dump_next_ref(struct ref *ref) { return try_dump_string(ref->filename); } static inline struct ref *get_initial_step() { return container_of(&head, struct ref, list); } static inline struct ref *next_step(struct ref *cur) { return container_of(cur->list.n, struct ref, list); } /* restarts a dump from dump_context or starts a new one if NULL */ struct ref *restart_dump(struct ref *last) { struct ref *curr; if (!last) last =3D get_initial_step(); curr =3D next_step(last); while (&curr->list !=3D &head) { if (try_dump_next_ref(curr)) { last =3D curr; curr =3D next_step(curr); } else { /* do something to yield or flush the output */ } } return last; } void cont_dump() { restart_dump(last_dumped); } Please note that here "last_dump" isn't updated and if the compiler sees it being written to, it eliminates some optimizations that result in the warni= ng (I think it sees that the get_initial_step() is conditional and thus doesn't complain anymore). I understand from your description that there could be an aliasing issue. I= 'd argue that as soon as we're using lists there are potential aliasing issues= and that these may then be addressed using -fno-strict-aliasing but this one ha= s no effect here either. Also I suspect based on your description, that accessing *any* field of a struct implies the whole struct must be mapped in memory. But then there are limits in case of aliased struct like above, or even when using VLAs since = you can't figure the possible extent of the variable part. I think I see how I could cheat to eliminate the warning (not easy to test = as I don't have the trunk version of the compiler locally), but I suspect that d= oing so would definitely make the code more error-prone. I sincerely think that this *exact* case is counter-productive as it will basically force a number of users of lists to disable the whole warning, wh= ich was otherwise particularly effective at detecting real out-of-bounds access= es, especially in such use cases. Or maybe you could assign it a different level (-Warray-bounds=3D3 ?) to indicate a suspicious usage that might also be a = valid one ? Thanks! Willy=