Commit d01b568a by Bernd Edlinger Committed by Jeff Law

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
parent 9a9f692b
2018-09-13 Bernd Edlinger <bernd.edlinger@hotmail.de> 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. * expr.c (string_constant): Adjust function comment.
Remove bogus check for zero termination. Remove bogus check for zero termination.
......
...@@ -604,12 +604,12 @@ c_strlen (tree src, int only_value, unsigned eltsize) ...@@ -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 In that case, the elements of the array after the terminating NUL are
all NUL. */ all NUL. */
HOST_WIDE_INT strelts = TREE_STRING_LENGTH (src); HOST_WIDE_INT strelts = TREE_STRING_LENGTH (src);
strelts = strelts / eltsize - 1; strelts = strelts / eltsize;
if (!tree_fits_uhwi_p (memsize)) if (!tree_fits_uhwi_p (memsize))
return NULL_TREE; 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 /* PTR can point to the byte representation of any string type, including
char* and wchar_t*. */ char* and wchar_t*. */
...@@ -617,10 +617,6 @@ c_strlen (tree src, int only_value, unsigned eltsize) ...@@ -617,10 +617,6 @@ c_strlen (tree src, int only_value, unsigned eltsize)
if (byteoff && TREE_CODE (byteoff) != INTEGER_CST) 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. */ /* The code below works only for single byte character types. */
if (eltsize != 1) if (eltsize != 1)
return NULL_TREE; return NULL_TREE;
...@@ -632,9 +628,13 @@ c_strlen (tree src, int only_value, unsigned eltsize) ...@@ -632,9 +628,13 @@ c_strlen (tree src, int only_value, unsigned eltsize)
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. */
if (len < strelts || len > maxelts) if (len + 1 < strelts || len >= maxelts)
return NULL_TREE; 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 /* 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 has no internal zero bytes. If the offset falls within the bounds
of the string subtract the offset from the length of the string, 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) ...@@ -644,7 +644,7 @@ c_strlen (tree src, int only_value, unsigned eltsize)
offsave = fold_convert (ssizetype, offsave); offsave = fold_convert (ssizetype, offsave);
tree condexp = fold_build2_loc (loc, LE_EXPR, boolean_type_node, offsave, tree condexp = fold_build2_loc (loc, LE_EXPR, boolean_type_node, offsave,
build_int_cst (ssizetype, len)); 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, return fold_build3_loc (loc, COND_EXPR, ssizetype, condexp, lenexp,
build_zero_cst (ssizetype)); build_zero_cst (ssizetype));
} }
...@@ -663,7 +663,7 @@ c_strlen (tree src, int only_value, unsigned eltsize) ...@@ -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 /* If the offset is known to be out of bounds, warn, and call strlen at
runtime. */ runtime. */
if (eltoff < 0 || eltoff > maxelts) if (eltoff < 0 || eltoff >= maxelts)
{ {
/* Suppress multiple warnings for propagated constant strings. */ /* Suppress multiple warnings for propagated constant strings. */
if (only_value != 2 if (only_value != 2
...@@ -691,9 +691,9 @@ c_strlen (tree src, int only_value, unsigned eltsize) ...@@ -691,9 +691,9 @@ c_strlen (tree src, int only_value, unsigned eltsize)
unsigned len = string_length (ptr + eltoff * eltsize, eltsize, unsigned len = string_length (ptr + eltoff * eltsize, 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. */
if (len > maxelts - eltoff) if (len >= maxelts - eltoff)
return NULL_TREE; return NULL_TREE;
return ssize_int (len); return ssize_int (len);
......
...@@ -14560,23 +14560,20 @@ fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE_INT off) ...@@ -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 /* Return a pointer P to a NUL-terminated string representing the sequence
of constant characters referred to by SRC (or a subsequence of such 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 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. constant offset). If STRLEN is non-null, store the number of bytes
If STRSIZE is non-null, store in *STRSIZE the size of the array in the string constant including the terminating NUL char. *STRLEN is
the string is stored in; in that case, even though P points to a NUL typically strlen(P) + 1 in the absence of embedded NUL characters. */
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"; */
const char * const char *
c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */, c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */)
unsigned HOST_WIDE_INT *strsize /* = NULL */)
{ {
tree offset_node; tree offset_node;
tree mem_size;
if (strlen) if (strlen)
*strlen = 0; *strlen = 0;
src = string_constant (src, &offset_node, NULL, NULL); src = string_constant (src, &offset_node, &mem_size, NULL);
if (src == 0) if (src == 0)
return NULL; return NULL;
...@@ -14589,25 +14586,14 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */, ...@@ -14589,25 +14586,14 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */,
offset = tree_to_uhwi (offset_node); 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 /* STRING_LENGTH is the size of the string literal, including any
embedded NULs. STRING_SIZE is the size of the array the string embedded NULs. STRING_SIZE is the size of the array the string
literal is stored in. */ literal is stored in. */
unsigned HOST_WIDE_INT string_length = TREE_STRING_LENGTH (src); unsigned HOST_WIDE_INT string_length = TREE_STRING_LENGTH (src);
unsigned HOST_WIDE_INT string_size = string_length; unsigned HOST_WIDE_INT string_size = tree_to_uhwi (mem_size);
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;
}
const char *string = TREE_STRING_POINTER (src); const char *string = TREE_STRING_POINTER (src);
...@@ -14619,21 +14605,26 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */, ...@@ -14619,21 +14605,26 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */,
|| offset >= string_size) || offset >= string_size)
return NULL; return NULL;
if (strsize) if (strlen)
{ {
/* Support even constant character arrays that aren't proper /* Compute and store the length of the substring at OFFSET.
NUL-terminated strings. */ All offsets past the initial length refer to null strings. */
*strsize = string_size; 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 tree eltype = TREE_TYPE (TREE_TYPE (src));
consecutive strings within the same array, such as the six /* Support only properly NUL-terminated single byte strings. */
substrings in "1\0002\0003". */ if (tree_to_uhwi (TYPE_SIZE_UNIT (eltype)) != 1)
return NULL; 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. */ /* 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 &); ...@@ -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_unop (enum tree_code, tree, tree);
extern tree const_binop (enum tree_code, tree, tree, tree); extern tree const_binop (enum tree_code, tree, tree, tree);
extern bool negate_mathfn_p (combined_fn); extern bool negate_mathfn_p (combined_fn);
extern const char *c_getstr (tree, unsigned HOST_WIDE_INT * = NULL, extern const char *c_getstr (tree, unsigned HOST_WIDE_INT * = NULL);
unsigned HOST_WIDE_INT * = NULL);
extern wide_int tree_nonzero_bits (const_tree); extern wide_int tree_nonzero_bits (const_tree);
/* Return OFF converted to a pointer offset type suitable as offset for /* 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, ...@@ -725,6 +725,8 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
tree srctype, desttype; tree srctype, desttype;
unsigned int src_align, dest_align; unsigned int src_align, dest_align;
tree off0; tree off0;
const char *tmp_str;
unsigned HOST_WIDE_INT tmp_len;
/* Build accesses at offset zero with a ref-all character type. */ /* Build accesses at offset zero with a ref-all character type. */
off0 = build_int_cst (build_pointer_type_for_mode (char_type_node, 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, ...@@ -742,7 +744,9 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
confuses the tree-ssa-strlen.c. This doesn't handle confuses the tree-ssa-strlen.c. This doesn't handle
the case in gcc.dg/strlenopt-8.c which is XFAILed for that the case in gcc.dg/strlenopt-8.c which is XFAILed for that
reason. */ 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); unsigned ilen = tree_to_uhwi (len);
if (pow2p_hwi (ilen)) if (pow2p_hwi (ilen))
......
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