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