Merge "__cxa_finalize: skip fflush call on dlclose" into qt-dev
diff --git a/libc/Android.bp b/libc/Android.bp
index 23ccbe3..a599028 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -762,12 +762,13 @@
                 "arch-arm/generic/bionic/strlen.c",
 
                 "arch-arm/bionic/__aeabi_read_tp.S",
-                "arch-arm/bionic/atomics_arm.c",
                 "arch-arm/bionic/__bionic_clone.S",
+                "arch-arm/bionic/__restore.S",
                 "arch-arm/bionic/_exit_with_stack_teardown.S",
+                "arch-arm/bionic/atomics_arm.c",
+                "arch-arm/bionic/bpabi.c",
                 "arch-arm/bionic/libcrt_compat.c",
                 "arch-arm/bionic/popcount_tab.c",
-                "arch-arm/bionic/__restore.S",
                 "arch-arm/bionic/setjmp.S",
                 "arch-arm/bionic/syscall.S",
                 "arch-arm/bionic/vfork.S",
@@ -1435,12 +1436,7 @@
             srcs: ["arch-x86/dynamic_function_dispatch.cpp"],
         },
         arm: {
-            srcs: [
-                "arch-arm/dynamic_function_dispatch.cpp",
-
-                // Workaround for b/120254692.
-                "arch-arm/dynamic_function_wrapper.S",
-            ],
+            srcs: ["arch-arm/dynamic_function_dispatch.cpp"],
         },
     },
 
diff --git a/libc/arch-arm/dynamic_function_wrapper.S b/libc/arch-arm/bionic/bpabi.c
similarity index 68%
rename from libc/arch-arm/dynamic_function_wrapper.S
rename to libc/arch-arm/bionic/bpabi.c
index 1d2842b..5c9cd99 100644
--- a/libc/arch-arm/dynamic_function_wrapper.S
+++ b/libc/arch-arm/bionic/bpabi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,12 +26,18 @@
  * SUCH DAMAGE.
  */
 
-#include <private/bionic_asm.h>
+extern long long __divdi3(long long, long long);
+extern unsigned long long __udivdi3(unsigned long long, unsigned long long);
 
-#define FUNCTION_DELEGATE(name, impl) \
-ENTRY(name); \
-    b impl; \
-END(name)
+long long __gnu_ldivmod_helper(long long a, long long b, long long* remainder) {
+  long long quotient = __divdi3(a, b);
+  *remainder = a - b * quotient;
+  return quotient;
+}
 
-FUNCTION_DELEGATE(strcmp, strcmp_internal)
-FUNCTION_DELEGATE(strlen, strlen_internal)
+unsigned long long __gnu_uldivmod_helper(unsigned long long a, unsigned long long b,
+                                         unsigned long long* remainder) {
+  unsigned long long quotient = __udivdi3(a, b);
+  *remainder = a - b * quotient;
+  return quotient;
+}
diff --git a/libc/arch-arm/dynamic_function_dispatch.cpp b/libc/arch-arm/dynamic_function_dispatch.cpp
index 09fd8f3..640f330 100644
--- a/libc/arch-arm/dynamic_function_dispatch.cpp
+++ b/libc/arch-arm/dynamic_function_dispatch.cpp
@@ -89,15 +89,11 @@
     return r0;
 }
 
-#define DEFINE_IFUNC_WITH_SUFFIX(name, suffix) \
-    name##_func name##suffix __attribute__((ifunc(#name "_resolver"))); \
+#define DEFINE_IFUNC(name) \
+    name##_func name __attribute__((ifunc(#name "_resolver"))); \
     __attribute__((visibility("hidden"))) \
     name##_func* name##_resolver()
 
-#define DEFINE_IFUNC(name) DEFINE_IFUNC_WITH_SUFFIX(name, )
-
-#define DEFINE_INTERNAL_IFUNC(name) DEFINE_IFUNC_WITH_SUFFIX(name, _internal)
-
 #define DECLARE_FUNC(type, name) \
     __attribute__((visibility("hidden"))) \
     type name
@@ -291,7 +287,7 @@
 }
 
 typedef int strcmp_func(const char* __lhs, const char* __rhs);
-DEFINE_INTERNAL_IFUNC(strcmp) {
+DEFINE_IFUNC(strcmp) {
     switch(get_cpu_variant()) {
         case kCortexA9:
             RETURN_FUNC(strcmp_func, strcmp_a9);
@@ -305,7 +301,7 @@
 }
 
 typedef size_t strlen_func(const char* __s);
-DEFINE_INTERNAL_IFUNC(strlen) {
+DEFINE_IFUNC(strlen) {
     switch(get_cpu_variant()) {
         case kCortexA9:
             RETURN_FUNC(strlen_func, strlen_a9);
diff --git a/libc/bionic/pthread_getschedparam.cpp b/libc/bionic/pthread_getschedparam.cpp
index ed1853b..765287f 100644
--- a/libc/bionic/pthread_getschedparam.cpp
+++ b/libc/bionic/pthread_getschedparam.cpp
@@ -28,9 +28,11 @@
 
 #include <errno.h>
 
+#include "private/bionic_defs.h"
 #include "private/ErrnoRestorer.h"
 #include "pthread_internal.h"
 
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
 int pthread_getschedparam(pthread_t t, int* policy, sched_param* param) {
   ErrnoRestorer errno_restorer;
 
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index d9ddf10..f92184e 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -199,6 +199,8 @@
                                                                    memory_order_relaxed))) {
             return 0;
         }
+    } else {
+        old_owner = atomic_load_explicit(&mutex.owner_tid, memory_order_relaxed);
     }
 
     if (tid != (old_owner & FUTEX_TID_MASK)) {
diff --git a/libc/bionic/pthread_setschedparam.cpp b/libc/bionic/pthread_setschedparam.cpp
index 8a02728..656fe32 100644
--- a/libc/bionic/pthread_setschedparam.cpp
+++ b/libc/bionic/pthread_setschedparam.cpp
@@ -30,9 +30,11 @@
 #include <pthread.h>
 #include <sched.h>
 
+#include "private/bionic_defs.h"
 #include "private/ErrnoRestorer.h"
 #include "pthread_internal.h"
 
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
 int pthread_setschedparam(pthread_t t, int policy, const sched_param* param) {
   ErrnoRestorer errno_restorer;
 
@@ -42,6 +44,7 @@
   return (sched_setscheduler(tid, policy, param) == -1) ? errno : 0;
 }
 
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
 int pthread_setschedprio(pthread_t t, int priority) {
   ErrnoRestorer errno_restorer;
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index d62eaec..b59df73 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1865,11 +1865,17 @@
 
     soinfo_list_t global_group = local_group_ns->get_global_group();
     bool linked = local_group.visit([&](soinfo* si) {
-      // Even though local group may contain accessible soinfos from other namesapces
+      // Even though local group may contain accessible soinfos from other namespaces
       // we should avoid linking them (because if they are not linked -> they
       // are in the local_group_roots and will be linked later).
       if (!si->is_linked() && si->get_primary_namespace() == local_group_ns) {
-        if (!si->link_image(global_group, local_group, extinfo, &relro_fd_offset) ||
+        const android_dlextinfo* link_extinfo = nullptr;
+        if (si == soinfos[0] || reserved_address_recursive) {
+          // Only forward extinfo for the first library unless the recursive
+          // flag is set.
+          link_extinfo = extinfo;
+        }
+        if (!si->link_image(global_group, local_group, link_extinfo, &relro_fd_offset) ||
             !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
           return false;
         }
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 3af52d4..eed84a4 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -538,6 +538,26 @@
   tf.fd = extinfo_.relro_fd;
 }
 
+TEST_F(DlExtRelroSharingTest, CheckRelroSizes) {
+  TemporaryFile tf1, tf2;
+  ASSERT_NOERROR(close(tf1.fd));
+  ASSERT_NOERROR(close(tf2.fd));
+
+  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameRecursive, tf1.path, false));
+  struct stat no_recursive;
+  ASSERT_NOERROR(fstat(extinfo_.relro_fd, &no_recursive));
+  tf1.fd = extinfo_.relro_fd;
+
+  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameRecursive, tf2.path, true));
+  struct stat with_recursive;
+  ASSERT_NOERROR(fstat(extinfo_.relro_fd, &with_recursive));
+  tf2.fd = extinfo_.relro_fd;
+
+  // RELRO file should end up bigger when we use the recursive flag, since it
+  // includes data for more than one library.
+  ASSERT_GT(with_recursive.st_size, no_recursive.st_size);
+}
+
 TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) {
   TemporaryFile tf; // // Use tf to get an unique filename.
   ASSERT_NOERROR(close(tf.fd));
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 7b64401..0bf8e29 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -1843,10 +1843,25 @@
   DISALLOW_COPY_AND_ASSIGN(PthreadMutex);
 };
 
+static int UnlockFromAnotherThread(pthread_mutex_t* mutex) {
+  pthread_t thread;
+  pthread_create(&thread, nullptr, [](void* mutex_voidp) -> void* {
+    pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(mutex_voidp);
+    intptr_t result = pthread_mutex_unlock(mutex);
+    return reinterpret_cast<void*>(result);
+  }, mutex);
+  void* result;
+  EXPECT_EQ(0, pthread_join(thread, &result));
+  return reinterpret_cast<intptr_t>(result);
+};
+
 static void TestPthreadMutexLockNormal(int protocol) {
   PthreadMutex m(PTHREAD_MUTEX_NORMAL, protocol);
 
   ASSERT_EQ(0, pthread_mutex_lock(&m.lock));
+  if (protocol == PTHREAD_PRIO_INHERIT) {
+    ASSERT_EQ(EPERM, UnlockFromAnotherThread(&m.lock));
+  }
   ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
   ASSERT_EQ(0, pthread_mutex_trylock(&m.lock));
   ASSERT_EQ(EBUSY, pthread_mutex_trylock(&m.lock));
@@ -1857,6 +1872,7 @@
   PthreadMutex m(PTHREAD_MUTEX_ERRORCHECK, protocol);
 
   ASSERT_EQ(0, pthread_mutex_lock(&m.lock));
+  ASSERT_EQ(EPERM, UnlockFromAnotherThread(&m.lock));
   ASSERT_EQ(EDEADLK, pthread_mutex_lock(&m.lock));
   ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
   ASSERT_EQ(0, pthread_mutex_trylock(&m.lock));
@@ -1873,7 +1889,9 @@
   PthreadMutex m(PTHREAD_MUTEX_RECURSIVE, protocol);
 
   ASSERT_EQ(0, pthread_mutex_lock(&m.lock));
+  ASSERT_EQ(EPERM, UnlockFromAnotherThread(&m.lock));
   ASSERT_EQ(0, pthread_mutex_lock(&m.lock));
+  ASSERT_EQ(EPERM, UnlockFromAnotherThread(&m.lock));
   ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
   ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
   ASSERT_EQ(0, pthread_mutex_trylock(&m.lock));