Fix gettid() after clone().

The tid is cached in the pthread_internal_t and is properly re-set after fork()
and pthread_create(). But after a plain clone() the value is stale from the
parent.

Test: mmma bionic/tests
Test: bionic-unit-tests-static --gtest_filter=*fork*:*clone*
Test: m checkbuild tests
Test: angler boots

Bug: 32305649
Change-Id: I026d416d1537484cd3e05c8493a35e5ed2acc8ed
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 80ebf6b..660679f 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -434,7 +434,7 @@
   ASSERT_NE(fork_result, -1);
   if (fork_result == 0) {
     // We're the child.
-    AssertGetPidCorrect();
+    ASSERT_NO_FATAL_FAILURE(AssertGetPidCorrect());
     ASSERT_EQ(parent_pid, getppid());
     _exit(123);
   } else {
@@ -444,14 +444,100 @@
   }
 }
 
+// gettid() is marked as __attribute_const__, which will have the compiler
+// optimize out multiple calls to gettid in the same function. This wrapper
+// defeats that optimization.
+static __attribute__((__noinline__)) pid_t GetTidForTest() {
+  __asm__("");
+  return gettid();
+}
+
+static void AssertGetTidCorrect() {
+  // The loop is just to make manual testing/debugging with strace easier.
+  pid_t gettid_syscall_result = syscall(__NR_gettid);
+  for (size_t i = 0; i < 128; ++i) {
+    ASSERT_EQ(gettid_syscall_result, GetTidForTest());
+  }
+}
+
+static void TestGetTidCachingWithFork(int (*fork_fn)()) {
+  pid_t parent_tid = GetTidForTest();
+  ASSERT_EQ(syscall(__NR_gettid), parent_tid);
+
+  pid_t fork_result = fork_fn();
+  ASSERT_NE(fork_result, -1);
+  if (fork_result == 0) {
+    // We're the child.
+    EXPECT_EQ(syscall(__NR_getpid), syscall(__NR_gettid));
+    EXPECT_EQ(getpid(), GetTidForTest()) << "real tid is " << syscall(__NR_gettid)
+                                         << ", pid is " << syscall(__NR_getpid);
+    ASSERT_NO_FATAL_FAILURE(AssertGetTidCorrect());
+    _exit(123);
+  } else {
+    // We're the parent.
+    ASSERT_EQ(parent_tid, GetTidForTest());
+    AssertChildExited(fork_result, 123);
+  }
+}
+
 TEST(UNISTD_TEST, getpid_caching_and_fork) {
   TestGetPidCachingWithFork(fork);
 }
 
+TEST(UNISTD_TEST, gettid_caching_and_fork) {
+  TestGetTidCachingWithFork(fork);
+}
+
 TEST(UNISTD_TEST, getpid_caching_and_vfork) {
   TestGetPidCachingWithFork(vfork);
 }
 
+static int CloneLikeFork() {
+  return clone(nullptr, nullptr, SIGCHLD, nullptr);
+}
+
+TEST(UNISTD_TEST, getpid_caching_and_clone_process) {
+  TestGetPidCachingWithFork(CloneLikeFork);
+}
+
+TEST(UNISTD_TEST, gettid_caching_and_clone_process) {
+  TestGetTidCachingWithFork(CloneLikeFork);
+}
+
+static int CloneAndSetTid() {
+  pid_t child_tid = 0;
+  pid_t parent_tid = GetTidForTest();
+
+  int rv = clone(nullptr, nullptr, CLONE_CHILD_SETTID | SIGCHLD, nullptr, nullptr, nullptr, &child_tid);
+  EXPECT_NE(-1, rv);
+
+  if (rv == 0) {
+    // Child.
+    EXPECT_EQ(child_tid, GetTidForTest());
+    EXPECT_NE(child_tid, parent_tid);
+  } else {
+    EXPECT_NE(child_tid, GetTidForTest());
+    EXPECT_NE(child_tid, parent_tid);
+    EXPECT_EQ(GetTidForTest(), parent_tid);
+  }
+
+  return rv;
+}
+
+TEST(UNISTD_TEST, gettid_caching_and_clone_process_settid) {
+  TestGetTidCachingWithFork(CloneAndSetTid);
+}
+
+static int CloneStartRoutine(int (*start_routine)(void*)) {
+  void* child_stack[1024];
+  int clone_result = clone(start_routine, &child_stack[1024], CLONE_NEWNS | SIGCHLD, NULL);
+  if (clone_result == -1 && errno == EPERM && getuid() != 0) {
+    GTEST_LOG_(INFO) << "This test only works if you have permission to CLONE_NEWNS; try running as root.\n";
+    return clone_result;
+  }
+  return clone_result;
+}
+
 static int GetPidCachingCloneStartRoutine(void*) {
   AssertGetPidCorrect();
   return 123;
@@ -461,12 +547,7 @@
   pid_t parent_pid = getpid();
   ASSERT_EQ(syscall(__NR_getpid), parent_pid);
 
-  void* child_stack[1024];
-  int clone_result = clone(GetPidCachingCloneStartRoutine, &child_stack[1024], CLONE_NEWNS | SIGCHLD, NULL);
-  if (clone_result == -1 && errno == EPERM && getuid() != 0) {
-    GTEST_LOG_(INFO) << "This test only works if you have permission to CLONE_NEWNS; try running as root.\n";
-    return;
-  }
+  int clone_result = CloneStartRoutine(GetPidCachingCloneStartRoutine);
   ASSERT_NE(clone_result, -1);
 
   ASSERT_EQ(parent_pid, getpid());
@@ -474,6 +555,23 @@
   AssertChildExited(clone_result, 123);
 }
 
+static int GetTidCachingCloneStartRoutine(void*) {
+  AssertGetTidCorrect();
+  return 123;
+}
+
+TEST(UNISTD_TEST, gettid_caching_and_clone) {
+  pid_t parent_tid = GetTidForTest();
+  ASSERT_EQ(syscall(__NR_gettid), parent_tid);
+
+  int clone_result = CloneStartRoutine(GetTidCachingCloneStartRoutine);
+  ASSERT_NE(clone_result, -1);
+
+  ASSERT_EQ(parent_tid, GetTidForTest());
+
+  AssertChildExited(clone_result, 123);
+}
+
 static void* GetPidCachingPthreadStartRoutine(void*) {
   AssertGetPidCorrect();
   return NULL;
@@ -492,6 +590,25 @@
   ASSERT_EQ(NULL, result);
 }
 
+static void* GetTidCachingPthreadStartRoutine(void*) {
+  AssertGetTidCorrect();
+  uint64_t tid = GetTidForTest();
+  return reinterpret_cast<void*>(tid);
+}
+
+TEST(UNISTD_TEST, gettid_caching_and_pthread_create) {
+  pid_t parent_tid = GetTidForTest();
+
+  pthread_t t;
+  ASSERT_EQ(0, pthread_create(&t, NULL, GetTidCachingPthreadStartRoutine, &parent_tid));
+
+  ASSERT_EQ(parent_tid, GetTidForTest());
+
+  void* result;
+  ASSERT_EQ(0, pthread_join(t, &result));
+  ASSERT_NE(static_cast<uint64_t>(parent_tid), reinterpret_cast<uint64_t>(result));
+}
+
 class UNISTD_DEATHTEST : public BionicDeathTest {};
 
 TEST_F(UNISTD_DEATHTEST, abort) {