Hi all,
This patch enables -fsanitize-recover for KASan by default. This causes
KASan to continue execution after error in case of inline
instrumentation. This feature is needed because
- reports during early bootstrap won't even be printed
- needed to run all tests w/o rebooting machine for every test
- needed for interactive work on desktop
Bootstrapped and regtested on x64.
Ok to commit?
-Y
commit d470f4d1214cbcbebb818778e6f554b346ee43d5
Author: Yury Gribov <y.gri...@samsung.com>
Date: Fri Aug 29 16:43:42 2014 +0400
2014-09-05 Yury Gribov <y.gri...@samsung.com>
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=<string> 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 <sanitizer/asan_interface.h>
+
+#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;
+}