https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105282
Bug ID: 105282 Summary: [11/12 Regression] V_INDIR overflow causes ICE on -O0 -flto Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: gcov-profile Assignee: unassigned at gcc dot gnu.org Reporter: slyfox at gcc dot gnu.org CC: marxin at gcc dot gnu.org Target Milestone: --- Initially the bug is reported by John Helmert III in https://bugs.gentoo.org/838094 where python-3.10.4 failed to build on -flto -O0. Here is the single-file minimal reproducer: #include <stddef.h> typedef void (*cb_t)(void); #define F(__fn) static void __fn(void) {} F(f00);F(f01);F(f02);F(f03);F(f04);F(f05);F(f06);F(f07);F(f08);F(f09); F(f10);F(f11);F(f12);F(f13);F(f14);F(f15);F(f16);F(f17);F(f18);F(f19); F(f20);F(f21);F(f22);F(f23);F(f24);F(f25);F(f26);F(f27);F(f28);F(f29); F(f30);F(f31);F(f32);F(f33);F(f34);F(f35);F(f36);F(f37);F(f38);F(f39); F(f40);F(f41);F(f42);F(f43);F(f44);F(f45);F(f46);F(f47);F(f48);F(f49); static void f(int i) { /* Needs to be bigger than gcc's GCOV_TOPN_MAXIMUM_TRACKED_VALUES == 32 * to overflow GCOV_COUNTER_V_INDIR couter type. */ static const cb_t fs[] = { &f00,&f01,&f02,&f03,&f04,&f05,&f06,&f07,&f08,&f09, &f10,&f11,&f12,&f13,&f14,&f15,&f16,&f17,&f18,&f19, &f20,&f21,&f22,&f23,&f24,&f25,&f26,&f27,&f28,&f29, &f30,&f31,&f32,&f33,&f34,&f35,&f36,&f37,&f38,&f39, &f40,&f41,&f42,&f43,&f44,&f45,&f46,&f47,&f48,&f49, }; size_t sz = sizeof (fs) / sizeof (fs[0]); fs[i % sz](); } int l(int argc, char * argv[]); int main(int argc, char *argv[]) { if (argc == 1) for (unsigned int i = 0; i < 25; i++) f(i); if (argc == 2) for (unsigned int i = 25; i < 50; i++) f(i); } Crashing: $ gcc -flto -O0 a.c -fprofile-generate -o a $ ./a # populate first 25 buckets $ ./a 1 # populate 25 more buckets, cause overflow $ gcc -flto -O0 a.c -fprofile-use during IPA pass: modref a.c:36:1: internal compiler error: in stream_out_histogram_value, at value-prof.cc:340 36 | } | ^ 0x8351fb stream_out_histogram_value(output_block*, histogram_value_t*) ../../gcc-12-20220410/gcc/value-prof.cc:340 0x1c848c0 output_gimple_stmt ../../gcc-12-20220410/gcc/gimple-streamer-out.cc:192 0x1c848c0 output_bb(output_block*, basic_block_def*, function*) ../../gcc-12-20220410/gcc/gimple-streamer-out.cc:227 0xdc91ad output_function ../../gcc-12-20220410/gcc/lto-streamer-out.cc:2453 0xdc91ad lto_output() ../../gcc-12-20220410/gcc/lto-streamer-out.cc:2796 0xe57b11 write_lto ../../gcc-12-20220410/gcc/passes.cc:2762 0xe57b11 ipa_write_summaries_1 ../../gcc-12-20220410/gcc/passes.cc:2826 0xe57b11 ipa_write_summaries() ../../gcc-12-20220410/gcc/passes.cc:2882 0xaac060 ipa_passes ../../gcc-12-20220410/gcc/cgraphunit.cc:2209 0xaac060 symbol_table::compile() ../../gcc-12-20220410/gcc/cgraphunit.cc:2282 0xaaea77 symbol_table::compile() ../../gcc-12-20220410/gcc/cgraphunit.cc:2262 0xaaea77 symbol_table::finalize_compilation_unit() ../../gcc-12-20220410/gcc/cgraphunit.cc:2530 Please submit a full bug report, with preprocessed source (by using -freport-bug). Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. $ gcc -v Using built-in specs. COLLECT_GCC=/<<NIX>>/gcc-debug-12.0.0/bin/gcc COLLECT_LTO_WRAPPER=/<<NIX>>/gcc-debug-12.0.0/libexec/gcc/x86_64-unknown-linux-gnu/12.0.1/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: Thread model: posix Supported LTO compression algorithms: zlib gcc version 12.0.1 20220410 (experimental) (GCC) I think it happens due to overly restrictive gcc_assert() in gcc/value-prof.cc: void stream_out_histogram_value (struct output_block *ob, histogram_value hist) { unsigned int i; ... for (i = 0; i < hist->n_counters; i++) { /* When user uses an unsigned type with a big value, constant converted to gcov_type (a signed type) can be negative. */ gcov_type value = hist->hvalue.counters[i]; if (hist->type == HIST_TYPE_TOPN_VALUES || hist->type == HIST_TYPE_IOR) /* Note that the IOR counter tracks pointer values and these can have sign bit set. */ ; else gcc_assert (value >= 0); streamer_write_gcov_count (ob, value); } ... } Note how it implies that all entries of HIST_TYPE_INDIR_CALL are expected to be non-nevative values. It's not true for a case when two merged histograms overflow at libgcc/libgcov-merge.c: /* ... We use -TOTAL for situation when merging dropped some values. The information is used for -fprofile-reproducible flag. */ void __gcov_merge_topn (gcov_type *counters, unsigned n_counters) { ... full |= gcov_topn_add_value (counters + GCOV_TOPN_MEM_COUNTERS * i, value, count, 0, 0); } if (full) *total = -(*total); } }