aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2017-10-19 14:09:52 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2017-10-19 14:09:52 +0200
commit07d7c611fc0c4be0a0be935efe97a7887e78bc2a (patch)
treedef604d8db44c55f5de1bb611ed83a32c753321d
parent5d3805fca3e9a199fbaa18aee3c05ecb30ebca61 (diff)
downloadgcc-07d7c611fc0c4be0a0be935efe97a7887e78bc2a.zip
gcc-07d7c611fc0c4be0a0be935efe97a7887e78bc2a.tar.gz
gcc-07d7c611fc0c4be0a0be935efe97a7887e78bc2a.tar.bz2
flag-types.h (enum sanitize_code): Add SANITIZE_BUILTIN.
* flag-types.h (enum sanitize_code): Add SANITIZE_BUILTIN. Or SANITIZE_BUILTIN into SANITIZE_UNDEFINED. * sanitizer.def (BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN, BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN_ABORT): New builtins. * opts.c (sanitizer_opts): Add builtin. * ubsan.c (instrument_builtin): New function. (pass_ubsan::execute): Call it. (pass_ubsan::gate): Enable even for SANITIZE_BUILTIN. * doc/invoke.texi: Document -fsanitize=builtin. * c-c++-common/ubsan/builtin-1.c: New test. From-SVN: r253888
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/doc/invoke.texi9
-rw-r--r--gcc/flag-types.h3
-rw-r--r--gcc/opts.c1
-rw-r--r--gcc/sanitizer.def8
-rw-r--r--gcc/testsuite/ChangeLog2
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/builtin-1.c36
-rw-r--r--gcc/ubsan.c76
8 files changed, 143 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2af7859..7865a03 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,15 @@
2017-10-19 Jakub Jelinek <jakub@redhat.com>
+ * flag-types.h (enum sanitize_code): Add SANITIZE_BUILTIN. Or
+ SANITIZE_BUILTIN into SANITIZE_UNDEFINED.
+ * sanitizer.def (BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN,
+ BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN_ABORT): New builtins.
+ * opts.c (sanitizer_opts): Add builtin.
+ * ubsan.c (instrument_builtin): New function.
+ (pass_ubsan::execute): Call it.
+ (pass_ubsan::gate): Enable even for SANITIZE_BUILTIN.
+ * doc/invoke.texi: Document -fsanitize=builtin.
+
* ubsan.c (ubsan_expand_null_ifn): Use _v1 suffixed type mismatch
builtins, store max (log2 (align), 0) into uchar field instead of
align into uptr field.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5e88279..a2ef6fe 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -11149,6 +11149,15 @@ to verify the referenced object has the correct dynamic type.
This option enables instrumentation of pointer arithmetics. If the pointer
arithmetics overflows, a run-time error is issued.
+@item -fsanitize=builtin
+@opindex fsanitize=builtin
+
+This option enables instrumentation of arguments to selected builtin
+functions. If an invalid value is passed to such arguments, a run-time
+error is issued. E.g.@ passing 0 as the argument to @code{__builtin_ctz}
+or @code{__builtin_clz} invokes undefined behavior and is diagnosed
+by this option.
+
@end table
While @option{-ftrapv} causes traps for signed overflows to be emitted,
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 1f439d3..bfea174 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -246,6 +246,7 @@ enum sanitize_code {
SANITIZE_VPTR = 1UL << 22,
SANITIZE_BOUNDS_STRICT = 1UL << 23,
SANITIZE_POINTER_OVERFLOW = 1UL << 24,
+ SANITIZE_BUILTIN = 1UL << 25,
SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
| SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
@@ -254,7 +255,7 @@ enum sanitize_code {
| SANITIZE_NONNULL_ATTRIBUTE
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE
| SANITIZE_OBJECT_SIZE | SANITIZE_VPTR
- | SANITIZE_POINTER_OVERFLOW,
+ | SANITIZE_POINTER_OVERFLOW | SANITIZE_BUILTIN,
SANITIZE_UNDEFINED_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
| SANITIZE_BOUNDS_STRICT
};
diff --git a/gcc/opts.c b/gcc/opts.c
index adf3d89..ee95c84 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1521,6 +1521,7 @@ const struct sanitizer_opts_s sanitizer_opts[] =
SANITIZER_OPT (object-size, SANITIZE_OBJECT_SIZE, true),
SANITIZER_OPT (vptr, SANITIZE_VPTR, true),
SANITIZER_OPT (pointer-overflow, SANITIZE_POINTER_OVERFLOW, true),
+ SANITIZER_OPT (builtin, SANITIZE_BUILTIN, true),
SANITIZER_OPT (all, ~0U, true),
#undef SANITIZER_OPT
{ NULL, 0U, 0UL, false }
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 27eb20c..00e7ae0 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -524,6 +524,14 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT,
"__ubsan_handle_nonnull_return_v1_abort",
BT_FN_VOID_PTR_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN,
+ "__ubsan_handle_invalid_builtin",
+ BT_FN_VOID_PTR,
+ ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN_ABORT,
+ "__ubsan_handle_invalid_builtin_abort",
+ BT_FN_VOID_PTR,
+ ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS,
"__ubsan_handle_dynamic_type_cache_miss",
BT_FN_VOID_PTR_PTR_PTR,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 43d32c4..0d812b6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,7 @@
2017-10-19 Jakub Jelinek <jakub@redhat.com>
+ * c-c++-common/ubsan/builtin-1.c: New test.
+
* c-c++-common/ubsan/float-cast-overflow-1.c: Drop value keyword
from expected output regexps.
* c-c++-common/ubsan/float-cast-overflow-2.c: Likewise.
diff --git a/gcc/testsuite/c-c++-common/ubsan/builtin-1.c b/gcc/testsuite/c-c++-common/ubsan/builtin-1.c
new file mode 100644
index 0000000..2f340e3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/builtin-1.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=undefined" } */
+
+#include <stdio.h>
+
+__attribute__((noinline, noclone)) unsigned long long
+foo (unsigned int x, unsigned long int y, unsigned long long int z, __UINTMAX_TYPE__ w)
+{
+ unsigned long long ret = 0;
+ fprintf (stderr, "FOO MARKER1\n");
+ ret += __builtin_ctz (x);
+ ret += __builtin_ctzl (y);
+ ret += __builtin_ctzll (z);
+ ret += __builtin_ctzimax (w);
+ fprintf (stderr, "FOO MARKER2\n");
+ ret += __builtin_clz (x);
+ ret += __builtin_clzl (y);
+ ret += __builtin_clzll (z);
+ ret += __builtin_clzimax (w);
+ fprintf (stderr, "FOO MARKER3\n");
+ return ret;
+}
+
+int
+main ()
+{
+ volatile __UINTMAX_TYPE__ t = 0;
+ t = foo (t, t, t, t);
+ return 0;
+}
+
+/* { dg-output "FOO MARKER1(\n|\r\n|\r)" } */
+/* { dg-output "(\[^\n\r]*runtime error: passing zero to ctz\\\(\\\), which is not a valid argument\[^\n\r]*(\n|\r\n|\r)){4}" } */
+/* { dg-output "FOO MARKER2(\n|\r\n|\r)" } */
+/* { dg-output "(\[^\n\r]*runtime error: passing zero to clz\\\(\\\), which is not a valid argument\[^\n\r]*(\n|\r\n|\r)){4}" } */
+/* { dg-output "FOO MARKER3" } */
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 0a0b4dd..a73061b 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -2221,6 +2221,72 @@ instrument_object_size (gimple_stmt_iterator *gsi, tree t, bool is_lhs)
gsi_insert_before (gsi, g, GSI_SAME_STMT);
}
+/* Instrument values passed to builtin functions. */
+
+static void
+instrument_builtin (gimple_stmt_iterator *gsi)
+{
+ gimple *stmt = gsi_stmt (*gsi);
+ location_t loc = gimple_location (stmt);
+ tree arg;
+ enum built_in_function fcode
+ = DECL_FUNCTION_CODE (gimple_call_fndecl (stmt));
+ int kind = 0;
+ switch (fcode)
+ {
+ CASE_INT_FN (BUILT_IN_CLZ):
+ kind = 1;
+ gcc_fallthrough ();
+ CASE_INT_FN (BUILT_IN_CTZ):
+ arg = gimple_call_arg (stmt, 0);
+ if (!integer_nonzerop (arg))
+ {
+ gimple *g;
+ if (!is_gimple_val (arg))
+ {
+ g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
+ gimple_set_location (g, loc);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ arg = gimple_assign_lhs (g);
+ }
+
+ basic_block then_bb, fallthru_bb;
+ *gsi = create_cond_insert_point (gsi, true, false, true,
+ &then_bb, &fallthru_bb);
+ g = gimple_build_cond (EQ_EXPR, arg,
+ build_zero_cst (TREE_TYPE (arg)),
+ NULL_TREE, NULL_TREE);
+ gimple_set_location (g, loc);
+ gsi_insert_after (gsi, g, GSI_NEW_STMT);
+
+ *gsi = gsi_after_labels (then_bb);
+ if (flag_sanitize_undefined_trap_on_error)
+ g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
+ else
+ {
+ tree t = build_int_cst (unsigned_char_type_node, kind);
+ tree data = ubsan_create_data ("__ubsan_builtin_data",
+ 1, &loc, NULL_TREE, t, NULL_TREE);
+ data = build_fold_addr_expr_loc (loc, data);
+ enum built_in_function bcode
+ = (flag_sanitize_recover & SANITIZE_BUILTIN)
+ ? BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN
+ : BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN_ABORT;
+ tree fn = builtin_decl_explicit (bcode);
+
+ g = gimple_build_call (fn, 1, data);
+ }
+ gimple_set_location (g, loc);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ ubsan_create_edge (g);
+ }
+ *gsi = gsi_for_stmt (stmt);
+ break;
+ default:
+ break;
+ }
+}
+
namespace {
const pass_data pass_data_ubsan =
@@ -2252,7 +2318,8 @@ public:
| SANITIZE_NONNULL_ATTRIBUTE
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE
| SANITIZE_OBJECT_SIZE
- | SANITIZE_POINTER_OVERFLOW));
+ | SANITIZE_POINTER_OVERFLOW
+ | SANITIZE_BUILTIN));
}
virtual unsigned int execute (function *);
@@ -2317,6 +2384,13 @@ pass_ubsan::execute (function *fun)
bb = gimple_bb (stmt);
}
+ if (sanitize_flags_p (SANITIZE_BUILTIN, fun->decl)
+ && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+ {
+ instrument_builtin (&gsi);
+ bb = gimple_bb (stmt);
+ }
+
if (sanitize_flags_p (SANITIZE_RETURNS_NONNULL_ATTRIBUTE, fun->decl)
&& gimple_code (stmt) == GIMPLE_RETURN)
{