https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80169

            Bug ID: 80169
           Summary: G++ (cc1plus) hangs forever compiling template when
                    size of array is enormous
           Product: gcc
           Version: 6.3.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dawid_jurek at vp dot pl
  Target Milestone: ---

0. Gcc version.

gcc -v

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc-multilib/src/gcc/configure --prefix=/usr
--libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man
--infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/
--enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared
--enable-threads=posix --enable-libmpx --with-system-zlib --with-isl
--enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu
--disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object
--enable-linker-build-id --enable-lto --enable-plugin
--enable-install-libiberty --with-linker-hash-style=gnu
--enable-gnu-indirect-function --enable-multilib --disable-werror
--enable-checking=release
Thread model: posix
gcc version 6.3.1 20170109 (GCC) 

1. Issue.

Snippet:

template <typename T>
struct GetTypeNameHelper
{
    static const char* GetTypeName(void)
    {
        static const size_t size = sizeof(__FUNCTION__) - sizeof("GetTypeName
");
        static char typeName[size] = {};
        return typeName;
    }
};
static void test_case__freeze()
{
    std::cout << GetTypeNameHelper<int>::GetTypeName() << "\n";
}

Running this: g++ -Wall -W -g -std=c++14 ../../src/main.cpp -o main 
for above snippet leads to hanging cc1plus process which must be interrupted by
Ctrl+C.

Anyway compilation for this snippet works as expected:

static const char* GetTypeName()
{
    static const size_t size = sizeof(__FUNCTION__) - sizeof("GetTypeName ");
    static char typeName[size] = {};
    return typeName;
}
static void test_case__ok()
{
    std::cout << GetTypeName() << "\n";
}

g++ -Wall -W -g -std=c++14 ../../src/main.cpp -o main 
../../src/main.cpp: In function ‘const char* ok_case::GetTypeName()’:
../../src/main.cpp:254:30: error: size of array ‘typeName’ is too large
     static char typeName[size] = {};
                              ^
../../src/main.cpp:255:12: error: ‘typeName’ was not declared in this scope
     return typeName;
            ^~~~~~~~

2. Analysis

I tried godbolt and seems that issue is easily reproducible for all gcc since
gcc 4.9. Please take a look on link [1] on bottom of my email. It means bug was
probably introduced in gcc 4.9. If you try g++ 4.8.5 then output is expected: 

<source>:9:21: error: size of variable 'typeName' is too large
static char typeName[size] = {};
^
Compiler exited with result code 1

But for g++ 4.9 and newer we get compilation timeouts: 

Killed - processing time exceeded
Compiler exited with result code null

Anyway I managed to reproduce problem in my local environment with debbugable
gcc 7 invoked under gdb. After investigation I localized root cause inside c++
front end internals.

/mnt/gcc/build/bin/gcc -wrapper /usr/bin/gdb,--args -Wall -W -g -std=c++14
../../src/main.cpp -o main
GNU gdb (GDB) 7.12.1
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from
/mnt/gcc/build/libexec/gcc/x86_64-pc-linux-gnu/7.0.1/cc1plus...done.
(gdb) r
Starting program: /mnt/gcc/build/libexec/gcc/x86_64-pc-linux-gnu/7.0.1/cc1plus
-quiet -D_GNU_SOURCE ../../src/main.cpp -quiet -dumpbase main.cpp
-mtune=generic -march=x86-64 -auxbase main -g -Wall -Wextra -std=c++14 -o
/tmp/ccrSwF5W.s
^C
Program received signal SIGINT, Interrupt.
zero_init_p (t=0x7ffff6a663f0) at .././../gcc/gcc/cp/tree.c:3834
3834      if (TYPE_PTRDATAMEM_P (t))
(gdb) bt
#0  zero_init_p (t=0x7ffff6a663f0) at .././../gcc/gcc/cp/tree.c:3834
#1  0x00000000006851e6 in process_init_constructor_array (complain=3,
init=<optimized out>, type=0x7ffff502b000) at .././../gcc/gcc/cp/typeck2.c:1328
#2  process_init_constructor (complain=3, init=<optimized out>,
type=0x7ffff502b000) at .././../gcc/gcc/cp/typeck2.c:1619
#3  digest_init_r (type=type@entry=0x7ffff502b000, init=<optimized out>,
init@entry=0x7ffff5017510, nested=nested@entry=false, flags=<optimized out>,
complain=complain@entry=3) at .././../gcc/gcc/cp/typeck2.c:1131
#4  0x0000000000687613 in digest_init_flags (complain=3, flags=<optimized out>,
init=0x7ffff5017510, type=0x7ffff502b000) at .././../gcc/gcc/cp/typeck2.c:1176
#5  store_init_value (decl=decl@entry=0x7ffff5006ab0,
init=init@entry=0x7ffff5017510, cleanups=cleanups@entry=0x7fffffffdcb0,
flags=flags@entry=2048) at .././../gcc/gcc/cp/typeck2.c:803
#6  0x00000000005e277b in check_initializer (decl=decl@entry=0x7ffff5006ab0,
init=0x7ffff5017510, flags=2048, flags@entry=0,
cleanups=cleanups@entry=0x7fffffffdcb0) at .././../gcc/gcc/cp/decl.c:6365
#7  0x000000000060d1ad in cp_finish_decl (decl=decl@entry=0x7ffff5006ab0,
init=<optimized out>, init_const_expr_p=<optimized out>,
asmspec_tree=<optimized out>, asmspec_tree@entry=0x0, flags=flags@entry=0)
    at .././../gcc/gcc/cp/decl.c:7037
#8  0x000000000064578b in tsubst_expr (t=0x7ffff54cd020, args=<optimized out>,
complain=3, in_decl=<optimized out>, integral_constant_expression_p=<optimized
out>) at .././../gcc/gcc/cp/pt.c:15828
#9  0x00000000006426ee in tsubst_expr (t=<optimized out>, args=0x7ffff54cd300,
complain=3, in_decl=0x7ffff524fe80, integral_constant_expression_p=<optimized
out>) at .././../gcc/gcc/cp/pt.c:15717
#10 0x0000000000642d81 in tsubst_expr (t=0x7ffff58453c0, args=0x7ffff54cd300,
complain=3, in_decl=0x7ffff524fe80, integral_constant_expression_p=<optimized
out>) at .././../gcc/gcc/cp/pt.c:15943
#11 0x000000000063f528 in instantiate_decl (d=<optimized out>,
d@entry=0x7ffff5252a00, defer_ok=<optimized out>, defer_ok@entry=false,
expl_inst_class_mem_p=expl_inst_class_mem_p@entry=false) at
.././../gcc/gcc/cp/pt.c:22894
#12 0x000000000067f6fc in instantiate_pending_templates
(retries=retries@entry=0) at .././../gcc/gcc/cp/pt.c:23015
#13 0x00000000006c2a49 in c_parse_final_cleanups () at
.././../gcc/gcc/cp/decl2.c:4526
#14 0x0000000000d3450f in compile_file () at .././../gcc/gcc/toplev.c:467
#15 0x00000000005b8468 in do_compile () at .././../gcc/gcc/toplev.c:2000
#16 toplev::main (this=this@entry=0x7fffffffe23e, argc=<optimized out>,
argc@entry=17, argv=<optimized out>, argv@entry=0x7fffffffe338) at
.././../gcc/gcc/toplev.c:2134
#17 0x00000000005ba76b in main (argc=17, argv=0x7fffffffe338) at
.././../gcc/gcc/main.c:39


Every time I stop cc1plus and check backtrace it contains
process_init_constructor_array. It clearly corresponds to empty list
initialization for array typeName in source code I provided.
It turns out cc1plus enters infinite loop here (gcc/cp/typeck2.c:1312)

  if (!unbounded)
    for (; i < len; ++i)
      {
      ...

The reason is simple. Right before entering loop variable len has maximal
unsigned long value (len = 18446744073709551615 = 0xFFFFFFFFFFFFFFFF).

(gdb) s
process_init_constructor_array (complain=3, init=0x7ffff5017510,
type=0x7ffff502b000) at .././../gcc/gcc/cp/typeck2.c:1278
1278      if (!unbounded && vec_safe_length (v) > len)
(gdb) info locals
i = <optimized out>
len = 18446744073709551615
flags = 0
ce = <optimized out>
unbounded = false
v = 0x0

Conclusion is that for some reason front end try to build constructor for every
array element. Unfortunately it doesn't detect that array is extremly large and
in consequence cc1plus enters infinite loop. Hope it helps for further
investigation in gcc team.

Regards,
Dawid 

[1]
https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,options:(colouriseAsm:%270%27,compileOnChange:%270%27),source:%27%23include+%3Ciostream%3E%0A%0Atemplate+%3Ctypename+T%3E%0Astruct+GetTypeNameHelper%0A%7B%0A++++static+const+char*+GetTypeName(void)%0A++++%7B%0A++++++++static+const+size_t+size+%3D+sizeof(__FUNCTION__)+-+sizeof(%22GetTypeName+%22)%3B%0A++++++++static+char+typeName%5Bsize%5D+%3D+%7B%7D%3B%0A++++++++return+typeName%3B%0A++++%7D%0A%7D%3B%0A%0Astatic+void+test_case__freeze()%0A%7B%0A++++std::cout+%3C%3C+GetTypeNameHelper%3Cint%3E::GetTypeName()+%3C%3C+%22%5Cn%22%3B%0A%7D%0A%0Aint+main()%0A%7B%0A++test_case__freeze()%3B%0A++return+0%3B%0A%7D%0A++%27),l:%275%27,n:%271%27,o:%27C%2B%2B+source+%231%27,t:%270%27)),k:47.03755465382113,l:%274%27,n:%270%27,o:%27%27,s:0,t:%270%27),(g:!((h:compiler,i:(compiler:g63,filters:(b:%270%27,commentOnly:%270%27,directives:%270%27,intel:%270%27),options:%27%27),l:%275%27,n:%270%27,o:%27%231+with+x86-64+gcc+6.3%27,t:%270%27)),k:18.110716230348245,l:%274%27,n:%270%27,o:%27%27,s:0,t:%270%27),(g:!((h:output,i:(compiler:1,editor:1),l:%275%27,n:%270%27,o:%27%231+with+x86-64+gcc+6.3%27,t:%270%27)),k:34.85172911583061,l:%274%27,n:%270%27,o:%27%27,s:0,t:%270%27)),l:%272%27,n:%270%27,o:%27%27,t:%270%27)),version:4

Reply via email to