re PR sanitizer/64265 (r217669 broke tsan)
authorJakub Jelinek <jakub@redhat.com>
Mon, 5 Jan 2015 21:47:51 +0000 (22:47 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 5 Jan 2015 21:47:51 +0000 (22:47 +0100)
PR sanitizer/64265
* gimplify.c (gimplify_function_tree): Add TSAN_FUNC_EXIT internal
call as cleanup of the whole body.
* internal-fn.def (TSAN_FUNC_EXIT): New internal call.
* tsan.c (replace_func_exit): New function.
(instrument_func_exit): Moved earlier.
(instrument_memory_accesses): Adjust TSAN_FUNC_EXIT internal calls.
Call instrument_func_exit if no TSAN_FUNC_EXIT internal calls have
been found.
(tsan_pass): Don't call instrument_func_exit.
* internal-fn.c (expand_TSAN_FUNC_EXIT): New function.
* tree-inline.c (copy_bb): Drop TSAN_FUNC_EXIT internal calls during
inlining.

From-SVN: r219202

gcc/ChangeLog
gcc/gimplify.c
gcc/internal-fn.c
gcc/internal-fn.def
gcc/tree-inline.c
gcc/tsan.c

index f62aed21f046c5b200c41ecc0d50bf7dc0269290..286ec01a4e3f039f74374276ead4634a3bc01621 100644 (file)
@@ -1,5 +1,19 @@
 2015-01-05  Jakub Jelinek  <jakub@redhat.com>
 
+       PR sanitizer/64265
+       * gimplify.c (gimplify_function_tree): Add TSAN_FUNC_EXIT internal
+       call as cleanup of the whole body.
+       * internal-fn.def (TSAN_FUNC_EXIT): New internal call.
+       * tsan.c (replace_func_exit): New function.
+       (instrument_func_exit): Moved earlier.
+       (instrument_memory_accesses): Adjust TSAN_FUNC_EXIT internal calls.
+       Call instrument_func_exit if no TSAN_FUNC_EXIT internal calls have
+       been found.
+       (tsan_pass): Don't call instrument_func_exit.
+       * internal-fn.c (expand_TSAN_FUNC_EXIT): New function.
+       * tree-inline.c (copy_bb): Drop TSAN_FUNC_EXIT internal calls during
+       inlining.
+
        PR sanitizer/64344
        * ubsan.h (ubsan_instrument_float_cast): Add ARG argument.
        * ubsan.c (ubsan_instrument_float_cast): Add ARG argument, pass
index d35734f8bb404d33723fc1cdd9952a0cb491cc38..b237cbf866ae448d1fe628f1771eb3f29ed49437 100644 (file)
@@ -9049,6 +9049,22 @@ gimplify_function_tree (tree fndecl)
       seq = NULL;
       gimple_seq_add_stmt (&seq, new_bind);
       gimple_set_body (fndecl, seq);
+      bind = new_bind;
+    }
+
+  if (flag_sanitize & SANITIZE_THREAD)
+    {
+      gcall *call = gimple_build_call_internal (IFN_TSAN_FUNC_EXIT, 0);
+      gimple tf = gimple_build_try (seq, call, GIMPLE_TRY_FINALLY);
+      gbind *new_bind = gimple_build_bind (NULL, tf, gimple_bind_block (bind));
+      /* Clear the block for BIND, since it is no longer directly inside
+        the function, but within a try block.  */
+      gimple_bind_set_block (bind, NULL);
+      /* Replace the current function body with the body
+        wrapped in the try/finally TF.  */
+      seq = NULL;
+      gimple_seq_add_stmt (&seq, new_bind);
+      gimple_set_body (fndecl, seq);
     }
 
   DECL_SAVED_TREE (fndecl) = NULL_TREE;
index 50f569455a3afdd543a7a5bb4153dafbe908050d..50e3c5114ded96a17a61cde817f64dbfaba5b207 100644 (file)
@@ -208,6 +208,14 @@ expand_ASAN_CHECK (gcall *stmt ATTRIBUTE_UNUSED)
   gcc_unreachable ();
 }
 
+/* This should get expanded in the tsan pass.  */
+
+static void
+expand_TSAN_FUNC_EXIT (gcall *)
+{
+  gcc_unreachable ();
+}
+
 /* Helper function for expand_addsub_overflow.  Return 1
    if ARG interpreted as signed in its precision is known to be always
    positive or 2 if ARG is known to be always negative, or 3 if ARG may
index 06d42648ccb9d515e5827cae39925a756543e2e7..f7ebce34225b32296ccfecebc95c5e412219cb98 100644 (file)
@@ -60,3 +60,4 @@ DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".W...")
 DEF_INTERNAL_FN (ADD_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (TSAN_FUNC_EXIT, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
index 902eb955d39f8c359e8647deb88358e2b3778699..5518d404ff94f2803d07c117cc0b5ab6e5bc9ec4 100644 (file)
@@ -1907,7 +1907,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
              gsi_replace (&copy_gsi, new_call, false);
              stmt = new_call;
            }
-         else if (is_gimple_call (stmt)
+         else if (call_stmt
                   && id->call_stmt
                   && (decl = gimple_call_fndecl (stmt))
                   && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
@@ -1934,6 +1934,15 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
              gsi_replace (&copy_gsi, new_stmt, false);
              stmt = new_stmt;
            }
+         else if (call_stmt
+                  && id->call_stmt
+                  && gimple_call_internal_p (stmt)
+                  && gimple_call_internal_fn (stmt) == IFN_TSAN_FUNC_EXIT)
+           {
+             /* Drop TSAN_FUNC_EXIT () internal calls during inlining.  */
+             gsi_remove (&copy_gsi, false);
+             continue;
+           }
 
          /* Statements produced by inlining can be unfolded, especially
             when we constant propagated some operands.  We can't fold
index 1bc146f198d370870d8970edae9f346fa45ad81f..567a4218bcd72674ce5e7d98251b98ec65d7609b 100644 (file)
@@ -704,6 +704,47 @@ instrument_gimple (gimple_stmt_iterator *gsi)
   return instrumented;
 }
 
+/* Replace TSAN_FUNC_EXIT internal call with function exit tsan builtin.  */
+
+static void
+replace_func_exit (gimple stmt)
+{
+  tree builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT);
+  gimple g = gimple_build_call (builtin_decl, 0);
+  gimple_set_location (g, cfun->function_end_locus);
+  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+  gsi_replace (&gsi, g, true);
+}
+
+/* Instrument function exit.  Used when TSAN_FUNC_EXIT does not exist.  */
+
+static void
+instrument_func_exit (void)
+{
+  location_t loc;
+  basic_block exit_bb;
+  gimple_stmt_iterator gsi;
+  gimple stmt, g;
+  tree builtin_decl;
+  edge e;
+  edge_iterator ei;
+
+  /* Find all function exits.  */
+  exit_bb = EXIT_BLOCK_PTR_FOR_FN (cfun);
+  FOR_EACH_EDGE (e, ei, exit_bb->preds)
+    {
+      gsi = gsi_last_bb (e->src);
+      stmt = gsi_stmt (gsi);
+      gcc_assert (gimple_code (stmt) == GIMPLE_RETURN
+                 || gimple_call_builtin_p (stmt, BUILT_IN_RETURN));
+      loc = gimple_location (stmt);
+      builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT);
+      g = gimple_build_call (builtin_decl, 0);
+      gimple_set_location (g, loc);
+      gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+    }
+}
+
 /* Instruments all interesting memory accesses in the current function.
    Return true if func entry/exit should be instrumented.  */
 
@@ -713,10 +754,38 @@ instrument_memory_accesses (void)
   basic_block bb;
   gimple_stmt_iterator gsi;
   bool fentry_exit_instrument = false;
+  bool func_exit_seen = false;
+  auto_vec<gimple> tsan_func_exits;
 
   FOR_EACH_BB_FN (bb, cfun)
     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-      fentry_exit_instrument |= instrument_gimple (&gsi);
+      {
+       gimple stmt = gsi_stmt (gsi);
+       if (is_gimple_call (stmt)
+           && gimple_call_internal_p (stmt)
+           && gimple_call_internal_fn (stmt) == IFN_TSAN_FUNC_EXIT)
+         {
+           if (fentry_exit_instrument)
+             replace_func_exit (stmt);
+           else
+             tsan_func_exits.safe_push (stmt);
+           func_exit_seen = true;
+         }
+       else
+         fentry_exit_instrument |= instrument_gimple (&gsi);
+      }
+  unsigned int i;
+  gimple stmt;
+  FOR_EACH_VEC_ELT (tsan_func_exits, i, stmt)
+    if (fentry_exit_instrument)
+      replace_func_exit (stmt);
+    else
+      {
+       gsi = gsi_for_stmt (stmt);
+       gsi_remove (&gsi, true);
+      }
+  if (fentry_exit_instrument && !func_exit_seen)
+    instrument_func_exit ();
   return fentry_exit_instrument;
 }
 
@@ -745,35 +814,6 @@ instrument_func_entry (void)
   gsi_insert_seq_on_edge_immediate (e, seq);
 }
 
-/* Instruments function exits.  */
-
-static void
-instrument_func_exit (void)
-{
-  location_t loc;
-  basic_block exit_bb;
-  gimple_stmt_iterator gsi;
-  gimple stmt, g;
-  tree builtin_decl;
-  edge e;
-  edge_iterator ei;
-
-  /* Find all function exits.  */
-  exit_bb = EXIT_BLOCK_PTR_FOR_FN (cfun);
-  FOR_EACH_EDGE (e, ei, exit_bb->preds)
-    {
-      gsi = gsi_last_bb (e->src);
-      stmt = gsi_stmt (gsi);
-      gcc_assert (gimple_code (stmt) == GIMPLE_RETURN
-                 || gimple_call_builtin_p (stmt, BUILT_IN_RETURN));
-      loc = gimple_location (stmt);
-      builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT);
-      g = gimple_build_call (builtin_decl, 0);
-      gimple_set_location (g, loc);
-      gsi_insert_before (&gsi, g, GSI_SAME_STMT);
-    }
-}
-
 /* ThreadSanitizer instrumentation pass.  */
 
 static unsigned
@@ -781,10 +821,7 @@ tsan_pass (void)
 {
   initialize_sanitizer_builtins ();
   if (instrument_memory_accesses ())
-    {
-      instrument_func_entry ();
-      instrument_func_exit ();
-    }
+    instrument_func_entry ();
   return 0;
 }