gimple-fold: Avoid ICEs with bogus declarations like const attribute no snprintf [PR117358]

Message ID Z0gw0o6IpsOdFujM@tucnak
State New
Headers
Series gimple-fold: Avoid ICEs with bogus declarations like const attribute no snprintf [PR117358] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_check--master-arm fail Patch failed to apply

Commit Message

Jakub Jelinek Nov. 28, 2024, 8:58 a.m. UTC
  Hi!

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
?

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk as
is or go with the above tests instead?

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.


	Jakub
  

Comments

Richard Biener Nov. 28, 2024, 9:39 a.m. UTC | #1
On Thu, 28 Nov 2024, Jakub Jelinek wrote:

> Hi!
> 
> 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
> ?

I think this doesn't work since a wrong pure/const attribute will
override this.  We'd have to check the flags against the
builtins.def attributes only.

> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk as
> is or go with the above tests instead?

The patch is OK.

Richard.

> 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.
> 
> --- gcc/gimple-fold.cc.jj	2024-11-23 13:00:29.566010380 +0100
> +++ gcc/gimple-fold.cc	2024-11-28 09:09:31.184314115 +0100
> @@ -1061,6 +1061,8 @@ gimple_fold_builtin_memory_op (gimple_st
>  	}
>        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
> @@ -1511,6 +1513,8 @@ gimple_fold_builtin_bcmp (gimple_stmt_it
>    /* 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);
> @@ -1537,6 +1541,8 @@ gimple_fold_builtin_bcopy (gimple_stmt_i
>       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);
> @@ -1562,6 +1568,8 @@ gimple_fold_builtin_bzero (gimple_stmt_i
>    /* 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);
>  
> @@ -1591,6 +1599,9 @@ gimple_fold_builtin_memset (gimple_stmt_
>        return true;
>      }
>  
> +  if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))
> +    return false;
> +
>    if (! tree_fits_uhwi_p (len))
>      return false;
>  
> @@ -1613,20 +1624,20 @@ gimple_fold_builtin_memset (gimple_stmt_
>    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),
> @@ -2240,7 +2251,7 @@ gimple_fold_builtin_strcpy (gimple_stmt_
>        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);
> @@ -2315,7 +2326,7 @@ gimple_fold_builtin_strncpy (gimple_stmt
>  
>    /* 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);
> @@ -2369,7 +2380,7 @@ gimple_fold_builtin_strchr (gimple_stmt_
>        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.  */
> @@ -2467,6 +2478,9 @@ gimple_fold_builtin_strstr (gimple_stmt_
>        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')
>      {
> @@ -2519,6 +2533,9 @@ gimple_fold_builtin_strcat (gimple_stmt_
>    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);
> @@ -2588,7 +2605,6 @@ gimple_fold_builtin_strcat_chk (gimple_s
>    tree fn;
>    const char *p;
>  
> -
>    p = c_getstr (src);
>    /* If the SRC parameter is "", return DEST.  */
>    if (p && *p == '\0')
> @@ -2600,6 +2616,9 @@ gimple_fold_builtin_strcat_chk (gimple_s
>    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)
> @@ -2690,7 +2709,7 @@ gimple_fold_builtin_strncat (gimple_stmt
>  
>    /* 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.  */
> @@ -2722,6 +2741,9 @@ gimple_fold_builtin_strncat_chk (gimple_
>        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);
> @@ -2812,6 +2834,9 @@ gimple_fold_builtin_string_compare (gimp
>        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.
> @@ -3104,7 +3129,7 @@ gimple_fold_builtin_fputs (gimple_stmt_i
>  	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
> @@ -3123,7 +3148,7 @@ gimple_fold_builtin_fputs (gimple_stmt_i
>  	  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
> @@ -3174,6 +3199,9 @@ gimple_fold_builtin_memory_chk (gimple_s
>  	}
>      }
>  
> +  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)
> @@ -3262,6 +3290,9 @@ gimple_fold_builtin_stxcpy_chk (gimple_s
>        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))
>      {
> @@ -3354,7 +3385,7 @@ gimple_fold_builtin_stxncpy_chk (gimple_
>    /* 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);
> @@ -3374,6 +3405,9 @@ gimple_fold_builtin_stpcpy (gimple_stmt_
>    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)
>      {
> @@ -3491,7 +3525,7 @@ gimple_fold_builtin_snprintf_chk (gimple
>       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
> @@ -3578,7 +3612,7 @@ gimple_fold_builtin_sprintf_chk (gimple_
>    /* 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
> @@ -3627,7 +3661,7 @@ gimple_fold_builtin_sprintf (gimple_stmt
>      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.  */
> @@ -3740,7 +3774,8 @@ gimple_fold_builtin_snprintf (gimple_stm
>    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)
> @@ -3898,6 +3933,9 @@ gimple_fold_builtin_fprintf (gimple_stmt
>    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)
>      {
> @@ -3977,6 +4015,9 @@ gimple_fold_builtin_printf (gimple_stmt_
>    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)
> @@ -4235,6 +4276,9 @@ gimple_fold_builtin_realloc (gimple_stmt
>    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);
> --- gcc/testsuite/gcc.c-torture/compile/pr117358.c.jj	2024-11-27 19:05:19.769389180 +0100
> +++ gcc/testsuite/gcc.c-torture/compile/pr117358.c	2024-11-27 19:05:02.643627376 +0100
> @@ -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); 
> +}
> 
> 	Jakub
> 
>
  

Patch

--- gcc/gimple-fold.cc.jj	2024-11-23 13:00:29.566010380 +0100
+++ gcc/gimple-fold.cc	2024-11-28 09:09:31.184314115 +0100
@@ -1061,6 +1061,8 @@  gimple_fold_builtin_memory_op (gimple_st
 	}
       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
@@ -1511,6 +1513,8 @@  gimple_fold_builtin_bcmp (gimple_stmt_it
   /* 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);
@@ -1537,6 +1541,8 @@  gimple_fold_builtin_bcopy (gimple_stmt_i
      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);
@@ -1562,6 +1568,8 @@  gimple_fold_builtin_bzero (gimple_stmt_i
   /* 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);
 
@@ -1591,6 +1599,9 @@  gimple_fold_builtin_memset (gimple_stmt_
       return true;
     }
 
+  if (!gimple_vdef (stmt) && gimple_in_ssa_p (cfun))
+    return false;
+
   if (! tree_fits_uhwi_p (len))
     return false;
 
@@ -1613,20 +1624,20 @@  gimple_fold_builtin_memset (gimple_stmt_
   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),
@@ -2240,7 +2251,7 @@  gimple_fold_builtin_strcpy (gimple_stmt_
       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);
@@ -2315,7 +2326,7 @@  gimple_fold_builtin_strncpy (gimple_stmt
 
   /* 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);
@@ -2369,7 +2380,7 @@  gimple_fold_builtin_strchr (gimple_stmt_
       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.  */
@@ -2467,6 +2478,9 @@  gimple_fold_builtin_strstr (gimple_stmt_
       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')
     {
@@ -2519,6 +2533,9 @@  gimple_fold_builtin_strcat (gimple_stmt_
   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);
@@ -2588,7 +2605,6 @@  gimple_fold_builtin_strcat_chk (gimple_s
   tree fn;
   const char *p;
 
-
   p = c_getstr (src);
   /* If the SRC parameter is "", return DEST.  */
   if (p && *p == '\0')
@@ -2600,6 +2616,9 @@  gimple_fold_builtin_strcat_chk (gimple_s
   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)
@@ -2690,7 +2709,7 @@  gimple_fold_builtin_strncat (gimple_stmt
 
   /* 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.  */
@@ -2722,6 +2741,9 @@  gimple_fold_builtin_strncat_chk (gimple_
       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);
@@ -2812,6 +2834,9 @@  gimple_fold_builtin_string_compare (gimp
       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.
@@ -3104,7 +3129,7 @@  gimple_fold_builtin_fputs (gimple_stmt_i
 	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
@@ -3123,7 +3148,7 @@  gimple_fold_builtin_fputs (gimple_stmt_i
 	  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
@@ -3174,6 +3199,9 @@  gimple_fold_builtin_memory_chk (gimple_s
 	}
     }
 
+  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)
@@ -3262,6 +3290,9 @@  gimple_fold_builtin_stxcpy_chk (gimple_s
       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))
     {
@@ -3354,7 +3385,7 @@  gimple_fold_builtin_stxncpy_chk (gimple_
   /* 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);
@@ -3374,6 +3405,9 @@  gimple_fold_builtin_stpcpy (gimple_stmt_
   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)
     {
@@ -3491,7 +3525,7 @@  gimple_fold_builtin_snprintf_chk (gimple
      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
@@ -3578,7 +3612,7 @@  gimple_fold_builtin_sprintf_chk (gimple_
   /* 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
@@ -3627,7 +3661,7 @@  gimple_fold_builtin_sprintf (gimple_stmt
     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.  */
@@ -3740,7 +3774,8 @@  gimple_fold_builtin_snprintf (gimple_stm
   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)
@@ -3898,6 +3933,9 @@  gimple_fold_builtin_fprintf (gimple_stmt
   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)
     {
@@ -3977,6 +4015,9 @@  gimple_fold_builtin_printf (gimple_stmt_
   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)
@@ -4235,6 +4276,9 @@  gimple_fold_builtin_realloc (gimple_stmt
   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);
--- gcc/testsuite/gcc.c-torture/compile/pr117358.c.jj	2024-11-27 19:05:19.769389180 +0100
+++ gcc/testsuite/gcc.c-torture/compile/pr117358.c	2024-11-27 19:05:02.643627376 +0100
@@ -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); 
+}