This is an archive of the discontinued LLVM Phabricator instance.

[Sanitizers] Order initialization of coverage and guard arrays
ClosedPublic

Authored by kutuzov.viktor.84 on Jan 9 2015, 5:01 AM.

Details

Summary

Since there's no guarantee the first InitializeGuardArray() call comes after Init(), we have to make sure the coverage is initialized before we add a guard array.

Diff Detail

Event Timeline

kutuzov.viktor.84 retitled this revision from to [Sanitizers] Order initialization of coverage and guard arrays.
kutuzov.viktor.84 updated this object.
kutuzov.viktor.84 edited the test plan for this revision. (Show Details)
kutuzov.viktor.84 added reviewers: kcc, samsonov.
kutuzov.viktor.84 added a subscriber: Unknown Object (MLST).
kcc edited edge metadata.Jan 9 2015, 12:52 PM

Since there's no guarantee the first InitializeGuardArray() call comes after Init(), we have to make sure the coverage is initialized before we add a guard array.

Could you please remind us why we can't guarantee this?
(Better yet, add a test)

Could you please remind us why we can't guarantee this?

Well, we probably can, but it seems it's not implemented for all cases. :-)

The instrumentation part of coverage (Instrumentation/SanitizerCoverage.cpp) generates module-scope global objects and puts calls to __sanitizer_cov_module_init() that is responsible for initializing module's guards to the ctors of these global objects. Similarly, __ubsan::InitIfNecessary() that takes care of the initialization of coverage (lib/ubsan/ubsan_init.cc) is either part of the .preinit_array or called from the ctor of another global object (ubsan_initializer)--depending on whether the SANITIZER_CAN_USE_PREINIT_ARRAY macro is defined. In the latter case, since these objects belong to different modules, they can generally be initialized in any order.

(Better yet, add a test)

Umm, I guess for this we would need to replace the ..._PREINIT_ARRAY macro with a run-time flag that controls the way the initialization is performed. Do we really want this?

kcc added inline comments.Jan 15 2015, 2:54 PM
lib/sanitizer_common/sanitizer_coverage_libcdep.cc
181

Maybe just call Init() here?

kutuzov.viktor.84 edited edge metadata.

Updated.

kcc accepted this revision.Jan 16 2015, 10:03 AM
kcc edited edge metadata.

LGTM

This revision is now accepted and ready to land.Jan 16 2015, 10:03 AM
This revision was automatically updated to reflect the committed changes.

There is actually a bigger problem here: if sanitizer_cov_module_init runs before asan_init (and that's possible since they are at the same priority), we will fail to activate asan, in particular - we won't update coverage and coverage_dir from activation flags.

I think the right fix would be reverting this change and lowering the priority of the coverate module initializer to 2 (keeping __asan_init at 1).

I think the right fix would be reverting this change and lowering the priority of the coverate module initializer to 2 (keeping __asan_init at 1).

AFAIU, priorities order initializers associated with the same module. If that is correct, then we couldn't fix this specific issue this way.

Priorities are per-DSO.
Constructors are emitted into numbered sections and sorted in the linker.

OK, it makes sense, thanks. However, while it works for Asan's __asan_init()t called from the code injected by the instrumentation part, it doesn't work for UBsan where, in omission of SANITIZER_CAN_USE_PREINIT_ARRAY, __ubsan::InitIfNecessary() is called from a regular constructor which has a lower priority than __sanitizer_cov_module_init. Maybe we should introduce instrumentation for UBsan or just replace the ubsan_initializer declaration:

class UbsanInitializer {
 public:
  UbsanInitializer() {
    InitIfNecessary();
  }
};
static UbsanInitializer ubsan_initializer;

with something like:

__attribute__((constructor(1)))
void __init_ubsan() {
  InitIfNecessary();
}

It sounds like __sancov module constructor should have the same logic as, for example, asan interceptors: initialize asan if not initialized yet. We could have a hook to "initialize the current sanitizer" available in sanitizer_common and call that.

This problem is tied to the concept of "current sanitizer" and the initialization order of UBSan which is currently very poorly defined (see ubsan init trying to guess if any other sanitizer has been initialized yet).

OK, it seems to be a design-level issue and needs some investigation. The question is: can we re-apply rL226440 for now to make things working with the existing UBsan tests on FreeBSD? Or, would you like me to prepare a patch introducing the ENSURE_UBSAN_INITED() kind of things? Thanks.

I think it's fine to reapply the original fix for now.