linker: remove link from external library on unload
am: b37d10cc80

Change-Id: I48901a8fbf4bc25fff1462e6086fc23b76ca2ba3
diff --git a/libc/bionic/pthread_cond.cpp b/libc/bionic/pthread_cond.cpp
index d36426c..c35d9f1 100644
--- a/libc/bionic/pthread_cond.cpp
+++ b/libc/bionic/pthread_cond.cpp
@@ -224,16 +224,18 @@
   return pthread_cond_timedwait_monotonic(cond_interface, mutex, abs_timeout);
 }
 
+// Force this function using CLOCK_MONOTONIC because it was always using
+// CLOCK_MONOTONIC in history.
 extern "C" int pthread_cond_timedwait_relative_np(pthread_cond_t* cond_interface,
                                                   pthread_mutex_t* mutex,
                                                   const timespec* rel_timeout) {
   timespec ts;
   timespec* abs_timeout = nullptr;
   if (rel_timeout != nullptr) {
-    absolute_timespec_from_timespec(ts, *rel_timeout, CLOCK_REALTIME);
+    absolute_timespec_from_timespec(ts, *rel_timeout, CLOCK_MONOTONIC);
     abs_timeout = &ts;
   }
-  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, true, abs_timeout);
+  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
 }
 
 extern "C" int pthread_cond_timeout_np(pthread_cond_t* cond_interface,
diff --git a/linker/linker.cpp b/linker/linker.cpp
index a287cf4..0ab8bd2 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -155,32 +155,35 @@
 static soinfo* sonext;
 static soinfo* somain; // main process, always the one after libdl_info
 
-static const char* const kDefaultLdPaths[] = {
 #if defined(__LP64__)
-  "/system/lib64",
-  "/vendor/lib64",
+static const char* const kSystemLibDir     = "/system/lib64";
+static const char* const kVendorLibDir     = "/vendor/lib64";
+static const char* const kAsanSystemLibDir = "/data/lib64";
+static const char* const kAsanVendorLibDir = "/data/vendor/lib64";
 #else
-  "/system/lib",
-  "/vendor/lib",
+static const char* const kSystemLibDir     = "/system/lib";
+static const char* const kVendorLibDir     = "/vendor/lib";
+static const char* const kAsanSystemLibDir = "/data/lib";
+static const char* const kAsanVendorLibDir = "/data/vendor/lib";
 #endif
+
+static const char* const kDefaultLdPaths[] = {
+  kSystemLibDir,
+  kVendorLibDir,
   nullptr
 };
 
 static const char* const kAsanDefaultLdPaths[] = {
-#if defined(__LP64__)
-  "/data/lib64",
-  "/system/lib64",
-  "/data/vendor/lib64",
-  "/vendor/lib64",
-#else
-  "/data/lib",
-  "/system/lib",
-  "/data/vendor/lib",
-  "/vendor/lib",
-#endif
+  kAsanSystemLibDir,
+  kSystemLibDir,
+  kAsanVendorLibDir,
+  kVendorLibDir,
   nullptr
 };
 
+// Is ASAN enabled?
+static bool g_is_asan = false;
+
 static bool is_system_library(const std::string& realpath) {
   for (const auto& dir : g_default_namespace.get_default_library_paths()) {
     if (file_is_in_dir(realpath, dir)) {
@@ -190,12 +193,16 @@
   return false;
 }
 
-#if defined(__LP64__)
-static const char* const kSystemLibDir = "/system/lib64";
-#else
-static const char* const kSystemLibDir = "/system/lib";
-#endif
-
+// Checks if the file exists and not a directory.
+static bool file_exists(const char* path) {
+  int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC));
+  if (fd == -1) {
+    return false;
+  } else {
+    close(fd);
+    return true;
+  }
+}
 static std::string dirname(const char *path);
 
 // TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
@@ -2373,8 +2380,27 @@
     }
   }
 
+  std::string asan_name_holder;
+
+  const char* translated_name = name;
+  if (g_is_asan) {
+    if (file_is_in_dir(name, kSystemLibDir)) {
+      asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(name);
+      if (file_exists(asan_name_holder.c_str())) {
+        translated_name = asan_name_holder.c_str();
+        PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
+      }
+    } else if (file_is_in_dir(name, kVendorLibDir)) {
+      asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(name);
+      if (file_exists(asan_name_holder.c_str())) {
+        translated_name = asan_name_holder.c_str();
+        PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
+      }
+    }
+  }
+
   ProtectedDataGuard guard;
-  soinfo* si = find_library(ns, name, flags, extinfo, caller);
+  soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
   if (si != nullptr) {
     si->call_constructors();
     return si->to_handle();
@@ -2507,8 +2533,8 @@
     find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
 
     if (candidate == nullptr) {
-      DL_ERR("error initializing public namespace: \"%s\" was not found"
-             " in the default namespace", soname.c_str());
+      DL_ERR("error initializing public namespace: a library with soname \"%s\""
+             " was not found in the default namespace", soname.c_str());
       return false;
     }
 
@@ -4125,6 +4151,7 @@
   const char* bname = basename(interp);
   if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
     g_default_ld_paths = kAsanDefaultLdPaths;
+    g_is_asan = true;
   } else {
     g_default_ld_paths = kDefaultLdPaths;
   }
@@ -4199,12 +4226,15 @@
     }
   }
 
-  const char* executable_path = get_executable_path();
   struct stat file_stat;
-  if (TEMP_FAILURE_RETRY(stat(executable_path, &file_stat)) != 0) {
-    __libc_fatal("unable to stat file for the executable \"%s\": %s", executable_path, strerror(errno));
+  // Stat "/proc/self/exe" instead of executable_path because
+  // the executable could be unlinked by this point and it should
+  // not cause a crash (see http://b/31084669)
+  if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
+    __libc_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
   }
 
+  const char* executable_path = get_executable_path();
   soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
   if (si == nullptr) {
     __libc_fatal("Couldn't allocate soinfo: out of memory?");
diff --git a/linker/linker.h b/linker/linker.h
index 3ea601f..49eee78 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -59,6 +59,12 @@
       __libc_format_fd(2, "\n"); \
     } while (false)
 
+#define DL_ERR_AND_LOG(fmt, x...) \
+  do { \
+    DL_ERR(fmt, x); \
+    PRINT(fmt, x); \
+  } while (false)
+
 #if defined(__LP64__)
 #define ELFW(what) ELF64_ ## what
 #else
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 136e432..3b60460 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -248,14 +248,15 @@
   return true;
 }
 
-bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size) {
+bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment) {
   off64_t range_start;
   off64_t range_end;
 
   return safe_add(&range_start, file_offset_, offset) &&
          safe_add(&range_end, range_start, size) &&
-         range_start < file_size_ &&
-         range_end <= file_size_;
+         (range_start < file_size_) &&
+         (range_end <= file_size_) &&
+         ((offset % alignment) == 0);
 }
 
 // Loads the program header table from an ELF file into a read-only private
@@ -272,8 +273,11 @@
 
   // Boundary checks
   size_t size = phdr_num_ * sizeof(ElfW(Phdr));
-  if (!CheckFileRange(header_.e_phoff, size)) {
-    DL_ERR("\"%s\" has invalid phdr offset/size", name_.c_str());
+  if (!CheckFileRange(header_.e_phoff, size, alignof(ElfW(Phdr)))) {
+    DL_ERR_AND_LOG("\"%s\" has invalid phdr offset/size: %zu/%zu",
+                   name_.c_str(),
+                   static_cast<size_t>(header_.e_phoff),
+                   size);
     return false;
   }
 
@@ -290,13 +294,16 @@
   shdr_num_ = header_.e_shnum;
 
   if (shdr_num_ == 0) {
-    DL_ERR("\"%s\" has no section headers", name_.c_str());
+    DL_ERR_AND_LOG("\"%s\" has no section headers", name_.c_str());
     return false;
   }
 
   size_t size = shdr_num_ * sizeof(ElfW(Shdr));
-  if (!CheckFileRange(header_.e_shoff, size)) {
-    DL_ERR("\"%s\" has invalid shdr offset/size", name_.c_str());
+  if (!CheckFileRange(header_.e_shoff, size, alignof(const ElfW(Shdr)))) {
+    DL_ERR_AND_LOG("\"%s\" has invalid shdr offset/size: %zu/%zu",
+                   name_.c_str(),
+                   static_cast<size_t>(header_.e_shoff),
+                   size);
     return false;
   }
 
@@ -320,26 +327,27 @@
   }
 
   if (dynamic_shdr == nullptr) {
-    DL_ERR("\"%s\" .dynamic section header was not found", name_.c_str());
+    DL_ERR_AND_LOG("\"%s\" .dynamic section header was not found", name_.c_str());
     return false;
   }
 
   if (dynamic_shdr->sh_link >= shdr_num_) {
-    DL_ERR("\"%s\" .dynamic section has invalid sh_link: %d", name_.c_str(), dynamic_shdr->sh_link);
+    DL_ERR_AND_LOG("\"%s\" .dynamic section has invalid sh_link: %d",
+                   name_.c_str(),
+                   dynamic_shdr->sh_link);
     return false;
   }
 
   const ElfW(Shdr)* strtab_shdr = &shdr_table_[dynamic_shdr->sh_link];
 
   if (strtab_shdr->sh_type != SHT_STRTAB) {
-    DL_ERR("\"%s\" .dynamic section has invalid link(%d) sh_type: %d (expected SHT_STRTAB)",
-           name_.c_str(), dynamic_shdr->sh_link, strtab_shdr->sh_type);
+    DL_ERR_AND_LOG("\"%s\" .dynamic section has invalid link(%d) sh_type: %d (expected SHT_STRTAB)",
+                   name_.c_str(), dynamic_shdr->sh_link, strtab_shdr->sh_type);
     return false;
   }
 
-  if (!CheckFileRange(dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
-    DL_ERR("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
-    PRINT("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
+  if (!CheckFileRange(dynamic_shdr->sh_offset, dynamic_shdr->sh_size, alignof(const ElfW(Dyn)))) {
+    DL_ERR_AND_LOG("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
     return false;
   }
 
@@ -350,9 +358,9 @@
 
   dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_fragment_.data());
 
-  if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
-    DL_ERR("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
-           name_.c_str());
+  if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size, alignof(const char))) {
+    DL_ERR_AND_LOG("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
+                   name_.c_str());
     return false;
   }
 
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 89ec094..d6276ed 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -65,7 +65,7 @@
   bool LoadSegments();
   bool FindPhdr();
   bool CheckPhdr(ElfW(Addr));
-  bool CheckFileRange(ElfW(Addr) offset, size_t size);
+  bool CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment);
 
   bool did_read_;
   bool did_load_;
diff --git a/tests/pty_test.cpp b/tests/pty_test.cpp
index 91d1f5e..a371434 100644
--- a/tests/pty_test.cpp
+++ b/tests/pty_test.cpp
@@ -14,11 +14,17 @@
  * limitations under the License.
  */
 
+#include <pty.h>
+
 #include <gtest/gtest.h>
 
-#include <pty.h>
+#include <pthread.h>
 #include <sys/ioctl.h>
 
+#include <atomic>
+
+#include <android-base/file.h>
+
 #include "utils.h"
 
 TEST(pty, openpty) {
@@ -64,3 +70,82 @@
 
   close(master);
 }
+
+struct PtyReader_28979140_Arg {
+ int slave_fd;
+ uint32_t data_count;
+ bool finished;
+ std::atomic<bool> matched;
+};
+
+static void PtyReader_28979140(PtyReader_28979140_Arg* arg) {
+  arg->finished = false;
+  cpu_set_t cpus;
+  ASSERT_EQ(0, sched_getaffinity(0, sizeof(cpu_set_t), &cpus));
+  CPU_CLR(0, &cpus);
+  ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));
+
+  uint32_t counter = 0;
+  while (counter <= arg->data_count) {
+    char buf[4096];  // Use big buffer to read to hit the bug more easily.
+    size_t to_read = std::min(sizeof(buf), (arg->data_count + 1 - counter) * sizeof(uint32_t));
+    ASSERT_TRUE(android::base::ReadFully(arg->slave_fd, buf, to_read));
+    size_t num_of_value = to_read / sizeof(uint32_t);
+    uint32_t* p = reinterpret_cast<uint32_t*>(buf);
+    while (num_of_value-- > 0) {
+      if (*p++ != counter++) {
+        arg->matched = false;
+      }
+    }
+  }
+  close(arg->slave_fd);
+  arg->finished = true;
+}
+
+TEST(pty, bug_28979140) {
+  // This test is to test a kernel bug, which uses a lock free ring-buffer to
+  // pass data through a raw pty, but missing necessary memory barriers.
+  if (sysconf(_SC_NPROCESSORS_ONLN) == 1) {
+    GTEST_LOG_(INFO) << "This test tests bug happens only on multiprocessors.";
+    return;
+  }
+  constexpr uint32_t TEST_DATA_COUNT = 200000;
+
+  // 1. Open raw pty.
+  int master;
+  int slave;
+  ASSERT_EQ(0, openpty(&master, &slave, nullptr, nullptr, nullptr));
+  termios tattr;
+  ASSERT_EQ(0, tcgetattr(slave, &tattr));
+  cfmakeraw(&tattr);
+  ASSERT_EQ(0, tcsetattr(slave, TCSADRAIN, &tattr));
+
+  // 2. Create thread for slave reader.
+  pthread_t thread;
+  PtyReader_28979140_Arg arg;
+  arg.slave_fd = slave;
+  arg.data_count = TEST_DATA_COUNT;
+  arg.matched = true;
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+                              reinterpret_cast<void*(*)(void*)>(PtyReader_28979140),
+                              &arg));
+
+  // 3. Make master thread and slave thread running on different cpus:
+  // master thread uses cpu 0, and slave thread uses other cpus.
+  cpu_set_t cpus;
+  CPU_ZERO(&cpus);
+  CPU_SET(0, &cpus);
+  ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));
+
+  // 4. Send data to slave.
+  uint32_t counter = 0;
+  while (counter <= TEST_DATA_COUNT) {
+    ASSERT_TRUE(android::base::WriteFully(master, &counter, sizeof(counter)));
+    ASSERT_TRUE(arg.matched) << "failed at count = " << counter;
+    counter++;
+  }
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+  ASSERT_TRUE(arg.finished);
+  ASSERT_TRUE(arg.matched);
+  close(master);
+}
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index ddb6c77..62401a6 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -221,14 +221,21 @@
   ASSERT_EQ(MAP_FAILED, mremap(nullptr, 0, 0, 0));
 }
 
-const size_t huge = size_t(PTRDIFF_MAX) + 1;
+constexpr size_t kHuge = size_t(PTRDIFF_MAX) + 1;
 
 TEST(sys_mman, mmap_PTRDIFF_MAX) {
-  ASSERT_EQ(MAP_FAILED, mmap(nullptr, huge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+  ASSERT_EQ(MAP_FAILED, mmap(nullptr, kHuge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
 }
 
 TEST(sys_mman, mremap_PTRDIFF_MAX) {
   void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   ASSERT_NE(MAP_FAILED, map);
-  ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, huge, MREMAP_MAYMOVE));
+  ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, kHuge, MREMAP_MAYMOVE));
+}
+
+TEST(sys_mman, mmap_bug_27265969) {
+  char* base = reinterpret_cast<char*>(mmap(nullptr, PAGE_SIZE * 2, PROT_EXEC | PROT_READ,
+                                            MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
+  // Some kernels had bugs that would cause segfaults here...
+  __builtin___clear_cache(base, base + (PAGE_SIZE * 2));
 }