[asan] Fall back to /proc/$PID/maps on Android L.
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Wed, 6 May 2015 18:55:31 +0000 (18:55 +0000)
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Wed, 6 May 2015 18:55:31 +0000 (18:55 +0000)
dl_iterate_phdr is somewhat broken in L (see the code for details).
We add runtime OS version detection and fallback to /proc/maps on L or earlier.
This fixes a number of ASan tests on L.

llvm-svn: 236628

compiler-rt/lib/sanitizer_common/sanitizer_common.h
compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc

index 2e920c8..01a15da 100644 (file)
@@ -622,11 +622,13 @@ void AndroidLogInit();
 void AndroidLogWrite(const char *buffer);
 void GetExtraActivationFlags(char *buf, uptr size);
 void SanitizerInitializeUnwinder();
+u32 AndroidGetApiLevel();
 #else
 INLINE void AndroidLogInit() {}
 INLINE void AndroidLogWrite(const char *buffer_unused) {}
 INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; }
 INLINE void SanitizerInitializeUnwinder() {}
+INLINE u32 AndroidGetApiLevel() { return 0; }
 #endif
 
 void *internal_start_thread(void(*func)(void*), void *arg);
index 14f0c91..40cedf3 100644 (file)
@@ -46,9 +46,7 @@
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
-#if !SANITIZER_ANDROID
 #include <link.h>
-#endif
 #include <pthread.h>
 #include <sched.h>
 #include <sys/mman.h>
@@ -964,6 +962,46 @@ void GetExtraActivationFlags(char *buf, uptr size) {
   CHECK(size > PROP_VALUE_MAX);
   __system_property_get("asan.options", buf);
 }
+
+#if __ANDROID_API__ < 21
+extern "C" __attribute__((weak)) int dl_iterate_phdr(
+    int (*)(struct dl_phdr_info *, size_t, void *), void *);
+#endif
+
+static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
+                                   void *data) {
+  // Any name starting with "lib" indicated a bug in L where library base names
+  // are returned instead of paths.
+  if (info->dlpi_name && info->dlpi_name[0] == 'l' &&
+      info->dlpi_name[1] == 'i' && info->dlpi_name[2] == 'b') {
+    *(bool *)data = true;
+    return 1;
+  }
+  return 0;
+}
+
+static atomic_uint32_t android_api_level;
+
+static u32 AndroidDetectApiLevel() {
+  if (!dl_iterate_phdr)
+    return 19; // K or lower
+  bool base_name_seen = false;
+  dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen);
+  if (base_name_seen)
+    return 22; // L MR1
+  return 23;   // post-L
+  // Plain L (API level 21) is completely broken wrt ASan and not very
+  // interesting to detect.
+}
+
+u32 AndroidGetApiLevel() {
+  u32 level = atomic_load(&android_api_level, memory_order_relaxed);
+  if (level) return level;
+  level = AndroidDetectApiLevel();
+  atomic_store(&android_api_level, level, memory_order_relaxed);
+  return level;
+}
+
 #endif
 
 bool IsDeadlySignal(int signum) {
index 7db7ce4..ba844be 100644 (file)
@@ -456,10 +456,11 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr(
 uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                       string_predicate_t filter) {
 #if SANITIZER_ANDROID && __ANDROID_API__ < 21
-  // Fall back to /proc/maps if dl_iterate_phdr is not available.
+  u32 api_level = AndroidGetApiLevel();
+  // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken.
   // The runtime check allows the same library to work with
   // both K and L (and future) Android releases.
-  if (!dl_iterate_phdr) {
+  if (api_level <= 22) { // L or earlier
     MemoryMappingLayout memory_mapping(false);
     return memory_mapping.DumpListOfModules(modules, max_modules, filter);
   }