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);