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
This commit is contained in:
parent
5d3805fca3
commit
07d7c611fc
8 changed files with 143 additions and 2 deletions
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
36
gcc/testsuite/c-c++-common/ubsan/builtin-1.c
Normal file
36
gcc/testsuite/c-c++-common/ubsan/builtin-1.c
Normal file
|
@ -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" } */
|
76
gcc/ubsan.c
76
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)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue