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.