From 7d583f4259a56c9054c28e883c375f9c57f8755d Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Sat, 29 Sep 2018 10:06:09 -0600 Subject: [PATCH] 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 --- gcc/ChangeLog | 18 +++++++++++- gcc/builtins.c | 70 +++++++++++++++++++++++++++++------------------ gcc/builtins.h | 9 +++++- gcc/gimple-fold.c | 31 ++++++++++++++++----- 4 files changed, 92 insertions(+), 36 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 859984cf7cb..29f52fd39d3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2018-09-29 Jeff Law + + * 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 PR target/87467 @@ -302,8 +318,8 @@ * config/i386/i386.h (NUM_MODES_FOR_MODE_SWITCHING): Update for removed I387_MASK_PM entity. -2018-09-26 Jeff Law +2018-09-26 Jeff Law Revert 2018-09-26 Alexey Neyman diff --git a/gcc/builtins.c b/gcc/builtins.c index e655623febd..fe411efd9a9 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -570,9 +570,10 @@ warn_string_no_nul (location_t loc, const char *fn, tree arg, tree decl) tree unterminated_array (tree exp) { - tree nonstr = NULL; - c_strlen (exp, 1, &nonstr); - return nonstr; + c_strlen_data data; + memset (&data, 0, sizeof (c_strlen_data)); + c_strlen (exp, 1, &data); + return data.decl; } /* Compute the length of a null-terminated character string or wide @@ -592,10 +593,12 @@ unterminated_array (tree exp) accesses. Note that this implies the result is not going to be emitted into the instruction stream. - If a not zero-terminated string value is encountered and NONSTR is - non-zero, the declaration of the string value is assigned to *NONSTR. - *NONSTR is accumulating, thus not cleared on success, therefore it has - to be initialized to NULL_TREE by the caller. + Additional information about the string accessed may be recorded + in DATA. For example, if SRC references an unterminated string, + then the declaration will be stored in the DECL field. If the + 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 4 for wide characer strings. ELTSIZE is by default 1. @@ -603,8 +606,16 @@ unterminated_array (tree exp) The value returned is of type `ssizetype'. */ 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); STRIP_NOPS (src); if (TREE_CODE (src) == COND_EXPR @@ -612,15 +623,15 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize) { tree len1, len2; - len1 = c_strlen (TREE_OPERAND (src, 1), only_value, nonstr, eltsize); - len2 = c_strlen (TREE_OPERAND (src, 2), only_value, nonstr, eltsize); + len1 = c_strlen (TREE_OPERAND (src, 1), only_value, data, eltsize); + len2 = c_strlen (TREE_OPERAND (src, 2), only_value, data, eltsize); if (tree_int_cst_equal (len1, len2)) return len1; } if (TREE_CODE (src) == COMPOUND_EXPR && (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); @@ -666,13 +677,15 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize) start searching for it. */ 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) return NULL_TREE; else if (len >= maxelts) { - if (nonstr && decl) - *nonstr = decl; + data->decl = decl; + data->len = ssize_int (len); return NULL_TREE; } @@ -737,11 +750,12 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize) strelts - eltoff); /* 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 (nonstr && decl) - *nonstr = decl; + data->decl = decl; + data->len = ssize_int (len); return NULL_TREE; } @@ -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 because the latter will potentially produce pessimized code 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) - || !(len = c_strlen (src, 0, &nonstr, 1))) + || !(len = c_strlen (src, 0, &data, 1))) return expand_movstr (dst, src, target, /*endp=*/2); - if (nonstr && !TREE_NO_WARNING (exp)) - warn_string_no_nul (EXPR_LOCATION (exp), "stpcpy", src, nonstr); + if (data.decl && !TREE_NO_WARNING (exp)) + warn_string_no_nul (EXPR_LOCATION (exp), "stpcpy", src, data.decl); lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1)); ret = expand_builtin_mempcpy_args (dst, src, lenp1, @@ -8444,22 +8459,23 @@ fold_builtin_strlen (location_t loc, tree type, tree arg) return NULL_TREE; else { - tree nonstr = NULL_TREE; - tree len = c_strlen (arg, 0, &nonstr); + c_strlen_data data; + memset (&data, 0, sizeof (c_strlen_data)); + tree len = c_strlen (arg, 0, &data); if (len) return fold_convert_loc (loc, type, len); - if (!nonstr) - c_strlen (arg, 1, &nonstr); + if (!data.decl) + c_strlen (arg, 1, &data); - if (nonstr) + if (data.decl) { if (EXPR_HAS_LOCATION (arg)) loc = EXPR_LOCATION (arg); else if (loc == UNKNOWN_LOCATION) loc = input_location; - warn_string_no_nul (loc, "strlen", arg, nonstr); + warn_string_no_nul (loc, "strlen", arg, data.decl); } return NULL_TREE; diff --git a/gcc/builtins.h b/gcc/builtins.h index 45ad684cb52..3801251f372 100644 --- a/gcc/builtins.h +++ b/gcc/builtins.h @@ -57,7 +57,14 @@ extern bool get_pointer_alignment_1 (tree, unsigned int *, unsigned HOST_WIDE_INT *); extern unsigned int get_pointer_alignment (tree); 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_receiver (rtx); extern void expand_builtin_update_setjmp_buf (rtx); diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 1e84722d22d..cf04c92180b 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -1337,7 +1337,23 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, return false; } 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) { @@ -2812,21 +2828,22 @@ gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi) } /* Set to non-null if ARG refers to an unterminated array. */ - tree nonstr = NULL; - tree len = c_strlen (src, 1, &nonstr, 1); + c_strlen_data data; + memset (&data, 0, sizeof (c_strlen_data)); + tree len = c_strlen (src, 1, &data, 1); if (!len || TREE_CODE (len) != INTEGER_CST) { - nonstr = unterminated_array (src); - if (!nonstr) + data.decl = unterminated_array (src); + if (!data.decl) return false; } - if (nonstr) + if (data.decl) { /* Avoid folding calls with unterminated arrays. */ 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); return false; } -- 2.30.2