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)