diff options
author | Martin Sebor <msebor@redhat.com> | 2016-09-21 01:39:27 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2016-09-20 19:39:27 -0600 |
commit | 88d0c3f0a1448e71dcf49c2f34909ec8d7ce348f (patch) | |
tree | 31a2a49deedcccbfcfdac5857b76449a9235f4a1 /gcc/gimple-fold.c | |
parent | 6283a8db1fdcd3d505fabe0dca27e8fdf10c2ac7 (diff) | |
download | gcc-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.c | 123 |
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]; } |