[compiler-rt] [llvm] [asan] Limit priority of ctor to kMax-1 (PR #101772)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 2 21:15:44 PDT 2024
MaskRay wrote:
> > > > asan changing the priority of a llvm.global_ctors element might be surprising. Is this change to work with some specific code or specific IR code generators that use 65535 (instrumentation cannot do anything with `.init_array.65535` in inline assembly)? Can we change these tools instead?
> > >
> > >
> > > No. The goal to be able to call `asan` runtime callback just after the last dynamic constructor.
> >
> >
> > Is there more information about this decision? What would break if the order is different?
> > So priority 65535 is unsuffixed `.init_array`. Lots of code might use inline asm `.section .init_array,"aw", at init_array`. Instrumentation cannot safely do anything with them (e.g. adding `.65534` suffix).
> > If instrumentation changes IR 65535 elements in `llvm.global_ctors` but not asm `.section .init_array`, this could be risky as well.
> > Execution order:
> > ```
> > a.o:(.init_array.1) b.o:(.init_array.1)
> > a.o:(.init_array.2) b.o:(.init_array.2)
> > ...
> > a.o:(.init_array.65533) b.o:(.init_array.65533)
> > a.o:(.init_array.65534) b.o:(.init_array.65534)
> > a.o:(.init_array) b.o:(.init_array)
> > ```
>
> I see what you mean. :(
>
> > Is there more information about this decision? What would break if the order is different?
>
> There is O(N^2) in init order checking, and it's heavy on our profiles, especial with dynamic linking:
>
> Now we for each TU:
>
> 1. poison ALL program globals, except the current TU
> 2. init globals in TU
> 3. Unpoison ALL globals
> 4. repeat
>
> With patches:
>
> 1. unpoison globals in prev TU
> 2. poison globals in the current TU
> 3. init globals in TU
> 4. do nothing
> 5. repeat
>
> But at the end we need to unpoison all globals once, before we get to `main()` So I didn't figure out a better way to call code reliably at the end of `.init_array`
I see. The ODR indicator optimization might intrigue you to investigate the initialization order check performance:) I have some notes about the performance issue and I did not find a good way to improve the coverage (`b.so` accessing `a`) or fix the performance issue without main/`__libc_start_main` hacks, and I did not think further.
(`clang++ -fsanitizje=address a0.cc a1.cc b.so -o a`) In `check_initialization_order=1,strict_init_order=1` mode,
* globals in `b0.cc` and `b1.cc` are registered
* b0.cc: `__asan_before_dynamic_init` poisons `b1`. Global initialization is run
* b1.cc: `__asan_before_dynamic_init` poisons `b0`. Global initialization is run
* globals in `a0.cc` and `a1.cc` are registered
* a0.cc: `__asan_before_dynamic_init` poisons `b0,b1,a1`. Global initialization is run. `__asan_register_globals` unpoisons `b0,b1,a1`
* a1.cc: `__asan_before_dynamic_init` poisons `b0,b1,a0`. Global initialization is run. `__asan_register_globals` unpoisons `b0,b1,a0`
Note, violations due to `b.so` accessing `a` cannot be detected.
---
`-Wl,--wrap=main`, while ugly, might be a solution but it is incompatible with existing `-Wl,--wrap=main` uses, so this might need to be opt-in or some opt-out mechanism might be needed.
https://github.com/llvm/llvm-project/pull/101772
More information about the llvm-commits
mailing list