Hi!

libasan currently has an assertion that __asan_before_dynamic_init
is called only after registering at least one global var.  I have no idea
how to always guarantee that without making the code too ugly or registering
dummy global vars, since the registration of globals is done at the end of
file compilation when all functions are already emitted, while the
before/after dynamic init pair needs to wrap the actual constructors in the
static initializers (also with a different priority), and when compiling
that function we don't know yet if all the globals will be optimized away or
not.  So, I'll work with upstream to tweak that.

That said, this patch tweaks at least the case where everything in the
static ctors function in between the wrapping function is optimized away,
plus makes sure that we ignore those builtins when checking if a function
is const/pure (if there are no memory accesses (direct or indirect) in
between those two, the function have no real effect).  If there are no
global ctors, we don't emit the static ctors function at all, if there are,
usually at least one global remains, and the case this patch solves is for
the case where all can be optimized away.  The only case which still fails
is when all the ctors are inlined and don't in the end reference any of the
globals they are constructing, just have some other side-effect.

Also, I've noticed that for non-__cxa_atexit compilation we emit the
__asan_*_dynamic_init calls even around dtors, which is undesirable.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-08-31  Jakub Jelinek  <ja...@redhat.com>

        PR sanitizer/77396
        * sanopt.c (sanopt_optimize_walker): Optimize away
        __asan_before_dynamic_init (...) immediately followed by
        __asan_after_dynamic_init ().
        * ipa-pure-const.c (special_builtin_state): Handle
        BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT and
        BUILT_IN_ASAN_AFTER_DYNAMIC_INIT.

        * decl2.c (do_static_initialization_or_destruction): Only
        call asan_dynamic_init_call if INITP is true.

        * g++.dg/asan/pr77396.C: New test.

--- gcc/sanopt.c.jj     2016-08-19 11:04:33.000000000 +0200
+++ gcc/sanopt.c        2016-08-30 12:15:53.466703044 +0200
@@ -538,6 +538,28 @@ sanopt_optimize_walker (basic_block bb,
       if (asan_check_optimize && !nonfreeing_call_p (stmt))
        info->freeing_call_events++;
 
+      /* If __asan_before_dynamic_init ("module"); is followed immediately
+        by __asan_after_dynamic_init ();, there is nothing to guard, so
+        optimize both away.  */
+      if (asan_check_optimize
+         && gimple_call_builtin_p (stmt, BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT))
+       {
+         gimple_stmt_iterator gsi2 = gsi;
+         gsi_next_nondebug (&gsi2);
+         if (!gsi_end_p (gsi2))
+           {
+             gimple *g = gsi_stmt (gsi2);
+             if (is_gimple_call (g)
+                 && gimple_call_builtin_p (g,
+                                           BUILT_IN_ASAN_AFTER_DYNAMIC_INIT))
+               {
+                 unlink_stmt_vdef (g);
+                 gsi_remove (&gsi2, true);
+                 remove = true;
+               }
+           }
+       }
+
       if (gimple_call_internal_p (stmt))
        switch (gimple_call_internal_fn (stmt))
          {
--- gcc/ipa-pure-const.c.jj     2016-05-20 09:05:08.000000000 +0200
+++ gcc/ipa-pure-const.c        2016-08-30 13:14:34.134647275 +0200
@@ -508,6 +508,8 @@ special_builtin_state (enum pure_const_s
        case BUILT_IN_FRAME_ADDRESS:
        case BUILT_IN_APPLY:
        case BUILT_IN_APPLY_ARGS:
+       case BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT:
+       case BUILT_IN_ASAN_AFTER_DYNAMIC_INIT:
          *looping = false;
          *state = IPA_CONST;
          return true;
--- gcc/cp/decl2.c.jj   2016-08-10 00:21:07.000000000 +0200
+++ gcc/cp/decl2.c      2016-08-30 13:21:30.416518361 +0200
@@ -3861,7 +3861,7 @@ do_static_initialization_or_destruction
      in other compilation units, or at least those that haven't been
      initialized yet.  Variables that need dynamic construction in
      the current compilation unit are kept accessible.  */
-  if (flag_sanitize & SANITIZE_ADDRESS)
+  if (initp && (flag_sanitize & SANITIZE_ADDRESS))
     finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/false));
 
   node = vars;
@@ -3914,7 +3914,7 @@ do_static_initialization_or_destruction
 
   /* Revert what __asan_before_dynamic_init did by calling
      __asan_after_dynamic_init.  */
-  if (flag_sanitize & SANITIZE_ADDRESS)
+  if (initp && (flag_sanitize & SANITIZE_ADDRESS))
     finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/true));
 
   /* Finish up the init/destruct if-stmt body.  */
--- gcc/testsuite/g++.dg/asan/pr77396.C.jj      2016-08-30 12:31:43.357025231 
+0200
+++ gcc/testsuite/g++.dg/asan/pr77396.C 2016-08-30 13:16:56.096898220 +0200
@@ -0,0 +1,12 @@
+// PR sanitizer/77396
+// { dg-do run }
+// { dg-set-target-env-var ASAN_OPTIONS "check_initialization_order=true" }
+
+static int a = 0; 
+static int b = a; 
+
+int
+main ()
+{
+  return 0;
+}

        Jakub

Reply via email to