Bug 105149 - [11 Regression] ICE in verify_ssa, at tree-ssa.cc:1211
Summary: [11 Regression] ICE in verify_ssa, at tree-ssa.cc:1211
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 12.0
: P2 normal
Target Milestone: 11.5
Assignee: Jakub Jelinek
URL:
Keywords: accepts-invalid, ice-on-invalid-code
Depends on:
Blocks:
 
Reported: 2022-04-04 16:42 UTC by G. Steinmetz
Modified: 2023-07-07 10:42 UTC (History)
2 users (show)

See Also:
Host:
Target: x86_64-pc-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-04-04 00:00:00


Attachments
gcc12-pr105149.patch (656 bytes, patch)
2022-04-07 10:41 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description G. Steinmetz 2022-04-04 16:42:42 UTC
Affects versions down to r6, at -O1+ :
(gcc configured with --enable-checking=yes)


$ cat z1.c
#include <stdarg.h>
void foo (int size, ...)
{
  struct {} d;
  va_list ap;
  d = va_arg (ap, typeof(d)()) ();
}


$ gcc-5 -c z1.c -O2
$ gcc-12-20220403 -c z1.c
$
$ gcc-12-20220403 -c z1.c -O2
z1.c: In function 'foo':
z1.c:7:1: error: virtual definition of statement not up to date
    7 | }
      | ^
D.1987 = _1;
during GIMPLE pass: ssa
z1.c:7:1: internal compiler error: verify_ssa failed
0x10a33db verify_ssa(bool, bool)
        ../../gcc/tree-ssa.cc:1211
0xd01ea7 execute_function_todo
        ../../gcc/passes.cc:2092
0xd027f2 execute_todo
        ../../gcc/passes.cc:2139
Comment 1 Jakub Jelinek 2022-04-04 17:11:37 UTC
Started with r6-91-gf8e89441bc5518f450b6511c59c17c837859d109
Comment 2 Richard Biener 2022-04-05 06:50:45 UTC
I will have a look.
Comment 3 Richard Biener 2022-04-05 07:34:31 UTC
The odd thing is that we parse

  d = va_arg (ap, typeof(d)()) ();

as function call, gimplifying it as

      _1 = .VA_ARG (&ap(address-taken), 0B, 0B);
      D.1987(address-taken) = _1;
      D.1987(address-taken) ();

 <modify_expr 0x7ffff6650d70
    type <record_type 0x7ffff66793f0 type_0 BLK
        size <integer_cst 0x7ffff6517dc8 constant 0>
        unit-size <integer_cst 0x7ffff6517d80 constant 0>
        align:8 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7ffff66793f0 context <function_decl 0x7ffff6656200 foo>
        chain <type_decl 0x7ffff65415f0 D.1983>>
    side-effects
    arg:0 <var_decl 0x7ffff6526bd0 d type <record_type 0x7ffff66793f0>
        used read BLK t.c:4:13 size <integer_cst 0x7ffff6517dc8 0> unit-size <integer_cst 0x7ffff6517d80 0>
        align:8 warn_if_not_align:0 context <function_decl 0x7ffff6656200 foo>
        chain <var_decl 0x7ffff6526c60 ap type <array_type 0x7ffff66792a0 va_list>
            addressable used read BLK t.c:5:11
            size <integer_cst 0x7ffff6537210 constant 192>
            unit-size <integer_cst 0x7ffff65371e0 constant 24>
            align:64 warn_if_not_align:0 context <function_decl 0x7ffff6656200 foo>>>
    arg:1 <call_expr 0x7ffff66786c0 type <record_type 0x7ffff66793f0>
        side-effects
        fn <addr_expr 0x7ffff66652a0 type <pointer_type 0x7ffff6679540>
            side-effects
            arg:0 <va_arg_expr 0x7ffff6665280 type <function_type 0x7ffff6679498>
                side-effects
                arg:0 <addr_expr 0x7ffff6665260 type <pointer_type 0x7ffff6542b28>
                    arg:0 <var_decl 0x7ffff6526c60 ap>>
                t.c:6:7 start: t.c:6:7 finish: t.c:6:7>
            t.c:6:7 start: t.c:6:7 finish: t.c:6:7>
        t.c:6:7 start: t.c:6:7 finish: t.c:6:33>
    t.c:6:5 start: t.c:6:3 finish: t.c:6:33>

I _think_ we fail to decay the function type in va_arg to a pointer type
or we fail to reject this testcase.

Somewhat reduced testcase:

#include <stdarg.h>
typedef struct {} D;
void foo (int size, ...)
{
  va_list ap;
  va_arg (ap, D()) ();
}

C17/7.16.1.1 isn't sufficiently clear as to whether this is valid, but
at least "The parameter type shall be a type name specified such that
the type of a pointer to an object that has the specified type can be
obtained simply by postfixing a * to type" isn't fulfilled here since
the corresponding pointer type would be D(*)(), not D()*.

clang rejects this with

t.c:6:15: error: second argument to 'va_arg' is of non-POD type 'D ()' [-Wnon-pod-varargs]
  va_arg (ap, D()) ();
              ^~~

but not sure if "POD" is a thing to use in C language diagnostics.

Anyway, defering to C frontend maintainers.
Comment 4 Richard Biener 2022-04-05 07:37:27 UTC
It looks like c_build_va_arg could be amended to reject FUNCTION_TYPE type.  But as said, not sure if this is valid or not.
Comment 5 Richard Biener 2022-04-05 07:40:53 UTC
The C++ frontend accepts this and diagnoses

In file included from t.c:1:
t.c: In function 'void foo(int, ...)':
t.c:6:15: warning: 'D()' is promoted to 'D (*)()' when passed through '...'
    6 |   va_arg (ap, D()) ();

and produces the following GENERIC, decaying the "loaded function":



 <call_expr 0x7ffff6692c00
    type <record_type 0x7ffff6681348 D cxx-odr-p type_5 QI
        size <integer_cst 0x7ffff653a048 constant 8>
        unit-size <integer_cst 0x7ffff653a060 constant 1>
        align:8 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7ffff6681348
        fields <function_decl 0x7ffff6685600 __dt  type <method_type 0x7ffff6698000>
            public abstract external autoinline decl_3 QI t.c:2:19 align:16 warn_if_not_align:0 context <record_type 0x7ffff6681348 D>
            full-name "D::~D() noexcept (<uninstantiated>)"
            not-really-extern chain <function_decl 0x7ffff6685800 __dt_base >> context <translation_unit_decl 0x7ffff6525168 t.c>
        full-name "struct D"
        X() X(constX&) this=(X&) n_parents=0 use_template=0 interface-unknown
        pointer_to_this <pointer_type 0x7ffff66817e0> chain <type_decl 0x7ffff6547980 ._anon_0>>
    side-effects
    fn <addr_expr 0x7ffff6678980
        type <pointer_type 0x7ffff6681690 type <function_type 0x7ffff66815e8>
            unsigned DI
            size <integer_cst 0x7ffff6517f48 constant 64>
            unit-size <integer_cst 0x7ffff6517f60 constant 8>
            align:64 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7ffff6681690>
        side-effects
        arg:0 <va_arg_expr 0x7ffff6678960 type <function_type 0x7ffff66815e8>
            side-effects
            arg:0 <addr_expr 0x7ffff6678a00 type <pointer_type 0x7ffff6544dc8>
                arg:0 <var_decl 0x7ffff6526c60 ap>>
            t.c:6:3 start: t.c:6:3 finish: t.c:6:3>
        t.c:6:3 start: t.c:6:3 finish: t.c:6:3>
    t.c:6:3 start: t.c:6:3 finish: t.c:6:3>

which we then gimplify to

      __builtin_trap ();
      <<< Unknown tree: integer_cst >>> ();
Comment 6 Richard Biener 2022-04-05 07:43:53 UTC
(In reply to Richard Biener from comment #5)
> The C++ frontend accepts this and diagnoses
> 
> In file included from t.c:1:
> t.c: In function 'void foo(int, ...)':
> t.c:6:15: warning: 'D()' is promoted to 'D (*)()' when passed through '...'
>     6 |   va_arg (ap, D()) ();
> 
> and produces the following GENERIC, decaying the "loaded function":

include/stdarg.h:49:44: note: in definition of macro 'va_arg'
   49 | #define va_arg(v,l)     __builtin_va_arg(v,l)
      |                                            ^
t.c:6:15: note: (so you should pass 'D (*)()' not 'D()' to 'va_arg')
    6 |   va_arg (ap, D()) ();
include/stdarg.h:49:44: note: in definition of macro 'va_arg'
   49 | #define va_arg(v,l)     __builtin_va_arg(v,l)
      |                                            ^
t.c:6:15: note: if this code is reached, the program will abort
    6 |   va_arg (ap, D()) ();
include/stdarg.h:49:44: note: in definition of macro 'va_arg'
   49 | #define va_arg(v,l)     __builtin_va_arg(v,l)
      |                                            ^

because the C++ implementation of lang_hooks.types.type_promotes_to
says the function type doesn't promote to itself.  The C frontend
seems to lack that.


> 
> 
>  <call_expr 0x7ffff6692c00
>     type <record_type 0x7ffff6681348 D cxx-odr-p type_5 QI
>         size <integer_cst 0x7ffff653a048 constant 8>
>         unit-size <integer_cst 0x7ffff653a060 constant 1>
>         align:8 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type
> 0x7ffff6681348
>         fields <function_decl 0x7ffff6685600 __dt  type <method_type
> 0x7ffff6698000>
>             public abstract external autoinline decl_3 QI t.c:2:19 align:16
> warn_if_not_align:0 context <record_type 0x7ffff6681348 D>
>             full-name "D::~D() noexcept (<uninstantiated>)"
>             not-really-extern chain <function_decl 0x7ffff6685800 __dt_base
> >> context <translation_unit_decl 0x7ffff6525168 t.c>
>         full-name "struct D"
>         X() X(constX&) this=(X&) n_parents=0 use_template=0 interface-unknown
>         pointer_to_this <pointer_type 0x7ffff66817e0> chain <type_decl
> 0x7ffff6547980 ._anon_0>>
>     side-effects
>     fn <addr_expr 0x7ffff6678980
>         type <pointer_type 0x7ffff6681690 type <function_type 0x7ffff66815e8>
>             unsigned DI
>             size <integer_cst 0x7ffff6517f48 constant 64>
>             unit-size <integer_cst 0x7ffff6517f60 constant 8>
>             align:64 warn_if_not_align:0 symtab:0 alias-set -1
> canonical-type 0x7ffff6681690>
>         side-effects
>         arg:0 <va_arg_expr 0x7ffff6678960 type <function_type 0x7ffff66815e8>
>             side-effects
>             arg:0 <addr_expr 0x7ffff6678a00 type <pointer_type
> 0x7ffff6544dc8>
>                 arg:0 <var_decl 0x7ffff6526c60 ap>>
>             t.c:6:3 start: t.c:6:3 finish: t.c:6:3>
>         t.c:6:3 start: t.c:6:3 finish: t.c:6:3>
>     t.c:6:3 start: t.c:6:3 finish: t.c:6:3>
> 
> which we then gimplify to
> 
>       __builtin_trap ();
>       <<< Unknown tree: integer_cst >>> ();
Comment 7 jsm-csl@polyomino.org.uk 2022-04-05 18:42:27 UTC
I think it's valid to reject this at compile time (rather than just 
generating a runtime trap): the "such that the type of a pointer to an 
object that has the specified type can be obtained simply by postfixing a 
* to type" can never be satisfied for a function type, even if e.g. a 
typedef name is used so that postfixing '*' produces valid syntax for the 
corresponding pointer type, because it still wouldn't be "the type of a 
pointer to an object".
Comment 8 Jakub Jelinek 2022-04-07 10:41:35 UTC
Created attachment 52767 [details]
gcc12-pr105149.patch

Untested patch to reject it.
Comment 9 GCC Commits 2022-04-08 07:17:42 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:6e2743687202c58a6553ae632ebbada3de38ad48

commit r12-8057-g6e2743687202c58a6553ae632ebbada3de38ad48
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Fri Apr 8 09:16:30 2022 +0200

    c: Error on va_arg with function type [PR105149]
    
    In the PR Joseph said that the C standard for va_arg talks about
    pointers to object type and as a function type is not object type,
    it is invalid.
    
    The following patch diagnoses it in the FE, instead of ICEing later on
    when optimizations are turned on (and with -O0 doing something weird
    at runtime).
    
    2022-04-08  Jakub Jelinek  <jakub@redhat.com>
    
            PR c/105149
            * c-typeck.cc (c_build_va_arg): Reject function types.
    
            * gcc.dg/pr105149.c: New test.
Comment 10 Jakub Jelinek 2022-04-08 08:11:45 UTC
Fixed on the trunk.  Unsure about backports though, if we do something for those, might be better to silently turn it into __builtin_trap() than to reject it when it wasn't rejected before.
Comment 11 Richard Biener 2022-05-27 09:47:48 UTC
GCC 9 branch is being closed
Comment 12 Jakub Jelinek 2022-06-28 10:48:50 UTC
GCC 10.4 is being released, retargeting bugs to GCC 10.5.
Comment 13 Richard Biener 2023-07-07 10:42:54 UTC
GCC 10 branch is being closed.