3

I'm trying to globally configure AddressSanitizer (ASan) for multiple executables in my C++ project by defining the __asan_default_options() function, like this:

extern "C" const char* __asan_default_options() {
    return "allow_user_poisoning=false";
}

I placed this function in a .cpp file, built it into a static library, and then linked that library into an executable. However, ASan does not seem to respect the options.

Note: If I instead add the .cpp file directly to the sources of each executable, it works as expected.

Note: I also found that using a CMake OBJECT library works. For example:

add_library(configAsan OBJECT asan_flags.cpp)
target_link_libraries(my_exec PRIVATE configAsan)

Question: Why does defining __asan_default_options() in a static library not work ?

I tried

add_library(configAsan STATIC asan_flags.cpp)
target_link_libraries(my_exec PRIVATE configAsan)

where my executable looks like this:

int main(int argc, char* argv[]) {
 int* p = new int[4];
 __asan_poison_memory_region(p + 1, 3 * sizeof(int));
 std::cout << "Accessing poisoned memory: " << p[1] << "\n"; 
 delete[] p; 
 return 0; 
}

Expected No use after poison error when running my_exec but got: Error message

4
  • Using an object library is a good solution Commented Jun 27 at 16:23
  • @AlanBirtles I agree, but I've been tinkering with these sanitizers a quite a bit and getting it all to work as one would normally do it is, in my experience, not always as straight forward as it may seem. I would very much like to see someone more experienced than me answer this question. I therefore vote to reopen, just because it just may reveal som nice things. Commented Jun 28 at 0:20
  • @TedLyngmo the question isn't really anything to do with sanitisers, it's just exporting a symbol from a static library which is covered by the duplicates Commented Jun 28 at 6:44
  • My guess is that the file doesn't even get linked into the executable, because there is no symbol to be resolved that pulls it in. Thre way such optional items work is that they usually have the default in a library; if you provide it in your executable then the library-version is not needed anymore. However, that doesn't work with libraries overriding libraries... Commented Jun 28 at 8:42

1 Answer 1

1

Refer to the Stackoverflow tag wiki on static libraries

From that you will learn that if an object file file.o is archived in a static library libstat.a and then libstat.a is input to the linkage of an executable, the linker by default will extract file.o from libstat.a and link file.o into the executable only if file.o provides a definition of at least one symbol that has been referenced in some object file already linked into the executable, but not yet defined by any file that has been linked. In short, file.o will be extracted and linked only if it provides a definition that the linkage already needs to resolve some symbol reference.

The file asan_flags.o, compiled from your asan_flags.cpp and archived as libconfigAsan.a(asanFlags.o), defines no symbol that has been referenced in any file already linked when the linker examines your libconfigAsan.a, so asan_flags.o is not extracted and linked. It might as well not exist.

Later in the linkage of your executable, the linker consumes libasan.so itself, which serves to resolve your reference to __asan_poison_memory_region and introduces a call to __asan_default_options into the linkage, which must be resolved. But by now your definition of that function in libconfigAsan.a(asan_flags.o) has been passed over and ignored. The linker finds a default definition of __asan_default_options in libasan.so itself and binds the reference to that definition - which is in fact a no-op. Hence the outcome you observe.

To override that no-op default definition with your own, you must make asan_flags.o be linked before libasan.so is consumed. One good way to do that is simply to input asan_flags.o explicitly to the linkage, not as an archive member of a static library. This is what you have achieved in CMake by building asan_flags.cpp as a CMake object library: that just compiles it to asan_flags.o. Any object file that is input to the linker explicitly is linked into the executable unconditionally. If an explicit object file was not unconditionally linked then no symbol references could get into the executable unconditionally and linkage could never get started.

This way, when libasan.so is consumed, your definition of __asan_default_options is already linked and references to that symbol will be bound to that definition: the linker will not seek another definition of a symbol that is already defined. (Even if you chose to link libasan statically, its default definition of __asan_default_options cannot possibly provoke a multiple definition error in collision with your own, because the default definition is weak and will still be overriden by your own.)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.