Tuesday, September 17, 2019

Sanitizing addresses of your Android NDK application.

In my attempt to squash all bugs, I ran my Android app with clang's address sanitizer. Because the steps are not trivial, I thought I would documents the process here.

This recipe makes some assumptions, though:

  • I'm on Linux.
  • I use AndroidStudio with CMake.
  • I run on the Android emulator. (A real device shouldn't be much different.)

First, we need to pass the -fsanitize=address flag to both the compiler and the linker. To compile your C/C++ code with this flag, use this in your CMakefile

target_compile_options(foo PRIVATE
        "$<$<CONFIG:DEBUG>:-fsanitize=address>"
)

And to link, add "-fsanitize=address" to your target_link_libraries.

Ok, now your shared-object has been built with the address sanitizer. But if you try to run it, you will see: dlopen failed: library "libclang_rt.asan-i686-android.so" not found.

Luckily, the Android NDK comes with the correct libraries, you just need to package them with your build. First locate where this library is on your system, doing:

$ locate libclang_rt.asan-i686-android.so
/home/bram/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/8.0.7/lib/linux/libclang_rt.asan-i686-android.so

You simply need to copy this alongside your own shared object file, as generated by cmake. In my case, it goes in: ./app/build/intermediates/cmake/debug/obj/x86/libclang_rt.asan-i686-android.so

If you now build and run your app on the emulator, your addresses will get sanitized. In my first run, it found a free() of a pointer that was never malloc()-ed in the Google Play Games SDK.

Note that if you want to do this on a ARM device, you would need libclang_rt.asan-arm-android.so and on a 64-bit ARM device, look for libclang_rt.asan-aarch64-android.so instead.

2 comments: