summaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2019-11-22 16:47:22 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2019-11-22 09:47:22 -0700
commitb5338fb359ea3480d6ed37bbc52fe2df49b82fb9 (patch)
tree2216f90a2e8eee2cdeb3d613c5d53dc9e791f4a9 /gcc/builtins.c
parent86b0eb81837f4912d3f10bcfad35086cc54a1841 (diff)
PR middle-end/88226 - missing warning on fprintf, fputs, and puts with an unterminated array
gcc/ChangeLog: PR middle-end/88226 * builtins.c (check_nul_terminated_array): New function. (fold_builtin_0): Remove declaration. (fold_builtin_1): Same. (fold_builtin_2): Same. (fold_builtin_3): Same. (fold_builtin_strpbrk): Add argument. (fold_builtin_strspn): Same. (fold_builtin_strcspn): Same. (expand_builtin_strcat): Call it. Remove unused argument. (expand_builtin_stpncpy): Same. (expand_builtin_strncat): Same. (expand_builtin_strncpy): Same. Adjust indentation. (expand_builtin_strcmp): Same. (expand_builtin_strncmp): Same. (expand_builtin_fork_or_exec): Same. (expand_builtin): Handle more built-ins. (fold_builtin_2): Add argument. (fold_builtin_n): Make static. Add argument. (fold_call_expr): Pass new argument to fold_builtin_n and fold_builtin_2. (fold_builtin_call_array): Pass new argument to fold_builtin_n. (fold_builtin_strpbrk): Add argument. Call check_nul_terminated_array. (fold_call_stmt): Pass new argument to fold_builtin_n. * builtins.h: Correct a comment. * gimple-fold.c (gimple_fold_builtin_strchr): Call check_nul_terminated_array. * tree-ssa-strlen.c (handle_builtin_strlen): Call check_nul_terminated_array. (handle_builtin_strchr): Same. (handle_builtin_string_cmp): Same. gcc/testsuite/ChangeLog: PR middle-end/88226 * gcc.dg/Wstringop-overflow-22.c: New test. * gcc.dg/tree-ssa/builtin-fprintf-warn-1.c: Remove xfails. From-SVN: r278623
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c420
1 files changed, 275 insertions, 145 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 50909af91f9..f8cd4b44fa8 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -131,7 +131,7 @@ static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len,
static rtx expand_builtin_memmove (tree, rtx);
static rtx expand_builtin_mempcpy (tree, rtx);
static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, memop_ret);
-static rtx expand_builtin_strcat (tree, rtx);
+static rtx expand_builtin_strcat (tree);
static rtx expand_builtin_strcpy (tree, rtx);
static rtx expand_builtin_strcpy_args (tree, tree, tree, rtx);
static rtx expand_builtin_stpcpy (tree, rtx, machine_mode);
@@ -166,15 +166,11 @@ static tree fold_builtin_fabs (location_t, tree, tree);
static tree fold_builtin_abs (location_t, tree, tree);
static tree fold_builtin_unordered_cmp (location_t, tree, tree, tree, enum tree_code,
enum tree_code);
-static tree fold_builtin_0 (location_t, tree);
-static tree fold_builtin_1 (location_t, tree, tree);
-static tree fold_builtin_2 (location_t, tree, tree, tree);
-static tree fold_builtin_3 (location_t, tree, tree, tree, tree);
static tree fold_builtin_varargs (location_t, tree, tree*, int);
-static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
-static tree fold_builtin_strspn (location_t, tree, tree);
-static tree fold_builtin_strcspn (location_t, tree, tree);
+static tree fold_builtin_strpbrk (location_t, tree, tree, tree, tree);
+static tree fold_builtin_strspn (location_t, tree, tree, tree);
+static tree fold_builtin_strcspn (location_t, tree, tree, tree);
static rtx expand_builtin_object_size (tree);
static rtx expand_builtin_memory_chk (tree, rtx, machine_mode,
@@ -564,6 +560,51 @@ warn_string_no_nul (location_t loc, const char *fn, tree arg, tree decl)
}
}
+/* For a call EXPR (which may be null) that expects a string argument
+ and SRC as the argument, returns false if SRC is a character array
+ with no terminating NUL. When nonnull, BOUND is the number of
+ characters in which to expect the terminating NUL.
+ When EXPR is nonnull also issues a warning. */
+
+bool
+check_nul_terminated_array (tree expr, tree src, tree bound /* = NULL_TREE */)
+{
+ tree size;
+ bool exact;
+ tree nonstr = unterminated_array (src, &size, &exact);
+ if (!nonstr)
+ return true;
+
+ /* NONSTR refers to the non-nul terminated constant array and SIZE
+ is the constant size of the array in bytes. EXACT is true when
+ SIZE is exact. */
+
+ if (bound)
+ {
+ wide_int min, max;
+ if (TREE_CODE (bound) == INTEGER_CST)
+ min = max = wi::to_wide (bound);
+ else
+ {
+ value_range_kind rng = get_range_info (bound, &min, &max);
+ if (rng != VR_RANGE)
+ return true;
+ }
+
+ if (wi::leu_p (min, wi::to_wide (size)))
+ return true;
+ }
+
+ if (expr && !TREE_NO_WARNING (expr))
+ {
+ tree fndecl = get_callee_fndecl (expr);
+ const char *fname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+ warn_string_no_nul (EXPR_LOCATION (expr), fname, src, nonstr);
+ }
+
+ return false;
+}
+
/* If EXP refers to an unterminated constant character array return
the declaration of the object of which the array is a member or
element and if SIZE is not null, set *SIZE to the size of
@@ -4024,7 +4065,7 @@ expand_movstr (tree dest, tree src, rtx target, memop_ret retmode)
to the library function. */
static rtx
-expand_builtin_strcat (tree exp, rtx)
+expand_builtin_strcat (tree exp)
{
if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
|| !warn_stringop_overflow)
@@ -4033,6 +4074,10 @@ expand_builtin_strcat (tree exp, rtx)
tree dest = CALL_EXPR_ARG (exp, 0);
tree src = CALL_EXPR_ARG (exp, 1);
+ /* Detect unterminated source (only). */
+ if (!check_nul_terminated_array (exp, src))
+ return NULL_RTX;
+
/* There is no way here to determine the length of the string in
the destination to which the SRC string is being appended so
just diagnose cases when the souce string is longer than
@@ -4228,6 +4273,8 @@ expand_builtin_stpncpy (tree exp, rtx)
/* The exact number of bytes to write (not the maximum). */
tree len = CALL_EXPR_ARG (exp, 2);
+ if (!check_nul_terminated_array (exp, src, len))
+ return NULL_RTX;
/* The size of the destination object. */
tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
@@ -4330,6 +4377,11 @@ expand_builtin_strncat (tree exp, rtx)
tree src = CALL_EXPR_ARG (exp, 1);
/* The upper bound on the number of bytes to write. */
tree maxread = CALL_EXPR_ARG (exp, 2);
+
+ /* Detect unterminated source (only). */
+ if (!check_nul_terminated_array (exp, src, maxread))
+ return NULL_RTX;
+
/* The length of the source sequence. */
tree slen = c_strlen (src, 1);
@@ -4391,59 +4443,63 @@ expand_builtin_strncpy (tree exp, rtx target)
{
location_t loc = EXPR_LOCATION (exp);
- if (validate_arglist (exp,
- POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
- {
- tree dest = CALL_EXPR_ARG (exp, 0);
- tree src = CALL_EXPR_ARG (exp, 1);
- /* The number of bytes to write (not the maximum). */
- tree len = CALL_EXPR_ARG (exp, 2);
- /* The length of the source sequence. */
- tree slen = c_strlen (src, 1);
+ if (!validate_arglist (exp,
+ POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+ tree dest = CALL_EXPR_ARG (exp, 0);
+ tree src = CALL_EXPR_ARG (exp, 1);
+ /* The number of bytes to write (not the maximum). */
+ tree len = CALL_EXPR_ARG (exp, 2);
- if (warn_stringop_overflow)
- {
- tree destsize = compute_objsize (dest,
- warn_stringop_overflow - 1);
+ if (!check_nul_terminated_array (exp, src, len))
+ return NULL_RTX;
- /* The number of bytes to write is LEN but check_access will also
- check SLEN if LEN's value isn't known. */
- check_access (exp, dest, src, len, /*maxread=*/NULL_TREE, src,
- destsize);
- }
+ /* The length of the source sequence. */
+ tree slen = c_strlen (src, 1);
- /* We must be passed a constant len and src parameter. */
- if (!tree_fits_uhwi_p (len) || !slen || !tree_fits_uhwi_p (slen))
- return NULL_RTX;
+ if (warn_stringop_overflow)
+ {
+ tree destsize = compute_objsize (dest,
+ warn_stringop_overflow - 1);
- slen = size_binop_loc (loc, PLUS_EXPR, slen, ssize_int (1));
+ /* The number of bytes to write is LEN but check_access will also
+ check SLEN if LEN's value isn't known. */
+ check_access (exp, dest, src, len, /*maxread=*/NULL_TREE, src,
+ destsize);
+ }
- /* We're required to pad with trailing zeros if the requested
- len is greater than strlen(s2)+1. In that case try to
- use store_by_pieces, if it fails, punt. */
- if (tree_int_cst_lt (slen, len))
- {
- unsigned int dest_align = get_pointer_alignment (dest);
- const char *p = c_getstr (src);
- rtx dest_mem;
-
- if (!p || dest_align == 0 || !tree_fits_uhwi_p (len)
- || !can_store_by_pieces (tree_to_uhwi (len),
- builtin_strncpy_read_str,
- CONST_CAST (char *, p),
- dest_align, false))
- return NULL_RTX;
+ /* We must be passed a constant len and src parameter. */
+ if (!tree_fits_uhwi_p (len) || !slen || !tree_fits_uhwi_p (slen))
+ return NULL_RTX;
- dest_mem = get_memory_rtx (dest, len);
- store_by_pieces (dest_mem, tree_to_uhwi (len),
- builtin_strncpy_read_str,
- CONST_CAST (char *, p), dest_align, false,
- RETURN_BEGIN);
- dest_mem = force_operand (XEXP (dest_mem, 0), target);
- dest_mem = convert_memory_address (ptr_mode, dest_mem);
- return dest_mem;
- }
+ slen = size_binop_loc (loc, PLUS_EXPR, slen, ssize_int (1));
+
+ /* We're required to pad with trailing zeros if the requested
+ len is greater than strlen(s2)+1. In that case try to
+ use store_by_pieces, if it fails, punt. */
+ if (tree_int_cst_lt (slen, len))
+ {
+ unsigned int dest_align = get_pointer_alignment (dest);
+ const char *p = c_getstr (src);
+ rtx dest_mem;
+
+ if (!p || dest_align == 0 || !tree_fits_uhwi_p (len)
+ || !can_store_by_pieces (tree_to_uhwi (len),
+ builtin_strncpy_read_str,
+ CONST_CAST (char *, p),
+ dest_align, false))
+ return NULL_RTX;
+
+ dest_mem = get_memory_rtx (dest, len);
+ store_by_pieces (dest_mem, tree_to_uhwi (len),
+ builtin_strncpy_read_str,
+ CONST_CAST (char *, p), dest_align, false,
+ RETURN_BEGIN);
+ dest_mem = force_operand (XEXP (dest_mem, 0), target);
+ dest_mem = convert_memory_address (ptr_mode, dest_mem);
+ return dest_mem;
}
+
return NULL_RTX;
}
@@ -4822,6 +4878,13 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return NULL_RTX;
+ tree arg1 = CALL_EXPR_ARG (exp, 0);
+ tree arg2 = CALL_EXPR_ARG (exp, 1);
+
+ if (!check_nul_terminated_array (exp, arg1)
+ || !check_nul_terminated_array (exp, arg2))
+ return NULL_RTX;
+
/* Due to the performance benefit, always inline the calls first. */
rtx result = NULL_RTX;
result = inline_expand_builtin_string_cmp (exp, target);
@@ -4833,9 +4896,6 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
if (cmpstr_icode == CODE_FOR_nothing && cmpstrn_icode == CODE_FOR_nothing)
return NULL_RTX;
- tree arg1 = CALL_EXPR_ARG (exp, 0);
- tree arg2 = CALL_EXPR_ARG (exp, 1);
-
unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
@@ -4941,6 +5001,14 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
return NULL_RTX;
+ tree arg1 = CALL_EXPR_ARG (exp, 0);
+ tree arg2 = CALL_EXPR_ARG (exp, 1);
+ tree arg3 = CALL_EXPR_ARG (exp, 2);
+
+ if (!check_nul_terminated_array (exp, arg1, arg3)
+ || !check_nul_terminated_array (exp, arg2, arg3))
+ return NULL_RTX;
+
/* Due to the performance benefit, always inline the calls first. */
rtx result = NULL_RTX;
result = inline_expand_builtin_string_cmp (exp, target);
@@ -4956,10 +5024,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
tree len;
- tree arg1 = CALL_EXPR_ARG (exp, 0);
- tree arg2 = CALL_EXPR_ARG (exp, 1);
- tree arg3 = CALL_EXPR_ARG (exp, 2);
-
unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
@@ -5954,6 +6018,26 @@ expand_builtin_fork_or_exec (tree fn, tree exp, rtx target, int ignore)
tree id, decl;
tree call;
+ if (DECL_FUNCTION_CODE (fn) != BUILT_IN_FORK)
+ {
+ /* Detect unterminated path. */
+ if (!check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0)))
+ return NULL_RTX;
+
+ /* Also detect unterminated first argument. */
+ switch (DECL_FUNCTION_CODE (fn))
+ {
+ case BUILT_IN_EXECL:
+ case BUILT_IN_EXECLE:
+ case BUILT_IN_EXECLP:
+ if (!check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0)))
+ return NULL_RTX;
+ default:
+ break;
+ }
+ }
+
+
/* If we are not profiling, just call the function. */
if (!profile_arc_flag)
return NULL_RTX;
@@ -7604,11 +7688,49 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
break;
case BUILT_IN_STRCAT:
- target = expand_builtin_strcat (exp, target);
+ target = expand_builtin_strcat (exp);
if (target)
return target;
break;
+ case BUILT_IN_GETTEXT:
+ case BUILT_IN_PUTS:
+ case BUILT_IN_PUTS_UNLOCKED:
+ case BUILT_IN_STRDUP:
+ if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
+ check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0));
+ break;
+
+ case BUILT_IN_INDEX:
+ case BUILT_IN_RINDEX:
+ case BUILT_IN_STRCHR:
+ case BUILT_IN_STRRCHR:
+ if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0));
+ break;
+
+ case BUILT_IN_FPUTS:
+ case BUILT_IN_FPUTS_UNLOCKED:
+ if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+ check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0));
+ break;
+
+ case BUILT_IN_STRNDUP:
+ if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ check_nul_terminated_array (exp,
+ CALL_EXPR_ARG (exp, 0),
+ CALL_EXPR_ARG (exp, 1));
+ break;
+
+ case BUILT_IN_STRCASECMP:
+ case BUILT_IN_STRSTR:
+ if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+ {
+ check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 0));
+ check_nul_terminated_array (exp, CALL_EXPR_ARG (exp, 1));
+ }
+ break;
+
case BUILT_IN_STRCPY:
target = expand_builtin_strcpy (exp, target);
if (target)
@@ -9671,11 +9793,12 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0)
}
-/* Fold a call to built-in function FNDECL with 2 arguments, ARG0 and ARG1.
- This function returns NULL_TREE if no simplification was possible. */
+/* Folds a call EXPR (which may be null) to built-in function FNDECL
+ with 2 arguments, ARG0 and ARG1. This function returns NULL_TREE
+ if no simplification was possible. */
static tree
-fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
+fold_builtin_2 (location_t loc, tree expr, tree fndecl, tree arg0, tree arg1)
{
tree type = TREE_TYPE (TREE_TYPE (fndecl));
enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
@@ -9703,13 +9826,13 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
return fold_builtin_modf (loc, arg0, arg1, type);
case BUILT_IN_STRSPN:
- return fold_builtin_strspn (loc, arg0, arg1);
+ return fold_builtin_strspn (loc, expr, arg0, arg1);
case BUILT_IN_STRCSPN:
- return fold_builtin_strcspn (loc, arg0, arg1);
+ return fold_builtin_strcspn (loc, expr, arg0, arg1);
case BUILT_IN_STRPBRK:
- return fold_builtin_strpbrk (loc, arg0, arg1, type);
+ return fold_builtin_strpbrk (loc, expr, arg0, arg1, type);
case BUILT_IN_EXPECT:
return fold_builtin_expect (loc, arg0, arg1, NULL_TREE, NULL_TREE);
@@ -9827,13 +9950,14 @@ fold_builtin_3 (location_t loc, tree fndecl,
return NULL_TREE;
}
-/* Fold a call to built-in function FNDECL. ARGS is an array of NARGS
- arguments. IGNORE is true if the result of the
- function call is ignored. This function returns NULL_TREE if no
- simplification was possible. */
+/* Folds a call EXPR (which may be null) to built-in function FNDECL.
+ ARGS is an array of NARGS arguments. IGNORE is true if the result
+ of the function call is ignored. This function returns NULL_TREE
+ if no simplification was possible. */
-tree
-fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool)
+static tree
+fold_builtin_n (location_t loc, tree expr, tree fndecl, tree *args,
+ int nargs, bool)
{
tree ret = NULL_TREE;
@@ -9846,7 +9970,7 @@ fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool)
ret = fold_builtin_1 (loc, fndecl, args[0]);
break;
case 2:
- ret = fold_builtin_2 (loc, fndecl, args[0], args[1]);
+ ret = fold_builtin_2 (loc, expr, fndecl, args[0], args[1]);
break;
case 3:
ret = fold_builtin_3 (loc, fndecl, args[0], args[1], args[2]);
@@ -9944,7 +10068,7 @@ fold_call_expr (location_t loc, tree exp, bool ignore)
else
{
tree *args = CALL_EXPR_ARGP (exp);
- ret = fold_builtin_n (loc, fndecl, args, nargs, ignore);
+ ret = fold_builtin_n (loc, exp, fndecl, args, nargs, ignore);
if (ret)
return ret;
}
@@ -9982,7 +10106,7 @@ fold_builtin_call_array (location_t loc, tree,
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return targetm.fold_builtin (fndecl, n, argarray, false);
else
- return fold_builtin_n (loc, fndecl, argarray, n, false);
+ return fold_builtin_n (loc, NULL_TREE, fndecl, argarray, n, false);
}
return NULL_TREE;
@@ -10134,51 +10258,53 @@ readonly_data_expr (tree exp)
form of the builtin function call. */
static tree
-fold_builtin_strpbrk (location_t loc, tree s1, tree s2, tree type)
+fold_builtin_strpbrk (location_t loc, tree expr, tree s1, tree s2, tree type)
{
if (!validate_arg (s1, POINTER_TYPE)
|| !validate_arg (s2, POINTER_TYPE))
return NULL_TREE;
- else
- {
- tree fn;
- const char *p1, *p2;
- p2 = c_getstr (s2);
- if (p2 == NULL)
- return NULL_TREE;
+ if (!check_nul_terminated_array (expr, s1)
+ || !check_nul_terminated_array (expr, s2))
+ return NULL_TREE;
- p1 = c_getstr (s1);
- if (p1 != NULL)
- {
- const char *r = strpbrk (p1, p2);
- tree tem;
+ tree fn;
+ const char *p1, *p2;
- if (r == NULL)
- return build_int_cst (TREE_TYPE (s1), 0);
+ p2 = c_getstr (s2);
+ if (p2 == NULL)
+ return NULL_TREE;
- /* Return an offset into the constant string argument. */
- tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
- return fold_convert_loc (loc, type, tem);
- }
+ p1 = c_getstr (s1);
+ if (p1 != NULL)
+ {
+ const char *r = strpbrk (p1, p2);
+ tree tem;
- if (p2[0] == '\0')
- /* strpbrk(x, "") == NULL.
- Evaluate and ignore s1 in case it had side-effects. */
- return omit_one_operand_loc (loc, type, integer_zero_node, s1);
+ if (r == NULL)
+ return build_int_cst (TREE_TYPE (s1), 0);
- if (p2[1] != '\0')
- return NULL_TREE; /* Really call strpbrk. */
+ /* Return an offset into the constant string argument. */
+ tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
+ return fold_convert_loc (loc, type, tem);
+ }
- fn = builtin_decl_implicit (BUILT_IN_STRCHR);
- if (!fn)
- return NULL_TREE;
+ if (p2[0] == '\0')
+ /* strpbrk(x, "") == NULL.
+ Evaluate and ignore s1 in case it had side-effects. */
+ return omit_one_operand_loc (loc, type, integer_zero_node, s1);
- /* New argument list transforming strpbrk(s1, s2) to
- strchr(s1, s2[0]). */
- return build_call_expr_loc (loc, fn, 2, s1,
- build_int_cst (integer_type_node, p2[0]));
- }
+ if (p2[1] != '\0')
+ return NULL_TREE; /* Really call strpbrk. */
+
+ fn = builtin_decl_implicit (BUILT_IN_STRCHR);
+ if (!fn)
+ return NULL_TREE;
+
+ /* New argument list transforming strpbrk(s1, s2) to
+ strchr(s1, s2[0]). */
+ return build_call_expr_loc (loc, fn, 2, s1,
+ build_int_cst (integer_type_node, p2[0]));
}
/* Simplify a call to the strspn builtin. S1 and S2 are the arguments
@@ -10200,23 +10326,25 @@ fold_builtin_strpbrk (location_t loc, tree s1, tree s2, tree type)
form of the builtin function call. */
static tree
-fold_builtin_strspn (location_t loc, tree s1, tree s2)
+fold_builtin_strspn (location_t loc, tree expr, tree s1, tree s2)
{
if (!validate_arg (s1, POINTER_TYPE)
|| !validate_arg (s2, POINTER_TYPE))
return NULL_TREE;
- else
- {
- const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
- /* If either argument is "", return NULL_TREE. */
- if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
- /* Evaluate and ignore both arguments in case either one has
- side-effects. */
- return omit_two_operands_loc (loc, size_type_node, size_zero_node,
+ if (!check_nul_terminated_array (expr, s1)
+ || !check_nul_terminated_array (expr, s2))
+ return NULL_TREE;
+
+ const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
+
+ /* If either argument is "", return NULL_TREE. */
+ if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
+ /* Evaluate and ignore both arguments in case either one has
+ side-effects. */
+ return omit_two_operands_loc (loc, size_type_node, size_zero_node,
s1, s2);
- return NULL_TREE;
- }
+ return NULL_TREE;
}
/* Simplify a call to the strcspn builtin. S1 and S2 are the arguments
@@ -10238,38 +10366,40 @@ fold_builtin_strspn (location_t loc, tree s1, tree s2)
form of the builtin function call. */
static tree
-fold_builtin_strcspn (location_t loc, tree s1, tree s2)
+fold_builtin_strcspn (location_t loc, tree expr, tree s1, tree s2)
{
if (!validate_arg (s1, POINTER_TYPE)
|| !validate_arg (s2, POINTER_TYPE))
return NULL_TREE;
- else
+
+ if (!check_nul_terminated_array (expr, s1)
+ || !check_nul_terminated_array (expr, s2))
+ return NULL_TREE;
+
+ /* If the first argument is "", return NULL_TREE. */
+ const char *p1 = c_getstr (s1);
+ if (p1 && *p1 == '\0')
{
- /* If the first argument is "", return NULL_TREE. */
- const char *p1 = c_getstr (s1);
- if (p1 && *p1 == '\0')
- {
- /* Evaluate and ignore argument s2 in case it has
- side-effects. */
- return omit_one_operand_loc (loc, size_type_node,
+ /* Evaluate and ignore argument s2 in case it has
+ side-effects. */
+ return omit_one_operand_loc (loc, size_type_node,
size_zero_node, s2);
- }
+ }
- /* If the second argument is "", return __builtin_strlen(s1). */
- const char *p2 = c_getstr (s2);
- if (p2 && *p2 == '\0')
- {
- tree fn = builtin_decl_implicit (BUILT_IN_STRLEN);
+ /* If the second argument is "", return __builtin_strlen(s1). */
+ const char *p2 = c_getstr (s2);
+ if (p2 && *p2 == '\0')
+ {
+ tree fn = builtin_decl_implicit (BUILT_IN_STRLEN);
- /* If the replacement _DECL isn't initialized, don't do the
- transformation. */
- if (!fn)
- return NULL_TREE;
+ /* If the replacement _DECL isn't initialized, don't do the
+ transformation. */
+ if (!fn)
+ return NULL_TREE;
- return build_call_expr_loc (loc, fn, 1, s1);
- }
- return NULL_TREE;
+ return build_call_expr_loc (loc, fn, 1, s1);
}
+ return NULL_TREE;
}
/* Fold the next_arg or va_start call EXP. Returns true if there was an error
@@ -11112,7 +11242,7 @@ fold_call_stmt (gcall *stmt, bool ignore)
}
else
{
- ret = fold_builtin_n (loc, fndecl, args, nargs, ignore);
+ ret = fold_builtin_n (loc, NULL_TREE, fndecl, args, nargs, ignore);
if (ret)
{
/* Propagate location information from original call to