From b71bbbe2b22460ff9200613784e631496fcfc054 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Sun, 23 Dec 2018 16:00:45 +0000 Subject: [PATCH] builtins.h (c_strlen_data): Add new fields and comments. * builtins.h (c_strlen_data): Add new fields and comments. * builtins.c (unterminated_array): Change field reference from "len" to "minlen" in c_strlen_data instance. * gimple-fold.c (get_range_strlen): Likewise. * gimple-ssa-sprintf.c (get_string_length): Likewise. Co-Authored-By: Jeff Law From-SVN: r267378 --- gcc/ChangeLog | 6 ++++++ gcc/builtins.c | 8 ++++---- gcc/builtins.h | 40 +++++++++++++++++++++++++++++++++++++++- gcc/gimple-fold.c | 4 ++-- gcc/gimple-ssa-sprintf.c | 6 +++--- 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f1f9d70f25b..cd2a294c583 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,6 +1,12 @@ 2018-12-23 Martin Sebor Jeff Law + * builtins.h (c_strlen_data): Add new fields and comments. + * builtins.c (unterminated_array): Change field reference from + "len" to "minlen" in c_strlen_data instance. + * gimple-fold.c (get_range_strlen): Likewise. + * gimple-ssa-sprintf.c (get_string_length): Likewise. + * builtins.c (unterminated_array): Rename "data" to "lendata". Fix a few comments. (expand_builtin_strnlen, expand_builtin_stpcpy_1): Likewise. diff --git a/gcc/builtins.c b/gcc/builtins.c index 0eb3df9ccc1..b56577e450c 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -577,11 +577,11 @@ unterminated_array (tree exp, tree *size /* = NULL */, bool *exact /* = NULL */) structure if EXP references a unterminated array. */ c_strlen_data lendata = { }; tree len = c_strlen (exp, 1, &lendata); - if (len == NULL_TREE && lendata.len && lendata.decl) + if (len == NULL_TREE && lendata.minlen && lendata.decl) { if (size) { - len = lendata.len; + len = lendata.minlen; if (lendata.off) { /* Constant offsets are already accounted for in LENDATA.MINLEN, @@ -720,7 +720,7 @@ c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize) { data->decl = decl; data->off = byteoff; - data->len = ssize_int (len); + data->minlen = ssize_int (len); return NULL_TREE; } @@ -794,7 +794,7 @@ c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize) { data->decl = decl; data->off = byteoff; - data->len = ssize_int (len); + data->minlen = ssize_int (len); return NULL_TREE; } diff --git a/gcc/builtins.h b/gcc/builtins.h index cf4f9b1b264..472a86d9ad0 100644 --- a/gcc/builtins.h +++ b/gcc/builtins.h @@ -57,10 +57,48 @@ 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); + struct c_strlen_data { + /* [MINLEN, MAXBOUND, MAXLEN] is a range describing the length of + one or more strings of possibly unknown length. For a single + string of known length the range is a constant where + MINLEN == MAXBOUND == MAXLEN holds. + For other strings, MINLEN is the length of the shortest known + string. MAXBOUND is the length of a string that could be stored + in the largest array referenced by the expression. MAXLEN is + the length of the longest sequence of non-zero bytes + in an object referenced by the expression. For such strings, + MINLEN <= MAXBOUND <= MAXLEN holds. For example, given: + struct A { char a[7], b[]; }; + extern struct A *p; + n = strlen (p->a); + the computed range will be [0, 6, ALL_ONES]. + However, for a conditional expression involving a string + of known length and an array of unknown bound such as + n = strlen (i ? p->b : "123"); + the range will be [3, 3, ALL_ONES]. + MINLEN != 0 && MAXLEN == ALL_ONES indicates that MINLEN is + the length of the shortest known string and implies that + the shortest possible string referenced by the expression may + actually be the empty string. This distinction is useful for + diagnostics. get_range_strlen() return value distinguishes + between these two cases. + As the tighter (and more optimistic) bound, MAXBOUND is suitable + for diagnostics but not for optimization. + As the more conservative bound, MAXLEN is intended to be used + for optimization. */ + tree minlen; + tree maxlen; + tree maxbound; + /* When non-null, NONSTR refers to the declaration known to store + an unterminated constant character array, as in: + const char s[] = { 'a', 'b', 'c' }; + It is used to diagnose uses of such arrays in functions such as + strlen() that expect a nul-terminated string as an argument. */ tree decl; - tree len; + /* Non-constant offset from the beginning of a string not accounted + for in the length range. Used to improve diagnostics. */ tree off; }; diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 0ba15149890..b1dd4416567 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -1343,8 +1343,8 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, if (!val && lendata.decl) { *nonstr = lendata.decl; - *minlen = lendata.len; - *maxlen = lendata.len; + *minlen = lendata.minlen; + *maxlen = lendata.minlen; return type == 0 ? false : true; } } diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index d6278305fc4..8284c76b0f7 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -2015,12 +2015,12 @@ get_string_length (tree str, unsigned eltsize) } else if (!slen && data.decl - && data.len - && TREE_CODE (data.len) == INTEGER_CST) + && data.minlen + && TREE_CODE (data.minlen) == INTEGER_CST) { /* STR was not properly NUL terminated, but we have length information about the unterminated string. */ - fmtresult res (tree_to_shwi (data.len)); + fmtresult res (tree_to_shwi (data.minlen)); res.nonstr = data.decl; return res; } -- 2.30.2