Created attachment 52943 [details] reduced testcase Compiler output: $ x86_64-pc-linux-gnu-gcc -O testcase.c -c /repo/gcc-trunk/gcc/expmed.cc:3272:26: runtime error: signed integer overflow: -9223372036854775808 - 1 cannot be represented in type 'long int' (gdb) bt #0 __ubsan::Diag::~Diag (this=this@entry=0x7fffffffc250, __in_chrg=<optimized out>) at /repo/gcc-trunk/libsanitizer/ubsan/ubsan_diag.cpp:343 #1 0x00000000074e14ec in handleIntegerOverflowImpl<__ubsan::Value> (Data=Data@entry=0x85fd8e0, LHS=LHS@entry=9223372036854775808, Operator=Operator@entry=0x7b7c28d "-", RHS=..., Opts=...) at /repo/gcc-trunk/libsanitizer/ubsan/ubsan_handlers.cpp:227 #2 0x00000000074e478d in __ubsan::__ubsan_handle_sub_overflow (Data=Data@entry=0x85fd8e0, LHS=LHS@entry=9223372036854775808, RHS=RHS@entry=1) at /repo/gcc-trunk/libsanitizer/ubsan/ubsan_handlers.cpp:244 #3 0x0000000001384d5d in choose_mult_variant (mode=E_DImode, val=<optimized out>, alg=0x7fffffffc6b0, variant=0x7fffffffc6ac, mult_cost=16) at /repo/gcc-trunk/gcc/expmed.cc:3272 #4 0x0000000001385946 in mult_by_coeff_cost (coeff=-9223372036854775808, mode=E_DImode, speed=<optimized out>) at /repo/gcc-trunk/gcc/expmed.cc:3610 #5 0x00000000068ae3ac in create_add_ssa_cand (gs=0x7ffff7851a50, base_in=0x7ffff7852ea0, addend_in=<optimized out>, subtract_p=false, speed=true) at /repo/gcc-trunk/gcc/gimple-ssa-strength-reduction.cc:1311 #6 0x00000000068b4668 in slsr_process_add (speed=true, rhs2=0x7ffff7852ea0, rhs1=<optimized out>, gs=<optimized out>) at /repo/gcc-trunk/gcc/gimple-ssa-strength-reduction.cc:1484 #7 find_candidates_dom_walker::before_dom_children (this=<optimized out>, bb=<optimized out>) at /repo/gcc-trunk/gcc/gimple-ssa-strength-reduction.cc:1803 #8 0x000000000665b9e5 in dom_walker::walk (this=<optimized out>, bb=0x7ffff76f4478) at /repo/gcc-trunk/gcc/domwalk.cc:309 #9 0x000000000689d07a in (anonymous namespace)::pass_strength_reduction::execute (this=<optimized out>, fun=0x7ffff784c0b8) at /repo/gcc-trunk/gcc/gimple-ssa-strength-reduction.cc:4039 #10 0x00000000021af318 in execute_one_pass (pass=0xc6701b0) at /repo/gcc-trunk/gcc/passes.cc:2638 #11 0x00000000021b2902 in execute_pass_list_1 (pass=0xc6701b0) at /repo/gcc-trunk/gcc/passes.cc:2738 #12 0x00000000021b2945 in execute_pass_list_1 (pass=0xc66dcc0) at /repo/gcc-trunk/gcc/passes.cc:2739 #13 0x00000000021b29f9 in execute_pass_list (fn=0x7ffff784c0b8, pass=<optimized out>) at /repo/gcc-trunk/gcc/passes.cc:2749 #14 0x0000000000f8cebc in cgraph_node::expand (this=0x7ffff784f110) at /repo/gcc-trunk/gcc/cgraphunit.cc:1835 #15 0x0000000000f92108 in expand_all_functions () at /repo/gcc-trunk/gcc/cgraphunit.cc:1999 #16 symbol_table::compile (this=0x7ffff76ec000) at /repo/gcc-trunk/gcc/cgraphunit.cc:2349 #17 0x0000000000fa02ad in symbol_table::compile (this=0x7ffff76ec000) at /repo/gcc-trunk/gcc/cgraphunit.cc:2262 #18 symbol_table::finalize_compilation_unit (this=0x7ffff76ec000) at /repo/gcc-trunk/gcc/cgraphunit.cc:2530 #19 0x00000000026d34a3 in compile_file () at /repo/gcc-trunk/gcc/toplev.cc:479 #20 0x0000000000917d45 in do_compile (no_backend=false) at /repo/gcc-trunk/gcc/toplev.cc:2168 #21 toplev::main (this=this@entry=0x7fffffffd27e, argc=<optimized out>, argc@entry=17, argv=<optimized out>, argv@entry=0x7fffffffd3c8) at /repo/gcc-trunk/gcc/toplev.cc:2320 #22 0x000000000091bb6b in main (argc=17, argv=0x7fffffffd3c8) at /repo/gcc-trunk/gcc/main.cc:39 $ x86_64-pc-linux-gnu-gcc -v Using built-in specs. COLLECT_GCC=/repo/gcc-trunk/binary-latest-amd64/bin/x86_64-pc-linux-gnu-gcc COLLECT_LTO_WRAPPER=/repo/gcc-trunk/binary-trunk-r13-167-20220507103325-g0c723bb4be2-checking-release-bootstrap-ubsan-amd64/bin/../libexec/gcc/x86_64-pc-linux-gnu/13.0.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /repo/gcc-trunk//configure --enable-languages=c,c++ --enable-valgrind-annotations --disable-nls --enable-checking=release --with-build-config=bootstrap-ubsan --with-cloog --with-ppl --with-isl --build=x86_64-pc-linux-gnu --host=x86_64-pc-linux-gnu --target=x86_64-pc-linux-gnu --with-ld=/usr/bin/x86_64-pc-linux-gnu-ld --with-as=/usr/bin/x86_64-pc-linux-gnu-as --disable-libstdcxx-pch --prefix=/repo/gcc-trunk//binary-trunk-r13-167-20220507103325-g0c723bb4be2-checking-release-bootstrap-ubsan-amd64 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 13.0.0 20220507 (experimental) (GCC)
choose_mult_variant (machine_mode mode, HOST_WIDE_INT val, ... synth_mult (&alg2, val - 1, &limit, mode); But slsr should not be processing any of these IR I don't think. _7 = _4 * Inf; c$imag_8 = (long intD.8) _7; # VUSE <.MEM_16> i.1_9 = iD.1980; # RANGE [-2147483648, 2147483647] _10 = (long intD.8) i.1_9; c$real_23 = c$real_6 * _10; c$imag_24 = c$imag_8 * _10; Huh? This does not make sense at all. float _4; float _7; if (tree_fits_shwi_p (rhs2)) return mult_by_coeff_cost (tree_to_shwi (rhs2), lhs_mode, speed); But I don't see that even call that. bool tree_fits_shwi_p (const_tree t) { return (t != NULL_TREE && TREE_CODE (t) == INTEGER_CST && wi::fits_shwi_p (wi::to_widest (t))); }
I see something similar when attempting a bootstrap with asan & ubsan on current gcc trunk: gcc/expmed.cc:3288:26: runtime error: signed integer overflow: -9223372036854775808 - 1 cannot be represented in type 'long int' Configure is: ../trunk/configure \ --disable-multilib \ --disable-werror \ --with-build-config=bootstrap-asan \ --with-build-config=bootstrap-ubsan \ --enable-checking=df,extra,fold,rtl,yes \ --enable-languages=c,c++,fortran And there are extra flags added to the top level Makefile: sed 's;-O2;-O3 -march=native;' < Makefile > Makefile.tmp diff Makefile Makefile.tmp mv Makefile.tmp Makefile I wonder if this is a regression for gcc-14.
Asan, most of the checking flags, fortran and the -march setting not required. Current configure script is: ../trunk.20210101/configure \ --disable-multilib \ --disable-werror \ --with-pkgversion=$HASH \ --with-build-config=bootstrap-ubsan \ --enable-checking=yes \ --enable-languages=c,c++ sed 's;-O2;-O3;' < Makefile > Makefile.tmp diff Makefile Makefile.tmp mv Makefile.tmp Makefile From the output of the bootstrap: Configuring stage 2 in x86_64-pc-linux-gnu/libgcc ../../trunk.20210101/gcc/poly-int.h:1089:5: runtime error: left shift of negative value -8 ../../trunk.20210101/gcc/poly-int.h:1089:5: runtime error: left shift of negative value -8 ../../trunk.20210101/gcc/expmed.cc:3288:26: runtime error: signed integer overflow: -9223372036854775808 - 1 cannot be represented in type 'long int' Configuring stage 2 in x86_64-pc-linux-gnu/libgomp
I see both /usr/src/gcc/obj5/./gcc/xgcc -B/usr/src/gcc/obj5/./gcc/ -B/usr/local/x86_64-pc-linux-gnu/bin/ -B/usr/local/x86_64-pc-linux-gnu/lib/ -isystem /usr/local/x86_64-pc-linux-gnu/include -isystem /usr/local/x86_64-pc-linux-gnu/sys-include -fno-checking -g -O3 -O2 -g -O3 -DIN_GCC -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -isystem ./include -fpic -mlong-double-80 -DUSE_ELF_SYMVER -fcf-protection -mshstk -g -DIN_LIBGCC2 -fbuilding-libgcc -fno-stack-protector -fpic -mlong-double-80 -DUSE_ELF_SYMVER -fcf-protection -mshstk -I. -I. -I../.././gcc -I../../../libgcc -I../../../libgcc/. -I../../../libgcc/../gcc -I../../../libgcc/../include -I../../../libgcc/config/libbid -DENABLE_DECIMAL_BID_FORMAT -DHAVE_CC_TLS -DUSE_TLS -o bid128_add.o -MT bid128_add.o -MD -MP -MF bid128_add.dep -c ../../../libgcc/config/libbid/bid128_add.c ../../gcc/expmed.cc:3288:26: runtime error: signed integer overflow: -9223372036854775808 - 1 cannot be represented in type 'long int' /usr/src/gcc/obj5/./gcc/xgcc -B/usr/src/gcc/obj5/./gcc/ -B/usr/local/x86_64-pc-linux-gnu/bin/ -B/usr/local/x86_64-pc-linux-gnu/lib/ -isystem /usr/local/x86_64-pc-linux-gnu/include -isystem /usr/local/x86_64-pc-linux-gnu/sys-include -fno-checking -g -O3 -O2 -g -O3 -DIN_GCC -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -isystem ./include -fpic -mlong-double-80 -DUSE_ELF_SYMVER -fcf-protection -mshstk -g -DIN_LIBGCC2 -fbuilding-libgcc -fno-stack-protector -fpic -mlong-double-80 -DUSE_ELF_SYMVER -fcf-protection -mshstk -I. -I. -I../.././gcc -I../../../libgcc -I../../../libgcc/. -I../../../libgcc/../gcc -I../../../libgcc/../include -I../../../libgcc/config/libbid -DENABLE_DECIMAL_BID_FORMAT -DHAVE_CC_TLS -DUSE_TLS -o unwind-dw2.o -MT unwind-dw2.o -MD -MP -MF unwind-dw2.dep -fexceptions -c ../../../libgcc/unwind-dw2.c -fvisibility=hidden -DHIDE_EXPORTS ../../gcc/poly-int.h:1089:5: runtime error: left shift of negative value -8 so will have a look at those.
The problem with expmed.c happens with -O2 -march=znver3, so it's more prevalent than I thought. The problem with poly-int.h seems to require -O3. So they look like two separate problems.
Testcase for the first compile time UB (-O3): long long a, b, c; void foo (long long e) { long long d = a & 9223372036854775808ULL; c = b; if (d && e) c = c | d; } Testcase for the second compile time UB (-O2): int a[64]; int p; void foo (void) { int stack_elt = 1; while (p) { stack_elt -= 11; a[stack_elt] != 0; } }
The second UB is on #2 ao_ref_init_from_vn_reference (ref=<optimized out>, set=1, base_set=1, type=<optimized out>, ops=...) at ../../gcc/tree-ssa-sccvn.cc:1224 1224 offset += op->off << LOG2_BITS_PER_UNIT; where op->off is negative. Isn't this just an unnecessary optimization? I mean can't we just do offset += op->off * BITS_PER_UNIT; BITS_PER_UNIT is a constant 8 on all targets we support...
The same function already does offset += pop->off * BITS_PER_UNIT; a few lines earlier, so I think doing it here is fine as well. Or yet another option is to cast pop->off or op->off to offset_int first and do the left shift in offset_int type where it is well defined. 2024-03-06 Jakub Jelinek <jakub@redhat.com> PR middle-end/105533 * tree-ssa-sccvn.cc (ao_ref_init_from_vn_reference) <case ARRAY_REF>: Multiple op->off by BITS_PER_UNIT instead of shifting it left by LOG2_BITS_PER_UNIT. --- gcc/tree-ssa-sccvn.cc.jj 2024-02-28 22:57:18.318658827 +0100 +++ gcc/tree-ssa-sccvn.cc 2024-03-06 14:52:16.819229719 +0100 @@ -1221,7 +1221,7 @@ ao_ref_init_from_vn_reference (ao_ref *r if (maybe_eq (op->off, -1)) max_size = -1; else - offset += op->off << LOG2_BITS_PER_UNIT; + offset += op->off * BITS_PER_UNIT; break; case REALPART_EXPR:
Created attachment 57632 [details] gcc14-pr105533.patch Untested fix for the other issue.
On Wed, 6 Mar 2024, jakub at gcc dot gnu.org wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105533 > > Jakub Jelinek <jakub at gcc dot gnu.org> changed: > > What |Removed |Added > ---------------------------------------------------------------------------- > CC| |rguenth at gcc dot gnu.org > > --- Comment #7 from Jakub Jelinek <jakub at gcc dot gnu.org> --- > The second UB is on > #2 ao_ref_init_from_vn_reference (ref=<optimized out>, set=1, base_set=1, > type=<optimized out>, ops=...) at ../../gcc/tree-ssa-sccvn.cc:1224 > 1224 offset += op->off << LOG2_BITS_PER_UNIT; > where op->off is negative. > Isn't this just an unnecessary optimization? I mean can't we just do > offset += op->off * BITS_PER_UNIT; > BITS_PER_UNIT is a constant 8 on all targets we support... It's a habit from dealing with offset_int (but this is poly_int64) where the multiply is possibly a lot more costly than a shift. So yeah, a multiply is fine I guess.
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:e1bd0f293d8407d4e8149fbafd470612323dc938 commit r14-9353-ge1bd0f293d8407d4e8149fbafd470612323dc938 Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Mar 7 10:01:08 2024 +0100 sccvn: Avoid UB in ao_ref_init_from_vn_reference [PR105533] When compiling libgcc or on e.g. int a[64]; int p; void foo (void) { int s = 1; while (p) { s -= 11; a[s] != 0; } } sccvn invokes UB in the compiler as detected by ubsan: ../../gcc/poly-int.h:1089:5: runtime error: left shift of negative value -40 The problem is that we still use C++11..C++17 as the implementation language and in those C++ versions shifting negative values left is UB (well defined since C++20) and above in offset += op->off << LOG2_BITS_PER_UNIT; op->off is poly_int64 with -40 value (in libgcc with -8). I understand the offset_int << LOG2_BITS_PER_UNIT shifts but it is then well defined during underlying implementation which is done on the uhwi limbs, but for poly_int64 we use offset += pop->off * BITS_PER_UNIT; a few lines earlier and I think that is both more readable in what it actually does and triggers UB only if there would be signed multiply overflow. In the end, the compiler will treat them the same at least at the RTL level (at least, if not and they aren't the same cost, it should). 2024-03-07 Jakub Jelinek <jakub@redhat.com> PR middle-end/105533 * tree-ssa-sccvn.cc (ao_ref_init_from_vn_reference) <case ARRAY_REF>: Multiple op->off by BITS_PER_UNIT instead of shifting it left by LOG2_BITS_PER_UNIT.
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:c655c8d8d845b36c59babb2413ce7aa3584dbeda commit r14-9354-gc655c8d8d845b36c59babb2413ce7aa3584dbeda Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Mar 7 10:02:00 2024 +0100 expand: Fix UB in choose_mult_variant [PR105533] As documented in the function comment, choose_mult_variant attempts to compute costs of 3 different cases, val, -val and val - 1. The -val case is actually only done if val fits into host int, so there should be no overflow, but the val - 1 case is done unconditionally. val is shwi (but inside of synth_mult already uhwi), so when val is HOST_WIDE_INT_MIN, val - 1 invokes UB. The following patch fixes that by using val - HOST_WIDE_INT_1U, but I'm not really convinced it would DTRT for > 64-bit modes, so I've guarded it as well. Though, arch would need to have really strange costs that something that could be expressed as x << 63 would be better expressed as (x * 0x7fffffffffffffff) + 1 In the long term, I think we should just rewrite choose_mult_variant/synth_mult etc. to work on wide_int. 2024-03-07 Jakub Jelinek <jakub@redhat.com> PR middle-end/105533 * expmed.cc (choose_mult_variant): Only try the val - 1 variant if val is not HOST_WIDE_INT_MIN or if mode has exactly HOST_BITS_PER_WIDE_INT precision. Avoid triggering UB while computing val - 1. * gcc.dg/pr105533.c: New test.
Seems fixed to me. I built a bootstrap with ASAN and UBSAN for languages C, C++ and Fortran and changed the usual -O2 for -O3 -march=znver3 and the bootstrap passed. I hadn't realised a bootstrap was such a good test of the compiler.
.