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 v5] Enable -fsanitize-recover for KASan


Hi all,

On 10/23/2014 11:11 AM, Yury Gribov wrote:
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

This is the third version of patch which renames -fsanitize-recover to
-fubsan-recover and introduces -fasan-recover (enabled by default for
KASan). It also moves flag handling to finish_options per Jakub's
request.

A new version of patch based upon Jakub's recent changes to
-fsanitize-recover=.  I've renamed __asan_report_recover_load* to
__asan_report_load*_noabort to match UBSan's style.

Note that currently -fsanitize=kernel-address
-fno-sanitize-recover=kernel-address won't work as expected because we
miss __asan_load*_abort family of functions in libasan.

A new version of patch with full support for __asan_report_loadX_noabort and __asan_loadX_noabort based upon recent discussion with KASan folks.

Bootstrapped and regtested on x64.

-Y

>From ee93b44c0b87da5346476c2554697168d07c6600 Mon Sep 17 00:00:00 2001
From: Yury Gribov <y.gribov@samsung.com>
Date: Wed, 22 Oct 2014 17:24:55 +0400
Subject: [PATCH] Enable -fsanitize-recover for KASan.

2014-10-23  Yury Gribov  <y.gribov@samsung.com>

gcc/
	* asan.c (report_error_func): Add noabort path.
	(check_func): Ditto.  Formatting.
	(asan_expand_check_ifn): Handle noabort path.
	* common.opt (flag_sanitize_recover): Add SANITIZE_KERNEL_ADDRESS
	to default value.
	* doc/invoke.texi (-fsanitize-recover=): Mention KASan.
	* opts.c (finish_options): Reword comment.
	* sanitizer.def: Add noabort ASan builtins.

gcc/testsuite/
	* c-c++-common/asan/kasan-recover-1.c: New test.
	* c-c++-common/asan/kasan-recover-2.c: New test.
---
 gcc/asan.c                                        |   81 ++++++++++++++-------
 gcc/common.opt                                    |    2 +-
 gcc/doc/invoke.texi                               |    8 +-
 gcc/opts.c                                        |    4 +-
 gcc/sanitizer.def                                 |   62 ++++++++++++++++
 gcc/testsuite/c-c++-common/asan/kasan-recover-1.c |   12 +++
 gcc/testsuite/c-c++-common/asan/kasan-recover-2.c |   12 +++
 7 files changed, 150 insertions(+), 31 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/asan/kasan-recover-1.c
 create mode 100644 gcc/testsuite/c-c++-common/asan/kasan-recover-2.c

diff --git a/gcc/asan.c b/gcc/asan.c
index 97f0b4c..93536ad 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -1344,44 +1344,72 @@ 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_LOAD1_NOABORT,
+	    BUILT_IN_ASAN_REPORT_LOAD2_NOABORT,
+	    BUILT_IN_ASAN_REPORT_LOAD4_NOABORT,
+	    BUILT_IN_ASAN_REPORT_LOAD8_NOABORT,
+	    BUILT_IN_ASAN_REPORT_LOAD16_NOABORT,
+	    BUILT_IN_ASAN_REPORT_LOAD_N_NOABORT },
+	  { BUILT_IN_ASAN_REPORT_STORE1_NOABORT,
+	    BUILT_IN_ASAN_REPORT_STORE2_NOABORT,
+	    BUILT_IN_ASAN_REPORT_STORE4_NOABORT,
+	    BUILT_IN_ASAN_REPORT_STORE8_NOABORT,
+	    BUILT_IN_ASAN_REPORT_STORE16_NOABORT,
+	    BUILT_IN_ASAN_REPORT_STORE_N_NOABORT } } };
   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}.
    IS_STORE is either 1 (for a store) or 0 (for a load).  */
 
 static tree
-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_STORE1, BUILT_IN_ASAN_STORE2,
-      BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
-      BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } };
+check_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
+	    int *nargs)
+{
+  static enum built_in_function check[2][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_STORE1, BUILT_IN_ASAN_STORE2,
+	    BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
+	    BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } },
+	{ { BUILT_IN_ASAN_LOAD1_NOABORT,
+	    BUILT_IN_ASAN_LOAD2_NOABORT,
+	    BUILT_IN_ASAN_LOAD4_NOABORT,
+	    BUILT_IN_ASAN_LOAD8_NOABORT,
+	    BUILT_IN_ASAN_LOAD16_NOABORT,
+	    BUILT_IN_ASAN_LOADN_NOABORT },
+	  { BUILT_IN_ASAN_STORE1_NOABORT,
+	    BUILT_IN_ASAN_STORE2_NOABORT,
+	    BUILT_IN_ASAN_STORE4_NOABORT,
+	    BUILT_IN_ASAN_STORE8_NOABORT,
+	    BUILT_IN_ASAN_STORE16_NOABORT,
+	    BUILT_IN_ASAN_STOREN_NOABORT } } };
   if (size_in_bytes == -1)
     {
       *nargs = 2;
-      return builtin_decl_implicit (check[is_store][5]);
+      return builtin_decl_implicit (check[recover_p][is_store][5]);
     }
   *nargs = 1;
-  return builtin_decl_implicit (check[is_store][exact_log2 (size_in_bytes)]);
+  int size_log2 = exact_log2 (size_in_bytes);
+  return builtin_decl_implicit (check[recover_p][is_store][size_log2]);
 }
 
 /* Split the current basic block and create a condition statement
@@ -2502,6 +2530,9 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
   gimple g = gsi_stmt (*iter);
   location_t loc = gimple_location (g);
 
+  bool recover_p
+    = (flag_sanitize & flag_sanitize_recover & SANITIZE_KERNEL_ADDRESS) != 0;
+
   HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
   gcc_assert (flags < ASAN_CHECK_LAST);
   bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
@@ -2530,7 +2561,7 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
       tree base_addr = gimple_assign_lhs (g);
 
       int nargs;
-      tree fun = check_func (is_store, size_in_bytes, &nargs);
+      tree fun = check_func (is_store, recover_p, size_in_bytes, &nargs);
       if (nargs == 1)
 	g = gimple_build_call (fun, 1, base_addr);
       else
@@ -2591,7 +2622,7 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
   basic_block then_bb, else_bb;
   gsi = create_cond_insert_point (&gsi, /*before_p*/false,
 				  /*then_more_likely_p=*/false,
-				  /*create_then_fallthru_edge=*/false,
+				  /*create_then_fallthru_edge*/recover_p,
 				  &then_bb,
 				  &else_bb);
 
@@ -2700,7 +2731,7 @@ 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, 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/common.opt b/gcc/common.opt
index da5250b..e385615 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -213,7 +213,7 @@ unsigned int flag_sanitize
 
 ; What sanitizers should recover from errors
 Variable
-unsigned int flag_sanitize_recover = SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT
+unsigned int flag_sanitize_recover = SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT | SANITIZE_KERNEL_ADDRESS
 
 ; Flag whether a prefix has been added to dump_base_name
 Variable
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c9ca404..6a425c0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -5657,13 +5657,13 @@ and program will exit after that with non-zero exit code.
 
 Currently this feature only works for @option{-fsanitize=undefined} (and its suboptions
 except for @option{-fsanitize=unreachable} and @option{-fsanitize=return}),
-@option{-fsanitize=float-cast-overflow} and @option{-fsanitize=float-divide-by-zero}.
-For these sanitizers error recovery is turned on by default.
+@option{-fsanitize=float-cast-overflow}, @option{-fsanitize=float-divide-by-zero} and
+@option{-fsanitize=kernel-address}.  For these sanitizers error recovery is turned on by default.
 
 Syntax without explicit @var{opts} parameter is deprecated.  It is equivalent to
-@option{-fsanitize-recover=undefined,float-cast-overflow,float-divide-by-zero}.
+@option{-fsanitize-recover=undefined,float-cast-overflow,float-divide-by-zero,kernel-address}.
 Similarly @option{-fno-sanitize-recover} is equivalent to
-@option{-fno-sanitize-recover=undefined,float-cast-overflow,float-divide-by-zero}.
+@option{-fno-sanitize-recover=undefined,float-cast-overflow,float-divide-by-zero,kernel-address}.
 
 @item -fsanitize-undefined-trap-on-error
 @opindex fsanitize-undefined-trap-on-error
diff --git a/gcc/opts.c b/gcc/opts.c
index 25f5235..7157865 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -877,7 +877,7 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   if (opts->x_dwarf_split_debug_info)
     opts->x_debug_generate_pub_sections = 2;
 
-  /* Userspace and kernel ASan conflict with each other and with TSan.  */
+  /* Userspace and kernel ASan conflict with each other.  */
 
   if ((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS)
       && (opts->x_flag_sanitize & SANITIZE_KERNEL_ADDRESS))
@@ -885,6 +885,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 	      "-fsanitize=address is incompatible with "
 	      "-fsanitize=kernel-address");
 
+  /* And with TSan.  */
+
   if ((opts->x_flag_sanitize & SANITIZE_ADDRESS)
       && (opts->x_flag_sanitize & SANITIZE_THREAD))
     error_at (loc,
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 722311a..cddc5ea 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_LOAD1_NOABORT,
+		      "__asan_report_load1_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD2_NOABORT,
+		      "__asan_report_load2_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD4_NOABORT,
+		      "__asan_report_load4_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD8_NOABORT,
+		      "__asan_report_load8_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD16_NOABORT,
+		      "__asan_report_load16_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD_N_NOABORT,
+		      "__asan_report_load_n_noabort",
+		      BT_FN_VOID_PTR_PTRMODE,
+		      ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE1_NOABORT,
+		      "__asan_report_store1_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE2_NOABORT,
+		      "__asan_report_store2_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE4_NOABORT,
+		      "__asan_report_store4_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE8_NOABORT,
+		      "__asan_report_store8_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE16_NOABORT,
+		      "__asan_report_store16_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE_N_NOABORT,
+		      "__asan_report_store_n_noabort",
+		      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",
@@ -81,6 +119,30 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE16, "__asan_store16",
 		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STOREN, "__asan_storeN",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD1_NOABORT, "__asan_load1_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD2_NOABORT, "__asan_load2_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD4_NOABORT, "__asan_load4_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD8_NOABORT, "__asan_load8_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD16_NOABORT, "__asan_load16_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOADN_NOABORT, "__asan_loadN_noabort",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE1_NOABORT, "__asan_store1_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE2_NOABORT, "__asan_store2_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE4_NOABORT, "__asan_store4_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE8_NOABORT, "__asan_store8_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE16_NOABORT, "__asan_store16_noabort",
+		      BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STOREN_NOABORT, "__asan_storeN_noabort",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REGISTER_GLOBALS,
 		      "__asan_register_globals",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
diff --git a/gcc/testsuite/c-c++-common/asan/kasan-recover-1.c b/gcc/testsuite/c-c++-common/asan/kasan-recover-1.c
new file mode 100644
index 0000000..6e04e5d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/kasan-recover-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-sanitize=address -fsanitize=kernel-address --param asan-instrumentation-with-call-threshold=100 -save-temps" } */
+
+void
+foo (int *p)
+{
+  *p = 0;
+}
+
+/* { dg-final { scan-assembler "__asan_report_store4_noabort" } } */
+/* { dg-final { cleanup-saved-temps } } */
+
diff --git a/gcc/testsuite/c-c++-common/asan/kasan-recover-2.c b/gcc/testsuite/c-c++-common/asan/kasan-recover-2.c
new file mode 100644
index 0000000..1091a07
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/kasan-recover-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-sanitize=address -fsanitize=kernel-address -save-temps" } */
+
+void
+foo (int *p)
+{
+  *p = 0;
+}
+
+/* { dg-final { scan-assembler "__asan_store4_noabort" } } */
+/* { dg-final { cleanup-saved-temps } } */
+
-- 
1.7.9.5


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