Commit 7d583f42 by Jeff Law Committed by Jeff Law

builtins.c (unterminated_array): Pass in c_strlen_data * to c_strlen rather than just a tree *.

	* builtins.c (unterminated_array): Pass in c_strlen_data * to
	c_strlen rather than just a tree *.
	(c_strlen): Change NONSTR argument to a c_strlen_data pointer.
	Update recursive calls appropriately.  If caller did not provide a
	suitable data pointer, create a local one.  When a non-terminated
	string is discovered, bubble up information about the string via the
	c_strlen_data object.
	* builtins.h (c_strlen): Update prototype.
	(c_strlen_data): New structure.
	* gimple-fold.c (get_range_strlen): Update calls to c_strlen.
	For a type 2 call, if c_strlen indicates a non-terminated string
	use the length of the non-terminated string.
	(gimple_fold_builtin_stpcpy): Update calls to c_strlen.

From-SVN: r264712
parent 23bce99c
2018-09-29 Jeff Law <law@redhat.com>
* builtins.c (unterminated_array): Pass in c_strlen_data * to
c_strlen rather than just a tree *.
(c_strlen): Change NONSTR argument to a c_strlen_data pointer.
Update recursive calls appropriately. If caller did not provide a
suitable data pointer, create a local one. When a non-terminated
string is discovered, bubble up information about the string via the
c_strlen_data object.
* builtins.h (c_strlen): Update prototype.
(c_strlen_data): New structure.
* gimple-fold.c (get_range_strlen): Update calls to c_strlen.
For a type 2 call, if c_strlen indicates a non-terminated string
use the length of the non-terminated string.
(gimple_fold_builtin_stpcpy): Update calls to c_strlen.
2018-09-29 Jakub Jelinek <jakub@redhat.com> 2018-09-29 Jakub Jelinek <jakub@redhat.com>
PR target/87467 PR target/87467
...@@ -302,8 +318,8 @@ ...@@ -302,8 +318,8 @@
* config/i386/i386.h (NUM_MODES_FOR_MODE_SWITCHING): Update * config/i386/i386.h (NUM_MODES_FOR_MODE_SWITCHING): Update
for removed I387_MASK_PM entity. for removed I387_MASK_PM entity.
2018-09-26 Jeff Law <law@redhat.com>
2018-09-26 Jeff Law <law@redhat.com>
Revert Revert
2018-09-26 Alexey Neyman <stilor@att.net> 2018-09-26 Alexey Neyman <stilor@att.net>
......
...@@ -570,9 +570,10 @@ warn_string_no_nul (location_t loc, const char *fn, tree arg, tree decl) ...@@ -570,9 +570,10 @@ warn_string_no_nul (location_t loc, const char *fn, tree arg, tree decl)
tree tree
unterminated_array (tree exp) unterminated_array (tree exp)
{ {
tree nonstr = NULL; c_strlen_data data;
c_strlen (exp, 1, &nonstr); memset (&data, 0, sizeof (c_strlen_data));
return nonstr; c_strlen (exp, 1, &data);
return data.decl;
} }
/* Compute the length of a null-terminated character string or wide /* Compute the length of a null-terminated character string or wide
...@@ -592,10 +593,12 @@ unterminated_array (tree exp) ...@@ -592,10 +593,12 @@ unterminated_array (tree exp)
accesses. Note that this implies the result is not going to be emitted accesses. Note that this implies the result is not going to be emitted
into the instruction stream. into the instruction stream.
If a not zero-terminated string value is encountered and NONSTR is Additional information about the string accessed may be recorded
non-zero, the declaration of the string value is assigned to *NONSTR. in DATA. For example, if SRC references an unterminated string,
*NONSTR is accumulating, thus not cleared on success, therefore it has then the declaration will be stored in the DECL field. If the
to be initialized to NULL_TREE by the caller. length of the unterminated string can be determined, it'll be
stored in the LEN field. Note this length could well be different
than what a C strlen call would return.
ELTSIZE is 1 for normal single byte character strings, and 2 or ELTSIZE is 1 for normal single byte character strings, and 2 or
4 for wide characer strings. ELTSIZE is by default 1. 4 for wide characer strings. ELTSIZE is by default 1.
...@@ -603,8 +606,16 @@ unterminated_array (tree exp) ...@@ -603,8 +606,16 @@ unterminated_array (tree exp)
The value returned is of type `ssizetype'. */ The value returned is of type `ssizetype'. */
tree tree
c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize) c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize)
{ {
/* If we were not passed a DATA pointer, then get one to a local
structure. That avoids having to check DATA for NULL before
each time we want to use it. */
c_strlen_data local_strlen_data;
memset (&local_strlen_data, 0, sizeof (c_strlen_data));
if (!data)
data = &local_strlen_data;
gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4); gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
STRIP_NOPS (src); STRIP_NOPS (src);
if (TREE_CODE (src) == COND_EXPR if (TREE_CODE (src) == COND_EXPR
...@@ -612,15 +623,15 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize) ...@@ -612,15 +623,15 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
{ {
tree len1, len2; tree len1, len2;
len1 = c_strlen (TREE_OPERAND (src, 1), only_value, nonstr, eltsize); len1 = c_strlen (TREE_OPERAND (src, 1), only_value, data, eltsize);
len2 = c_strlen (TREE_OPERAND (src, 2), only_value, nonstr, eltsize); len2 = c_strlen (TREE_OPERAND (src, 2), only_value, data, eltsize);
if (tree_int_cst_equal (len1, len2)) if (tree_int_cst_equal (len1, len2))
return len1; return len1;
} }
if (TREE_CODE (src) == COMPOUND_EXPR if (TREE_CODE (src) == COMPOUND_EXPR
&& (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0)))) && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
return c_strlen (TREE_OPERAND (src, 1), only_value, nonstr, eltsize); return c_strlen (TREE_OPERAND (src, 1), only_value, data, eltsize);
location_t loc = EXPR_LOC_OR_LOC (src, input_location); location_t loc = EXPR_LOC_OR_LOC (src, input_location);
...@@ -666,13 +677,15 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize) ...@@ -666,13 +677,15 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
start searching for it. */ start searching for it. */
unsigned len = string_length (ptr, eltsize, strelts); unsigned len = string_length (ptr, eltsize, strelts);
/* Return when an embedded null character is found or none at all. */ /* Return when an embedded null character is found or none at all.
In the latter case, set the DECL/LEN field in the DATA structure
so that callers may examine them. */
if (len + 1 < strelts) if (len + 1 < strelts)
return NULL_TREE; return NULL_TREE;
else if (len >= maxelts) else if (len >= maxelts)
{ {
if (nonstr && decl) data->decl = decl;
*nonstr = decl; data->len = ssize_int (len);
return NULL_TREE; return NULL_TREE;
} }
...@@ -737,11 +750,12 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize) ...@@ -737,11 +750,12 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
strelts - eltoff); strelts - eltoff);
/* Don't know what to return if there was no zero termination. /* Don't know what to return if there was no zero termination.
Ideally this would turn into a gcc_checking_assert over time. */ Ideally this would turn into a gcc_checking_assert over time.
Set DECL/LEN so callers can examine them. */
if (len >= maxelts - eltoff) if (len >= maxelts - eltoff)
{ {
if (nonstr && decl) data->decl = decl;
*nonstr = decl; data->len = ssize_int (len);
return NULL_TREE; return NULL_TREE;
} }
...@@ -3965,13 +3979,14 @@ expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode) ...@@ -3965,13 +3979,14 @@ expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode)
compile-time, not an expression containing a string. This is compile-time, not an expression containing a string. This is
because the latter will potentially produce pessimized code because the latter will potentially produce pessimized code
when used to produce the return value. */ when used to produce the return value. */
tree nonstr = NULL_TREE; c_strlen_data data;
memset (&data, 0, sizeof (c_strlen_data));
if (!c_getstr (src, NULL) if (!c_getstr (src, NULL)
|| !(len = c_strlen (src, 0, &nonstr, 1))) || !(len = c_strlen (src, 0, &data, 1)))
return expand_movstr (dst, src, target, /*endp=*/2); return expand_movstr (dst, src, target, /*endp=*/2);
if (nonstr && !TREE_NO_WARNING (exp)) if (data.decl && !TREE_NO_WARNING (exp))
warn_string_no_nul (EXPR_LOCATION (exp), "stpcpy", src, nonstr); warn_string_no_nul (EXPR_LOCATION (exp), "stpcpy", src, data.decl);
lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1)); lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
ret = expand_builtin_mempcpy_args (dst, src, lenp1, ret = expand_builtin_mempcpy_args (dst, src, lenp1,
...@@ -8444,22 +8459,23 @@ fold_builtin_strlen (location_t loc, tree type, tree arg) ...@@ -8444,22 +8459,23 @@ fold_builtin_strlen (location_t loc, tree type, tree arg)
return NULL_TREE; return NULL_TREE;
else else
{ {
tree nonstr = NULL_TREE; c_strlen_data data;
tree len = c_strlen (arg, 0, &nonstr); memset (&data, 0, sizeof (c_strlen_data));
tree len = c_strlen (arg, 0, &data);
if (len) if (len)
return fold_convert_loc (loc, type, len); return fold_convert_loc (loc, type, len);
if (!nonstr) if (!data.decl)
c_strlen (arg, 1, &nonstr); c_strlen (arg, 1, &data);
if (nonstr) if (data.decl)
{ {
if (EXPR_HAS_LOCATION (arg)) if (EXPR_HAS_LOCATION (arg))
loc = EXPR_LOCATION (arg); loc = EXPR_LOCATION (arg);
else if (loc == UNKNOWN_LOCATION) else if (loc == UNKNOWN_LOCATION)
loc = input_location; loc = input_location;
warn_string_no_nul (loc, "strlen", arg, nonstr); warn_string_no_nul (loc, "strlen", arg, data.decl);
} }
return NULL_TREE; return NULL_TREE;
......
...@@ -57,7 +57,14 @@ extern bool get_pointer_alignment_1 (tree, unsigned int *, ...@@ -57,7 +57,14 @@ extern bool get_pointer_alignment_1 (tree, unsigned int *,
unsigned HOST_WIDE_INT *); unsigned HOST_WIDE_INT *);
extern unsigned int get_pointer_alignment (tree); extern unsigned int get_pointer_alignment (tree);
extern unsigned string_length (const void*, unsigned, unsigned); extern unsigned string_length (const void*, unsigned, unsigned);
extern tree c_strlen (tree, int, tree * = NULL, unsigned = 1); struct c_strlen_data
{
tree decl;
tree len;
tree off;
};
extern tree c_strlen (tree, int, c_strlen_data * = NULL, unsigned = 1);
extern void expand_builtin_setjmp_setup (rtx, rtx); extern void expand_builtin_setjmp_setup (rtx, rtx);
extern void expand_builtin_setjmp_receiver (rtx); extern void expand_builtin_setjmp_receiver (rtx);
extern void expand_builtin_update_setjmp_buf (rtx); extern void expand_builtin_update_setjmp_buf (rtx);
......
...@@ -1337,7 +1337,23 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, ...@@ -1337,7 +1337,23 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
return false; return false;
} }
else else
val = c_strlen (arg, 1, nonstr, eltsize); {
c_strlen_data data;
memset (&data, 0, sizeof (c_strlen_data));
val = c_strlen (arg, 1, &data, eltsize);
/* If we potentially had a non-terminated string, then
bubble that information up to the caller. */
if (!val)
{
*nonstr = data.decl;
/* If TYPE is asking for a maximum, then use any
length (including the length of an unterminated
string) for VAL. */
if (type == 2)
val = data.len;
}
}
if (!val && fuzzy) if (!val && fuzzy)
{ {
...@@ -2812,21 +2828,22 @@ gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi) ...@@ -2812,21 +2828,22 @@ gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi)
} }
/* Set to non-null if ARG refers to an unterminated array. */ /* Set to non-null if ARG refers to an unterminated array. */
tree nonstr = NULL; c_strlen_data data;
tree len = c_strlen (src, 1, &nonstr, 1); memset (&data, 0, sizeof (c_strlen_data));
tree len = c_strlen (src, 1, &data, 1);
if (!len if (!len
|| TREE_CODE (len) != INTEGER_CST) || TREE_CODE (len) != INTEGER_CST)
{ {
nonstr = unterminated_array (src); data.decl = unterminated_array (src);
if (!nonstr) if (!data.decl)
return false; return false;
} }
if (nonstr) if (data.decl)
{ {
/* Avoid folding calls with unterminated arrays. */ /* Avoid folding calls with unterminated arrays. */
if (!gimple_no_warning_p (stmt)) if (!gimple_no_warning_p (stmt))
warn_string_no_nul (loc, "stpcpy", src, nonstr); warn_string_no_nul (loc, "stpcpy", src, data.decl);
gimple_set_no_warning (stmt, true); gimple_set_no_warning (stmt, true);
return false; return false;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment