This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Enable -fsanitize-recover for KASan


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.gribov@samsung.com>
Date:   Fri Aug 29 16:43:42 2014 +0400

    2014-09-05  Yury Gribov  <y.gribov@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;
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]