From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id D95BC385803B; Tue, 18 Jan 2022 00:47:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D95BC385803B From: "msebor at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug middle-end/103483] [12 regression] context-sensitive ranges change triggers stringop-overread Date: Tue, 18 Jan 2022 00:47:13 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: middle-end X-Bugzilla-Version: 12.0 X-Bugzilla-Keywords: diagnostic X-Bugzilla-Severity: normal X-Bugzilla-Who: msebor at gcc dot gnu.org X-Bugzilla-Status: NEW X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: 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: Tue, 18 Jan 2022 00:47:14 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D103483 --- Comment #17 from Martin Sebor --- Jaosn: this is how all middle-end warnings have always behaved. They trigg= er on invalid statements present in the IL. A statement is considered invalid when any of its operands is out of bounds or in some other way not valid fo= r it (e.g., null in -Wnonnull, or not pointing to the first byte allocated on the heap in -Wfree-nonheap-pointer, or not matching an allocation call in -Wmismatched-dealloc). Warnings don't differentiate between constant opera= nds or those in some range. We have been making more extensive use of ranges s= ince get_range_info() was introduced, but prior to that, -Warray-bounds made use= of ranges as well (thanks to VRP). Even in warnings that don't use ranges, constant operands need not be literals: they can be reduced to constants fr= om ranges by various transformations (jump threading is just one of them). For more background please see my two-part article from 2019: Understanding GCC Warnings: https://developers.redhat.com/blog/2019/03/13/understanding-gcc-warnings =20 https://developers.redhat.com/blog/2019/03/13/understanding-gcc-warnings-pa= rt-2 It's easy to derive examples from the one in comment #12 or comment #15 sho= wing other similar warnings: replacing the memcpy() call with an array subscript triggers a -Warray-bounds; snprintf() triggers -Wformat-truncation; malloc() triggers -Walloc-size-larger-than; etc. See below. (I also showed an exam= ple with -Wnonnull in comment #13. It's issued on the same basis.) It might seem like the common denominator in all these instances is ranges,= but they're a red herring. The same effect can be demonstrated without them. = The root cause behind them all is that (again) warnings are designed to trigger= for apparently reachable invalid IL. See pr54202 for an example from 2012 with -Wfree-nonheap-object. The warning is simply based on what the pointer poi= nts to, irrespective of the conditions under which the invalid statement is evaluated. If you consider any of the warnings above false positives you must consider= as such all of them. It makes no sense to do something about just a subset of them and not the rest. And to avoid them altogether you have to disable (o= r at least seriously cripple) all those we've ever added into the middle end. Y= ou could, for example, only warn in statements that are reached unconditionally from function entry. Removing them them all from -Wall and making them opt= -in would reduce the number of complaints but only as a result of the number of users explicitly enabling the warnings, without actually improving anything (besides, by being included in -Wall most already are opt-in). In any even= t, any of these alternatives would compromise the security improvements we have invested so much in over the years. The best solution, in my view, is to s= how users the conditionals under which the invalid statements can be reached. I hoped to be able to do that by extending Ranger (https://gcc.gnu.org/pipermail/gcc/2021-December/237922.html) but it could = also be done by rolling a range propagation engine just for warnings (like for t= he static analyzer). char *sink; __attribute__ ((noipa)) int mystrlen (const char *p) { return __builtin_strlen (p); } inline void copy(const char *p) { int L =3D mystrlen (p); if (L < 5) /* Small string magic. */; else *sink =3D p[L]; } void f() {=20 copy ("12"); }=20 In function =E2=80=98copy=E2=80=99, inlined from =E2=80=98f=E2=80=99 at a.c:18:3: a.c:14:13: warning: array subscript [5, 2147483647] is outside array bounds= of =E2=80=98char[3]=E2=80=99 [-Warray-bounds] 14 | *sink =3D p[L]; | ~^~~ char *sink; __attribute__ ((noipa)) int mystrlen (const char *p) { return __builtin_strlen (p); } inline void copy(const char *p) { int L =3D mystrlen (p); if (L < 5) /* Small string magic. */; else __builtin_snprintf (sink, 5, "%*s", L, p); } void f() {=20 copy ("12"); }=20 a.c: In function =E2=80=98f=E2=80=99: a.c:14:38: warning: =E2=80=98__builtin_snprintf=E2=80=99 output truncated b= efore the last format character [-Wformat-truncation=3D] 14 | __builtin_snprintf (sink, 5, "%*s", L, p); | ^ In function =E2=80=98copy=E2=80=99, inlined from =E2=80=98f=E2=80=99 at a.c:18:3: a.c:14:5: note: =E2=80=98__builtin_snprintf=E2=80=99 output between 6 and 2= 147483648 bytes into a destination of size 5 14 | __builtin_snprintf (sink, 5, "%*s", L, p); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $ gcc -O2 -S -Walloc-size-larger-than=3D4 a.c har *sink; __attribute__ ((noipa)) int mystrlen (const char *p) { return __builtin_strlen (p); } inline void copy(const char *p) { int L =3D mystrlen (p); if (L < 5) /* Small string magic. */; else sink =3D __builtin_malloc (L); } void f() {=20 copy ("12"); }=20 In function =E2=80=98copy=E2=80=99, inlined from =E2=80=98f=E2=80=99 at a.c:18:3: a.c:14:12: warning: argument 1 range [5, 2147483647] exceeds maximum object size 4 [-Walloc-size-larger-than=3D] 14 | sink =3D __builtin_malloc (L); | ^~~~~~~~~~~~~~~~~~~~ a.c:14:12: note: in a call to built-in allocation function =E2=80=98__built= in_malloc=E2=80=99=