commit d470f4d1214cbcbebb818778e6f554b346ee43d5 Author: Yury Gribov Date: Fri Aug 29 16:43:42 2014 +0400 2014-09-05 Yury Gribov gcc/ * asan.c (report_error_func): Optionally call recoverable routines. (asan_expand_check_ifn): Likewise. (check_func): Fix formatting. * common.opt (fsanitize-recover): Disable by default. * sanitizer.def: New builtins. * opts.c (common_handle_option): Enable flag_sanitize_recover for UBSan and KASan by default. * flag-types.h (SANITIZE_UNDEFINED_NONDEFAULT): Rename. * gcc.c (sanitize_spec_function): Likewise. * opts.c (common_handle_option): Likewise. gcc/testsuite/ * c-c++-common/asan/recovery-1.c: New test. * c-c++-common/asan/recovery-2.c: New test. * c-c++-common/asan/recovery-common.inc: New file. diff --git a/gcc/asan.c b/gcc/asan.c index e6820ea..1d0a26a 100644 --- a/gcc/asan.c +++ b/gcc/asan.c @@ -1373,22 +1373,36 @@ asan_protect_global (tree decl) IS_STORE is either 1 (for a store) or 0 (for a load). */ static tree -report_error_func (bool is_store, HOST_WIDE_INT size_in_bytes, int *nargs) -{ - static enum built_in_function report[2][6] - = { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2, - BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8, - BUILT_IN_ASAN_REPORT_LOAD16, BUILT_IN_ASAN_REPORT_LOAD_N }, - { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2, - BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8, - BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } }; +report_error_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes, + int *nargs) +{ + static enum built_in_function report[2][2][6] + = { { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2, + BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8, + BUILT_IN_ASAN_REPORT_LOAD16, BUILT_IN_ASAN_REPORT_LOAD_N }, + { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2, + BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8, + BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } }, + { { BUILT_IN_ASAN_REPORT_RECOVER_LOAD1, + BUILT_IN_ASAN_REPORT_RECOVER_LOAD2, + BUILT_IN_ASAN_REPORT_RECOVER_LOAD4, + BUILT_IN_ASAN_REPORT_RECOVER_LOAD8, + BUILT_IN_ASAN_REPORT_RECOVER_LOAD16, + BUILT_IN_ASAN_REPORT_RECOVER_LOAD_N }, + { BUILT_IN_ASAN_REPORT_RECOVER_STORE1, + BUILT_IN_ASAN_REPORT_RECOVER_STORE2, + BUILT_IN_ASAN_REPORT_RECOVER_STORE4, + BUILT_IN_ASAN_REPORT_RECOVER_STORE8, + BUILT_IN_ASAN_REPORT_RECOVER_STORE16, + BUILT_IN_ASAN_REPORT_RECOVER_STORE_N } } }; if (size_in_bytes == -1) { *nargs = 2; - return builtin_decl_implicit (report[is_store][5]); + return builtin_decl_implicit (report[recover_p][is_store][5]); } *nargs = 1; - return builtin_decl_implicit (report[is_store][exact_log2 (size_in_bytes)]); + int size_log2 = exact_log2 (size_in_bytes); + return builtin_decl_implicit (report[recover_p][is_store][size_log2]); } /* Construct a function tree for __asan_{load,store}{1,2,4,8,16,_n}. @@ -1399,11 +1413,11 @@ check_func (bool is_store, int size_in_bytes, int *nargs) { static enum built_in_function check[2][6] = { { BUILT_IN_ASAN_LOAD1, BUILT_IN_ASAN_LOAD2, - BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8, - BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN }, + BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8, + BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN }, { BUILT_IN_ASAN_STORE1, BUILT_IN_ASAN_STORE2, - BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8, - BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } }; + BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8, + BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } }; if (size_in_bytes == -1) { *nargs = 2; @@ -2574,9 +2588,10 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls) /* Get an iterator on the point where we can add the condition statement for the instrumentation. */ basic_block then_bb, else_bb; + bool create_then_fallthru_edge = flag_sanitize_recover != 0; gsi = create_cond_insert_point (&gsi, /*before_p*/false, /*then_more_likely_p=*/false, - /*create_then_fallthru_edge=*/false, + create_then_fallthru_edge, &then_bb, &else_bb); @@ -2675,7 +2690,9 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls) /* Generate call to the run-time library (e.g. __asan_report_load8). */ gsi = gsi_start_bb (then_bb); int nargs; - tree fun = report_error_func (is_store, size_in_bytes, &nargs); + tree fun = report_error_func (is_store, + /*recover_p*/flag_sanitize_recover != 0, + size_in_bytes, &nargs); g = gimple_build_call (fun, nargs, base_addr, len); gimple_set_location (g, loc); gsi_insert_after (&gsi, g, GSI_NEW_STMT); diff --git a/gcc/builtins.def b/gcc/builtins.def index cd823a3..261373c 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -176,7 +176,7 @@ along with GCC; see the file COPYING3. If not see DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ true, true, true, ATTRS, true, \ (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \ - | SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT))) + | SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT))) #undef DEF_CILKPLUS_BUILTIN #define DEF_CILKPLUS_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ diff --git a/gcc/common.opt b/gcc/common.opt index 9c9434f..eb8d7e3 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -884,8 +884,8 @@ Common Joined RejectNegative Var(common_deferred_options) Defer -fasan-shadow-offset= Use custom shadow memory offset. fsanitize-recover -Common Report Var(flag_sanitize_recover) Init(1) -After diagnosing undefined behavior attempt to continue execution +Common Report Var(flag_sanitize_recover) +After diagnosing error attempt to continue execution fsanitize-undefined-trap-on-error Common Report Var(flag_sanitize_undefined_trap_on_error) Init(0) diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 135c343..7b4d7e4 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -238,7 +238,7 @@ enum sanitize_code { | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM | SANITIZE_BOUNDS | SANITIZE_ALIGNMENT, - SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST + SANITIZE_UNDEFINED_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST }; /* flag_vtable_verify initialization levels. */ diff --git a/gcc/gcc.c b/gcc/gcc.c index c550d9d..b2031ed 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -8236,7 +8236,7 @@ sanitize_spec_function (int argc, const char **argv) if (strcmp (argv[0], "thread") == 0) return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL; if (strcmp (argv[0], "undefined") == 0) - return ((flag_sanitize & (SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT)) + return ((flag_sanitize & (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT)) && !flag_sanitize_undefined_trap_on_error) ? "" : NULL; if (strcmp (argv[0], "leak") == 0) return ((flag_sanitize diff --git a/gcc/opts.c b/gcc/opts.c index 496c073..027b648 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1545,6 +1545,12 @@ common_handle_option (struct gcc_options *opts, if (flag_sanitize & SANITIZE_NULL) opts->x_flag_delete_null_pointer_checks = 0; + /* UBSan and KASan enable recovery by default. */ + opts->x_flag_sanitize_recover + = !!(flag_sanitize & (SANITIZE_UNDEFINED + | SANITIZE_UNDEFINED_NONDEFAULT + | SANITIZE_KERNEL_ADDRESS)); + /* Kernel ASan implies normal ASan but does not yet support all features. */ if (flag_sanitize & SANITIZE_KERNEL_ADDRESS) diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def index 1f5ef21..c06823e 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -57,6 +57,44 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE16, "__asan_report_store16", DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE_N, "__asan_report_store_n", BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_LOAD1, + "__asan_report_recover_load1", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_LOAD2, + "__asan_report_recover_load2", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_LOAD4, + "__asan_report_recover_load4", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_LOAD8, + "__asan_report_recover_load8", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_LOAD16, + "__asan_report_recover_load16", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_LOAD_N, + "__asan_report_recover_load_n", + BT_FN_VOID_PTR_PTRMODE, + ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_STORE1, + "__asan_report_recover_store1", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_STORE2, + "__asan_report_recover_store2", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_STORE4, + "__asan_report_recover_store4", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_STORE8, + "__asan_report_recover_store8", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_STORE16, + "__asan_report_recover_store16", + BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_RECOVER_STORE_N, + "__asan_report_recover_store_n", + BT_FN_VOID_PTR_PTRMODE, + ATTR_TMPURE_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD1, "__asan_load1", BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD2, "__asan_load2", diff --git a/gcc/testsuite/c-c++-common/asan/recovery-1.c b/gcc/testsuite/c-c++-common/asan/recovery-1.c new file mode 100644 index 0000000..ac3d5a7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/recovery-1.c @@ -0,0 +1,8 @@ +/* Check that -fsanitize-recover is disabled for ASan by default. */ + +/* { dg-do run } */ +/* { dg-shouldfail "asan" } */ + +#include "recovery-common.inc" + +/* { dg-output "ERROR: AddressSanitizer:\[^\n\r]*on address\[^\n\r]*" } */ diff --git a/gcc/testsuite/c-c++-common/asan/recovery-2.c b/gcc/testsuite/c-c++-common/asan/recovery-2.c new file mode 100644 index 0000000..001eb0a --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/recovery-2.c @@ -0,0 +1,6 @@ +/* Check that -fsanitize-recover works for ASan. */ + +/* { dg-do run } */ +/* { dg-options "-fsanitize-recover" } */ + +#include "recovery-common.inc" diff --git a/gcc/testsuite/c-c++-common/asan/recovery-common.inc b/gcc/testsuite/c-c++-common/asan/recovery-common.inc new file mode 100644 index 0000000..43f0e10 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/recovery-common.inc @@ -0,0 +1,31 @@ +#include + +#define NREPORTS 5 + +static int counter = NREPORTS; + +#ifdef __cplusplus +extern "C" +#endif +void __attribute__((used)) +__asan_report_recover_store4 (void *p) +{ + --counter; +} + +void __attribute__((noinline, noclone)) +foo (int *p) +{ + *p = 0; +} + +int main () +{ + int x, i; + __asan_poison_memory_region (&x, sizeof (x)); + for (i = 0; i < NREPORTS; ++i) + foo (&x); + if (counter != 0) + __builtin_abort (); + return 0; +}