Bug 78460

Summary: [7/8 Regression] [SH] OOM building glibc string tst-cmp.c
Product: gcc Reporter: Joseph S. Myers <jsm28>
Component: targetAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: fw
Priority: P4 Keywords: memory-hog
Version: 7.0   
Target Milestone: 7.3   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67712
Host: Target: sh4-linux-gnu
Build: Known to work:
Known to fail: Last reconfirmed: 2016-11-22 00:00:00
Attachments: preprocessed source

Description Joseph S. Myers 2016-11-22 01:29:57 UTC
Created attachment 40105 [details]
preprocessed source

GCC mainline built for sh4-linux-gnu runs out of memory building string/tst-cmp.c.  The symptom observed is that cc1's memory usage goes up by a bit under 1GB a second until it's killed after exhausting memory and swap (on a system with 128GB of each).  Compile with: sh4-glibc-linux-gnu-gcc -S tst-cmp.i -fno-isolate-erroneous-paths-dereference -fno-isolate-erroneous-paths-attribute -std=gnu11 -fgnu89-inline  -O2 -fmerge-all-constants -g

Preprocessed source attached.
Comment 1 Martin Liška 2016-11-22 13:58:59 UTC
Simple test-case:
int foo(char *left, char *right)
{
  return strncmp (left, right, 4294967295U);
}

triggers ICE after I added:
diff --git a/gcc/config/sh/sh-mem.cc b/gcc/config/sh/sh-mem.cc
index f91afa5..018d8bb 100644
--- a/gcc/config/sh/sh-mem.cc
+++ b/gcc/config/sh/sh-mem.cc
@@ -364,6 +364,7 @@ sh_expand_cmpnstr (rtx *operands)
       rtx_code_label *L_end_loop_long = gen_label_rtx ();
 
       int bytes = INTVAL (operands[3]);
+      gcc_assert (bytes >= 0);
       int witers = bytes / 4;
 
       if (witers > 1)

Looks 'int' should be replaces with unsigned HOST_WIDE_INT, but still using a cross compiler, where host is x86_64, I get:

(gdb) p debug_rtx(operands[3])
(const_int -1 [0xffffffffffffffff])
$1 = void

and thus unsigned HOST_WIDE_INT bytes = INTVAL (operands[3]);
is 18446744073709551615 (0xffffffffffffffff).

Apart from that, I wondering why there's no limit, as for instance:
strncmp (left, right, 1000); emits battalion of instructions.
Comment 2 Oleg Endo 2016-11-24 13:13:46 UTC
(In reply to Martin Liška from comment #1)
> 
> Apart from that, I wondering why there's no limit, as for instance:
> strncmp (left, right, 1000); emits battalion of instructions.

Oh yeah, that's PR 67712.
Comment 3 Florian Weimer 2017-05-01 13:34:03 UTC
I see ~500 GiB with GCC 7.0.1 20170501 (prerelease) [gcc-7-branch revision 247430].  This interferes rather badly with cross-compiler-based testing.
Comment 4 jsm-csl@polyomino.org.uk 2017-05-01 13:38:26 UTC
FWIW, my build-many-glibcs.py bots for GCC 7 and mainline are run with 
"ulimit -v 16777216" to limit the effects of this bug.
Comment 5 Jakub Jelinek 2017-05-02 15:58:20 UTC
GCC 7.1 has been released.
Comment 6 Joseph S. Myers 2017-08-15 23:43:09 UTC
Author: jsm28
Date: Tue Aug 15 23:42:23 2017
New Revision: 251108

URL: https://gcc.gnu.org/viewcvs?rev=251108&root=gcc&view=rev
Log:
Limit SH strncmp inline expansion (PR target/78460).

GCC mainline built for sh4-linux-gnu runs out of memory building a
glibc test, which calls strncmp with very large constant size
argument, resulting in the SH inline strncmp expansion trying to
inline a fully unrolled expansion of strncmp for that size.

This patch limits that fully unrolled expansion to the case of less
than 32 bytes.  This is explicitly *not* trying to be optimal in any
way (very likely a lower threshold makes sense), just to limit enough
to avoid the out-of-memory issue in the glibc testsuite.

I have *not* run the GCC testsuite for SH.  I have verified that this
allows the glibc testsuite to build OK, with both GCC mainline and GCC
7 branch (and that the included test builds quickly with patched GCC,
runs out of memory with unpatched GCC).

	PR target/78460
	PR target/67712
gcc:
	* config/sh/sh-mem.cc (sh_expand_cmpnstr): Only unroll for
	constant count if that count is less than 32.

gcc/testsuite:
	* gcc.c-torture/compile/string-large-1.c: New test.

Added:
    trunk/gcc/testsuite/gcc.c-torture/compile/string-large-1.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/sh/sh-mem.cc
    trunk/gcc/testsuite/ChangeLog
Comment 7 Joseph S. Myers 2017-08-15 23:44:01 UTC
Author: jsm28
Date: Tue Aug 15 23:43:11 2017
New Revision: 251109

URL: https://gcc.gnu.org/viewcvs?rev=251109&root=gcc&view=rev
Log:
Limit SH strncmp inline expansion (PR target/78460).

GCC mainline built for sh4-linux-gnu runs out of memory building a
glibc test, which calls strncmp with very large constant size
argument, resulting in the SH inline strncmp expansion trying to
inline a fully unrolled expansion of strncmp for that size.

This patch limits that fully unrolled expansion to the case of less
than 32 bytes.  This is explicitly *not* trying to be optimal in any
way (very likely a lower threshold makes sense), just to limit enough
to avoid the out-of-memory issue in the glibc testsuite.

I have *not* run the GCC testsuite for SH.  I have verified that this
allows the glibc testsuite to build OK, with both GCC mainline and GCC
7 branch (and that the included test builds quickly with patched GCC,
runs out of memory with unpatched GCC).

	PR target/78460
	PR target/67712
gcc:
	* config/sh/sh-mem.cc (sh_expand_cmpnstr): Only unroll for
	constant count if that count is less than 32.

gcc/testsuite:
	* gcc.c-torture/compile/string-large-1.c: New test.

Added:
    branches/gcc-7-branch/gcc/testsuite/gcc.c-torture/compile/string-large-1.c
Modified:
    branches/gcc-7-branch/gcc/ChangeLog
    branches/gcc-7-branch/gcc/config/sh/sh-mem.cc
    branches/gcc-7-branch/gcc/testsuite/ChangeLog
Comment 8 Joseph S. Myers 2017-08-15 23:51:59 UTC
Fixed for GCC 7.3 and GCC 8.
Comment 9 Aldy Hernandez 2017-09-13 17:00:27 UTC
Author: aldyh
Date: Wed Sep 13 16:59:51 2017
New Revision: 252436

URL: https://gcc.gnu.org/viewcvs?rev=252436&root=gcc&view=rev
Log:
Limit SH strncmp inline expansion (PR target/78460).

GCC mainline built for sh4-linux-gnu runs out of memory building a
glibc test, which calls strncmp with very large constant size
argument, resulting in the SH inline strncmp expansion trying to
inline a fully unrolled expansion of strncmp for that size.

This patch limits that fully unrolled expansion to the case of less
than 32 bytes.  This is explicitly *not* trying to be optimal in any
way (very likely a lower threshold makes sense), just to limit enough
to avoid the out-of-memory issue in the glibc testsuite.

I have *not* run the GCC testsuite for SH.  I have verified that this
allows the glibc testsuite to build OK, with both GCC mainline and GCC
7 branch (and that the included test builds quickly with patched GCC,
runs out of memory with unpatched GCC).

	PR target/78460
	PR target/67712
gcc:
	* config/sh/sh-mem.cc (sh_expand_cmpnstr): Only unroll for
	constant count if that count is less than 32.

gcc/testsuite:
	* gcc.c-torture/compile/string-large-1.c: New test.

Added:
    branches/range-gen2/gcc/testsuite/gcc.c-torture/compile/string-large-1.c
Modified:
    branches/range-gen2/gcc/ChangeLog
    branches/range-gen2/gcc/config/sh/sh-mem.cc
    branches/range-gen2/gcc/testsuite/ChangeLog