Bug 85213 - [8 Regression] -fsanitize=undefined internal compiler error: in fold_convert_loc, at fold-const.c:2402
Summary: [8 Regression] -fsanitize=undefined internal compiler error: in fold_convert_...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: sanitizer (show other bugs)
Version: 8.0.1
: P1 normal
Target Milestone: 8.0
Assignee: Jakub Jelinek
URL:
Keywords: ice-on-valid-code
Depends on:
Blocks: 100733
  Show dependency treegraph
 
Reported: 2018-04-04 20:45 UTC by Vegard Nossum
Modified: 2021-05-23 17:25 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-04-04 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vegard Nossum 2018-04-04 20:45:32 UTC
Input (valid AFAICT):

int f(int x) {
  return (__builtin_expect(({ x != 0; }) ? 0 : 1, 3) == 0) * -1 << 0;
}

Output:

$ cc1plus -O1 -fsanitize=undefined -g
 int f(int)
Analyzing compilation unit

output/ice-fold_covert_loc.cc:2:27: internal compiler error: in fold_convert_loc, at fold-const.c:2402
   return (__builtin_expect(({ x != 0; }) ? 0 : 1, 3) == 0) * -1 << 0;
           ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
0x1fb2e1b fold_convert_loc(unsigned int, tree_node*, tree_node*)
        /home/vegard/git/gcc/gcc/fold-const.c:2401
0x227d824 gimplify_cond_expr
        /home/vegard/git/gcc/gcc/gimplify.c:4034
0x222a3a6 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        /home/vegard/git/gcc/gcc/gimplify.c:11391
0x2236ae1 gimplify_stmt(tree_node**, gimple**)
        /home/vegard/git/gcc/gcc/gimplify.c:6658
0x227cfbe gimplify_cond_expr
        /home/vegard/git/gcc/gcc/gimplify.c:4022
0x222a3a6 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        /home/vegard/git/gcc/gcc/gimplify.c:11391
0x225b10c gimplify_expr
        /home/vegard/git/gcc/gcc/gimplify.c:12430
0x22606a8 gimplify_arg(tree_node**, gimple**, unsigned int, bool)
        /home/vegard/git/gcc/gcc/gimplify.c:3176
0x2262d8b gimplify_call_expr
        /home/vegard/git/gcc/gcc/gimplify.c:3382
0x222936f gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        /home/vegard/git/gcc/gcc/gimplify.c:11406
0x2227a92 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        /home/vegard/git/gcc/gcc/gimplify.c:12159
0x22234a7 internal_get_tmp_var
        /home/vegard/git/gcc/gcc/gimplify.c:575
0x222e2e0 get_initialized_tmp_var(tree_node*, gimple**, gimple**, bool)
        /home/vegard/git/gcc/gcc/gimplify.c:628
0x222e2e0 gimplify_save_expr
        /home/vegard/git/gcc/gcc/gimplify.c:5931
0x222e2e0 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        /home/vegard/git/gcc/gcc/gimplify.c:11734
0x2227a92 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        /home/vegard/git/gcc/gcc/gimplify.c:12159
0x2227ac0 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        /home/vegard/git/gcc/gcc/gimplify.c:12161
0x227d943 gimplify_cond_expr
        /home/vegard/git/gcc/gcc/gimplify.c:4063
0x222a3a6 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        /home/vegard/git/gcc/gcc/gimplify.c:11391
0x227c58d gimplify_stmt(tree_node**, gimple**)
        /home/vegard/git/gcc/gcc/gimplify.c:6658
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

Built from r259106.

Test case was minimised by C-Reduce.

It seems -fsanitize=shift is enough to trigger it. The shift is by 0, though, so it should be valid (even though the shifted value is potentially negative).

7.3.0 seems to accept it just fine.
Comment 1 Marek Polacek 2018-04-04 20:55:53 UTC
Started with r255947.
Comment 2 Jakub Jelinek 2018-04-05 06:16:13 UTC
I'll handle this.
Comment 3 Jakub Jelinek 2018-04-05 09:28:18 UTC
The problem is that twoval_comparison_p breaks appart SAVE_EXPR if their argument has no side effects.
First, cp_build_binary_op calls save_expr on:
(__builtin_expect ((long int) (# DEBUG BEGIN STMT;
x != 0; ? 0 : 1), (long int) NON_LVALUE_EXPR <3>) == 0) * -1;
and that resulting SAVE_EXPR is used in 2+ places, where one of them is a comparison against INTEGER_CST, which is optimized using twoval_comparison_p as
another SAVE_EXPR with
__builtin_expect ((long int) (# DEBUG BEGIN STMT;
x != 0; ? 0 : 1), (long int) NON_LVALUE_EXPR <3>) == 0;
body.  As mostly_copy_tree_r does not unshare STATEMENT_LISTs, we hand over to the gimplifier the above two SAVE_EXPRs and both contain the same STATEMENT_LIST, so we try to gimplify it twice, which as we know from other PRs doesn't really work at all.
Now, not looking through SAVE_EXPRs in twoval_comparison_p if it contains a STATEMENT_LIST might result in -fcompare-debug failures, because with -g0 there could be no STATEMENT_LIST, while with -g we have one.
Not sure what our options are, besides just killing the SAVE_EXPR handling in twoval_comparison_p.
Comment 4 Richard Biener 2018-04-05 11:56:09 UTC
(In reply to Jakub Jelinek from comment #3)
> The problem is that twoval_comparison_p breaks appart SAVE_EXPR if their
> argument has no side effects.
> First, cp_build_binary_op calls save_expr on:
> (__builtin_expect ((long int) (# DEBUG BEGIN STMT;
> x != 0; ? 0 : 1), (long int) NON_LVALUE_EXPR <3>) == 0) * -1;
> and that resulting SAVE_EXPR is used in 2+ places, where one of them is a
> comparison against INTEGER_CST, which is optimized using twoval_comparison_p
> as
> another SAVE_EXPR with
> __builtin_expect ((long int) (# DEBUG BEGIN STMT;
> x != 0; ? 0 : 1), (long int) NON_LVALUE_EXPR <3>) == 0;
> body.  As mostly_copy_tree_r does not unshare STATEMENT_LISTs, we hand over
> to the gimplifier the above two SAVE_EXPRs and both contain the same
> STATEMENT_LIST, so we try to gimplify it twice, which as we know from other
> PRs doesn't really work at all.
> Now, not looking through SAVE_EXPRs in twoval_comparison_p if it contains a
> STATEMENT_LIST might result in -fcompare-debug failures, because with -g0
> there could be no STATEMENT_LIST, while with -g we have one.
> Not sure what our options are, besides just killing the SAVE_EXPR handling
> in twoval_comparison_p.

unshare the expression in twoval_comparison_p?
Comment 5 Jakub Jelinek 2018-04-05 12:02:27 UTC
unshare_expr doesn't unshare the STATEMENT_LISTs embedded inside of it
(and wonder what would Alex' code do if we have two separate DEBUG_BEGIN_STMTs for the same statement).
Comment 6 Jakub Jelinek 2018-04-06 11:25:13 UTC
Author: jakub
Date: Fri Apr  6 11:24:36 2018
New Revision: 259167

URL: https://gcc.gnu.org/viewcvs?rev=259167&root=gcc&view=rev
Log:
	PR sanitizer/85213
	* fold-const.c (twoval_comparison_p): Remove SAVE_P argument and don't
	look through SAVE_EXPRs with non-side-effects argument.  Adjust
	recursive calls.
	(fold_comparison): Adjust twoval_comparison_p caller, don't handle
	save_p here.

	* c-c++-common/ubsan/pr85213.c: New test.

Added:
    trunk/gcc/testsuite/c-c++-common/ubsan/pr85213.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/fold-const.c
    trunk/gcc/testsuite/ChangeLog
Comment 7 Jakub Jelinek 2018-04-06 11:26:13 UTC
Fixed.