builtins.c (c_strlen): Handle not zero terminated STRING_CSTs correctly.
* builtins.c (c_strlen): Handle not zero terminated STRING_CSTs correctly. * fold-const.c (c_getstr): Fix function comment. Remove unused third argument. Fix range checks. * fold-const.h (c_getstr): Adjust protoype. * gimple-fold.c (gimple_fold_builtin_memory_op): Avoid folding when string is constant but contains no NUL byte. From-SVN: r264301
This commit is contained in:
parent
9a9f692b6c
commit
d01b568a78
5 changed files with 50 additions and 48 deletions
|
@ -1,5 +1,13 @@
|
|||
2018-09-13 Bernd Edlinger <bernd.edlinger@hotmail.de>
|
||||
|
||||
* builtins.c (c_strlen): Handle not zero terminated STRING_CSTs
|
||||
correctly.
|
||||
* fold-const.c (c_getstr): Fix function comment. Remove unused third
|
||||
argument. Fix range checks.
|
||||
* fold-const.h (c_getstr): Adjust protoype.
|
||||
* gimple-fold.c (gimple_fold_builtin_memory_op): Avoid folding when
|
||||
string is constant but contains no NUL byte.
|
||||
|
||||
* expr.c (string_constant): Adjust function comment.
|
||||
Remove bogus check for zero termination.
|
||||
|
||||
|
|
|
@ -604,12 +604,12 @@ c_strlen (tree src, int only_value, unsigned eltsize)
|
|||
In that case, the elements of the array after the terminating NUL are
|
||||
all NUL. */
|
||||
HOST_WIDE_INT strelts = TREE_STRING_LENGTH (src);
|
||||
strelts = strelts / eltsize - 1;
|
||||
strelts = strelts / eltsize;
|
||||
|
||||
if (!tree_fits_uhwi_p (memsize))
|
||||
return NULL_TREE;
|
||||
|
||||
HOST_WIDE_INT maxelts = tree_to_uhwi (memsize) / eltsize - 1;
|
||||
HOST_WIDE_INT maxelts = tree_to_uhwi (memsize) / eltsize;
|
||||
|
||||
/* PTR can point to the byte representation of any string type, including
|
||||
char* and wchar_t*. */
|
||||
|
@ -617,10 +617,6 @@ c_strlen (tree src, int only_value, unsigned eltsize)
|
|||
|
||||
if (byteoff && TREE_CODE (byteoff) != INTEGER_CST)
|
||||
{
|
||||
/* For empty strings the result should be zero. */
|
||||
if (maxelts == 0)
|
||||
return ssize_int (0);
|
||||
|
||||
/* The code below works only for single byte character types. */
|
||||
if (eltsize != 1)
|
||||
return NULL_TREE;
|
||||
|
@ -632,9 +628,13 @@ c_strlen (tree src, int only_value, unsigned eltsize)
|
|||
unsigned len = string_length (ptr, eltsize, strelts);
|
||||
|
||||
/* Return when an embedded null character is found or none at all. */
|
||||
if (len < strelts || len > maxelts)
|
||||
if (len + 1 < strelts || len >= maxelts)
|
||||
return NULL_TREE;
|
||||
|
||||
/* For empty strings the result should be zero. */
|
||||
if (len == 0)
|
||||
return ssize_int (0);
|
||||
|
||||
/* We don't know the starting offset, but we do know that the string
|
||||
has no internal zero bytes. If the offset falls within the bounds
|
||||
of the string subtract the offset from the length of the string,
|
||||
|
@ -644,7 +644,7 @@ c_strlen (tree src, int only_value, unsigned eltsize)
|
|||
offsave = fold_convert (ssizetype, offsave);
|
||||
tree condexp = fold_build2_loc (loc, LE_EXPR, boolean_type_node, offsave,
|
||||
build_int_cst (ssizetype, len));
|
||||
tree lenexp = size_diffop_loc (loc, ssize_int (strelts), offsave);
|
||||
tree lenexp = size_diffop_loc (loc, ssize_int (len), offsave);
|
||||
return fold_build3_loc (loc, COND_EXPR, ssizetype, condexp, lenexp,
|
||||
build_zero_cst (ssizetype));
|
||||
}
|
||||
|
@ -663,7 +663,7 @@ c_strlen (tree src, int only_value, unsigned eltsize)
|
|||
|
||||
/* If the offset is known to be out of bounds, warn, and call strlen at
|
||||
runtime. */
|
||||
if (eltoff < 0 || eltoff > maxelts)
|
||||
if (eltoff < 0 || eltoff >= maxelts)
|
||||
{
|
||||
/* Suppress multiple warnings for propagated constant strings. */
|
||||
if (only_value != 2
|
||||
|
@ -691,9 +691,9 @@ c_strlen (tree src, int only_value, unsigned eltsize)
|
|||
unsigned len = string_length (ptr + eltoff * eltsize, eltsize,
|
||||
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. */
|
||||
if (len > maxelts - eltoff)
|
||||
if (len >= maxelts - eltoff)
|
||||
return NULL_TREE;
|
||||
|
||||
return ssize_int (len);
|
||||
|
|
|
@ -14560,23 +14560,20 @@ fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE_INT off)
|
|||
/* Return a pointer P to a NUL-terminated string representing the sequence
|
||||
of constant characters referred to by SRC (or a subsequence of such
|
||||
characters within it if SRC is a reference to a string plus some
|
||||
constant offset). If STRLEN is non-null, store stgrlen(P) in *STRLEN.
|
||||
If STRSIZE is non-null, store in *STRSIZE the size of the array
|
||||
the string is stored in; in that case, even though P points to a NUL
|
||||
terminated string, SRC need not refer to one. This can happen when
|
||||
SRC refers to a constant character array initialized to all non-NUL
|
||||
values, as in the C declaration: char a[4] = "1234"; */
|
||||
constant offset). If STRLEN is non-null, store the number of bytes
|
||||
in the string constant including the terminating NUL char. *STRLEN is
|
||||
typically strlen(P) + 1 in the absence of embedded NUL characters. */
|
||||
|
||||
const char *
|
||||
c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */,
|
||||
unsigned HOST_WIDE_INT *strsize /* = NULL */)
|
||||
c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */)
|
||||
{
|
||||
tree offset_node;
|
||||
tree mem_size;
|
||||
|
||||
if (strlen)
|
||||
*strlen = 0;
|
||||
|
||||
src = string_constant (src, &offset_node, NULL, NULL);
|
||||
src = string_constant (src, &offset_node, &mem_size, NULL);
|
||||
if (src == 0)
|
||||
return NULL;
|
||||
|
||||
|
@ -14589,25 +14586,14 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */,
|
|||
offset = tree_to_uhwi (offset_node);
|
||||
}
|
||||
|
||||
if (!tree_fits_uhwi_p (mem_size))
|
||||
return NULL;
|
||||
|
||||
/* STRING_LENGTH is the size of the string literal, including any
|
||||
embedded NULs. STRING_SIZE is the size of the array the string
|
||||
literal is stored in. */
|
||||
unsigned HOST_WIDE_INT string_length = TREE_STRING_LENGTH (src);
|
||||
unsigned HOST_WIDE_INT string_size = string_length;
|
||||
tree type = TREE_TYPE (src);
|
||||
if (tree size = TYPE_SIZE_UNIT (type))
|
||||
if (tree_fits_shwi_p (size))
|
||||
string_size = tree_to_uhwi (size);
|
||||
|
||||
if (strlen)
|
||||
{
|
||||
/* Compute and store the length of the substring at OFFSET.
|
||||
All offsets past the initial length refer to null strings. */
|
||||
if (offset <= string_length)
|
||||
*strlen = string_length - offset;
|
||||
else
|
||||
*strlen = 0;
|
||||
}
|
||||
unsigned HOST_WIDE_INT string_size = tree_to_uhwi (mem_size);
|
||||
|
||||
const char *string = TREE_STRING_POINTER (src);
|
||||
|
||||
|
@ -14619,21 +14605,26 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */,
|
|||
|| offset >= string_size)
|
||||
return NULL;
|
||||
|
||||
if (strsize)
|
||||
if (strlen)
|
||||
{
|
||||
/* Support even constant character arrays that aren't proper
|
||||
NUL-terminated strings. */
|
||||
*strsize = string_size;
|
||||
/* Compute and store the length of the substring at OFFSET.
|
||||
All offsets past the initial length refer to null strings. */
|
||||
if (offset < string_length)
|
||||
*strlen = string_length - offset;
|
||||
else
|
||||
*strlen = 1;
|
||||
}
|
||||
else if (string[string_length - 1] != '\0')
|
||||
else
|
||||
{
|
||||
/* Support only properly NUL-terminated strings but handle
|
||||
consecutive strings within the same array, such as the six
|
||||
substrings in "1\0002\0003". */
|
||||
return NULL;
|
||||
tree eltype = TREE_TYPE (TREE_TYPE (src));
|
||||
/* Support only properly NUL-terminated single byte strings. */
|
||||
if (tree_to_uhwi (TYPE_SIZE_UNIT (eltype)) != 1)
|
||||
return NULL;
|
||||
if (string[string_length - 1] != '\0')
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return offset <= string_length ? string + offset : "";
|
||||
return offset < string_length ? string + offset : "";
|
||||
}
|
||||
|
||||
/* Given a tree T, compute which bits in T may be nonzero. */
|
||||
|
|
|
@ -187,8 +187,7 @@ extern bool expr_not_equal_to (tree t, const wide_int &);
|
|||
extern tree const_unop (enum tree_code, tree, tree);
|
||||
extern tree const_binop (enum tree_code, tree, tree, tree);
|
||||
extern bool negate_mathfn_p (combined_fn);
|
||||
extern const char *c_getstr (tree, unsigned HOST_WIDE_INT * = NULL,
|
||||
unsigned HOST_WIDE_INT * = NULL);
|
||||
extern const char *c_getstr (tree, unsigned HOST_WIDE_INT * = NULL);
|
||||
extern wide_int tree_nonzero_bits (const_tree);
|
||||
|
||||
/* Return OFF converted to a pointer offset type suitable as offset for
|
||||
|
|
|
@ -725,6 +725,8 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
|
|||
tree srctype, desttype;
|
||||
unsigned int src_align, dest_align;
|
||||
tree off0;
|
||||
const char *tmp_str;
|
||||
unsigned HOST_WIDE_INT tmp_len;
|
||||
|
||||
/* Build accesses at offset zero with a ref-all character type. */
|
||||
off0 = build_int_cst (build_pointer_type_for_mode (char_type_node,
|
||||
|
@ -742,7 +744,9 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
|
|||
confuses the tree-ssa-strlen.c. This doesn't handle
|
||||
the case in gcc.dg/strlenopt-8.c which is XFAILed for that
|
||||
reason. */
|
||||
&& !c_strlen (src, 2))
|
||||
&& !c_strlen (src, 2)
|
||||
&& !((tmp_str = c_getstr (src, &tmp_len)) != NULL
|
||||
&& memchr (tmp_str, 0, tmp_len) == NULL))
|
||||
{
|
||||
unsigned ilen = tree_to_uhwi (len);
|
||||
if (pow2p_hwi (ilen))
|
||||
|
|
Loading…
Add table
Reference in a new issue