[gcc r13-9693] gimple-fold: Avoid ICEs with bogus declarations like const attribute no snprintf [PR117358]
Jakub Jelinek
jakub@gcc.gnu.org
Mon May 26 15:46:14 GMT 2025
https://gcc.gnu.org/g:65724317b26eb16a3cd7279aacd68f4c85b355c0
commit r13-9693-g65724317b26eb16a3cd7279aacd68f4c85b355c0
Author: Jakub Jelinek <jakub@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 <jakub@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 b5f4a9ec0a1c..180817cc8680 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -938,6 +938,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
@@ -1376,6 +1378,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);
@@ -1402,6 +1406,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);
@@ -1427,6 +1433,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);
@@ -1456,6 +1464,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;
@@ -1477,20 +1488,20 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len)
if (!INTEGRAL_TYPE_P (etype)
&& !POINTER_TYPE_P (etype))
- 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),
@@ -2104,7 +2115,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);
@@ -2179,7 +2190,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);
@@ -2233,7 +2244,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. */
@@ -2331,6 +2342,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')
{
@@ -2383,6 +2397,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);
@@ -2452,7 +2469,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')
@@ -2464,6 +2480,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)
@@ -2554,7 +2573,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. */
@@ -2586,6 +2605,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);
@@ -2676,6 +2698,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.
@@ -2968,7 +2993,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
@@ -2987,7 +3012,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
@@ -3038,6 +3063,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)
@@ -3136,6 +3164,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))
{
@@ -3229,7 +3260,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);
@@ -3250,6 +3281,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)
{
@@ -3367,7 +3401,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
@@ -3454,7 +3488,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
@@ -3503,7 +3537,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. */
@@ -3616,7 +3650,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)
@@ -3774,6 +3809,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)
{
@@ -3853,6 +3891,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)
@@ -4094,6 +4135,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);
+}
More information about the Gcc-cvs
mailing list