Support CLONE_VFORK with CLONE_VM

Test: The affected app doesn't crash anymore
Test: CtsBionicTestCases
Bug: 323981318
Bug: 156400255
Change-Id: Iab5bb6da9e495e669f49dff39eda6eafd41b31ed
diff --git a/guest_os_primitives/guest_thread_clone.cc b/guest_os_primitives/guest_thread_clone.cc
index d569186..8c6c6ac 100644
--- a/guest_os_primitives/guest_thread_clone.cc
+++ b/guest_os_primitives/guest_thread_clone.cc
@@ -15,6 +15,7 @@
  */
 
 #include <linux/unistd.h>
+#include <sched.h>
 #include <semaphore.h>
 
 #include "berberis/base/checks.h"
@@ -22,6 +23,7 @@
 #include "berberis/guest_os_primitives/guest_thread.h"
 #include "berberis/guest_os_primitives/guest_thread_manager.h"  // ResetCurrentGuestThreadAfterFork
 #include "berberis/guest_os_primitives/scoped_pending_signals.h"
+#include "berberis/guest_state/guest_addr.h"
 #include "berberis/guest_state/guest_state_opaque.h"
 #include "berberis/runtime/execute_guest.h"
 #include "berberis/runtime_primitives/runtime_library.h"
@@ -76,20 +78,13 @@
 
 }  // namespace
 
+// go/berberis-guest-threads
 pid_t CloneGuestThread(GuestThread* thread,
                        int flags,
                        GuestAddr guest_stack_top,
                        GuestAddr parent_tid,
                        GuestAddr new_tls,
                        GuestAddr child_tid) {
-  // TODO(b/280551726): Legacy hack to handle vfork, investigate if still needed.
-  if ((flags & CLONE_VFORK)) {
-    if ((flags & CLONE_VM)) {
-      TRACE("cleared CLONE_VM for CLONE_VFORK");
-      flags &= ~CLONE_VM;
-    }
-  }
-
   ThreadState& thread_state = *thread->state();
   if (!(flags & CLONE_VM)) {
     // Memory is *not* shared with the child.
@@ -117,11 +112,6 @@
   // cannot use host local variables. For now, use clone function to pass parameters to the child.
   // The child needs new instance of guest thread object.
 
-  if (guest_stack_top == 0) {
-    TRACE("CLONE_VM without new stack");
-    return EINVAL;
-  }
-
   GuestThreadCloneInfo info;
 
   info.thread = GuestThread::CreateClone(thread);
@@ -130,7 +120,6 @@
   }
 
   ThreadState& clone_thread_state = *info.thread->state();
-  SetStackRegister(GetCPUState(clone_thread_state), guest_stack_top);
 
   if ((flags & CLONE_SETTLS)) {
     SetTlsAddr(clone_thread_state, new_tls);
@@ -141,7 +130,19 @@
   CPUState& clone_cpu = GetCPUState(clone_thread_state);
   AdvanceInsnAddrBeyondSyscall(clone_cpu);
   SetReturnValueRegister(clone_cpu, 0);  // Syscall return value
-  SetLinkRegister(clone_cpu, 0);         // Caller address
+
+  if (guest_stack_top != kNullGuestAddr) {
+    SetStackRegister(GetCPUState(clone_thread_state), guest_stack_top);
+    SetLinkRegister(clone_cpu, kNullGuestAddr);
+  } else {
+    if (!(flags & CLONE_VFORK)) {
+      TRACE("CLONE_VM with NULL guest stack and not in CLONE_VFORK mode, returning EINVAL");
+      return EINVAL;
+    }
+    // See b/323981318 and b/156400255.
+    TRACE("CLONE_VFORK with CLONE_VM and NULL guest stack, will share guest stack with parent");
+    // GuestThread::CreateClone has already copied stack and link pointers to new thread.
+  }
 
   // Thread must start with pending signals while it's executing runtime code.
   SetPendingSignalsStatusAtomic(clone_thread_state, kPendingSignalsEnabled);