On Wed, 31 Aug 2016, Jakub Jelinek wrote:

> 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?

Hmm, maybe simply do

  if (gimple_call_builtin_p (g, BUILT_IN_ASAN_AFTER_DYNAMIC_INIT))
    {
      gimple *def = SSA_NAME_DEF_STMT (gimple_vuse (g));
      if (gimple_call_builtin_p (def, BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT))
        ... remove both ...

intervening non-memory-def stmts do not really matter, do they?  If
loads matter then checking for the single-vdef-use of
BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT to be BUILT_IN_ASAN_AFTER_DYNAMIC_INIT
would also work.

Otherwise looks ok but I wonder why libasan needs to assert this ..

Richard.

> 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
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 
21284 (AG Nuernberg)

Reply via email to