Commit 07d7c611 by Jakub Jelinek Committed by Jakub Jelinek

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
parent 5d3805fc
2017-10-19 Jakub Jelinek <jakub@redhat.com> 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 * ubsan.c (ubsan_expand_null_ifn): Use _v1 suffixed type mismatch
builtins, store max (log2 (align), 0) into uchar field instead of builtins, store max (log2 (align), 0) into uchar field instead of
align into uptr field. align into uptr field.
...@@ -11149,6 +11149,15 @@ to verify the referenced object has the correct dynamic type. ...@@ -11149,6 +11149,15 @@ to verify the referenced object has the correct dynamic type.
This option enables instrumentation of pointer arithmetics. If the pointer This option enables instrumentation of pointer arithmetics. If the pointer
arithmetics overflows, a run-time error is issued. 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 @end table
While @option{-ftrapv} causes traps for signed overflows to be emitted, While @option{-ftrapv} causes traps for signed overflows to be emitted,
...@@ -246,6 +246,7 @@ enum sanitize_code { ...@@ -246,6 +246,7 @@ enum sanitize_code {
SANITIZE_VPTR = 1UL << 22, SANITIZE_VPTR = 1UL << 22,
SANITIZE_BOUNDS_STRICT = 1UL << 23, SANITIZE_BOUNDS_STRICT = 1UL << 23,
SANITIZE_POINTER_OVERFLOW = 1UL << 24, SANITIZE_POINTER_OVERFLOW = 1UL << 24,
SANITIZE_BUILTIN = 1UL << 25,
SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT, SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
| SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
...@@ -254,7 +255,7 @@ enum sanitize_code { ...@@ -254,7 +255,7 @@ enum sanitize_code {
| SANITIZE_NONNULL_ATTRIBUTE | SANITIZE_NONNULL_ATTRIBUTE
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE | SANITIZE_RETURNS_NONNULL_ATTRIBUTE
| SANITIZE_OBJECT_SIZE | SANITIZE_VPTR | SANITIZE_OBJECT_SIZE | SANITIZE_VPTR
| SANITIZE_POINTER_OVERFLOW, | SANITIZE_POINTER_OVERFLOW | SANITIZE_BUILTIN,
SANITIZE_UNDEFINED_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST SANITIZE_UNDEFINED_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
| SANITIZE_BOUNDS_STRICT | SANITIZE_BOUNDS_STRICT
}; };
......
...@@ -1521,6 +1521,7 @@ const struct sanitizer_opts_s sanitizer_opts[] = ...@@ -1521,6 +1521,7 @@ const struct sanitizer_opts_s sanitizer_opts[] =
SANITIZER_OPT (object-size, SANITIZE_OBJECT_SIZE, true), SANITIZER_OPT (object-size, SANITIZE_OBJECT_SIZE, true),
SANITIZER_OPT (vptr, SANITIZE_VPTR, true), SANITIZER_OPT (vptr, SANITIZE_VPTR, true),
SANITIZER_OPT (pointer-overflow, SANITIZE_POINTER_OVERFLOW, true), SANITIZER_OPT (pointer-overflow, SANITIZE_POINTER_OVERFLOW, true),
SANITIZER_OPT (builtin, SANITIZE_BUILTIN, true),
SANITIZER_OPT (all, ~0U, true), SANITIZER_OPT (all, ~0U, true),
#undef SANITIZER_OPT #undef SANITIZER_OPT
{ NULL, 0U, 0UL, false } { NULL, 0U, 0UL, false }
......
...@@ -524,6 +524,14 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT, ...@@ -524,6 +524,14 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT,
"__ubsan_handle_nonnull_return_v1_abort", "__ubsan_handle_nonnull_return_v1_abort",
BT_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST) 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, DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS,
"__ubsan_handle_dynamic_type_cache_miss", "__ubsan_handle_dynamic_type_cache_miss",
BT_FN_VOID_PTR_PTR_PTR, BT_FN_VOID_PTR_PTR_PTR,
......
2017-10-19 Jakub Jelinek <jakub@redhat.com> 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 * c-c++-common/ubsan/float-cast-overflow-1.c: Drop value keyword
from expected output regexps. from expected output regexps.
* c-c++-common/ubsan/float-cast-overflow-2.c: Likewise. * c-c++-common/ubsan/float-cast-overflow-2.c: Likewise.
......
/* { 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" } */
...@@ -2221,6 +2221,72 @@ instrument_object_size (gimple_stmt_iterator *gsi, tree t, bool is_lhs) ...@@ -2221,6 +2221,72 @@ instrument_object_size (gimple_stmt_iterator *gsi, tree t, bool is_lhs)
gsi_insert_before (gsi, g, GSI_SAME_STMT); 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 { namespace {
const pass_data pass_data_ubsan = const pass_data pass_data_ubsan =
...@@ -2252,7 +2318,8 @@ public: ...@@ -2252,7 +2318,8 @@ public:
| SANITIZE_NONNULL_ATTRIBUTE | SANITIZE_NONNULL_ATTRIBUTE
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE | SANITIZE_RETURNS_NONNULL_ATTRIBUTE
| SANITIZE_OBJECT_SIZE | SANITIZE_OBJECT_SIZE
| SANITIZE_POINTER_OVERFLOW)); | SANITIZE_POINTER_OVERFLOW
| SANITIZE_BUILTIN));
} }
virtual unsigned int execute (function *); virtual unsigned int execute (function *);
...@@ -2317,6 +2384,13 @@ pass_ubsan::execute (function *fun) ...@@ -2317,6 +2384,13 @@ pass_ubsan::execute (function *fun)
bb = gimple_bb (stmt); 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) if (sanitize_flags_p (SANITIZE_RETURNS_NONNULL_ATTRIBUTE, fun->decl)
&& gimple_code (stmt) == GIMPLE_RETURN) && gimple_code (stmt) == GIMPLE_RETURN)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment