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