https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127658

            Bug ID: 127658
           Summary: ICE in build_complex_type (tree.cc:8055) /
                    fold_convert_loc: argument checks of const
                    type-generic builtins are skipped when the builtin is
                    called as (*__builtin_add_overflow_p) (...)
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: accepts-invalid, ice-on-invalid-code
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: captainnemo9292 at gmail dot com
  Target Milestone: ---

Calling a type-generic builtin through an explicit dereference bypasses the
argument checking that the direct call gets, and the folder then ICEs on the
unchecked arguments:

  int a;
  int f (void) { return (*__builtin_add_overflow_p) (a, 1, &a); }

  $ gcc -c t.c
  t.c:2:1: internal compiler error: in build_complex_type, at tree.cc:8055
  fold(tree_node*)
  c_fully_fold(tree_node*, bool, bool*, bool)
  c_finish_return

https://godbolt.org/z/Y6j4Yvx3s - 12.1 through trunk (17.0 20260928), release
and checking builds, any -O level.  The direct call is rejected as it should
be:

  t.c:2:29: error: argument 3 in call to function '__builtin_add_overflow_p'
does not have integral type

Other shapes of the same hole:

  (*__builtin_add_overflow_p) (a, 1, 1.0)   ICE in fold_convert_loc,
fold-const.cc:2620
  (*__builtin_clzg) (1.0)                   ICE in fold_convert_loc,
fold-const.cc:2620
  (*__builtin_add_overflow_p) (a, 1)        accepted silently (two arguments)
  (*__builtin_add_overflow_p) (1, 1, s)     accepted silently (struct as 3rd
argument)
  (*__builtin_isinf_sign) (1, 2)            accepted silently (too many
arguments)

while (*__builtin_add_overflow) (a, 1, 3) and (*__builtin_clear_padding) (1)
are diagnosed normally.  The difference is that the affected builtins are
declared const (or noreturn):

- build_unary_op (ADDR_EXPR) merges TREE_READONLY / TREE_THIS_VOLATILE of a
  FUNCTION_DECL into the pointed-to type ("If the lvalue is const or volatile,
  merge that into the type to which the address will point"), so &f has type
  pointer to *qualified* function type.
- build_indirect_ref only folds *&f back to f when TREE_TYPE (f) is
  pointer-identical to the pointed-to type; for these builtins it is not, so
  the parser produces INDIRECT_REF <ADDR_EXPR <f>> instead of f.
- build_function_call_vec sets fundecl only when the callee is a FUNCTION_DECL,
  so fundecl is NULL and neither builtin_function_validate_nargs nor
  check_builtin_function_arguments run.  convert_arguments also skips the
  special *_overflow_p / type-generic handling for the same reason.
- c_fully_fold then folds &*&f back to &f, the CALL_EXPR targets the builtin
  after all, and fold_builtin_arith_overflow / fold_builtin_bit_query see
  argument types they were never meant to see.

Probably build_function_call_vec (or c_parser_postfix_expression_after_primary)
should look through INDIRECT_REF <ADDR_EXPR <FUNCTION_DECL>> when deriving
fundecl, or build_indirect_ref should compare unqualified function types.

Found by fuzzing; reduced by hand.
  • [Bug c/127658] New: ICE in b... captainnemo9292 at gmail dot com via Gcc-bugs

Reply via email to