Track whether a thread is currently vforked.

Our various fd debugging facilities get extremely confused by a vforked
process closing file descriptors in preparation to exec: fdsan can
abort, and fdtrack will delete backtraces for any file descriptors that
get closed. Keep track of whether we're in a vforked child in order to
be able to detect this.

Bug: http://b/153926671
Test: 32/64-bit bionic-unit-tests on blueline, x86_64 emulator
Change-Id: I8a082fd06bfdfef0e2a88dbce350b6f667f7df9f
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index f3b08c3..6b28561 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -41,6 +41,10 @@
 
 #include "private/get_cpu_count_from_string.h"
 
+#if defined(__BIONIC__)
+#include "bionic/pthread_internal.h"
+#endif
+
 #if defined(NOFORTIFY)
 #define UNISTD_TEST unistd_nofortify
 #define UNISTD_DEATHTEST unistd_nofortify_DeathTest
@@ -431,6 +435,45 @@
   TestSyncFunction(syncfs);
 }
 
+TEST(UNISTD_TEST, vfork) {
+#if defined(__BIONIC__)
+  pthread_internal_t* self = __get_thread();
+
+  pid_t cached_pid;
+  ASSERT_TRUE(self->get_cached_pid(&cached_pid));
+  ASSERT_EQ(syscall(__NR_getpid), cached_pid);
+  ASSERT_FALSE(self->is_vforked());
+
+  pid_t rc = vfork();
+  ASSERT_NE(-1, rc);
+  if (rc == 0) {
+    if (self->get_cached_pid(&cached_pid)) {
+      const char* error = "__get_thread()->cached_pid_ set after vfork\n";
+      write(STDERR_FILENO, error, strlen(error));
+      _exit(1);
+    }
+
+    if (!self->is_vforked()) {
+      const char* error = "__get_thread()->vforked_ not set after vfork\n";
+      write(STDERR_FILENO, error, strlen(error));
+      _exit(1);
+    }
+
+    _exit(0);
+  } else {
+    ASSERT_TRUE(self->get_cached_pid(&cached_pid));
+    ASSERT_EQ(syscall(__NR_getpid), cached_pid);
+    ASSERT_FALSE(self->is_vforked());
+
+    int status;
+    pid_t wait_result = waitpid(rc, &status, 0);
+    ASSERT_EQ(wait_result, rc);
+    ASSERT_TRUE(WIFEXITED(status));
+    ASSERT_EQ(0, WEXITSTATUS(status));
+  }
+#endif
+}
+
 static void AssertGetPidCorrect() {
   // The loop is just to make manual testing/debugging with strace easier.
   pid_t getpid_syscall_result = syscall(__NR_getpid);