https://gcc.gnu.org/g:e326152845584d78410963e5c3d31cdbdf8f50fe
commit r14-11807-ge326152845584d78410963e5c3d31cdbdf8f50fe Author: Jakub Jelinek <ja...@redhat.com> Date: Thu Nov 28 10:51:16 2024 +0100 gimple-fold: Avoid ICEs with bogus declarations like const attribute no snprintf [PR117358] When one puts incorrect const or pure attributes on declarations of various C APIs which have corresponding builtins (vs. what they actually do), we can get tons of ICEs in gimple-fold.cc. The following patch fixes it by giving up gimple_fold_builtin_* folding if the functions don't have gimple_vdef (or for pure functions like bcmp/strchr/strstr gimple_vuse) when in SSA form (during gimplification they will surely have both of those NULL even when declared correctly, yet it is highly desirable to fold them). Or shall I replace !gimple_vdef (stmt) && gimple_in_ssa_p (cfun) tests with (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) != 0 and !gimple_vuse (stmt) && gimple_in_ssa_p (cfun) with (gimple_call_flags (stmt) & (ECF_CONST | ECF_NOVOPS)) != 0 ? 2024-11-28 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/117358 * gimple-fold.cc (gimple_fold_builtin_memory_op): Punt if stmt has no vdef in ssa form. (gimple_fold_builtin_bcmp): Punt if stmt has no vuse in ssa form. (gimple_fold_builtin_bcopy): Punt if stmt has no vdef in ssa form. (gimple_fold_builtin_bzero): Likewise. (gimple_fold_builtin_memset): Likewise. Use return false instead of return NULL_TREE. (gimple_fold_builtin_strcpy): Punt if stmt has no vdef in ssa form. (gimple_fold_builtin_strncpy): Likewise. (gimple_fold_builtin_strchr): Punt if stmt has no vuse in ssa form. (gimple_fold_builtin_strstr): Likewise. (gimple_fold_builtin_strcat): Punt if stmt has no vdef in ssa form. (gimple_fold_builtin_strcat_chk): Likewise. (gimple_fold_builtin_strncat): Likewise. (gimple_fold_builtin_strncat_chk): Likewise. (gimple_fold_builtin_string_compare): Likewise. (gimple_fold_builtin_fputs): Likewise. (gimple_fold_builtin_memory_chk): Likewise. (gimple_fold_builtin_stxcpy_chk): Likewise. (gimple_fold_builtin_stxncpy_chk): Likewise. (gimple_fold_builtin_stpcpy): Likewise. (gimple_fold_builtin_snprintf_chk): Likewise. (gimple_fold_builtin_sprintf_chk): Likewise. (gimple_fold_builtin_sprintf): Likewise. (gimple_fold_builtin_snprintf): Likewise. (gimple_fold_builtin_fprintf): Likewise. (gimple_fold_builtin_printf): Likewise. (gimple_fold_builtin_realloc): Likewise. * gcc.c-torture/compile/pr117358.c: New test. (cherry picked from commit 29032dfa57629d1713a97b17a785273823993a91) Diff: --- gcc/gimple-fold.cc | 76 ++++++++++++++++++++------ gcc/testsuite/gcc.c-torture/compile/pr117358.c | 17 ++++++ 2 files changed, 77 insertions(+), 16 deletions(-) diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 3548c9144829..0d90bab595fc 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -936,6 +936,8 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi, } goto done; } + else if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; else { /* We cannot (easily) change the type of the copy if it is a storage @@ -1377,6 +1379,8 @@ gimple_fold_builtin_bcmp (gimple_stmt_iterator *gsi) /* Transform bcmp (a, b, len) into memcmp (a, b, len). */ gimple *stmt = gsi_stmt (*gsi); + if (!gimple_vuse (stmt) && gimple_in_ssa_p (cfun)) + return false; tree a = gimple_call_arg (stmt, 0); tree b = gimple_call_arg (stmt, 1); tree len = gimple_call_arg (stmt, 2); @@ -1403,6 +1407,8 @@ gimple_fold_builtin_bcopy (gimple_stmt_iterator *gsi) len) into memmove (dest, src, len). */ gimple *stmt = gsi_stmt (*gsi); + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; tree src = gimple_call_arg (stmt, 0); tree dest = gimple_call_arg (stmt, 1); tree len = gimple_call_arg (stmt, 2); @@ -1428,6 +1434,8 @@ gimple_fold_builtin_bzero (gimple_stmt_iterator *gsi) /* Transform bzero (dest, len) into memset (dest, 0, len). */ gimple *stmt = gsi_stmt (*gsi); + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; tree dest = gimple_call_arg (stmt, 0); tree len = gimple_call_arg (stmt, 1); @@ -1457,6 +1465,9 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len) return true; } + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + if (! tree_fits_uhwi_p (len)) return false; @@ -1479,20 +1490,20 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len) if ((!INTEGRAL_TYPE_P (etype) && !POINTER_TYPE_P (etype)) || TREE_CODE (etype) == BITINT_TYPE) - return NULL_TREE; + return false; if (! var_decl_component_p (var)) - return NULL_TREE; + return false; length = tree_to_uhwi (len); if (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (etype)) != length || (GET_MODE_PRECISION (SCALAR_INT_TYPE_MODE (etype)) != GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (etype))) || get_pointer_alignment (dest) / BITS_PER_UNIT < length) - return NULL_TREE; + return false; if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT) - return NULL_TREE; + return false; if (!type_has_mode_precision_p (etype)) etype = lang_hooks.types.type_for_mode (SCALAR_INT_TYPE_MODE (etype), @@ -2106,7 +2117,7 @@ gimple_fold_builtin_strcpy (gimple_stmt_iterator *gsi, return false; } - if (!len) + if (!len || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; len = fold_convert_loc (loc, size_type_node, len); @@ -2181,7 +2192,7 @@ gimple_fold_builtin_strncpy (gimple_stmt_iterator *gsi, /* OK transform into builtin memcpy. */ tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; len = fold_convert_loc (loc, size_type_node, len); @@ -2235,7 +2246,7 @@ gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr) return true; } - if (!integer_zerop (c)) + if (!integer_zerop (c) || (!gimple_vuse (stmt) && gimple_in_ssa_p (cfun))) return false; /* Transform strrchr (s, 0) to strchr (s, 0) when optimizing for size. */ @@ -2333,6 +2344,9 @@ gimple_fold_builtin_strstr (gimple_stmt_iterator *gsi) return true; } + if (!gimple_vuse (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* Transform strstr (x, "c") into strchr (x, 'c'). */ if (q[1] == '\0') { @@ -2385,6 +2399,9 @@ gimple_fold_builtin_strcat (gimple_stmt_iterator *gsi, tree dst, tree src) if (!optimize_bb_for_speed_p (gimple_bb (stmt))) return false; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* See if we can store by pieces into (dst + strlen(dst)). */ tree newdst; tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN); @@ -2454,7 +2471,6 @@ gimple_fold_builtin_strcat_chk (gimple_stmt_iterator *gsi) tree fn; const char *p; - p = c_getstr (src); /* If the SRC parameter is "", return DEST. */ if (p && *p == '\0') @@ -2466,6 +2482,9 @@ gimple_fold_builtin_strcat_chk (gimple_stmt_iterator *gsi) if (! tree_fits_uhwi_p (size) || ! integer_all_onesp (size)) return false; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* If __builtin_strcat_chk is used, assume strcat is available. */ fn = builtin_decl_explicit (BUILT_IN_STRCAT); if (!fn) @@ -2556,7 +2575,7 @@ gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi) /* If the replacement _DECL isn't initialized, don't do the transformation. */ - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; /* Otherwise, emit a call to strcat. */ @@ -2588,6 +2607,9 @@ gimple_fold_builtin_strncat_chk (gimple_stmt_iterator *gsi) return true; } + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + if (! integer_all_onesp (size)) { tree src_len = c_strlen (src, 1); @@ -2678,6 +2700,9 @@ gimple_fold_builtin_string_compare (gimple_stmt_iterator *gsi) return true; } + if (!gimple_vuse (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* Initially set to the number of characters, including the terminating nul if each array has one. LENx == strnlen (Sx, LENx) implies that the array Sx is not terminated by a nul. @@ -2970,7 +2995,7 @@ gimple_fold_builtin_fputs (gimple_stmt_iterator *gsi, const char *p = c_getstr (arg0); if (p != NULL) { - if (!fn_fputc) + if (!fn_fputc || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; gimple *repl @@ -2989,7 +3014,7 @@ gimple_fold_builtin_fputs (gimple_stmt_iterator *gsi, return false; /* New argument list transforming fputs(string, stream) to fwrite(string, 1, len, stream). */ - if (!fn_fwrite) + if (!fn_fwrite || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; gimple *repl @@ -3040,6 +3065,9 @@ gimple_fold_builtin_memory_chk (gimple_stmt_iterator *gsi, } } + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + tree maxlen = get_maxval_strlen (len, SRK_INT_VALUE); if (! integer_all_onesp (size) && !known_lower (stmt, len, size) @@ -3138,6 +3166,9 @@ gimple_fold_builtin_stxcpy_chk (gimple_stmt_iterator *gsi, return true; } + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + tree maxlen = get_maxval_strlen (src, SRK_STRLENMAX); if (! integer_all_onesp (size)) { @@ -3231,7 +3262,7 @@ gimple_fold_builtin_stxncpy_chk (gimple_stmt_iterator *gsi, /* If __builtin_st{r,p}ncpy_chk is used, assume st{r,p}ncpy is available. */ fn = builtin_decl_explicit (fcode == BUILT_IN_STPNCPY_CHK && !ignore ? BUILT_IN_STPNCPY : BUILT_IN_STRNCPY); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; gcall *repl = gimple_build_call (fn, 3, dest, src, len); @@ -3252,6 +3283,9 @@ gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi) tree src = gimple_call_arg (stmt, 1); tree fn, lenp1; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* If the result is unused, replace stpcpy with strcpy. */ if (gimple_call_lhs (stmt) == NULL_TREE) { @@ -3369,7 +3403,7 @@ gimple_fold_builtin_snprintf_chk (gimple_stmt_iterator *gsi, available. */ fn = builtin_decl_explicit (fcode == BUILT_IN_VSNPRINTF_CHK ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; /* Replace the called function and the first 5 argument by 3 retaining @@ -3456,7 +3490,7 @@ gimple_fold_builtin_sprintf_chk (gimple_stmt_iterator *gsi, /* If __builtin_{,v}sprintf_chk is used, assume {,v}sprintf is available. */ fn = builtin_decl_explicit (fcode == BUILT_IN_VSPRINTF_CHK ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; /* Replace the called function and the first 4 argument by 2 retaining @@ -3505,7 +3539,7 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi) return false; tree fn = builtin_decl_implicit (BUILT_IN_STRCPY); - if (!fn) + if (!fn || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; /* If the format doesn't contain % args or %%, use strcpy. */ @@ -3618,7 +3652,8 @@ gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi) tree orig = NULL_TREE; const char *fmt_str = NULL; - if (gimple_call_num_args (stmt) > 4) + if (gimple_call_num_args (stmt) > 4 + || (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))) return false; if (gimple_call_num_args (stmt) == 4) @@ -3776,6 +3811,9 @@ gimple_fold_builtin_fprintf (gimple_stmt_iterator *gsi, if (!init_target_chars ()) return false; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* If the format doesn't contain % args or %%, use strcpy. */ if (strchr (fmt_str, target_percent) == NULL) { @@ -3855,6 +3893,9 @@ gimple_fold_builtin_printf (gimple_stmt_iterator *gsi, tree fmt, if (gimple_call_lhs (stmt) != NULL_TREE) return false; + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + /* Check whether the format is a literal string constant. */ fmt_str = c_getstr (fmt); if (fmt_str == NULL) @@ -4096,6 +4137,9 @@ gimple_fold_builtin_realloc (gimple_stmt_iterator *gsi) tree arg = gimple_call_arg (stmt, 0); tree size = gimple_call_arg (stmt, 1); + if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun)) + return false; + if (operand_equal_p (arg, null_pointer_node, 0)) { tree fn_malloc = builtin_decl_implicit (BUILT_IN_MALLOC); diff --git a/gcc/testsuite/gcc.c-torture/compile/pr117358.c b/gcc/testsuite/gcc.c-torture/compile/pr117358.c new file mode 100644 index 000000000000..023284aff962 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr117358.c @@ -0,0 +1,17 @@ +/* PR tree-optimization/117358 */ + +char a; +/* This attribute is bogus, snprintf isn't const. Just verify we don't ICE on it. */ +int __attribute__((const)) snprintf (char *, __SIZE_TYPE__, const char *, ...); + +long +foo (long d) +{ + return snprintf (&a, d, ""); +} + +int +bar (void) +{ + return foo (1); +}