summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/asan.c3
-rw-r--r--gcc/c-family/ChangeLog6
-rw-r--r--gcc/c-family/c-ubsan.c23
-rw-r--r--gcc/c-family/c-ubsan.h1
-rw-r--r--gcc/c/ChangeLog4
-rw-r--r--gcc/c/c-decl.c11
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/decl.c55
-rw-r--r--gcc/flag-types.h2
-rw-r--r--gcc/opts.c1
-rw-r--r--gcc/sanitizer.def4
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/vla-1.c48
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/vla-2.c15
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/vla-3.c16
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/vla-4.c13
-rw-r--r--gcc/testsuite/g++.dg/ubsan/cxx1y-vla.C13
18 files changed, 211 insertions, 28 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cf54bafa43f..cc163f1cb83 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2013-11-03 Marek Polacek <polacek@redhat.com>
+
+ Implement -fsanitize=vla-bound.
+ * opts.c (common_handle_option): Handle vla-bound.
+ * sanitizer.def (BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE):
+ Define.
+ * flag-types.h (enum sanitize_code): Add SANITIZE_VLA.
+ * asan.c (initialize_sanitizer_builtins): Build BT_FN_VOID_PTR_PTR.
+
2013-11-02 Bill Schmidt <wschmidt@vnet.linux.ibm.com>
* config/rs6000/rs6000.c (rs6000_expand_vector_set): Adjust for
diff --git a/gcc/asan.c b/gcc/asan.c
index 81397198f60..763c59aaed4 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -2021,6 +2021,9 @@ initialize_sanitizer_builtins (void)
tree BT_FN_VOID = build_function_type_list (void_type_node, NULL_TREE);
tree BT_FN_VOID_PTR
= build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
+ tree BT_FN_VOID_PTR_PTR
+ = build_function_type_list (void_type_node, ptr_type_node,
+ ptr_type_node, NULL_TREE);
tree BT_FN_VOID_PTR_PTR_PTR
= build_function_type_list (void_type_node, ptr_type_node,
ptr_type_node, ptr_type_node, NULL_TREE);
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 13a66871c3a..569f4c203d7 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2013-11-03 Marek Polacek <polacek@redhat.com>
+
+ * c-ubsan.c: Don't include hash-table.h.
+ (ubsan_instrument_vla): New function.
+ * c-ubsan.h: Declare it.
+
2013-10-31 David Malcolm <dmalcolm@redhat.com>
Automated part of renaming of symtab_node_base to symtab_node.
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index 0bfc660cdd5..c9896381db2 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -25,7 +25,6 @@ along with GCC; see the file COPYING3. If not see
#include "alloc-pool.h"
#include "cgraph.h"
#include "gimple.h"
-#include "hash-table.h"
#include "output.h"
#include "toplev.h"
#include "ubsan.h"
@@ -86,8 +85,7 @@ ubsan_instrument_division (location_t loc, tree op0, tree op1)
return t;
}
-/* Instrument left and right shifts. If not instrumenting, return
- NULL_TREE. */
+/* Instrument left and right shifts. */
tree
ubsan_instrument_shift (location_t loc, enum tree_code code,
@@ -158,3 +156,22 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
return t;
}
+
+/* Instrument variable length array bound. */
+
+tree
+ubsan_instrument_vla (location_t loc, tree size)
+{
+ tree type = TREE_TYPE (size);
+ tree t, tt;
+
+ t = fold_build2 (LE_EXPR, boolean_type_node, size, build_int_cst (type, 0));
+ tree data = ubsan_create_data ("__ubsan_vla_data",
+ loc, ubsan_type_descriptor (type), NULL_TREE);
+ data = build_fold_addr_expr_loc (loc, data);
+ tt = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE);
+ tt = build_call_expr_loc (loc, tt, 2, data, ubsan_encode_value (size));
+ t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_zero_node);
+
+ return t;
+}
diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h
index b032b707cc3..fdf27d9e21e 100644
--- a/gcc/c-family/c-ubsan.h
+++ b/gcc/c-family/c-ubsan.h
@@ -23,5 +23,6 @@ along with GCC; see the file COPYING3. If not see
extern tree ubsan_instrument_division (location_t, tree, tree);
extern tree ubsan_instrument_shift (location_t, enum tree_code, tree, tree);
+extern tree ubsan_instrument_vla (location_t, tree);
#endif /* GCC_C_UBSAN_H */
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index f009ee9af1e..efb4ba88c38 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,7 @@
+2013-11-03 Marek Polacek <polacek@redhat.com>
+
+ * c-decl.c (grokdeclarator): Add VLA instrumentation.
+
2013-11-01 Jakub Jelinek <jakub@redhat.com>
* c-typeck.c (c_finish_omp_clauses) <case OMP_CLAUSE_UNIFORM>: Go to
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 64718c55294..2833fdba486 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see
#include "c-family/c-common.h"
#include "c-family/c-objc.h"
#include "c-family/c-pragma.h"
+#include "c-family/c-ubsan.h"
#include "c-lang.h"
#include "langhooks.h"
#include "tree-iterator.h"
@@ -5411,6 +5412,16 @@ grokdeclarator (const struct c_declarator *declarator,
with known value. */
this_size_varies = size_varies = true;
warn_variable_length_array (name, size);
+ if (flag_sanitize & SANITIZE_VLA
+ && decl_context == NORMAL)
+ {
+ /* Evaluate the array size only once. */
+ size = c_save_expr (size);
+ size = c_fully_fold (size, false, NULL);
+ size = fold_build2 (COMPOUND_EXPR, TREE_TYPE (size),
+ ubsan_instrument_vla (loc, size),
+ size);
+ }
}
if (integer_zerop (size) && !this_size_varies)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 694aaae6de3..cadf6749e6c 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,10 @@
+2013-11-03 Marek Polacek <polacek@redhat.com>
+
+ * decl.c (cp_finish_decl): Move C++1y bounds checking...
+ (compute_array_index_type): ...here. Add VLA instrumentation.
+ Call stabilize_vla_size.
+ (grokdeclarator): Don't call stabilize_vla_size here.
+
2013-11-02 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/29234
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 09c1daaa243..e662764da85 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see
#include "c-family/c-objc.h"
#include "c-family/c-pragma.h"
#include "c-family/c-target.h"
+#include "c-family/c-ubsan.h"
#include "diagnostic.h"
#include "intl.h"
#include "debug.h"
@@ -6399,17 +6400,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
&& TYPE_FOR_JAVA (type) && MAYBE_CLASS_TYPE_P (type))
error ("non-static data member %qD has Java class type", decl);
- if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (type))
- {
- /* If the VLA bound is larger than half the address space, or less
- than zero, throw std::bad_array_length. */
- tree max = convert (ssizetype, TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
- tree comp = build2 (LT_EXPR, boolean_type_node, max, ssize_int (-1));
- comp = build3 (COND_EXPR, void_type_node, comp,
- throw_bad_array_length (), void_zero_node);
- finish_expr_stmt (comp);
- }
-
/* Add this declaration to the statement-tree. This needs to happen
after the call to check_initializer so that the DECL_EXPR for a
reference temp is added before the DECL_EXPR for the reference itself. */
@@ -8379,6 +8369,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
{
/* A variable sized array. */
itype = variable_size (itype);
+
if (TREE_CODE (itype) != SAVE_EXPR)
{
/* Look for SIZEOF_EXPRs in itype and fold them, otherwise
@@ -8390,6 +8381,32 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
if (found)
itype = variable_size (fold (newitype));
}
+
+ stabilize_vla_size (itype);
+
+ if (cxx_dialect >= cxx1y)
+ {
+ /* If the VLA bound is larger than half the address space,
+ or less than zero, throw std::bad_array_length. */
+ tree comp = build2 (LT_EXPR, boolean_type_node, itype,
+ ssize_int (-1));
+ comp = build3 (COND_EXPR, void_type_node, comp,
+ throw_bad_array_length (), void_zero_node);
+ finish_expr_stmt (comp);
+ }
+ else if (flag_sanitize & SANITIZE_VLA)
+ {
+ /* From C++1y onwards, we throw an exception on a negative
+ length size of an array; see above. */
+
+ /* We have to add 1 -- in the ubsan routine we generate
+ LE_EXPR rather than LT_EXPR. */
+ tree t = fold_build2 (PLUS_EXPR, TREE_TYPE (itype), itype,
+ build_one_cst (TREE_TYPE (itype)));
+ t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t),
+ ubsan_instrument_vla (input_location, t), t);
+ finish_expr_stmt (t);
+ }
}
/* Make sure that there was no overflow when creating to a signed
index type. (For example, on a 32-bit machine, an array with
@@ -9790,12 +9807,8 @@ grokdeclarator (const cp_declarator *declarator,
&& (decl_context == NORMAL || decl_context == FIELD)
&& at_function_scope_p ()
&& variably_modified_type_p (type, NULL_TREE))
- {
- /* First break out any side-effects. */
- stabilize_vla_size (TYPE_SIZE (type));
- /* And then force evaluation of the SAVE_EXPR. */
- finish_expr_stmt (TYPE_SIZE (type));
- }
+ /* Force evaluation of the SAVE_EXPR. */
+ finish_expr_stmt (TYPE_SIZE (type));
if (declarator->kind == cdk_reference)
{
@@ -9886,14 +9899,6 @@ grokdeclarator (const cp_declarator *declarator,
}
}
- /* We need to stabilize side-effects in VLA sizes for regular array
- declarations too, not just pointers to arrays. */
- if (type != error_mark_node && !TYPE_NAME (type)
- && (decl_context == NORMAL || decl_context == FIELD)
- && at_function_scope_p ()
- && variably_modified_type_p (type, NULL_TREE))
- stabilize_vla_size (TYPE_SIZE (type));
-
/* A `constexpr' specifier used in an object declaration declares
the object as `const'. */
if (constexpr_p && innermost_code != cdk_function)
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index a2be8bb1ad2..7d0ac3582e4 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -210,7 +210,9 @@ enum sanitize_code {
SANITIZE_SHIFT = 1 << 2,
SANITIZE_DIVIDE = 1 << 3,
SANITIZE_UNREACHABLE = 1 << 4,
+ SANITIZE_VLA = 1 << 5,
SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
+ | SANITIZE_VLA
};
/* flag_vtable_verify initialization levels. */
diff --git a/gcc/opts.c b/gcc/opts.c
index 1d02b1020d5..4db20f038d9 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1444,6 +1444,7 @@ common_handle_option (struct gcc_options *opts,
{ "undefined", SANITIZE_UNDEFINED, sizeof "undefined" - 1 },
{ "unreachable", SANITIZE_UNREACHABLE,
sizeof "unreachable" - 1 },
+ { "vla-bound", SANITIZE_VLA, sizeof "vla-bound" - 1 },
{ NULL, 0, 0 }
};
const char *comma;
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 4c8a0377d8b..c7c780929b8 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -297,3 +297,7 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE,
"__ubsan_handle_builtin_unreachable",
BT_FN_VOID_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE,
+ "__ubsan_handle_vla_bound_not_positive",
+ BT_FN_VOID_PTR_PTR,
+ ATTR_COLD_NOTHROW_LEAF_LIST)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e0dad494f4a..bf66f303452 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2013-11-03 Marek Polacek <polacek@redhat.com>
+
+ * g++.dg/ubsan/cxx1y-vla.C: New test.
+ * c-c++-common/ubsan/vla-3.c: New test.
+ * c-c++-common/ubsan/vla-2.c: New test.
+ * c-c++-common/ubsan/vla-4.c: New test.
+ * c-c++-common/ubsan/vla-1.c: New test.
+
2013-11-02 Bill Schmidt <wschmidt@vnet.linux.ibm.com>
* gcc.dg/vmx/vec-set.c: New.
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
new file mode 100644
index 00000000000..6c1d81e9d22
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
@@ -0,0 +1,48 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=vla-bound -w" } */
+
+static int
+bar (void)
+{
+ return -42;
+}
+
+typedef long int V;
+int
+main (void)
+{
+ int x = -1;
+ double di = -3.2;
+ V v = -666;
+
+ int a[x];
+ int aa[x][x];
+ int aaa[x][x][x];
+ int b[x - 4];
+ int c[(int) di];
+ int d[1 + x];
+ int e[1 ? x : -1];
+ int f[++x];
+ int g[(signed char) --x];
+ int h[(++x, --x, x)];
+ int i[v];
+ int j[bar ()];
+
+ return 0;
+}
+
+/* { dg-output "variable length array bound evaluates to non-positive value -1(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -1(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -1(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -1(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -1(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -1(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -5(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -3(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value 0(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -1(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value 0(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -1(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -1(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -666(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive value -42(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-2.c b/gcc/testsuite/c-c++-common/ubsan/vla-2.c
new file mode 100644
index 00000000000..2fbeb7113b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-2.c
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=vla-bound -w" } */
+
+int
+main (void)
+{
+ const int t = 0;
+ struct s {
+ int x;
+ /* Don't instrument this one. */
+ int g[t];
+ };
+
+ return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-3.c b/gcc/testsuite/c-c++-common/ubsan/vla-3.c
new file mode 100644
index 00000000000..20dd38b79a7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-3.c
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=vla-bound -w" } */
+
+/* Don't instrument the arrays here. */
+int
+foo (int n, int a[])
+{
+ return a[n - 1];
+}
+
+int
+main (void)
+{
+ int a[6] = { };
+ return foo (3, a);
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-4.c b/gcc/testsuite/c-c++-common/ubsan/vla-4.c
new file mode 100644
index 00000000000..3f7dd1de50c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-4.c
@@ -0,0 +1,13 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=vla-bound" } */
+
+int
+main (void)
+{
+ int x = 1;
+ /* Check that the size of an array is evaluated only once. */
+ int a[++x];
+ if (x != 2)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/ubsan/cxx1y-vla.C b/gcc/testsuite/g++.dg/ubsan/cxx1y-vla.C
new file mode 100644
index 00000000000..350db3f3473
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/cxx1y-vla.C
@@ -0,0 +1,13 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=vla-bound -w -std=c++1y" } */
+/* { dg-shouldfail "ubsan" } */
+
+int
+main (void)
+{
+ int y = -18;
+ int a[y];
+ return 0;
+}
+
+/* { dg-output "terminate called after throwing an instance" } */