aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2016-09-21 01:39:27 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2016-09-20 19:39:27 -0600
commit88d0c3f0a1448e71dcf49c2f34909ec8d7ce348f (patch)
tree31a2a49deedcccbfcfdac5857b76449a9235f4a1 /gcc/gimple-fold.c
parent6283a8db1fdcd3d505fabe0dca27e8fdf10c2ac7 (diff)
downloadgcc-88d0c3f0a1448e71dcf49c2f34909ec8d7ce348f.zip
gcc-88d0c3f0a1448e71dcf49c2f34909ec8d7ce348f.tar.gz
gcc-88d0c3f0a1448e71dcf49c2f34909ec8d7ce348f.tar.bz2
PR middle-end/49905 - Better sanity checking on sprintf src & dest to
gcc/ChangeLog: PR middle-end/49905 * Makefile.in (OBJS): Add gimple-ssa-sprintf.o. * config/linux.h (TARGET_PRINTF_POINTER_FORMAT): Redefine. * config/linux.c (gnu_libc_printf_pointer_format): New function. * config/sol2.h (TARGET_PRINTF_POINTER_FORMAT): Same. * config/sol2.c (solaris_printf_pointer_format): New function. * doc/invoke.texi (-Wformat-length, -fprintf-return-value): New options. * doc/tm.texi.in (TARGET_PRINTF_POINTER_FORMAT): Document. * doc/tm.texi: Regenerate. * gimple-fold.h (get_range_strlen): New function. (get_maxval_strlen): Declare existing function. * gimple-fold.c (get_range_strlen): Add arguments and compute both maximum and minimum. (get_range_strlen): Define overload. (get_maxval_strlen): Adjust. * gimple-ssa-sprintf.c: New file and pass. * passes.def (pass_sprintf_length): Add new pass. * targhooks.h (default_printf_pointer_format): Declare new function. (gnu_libc_printf_pointer_format): Same. (solaris_libc_printf_pointer_format): Same. * targhooks.c (default_printf_pointer_format): Define new function. * tree-pass.h (make_pass_sprintf_length): Declare new function. * print-tree.c: Increase buffer size. gcc/c-family/ChangeLog: PR middle-end/49905 * c.opt: Add -Wformat-length and -fprintf-return-value. gcc/testsuite/ChangeLog: PR middle-end/49905 * gcc.dg/builtin-stringop-chk-1.c: Adjust. * gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: New test. * gcc.dg/tree-ssa/builtin-sprintf-warn-2.c: New test. * gcc.dg/tree-ssa/builtin-sprintf-warn-3.c: New test. * gcc.dg/tree-ssa/builtin-sprintf-warn-4.c: New test. * gcc.dg/tree-ssa/builtin-sprintf.c: New test. * gcc.dg/tree-ssa/builtin-sprintf-2.c: New test. From-SVN: r240298
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c123
1 files changed, 97 insertions, 26 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 2e0bd80..addabb7 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1159,21 +1159,30 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len)
}
-/* Return the string length, maximum string length or maximum value of
- ARG in LENGTH.
- If ARG is an SSA name variable, follow its use-def chains. If LENGTH
- is not NULL and, for TYPE == 0, its value is not equal to the length
- we determine or if we are unable to determine the length or value,
- return false. VISITED is a bitmap of visited variables.
- TYPE is 0 if string length should be returned, 1 for maximum string
- length and 2 for maximum value ARG can have. */
+/* Obtain the minimum and maximum string length or minimum and maximum
+ value of ARG in LENGTH[0] and LENGTH[1], respectively.
+ If ARG is an SSA name variable, follow its use-def chains. When
+ TYPE == 0, if LENGTH[1] is not equal to the length we determine or
+ if we are unable to determine the length or value, return False.
+ VISITED is a bitmap of visited variables.
+ TYPE is 0 if string length should be obtained, 1 for maximum string
+ length and 2 for maximum value ARG can have.
+ When FUZZY is set and the length of a string cannot be determined,
+ the function instead considers as the maximum possible length the
+ size of a character array it may refer to. */
static bool
-get_maxval_strlen (tree arg, tree *length, bitmap *visited, int type)
+get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
+ bool fuzzy)
{
tree var, val;
gimple *def_stmt;
+ /* The minimum and maximum length. The MAXLEN pointer stays unchanged
+ but MINLEN may be cleared during the execution of the function. */
+ tree *minlen = length;
+ tree *const maxlen = length + 1;
+
if (TREE_CODE (arg) != SSA_NAME)
{
/* We can end up with &(*iftmp_1)[0] here as well, so handle it. */
@@ -1184,8 +1193,8 @@ get_maxval_strlen (tree arg, tree *length, bitmap *visited, int type)
tree aop0 = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
if (TREE_CODE (aop0) == INDIRECT_REF
&& TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME)
- return get_maxval_strlen (TREE_OPERAND (aop0, 0),
- length, visited, type);
+ return get_range_strlen (TREE_OPERAND (aop0, 0),
+ length, visited, type, fuzzy);
}
if (type == 2)
@@ -1197,26 +1206,60 @@ get_maxval_strlen (tree arg, tree *length, bitmap *visited, int type)
}
else
val = c_strlen (arg, 1);
+
+ if (!val && fuzzy)
+ {
+ if (TREE_CODE (arg) == ADDR_EXPR)
+ return get_range_strlen (TREE_OPERAND (arg, 0), length,
+ visited, type, fuzzy);
+
+ if (TREE_CODE (arg) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1))) == ARRAY_TYPE)
+ {
+ /* Use the type of the member array to determine the upper
+ bound on the length of the array. This may be overly
+ optimistic if the array itself isn't NUL-terminated and
+ the caller relies on the subsequent member to contain
+ the NUL. */
+ arg = TREE_OPERAND (arg, 1);
+ val = TYPE_SIZE_UNIT (TREE_TYPE (arg));
+ if (!val || integer_zerop (val))
+ return false;
+ val = fold_build2 (MINUS_EXPR, TREE_TYPE (val), val,
+ integer_one_node);
+ /* Avoid using the array size as the minimum. */
+ minlen = NULL;
+ }
+ }
+
if (!val)
return false;
- if (*length)
+ if (minlen
+ && (!*minlen
+ || (type > 0
+ && TREE_CODE (*minlen) == INTEGER_CST
+ && TREE_CODE (val) == INTEGER_CST
+ && tree_int_cst_lt (val, *minlen))))
+ *minlen = val;
+
+ if (*maxlen)
{
if (type > 0)
{
- if (TREE_CODE (*length) != INTEGER_CST
+ if (TREE_CODE (*maxlen) != INTEGER_CST
|| TREE_CODE (val) != INTEGER_CST)
return false;
- if (tree_int_cst_lt (*length, val))
- *length = val;
+ if (tree_int_cst_lt (*maxlen, val))
+ *maxlen = val;
return true;
}
- else if (simple_cst_equal (val, *length) != 1)
+ else if (simple_cst_equal (val, *maxlen) != 1)
return false;
}
- *length = val;
+ *maxlen = val;
return true;
}
@@ -1244,14 +1287,14 @@ get_maxval_strlen (tree arg, tree *length, bitmap *visited, int type)
|| gimple_assign_unary_nop_p (def_stmt))
{
tree rhs = gimple_assign_rhs1 (def_stmt);
- return get_maxval_strlen (rhs, length, visited, type);
+ return get_range_strlen (rhs, length, visited, type, fuzzy);
}
else if (gimple_assign_rhs_code (def_stmt) == COND_EXPR)
{
tree op2 = gimple_assign_rhs2 (def_stmt);
tree op3 = gimple_assign_rhs3 (def_stmt);
- return get_maxval_strlen (op2, length, visited, type)
- && get_maxval_strlen (op3, length, visited, type);
+ return get_range_strlen (op2, length, visited, type, fuzzy)
+ && get_range_strlen (op3, length, visited, type, fuzzy);
}
return false;
@@ -1274,8 +1317,13 @@ get_maxval_strlen (tree arg, tree *length, bitmap *visited, int type)
if (arg == gimple_phi_result (def_stmt))
continue;
- if (!get_maxval_strlen (arg, length, visited, type))
- return false;
+ if (!get_range_strlen (arg, length, visited, type, fuzzy))
+ {
+ if (fuzzy)
+ *maxlen = build_all_ones_cst (size_type_node);
+ else
+ return false;
+ }
}
}
return true;
@@ -1285,17 +1333,40 @@ get_maxval_strlen (tree arg, tree *length, bitmap *visited, int type)
}
}
+/* Determine the minimum and maximum value or string length that ARG
+ refers to and store each in the first two elements of MINMAXLEN.
+ For expressions that point to strings of unknown lengths that are
+ character arrays, use the upper bound of the array as the maximum
+ length. For example, given an expression like 'x ? array : "xyz"'
+ and array declared as 'char array[8]', MINMAXLEN[0] will be set
+ to 3 and MINMAXLEN[1] to 7, the longest string that could be
+ stored in array.
+*/
+
+void get_range_strlen (tree arg, tree minmaxlen[2])
+{
+ bitmap visited = NULL;
+
+ minmaxlen[0] = NULL_TREE;
+ minmaxlen[1] = NULL_TREE;
+
+ get_range_strlen (arg, minmaxlen, &visited, 1, true);
+
+ if (visited)
+ BITMAP_FREE (visited);
+}
+
tree
get_maxval_strlen (tree arg, int type)
{
bitmap visited = NULL;
- tree len = NULL_TREE;
- if (!get_maxval_strlen (arg, &len, &visited, type))
- len = NULL_TREE;
+ tree len[2] = { NULL_TREE, NULL_TREE };
+ if (!get_range_strlen (arg, len, &visited, type, false))
+ len[1] = NULL_TREE;
if (visited)
BITMAP_FREE (visited);
- return len;
+ return len[1];
}