]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
hurd: Remove __hurd_local_reply_port
authorSergey Bugaev <bugaevc@gmail.com>
Thu, 13 Apr 2023 11:58:12 +0000 (14:58 +0300)
committerSamuel Thibault <samuel.thibault@ens-lyon.org>
Fri, 14 Apr 2023 10:31:22 +0000 (10:31 +0000)
Now that the signal code no longer accesses it, the only real user of it
was mig-reply.c, so move the logic for managing the port there.

If we're in SHARED and outside of rtld, we know that __LIBC_NO_TLS ()
always evaluates to 0, and a TLS reply port will always be used, not
__hurd_reply_port0. Still, the compiler does not see that
__hurd_reply_port0 is never used due to its address being taken. To deal
with this, explicitly compile out __hurd_reply_port0 when we know we
won't use it.

Also, instead of accessing the port via THREAD_SELF->reply_port, this
uses THREAD_GETMEM and THREAD_SETMEM directly, avoiding possible
miscompilations.

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
hurd/hurd/threadvar.h
sysdeps/mach/hurd/dl-sysdep.c
sysdeps/mach/hurd/mig-reply.c
sysdeps/mach/sysdep.h

index f5c6a278a6598295c4062827234feeb87ff175ca..c476d98880c685beb32d533be3f759c65caccefd 100644 (file)
 extern unsigned long int __hurd_sigthread_stack_base;
 extern unsigned long int __hurd_sigthread_stack_end;
 
-/* Store the MiG reply port reply port until we enable TLS.  */
-extern mach_port_t __hurd_reply_port0;
-
-/* This returns either the TLS reply port variable, or a single-thread variable
-   when TLS is not initialized yet.  */
-#define __hurd_local_reply_port (*(__LIBC_NO_TLS () ? &__hurd_reply_port0 : &THREAD_SELF->reply_port))
-
 #endif /* hurd/threadvar.h */
index a2115f6edb742f18cf8e5b31013fe096637d7e51..2d595d000691e67422555e89fa88b7fe89ff8a4f 100644 (file)
@@ -238,7 +238,7 @@ _dl_sysdep_start_cleanup (void)
   /* Deallocate the reply port and task port rights acquired by
      __mach_init.  We are done with them now, and the user will
      reacquire them for himself when he wants them.  */
-  __mig_dealloc_reply_port (MACH_PORT_NULL);
+  __mig_dealloc_reply_port (__mig_get_reply_port ());
   __mach_port_deallocate (__mach_task_self (), __mach_host_self_);
   __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
 }
index 33ff260e3664f8967ba5338ec789c41c8a522899..3fdee80e5a9a7c8c191c29b28f49e3c1799349f2 100644 (file)
 
 #include <mach.h>
 #include <mach/mig_support.h>
-#include <hurd/threadvar.h>
+#include <tls.h>
 
 /* These functions are called by MiG-generated code.  */
 
+#if !defined (SHARED) || IS_IN (rtld)
 mach_port_t __hurd_reply_port0;
+#endif
+
+static mach_port_t
+get_reply_port (void)
+{
+#if !defined (SHARED) || IS_IN (rtld)
+  if (__LIBC_NO_TLS ())
+    return __hurd_reply_port0;
+#endif
+  return THREAD_GETMEM (THREAD_SELF, reply_port);
+}
+
+static void
+set_reply_port (mach_port_t port)
+{
+#if !defined (SHARED) || IS_IN (rtld)
+  if (__LIBC_NO_TLS ())
+    __hurd_reply_port0 = port;
+  else
+#endif
+    THREAD_SETMEM (THREAD_SELF, reply_port, port);
+}
 
 /* Called by MiG to get a reply port.  */
 mach_port_t
 __mig_get_reply_port (void)
 {
-  if (__hurd_local_reply_port == MACH_PORT_NULL
-      || (&__hurd_local_reply_port != &__hurd_reply_port0
-         && __hurd_local_reply_port == __hurd_reply_port0))
-    __hurd_local_reply_port = __mach_reply_port ();
-
-  return __hurd_local_reply_port;
+  mach_port_t port = get_reply_port ();
+  if (__glibc_unlikely (port == MACH_PORT_NULL))
+    {
+      port = __mach_reply_port ();
+      set_reply_port (port);
+    }
+  return port;
 }
 weak_alias (__mig_get_reply_port, mig_get_reply_port)
 libc_hidden_def (__mig_get_reply_port)
@@ -41,12 +65,34 @@ libc_hidden_def (__mig_get_reply_port)
 void
 __mig_dealloc_reply_port (mach_port_t arg)
 {
-  mach_port_t port = __hurd_local_reply_port;
-  __hurd_local_reply_port = MACH_PORT_NULL;    /* So the mod_refs RPC won't use it.  */
+  error_t err;
+  mach_port_t port = get_reply_port ();
+
+  set_reply_port (MACH_PORT_NULL);     /* So the mod_refs RPC won't use it.  */
+
+  /* Normally, ARG should be the same as PORT that we store.  However, if a
+     signal has interrupted the RPC, the stored PORT has been deallocated and
+     reset to MACH_PORT_NULL (or possibly MACH_PORT_DEAD).  In this case the
+     MIG routine still has the old name, which it passes to us here.  We must
+     not deallocate (or otherwise touch) it, since it may be already allocated
+     to another port right.  Fortunately MIG itself doesn't do anything with
+     the reply port on errors either, other than immediately calling this
+     function.
+
+     And so:
+     1. Assert that things are sane, i.e. and PORT is either invalid or same
+        as ARG.
+     2. Only deallocate the name if our stored PORT still names it.  In that
+        case we're sure the right has not been deallocated / the name reused.
+    */
+
+  if (!MACH_PORT_VALID (port))
+    return;
+  assert (port == arg);
 
-  if (MACH_PORT_VALID (port))
-    __mach_port_mod_refs (__mach_task_self (), port,
-                         MACH_PORT_RIGHT_RECEIVE, -1);
+  err = __mach_port_mod_refs (__mach_task_self (), port,
+                              MACH_PORT_RIGHT_RECEIVE, -1);
+  assert_perror (err);
 }
 weak_alias (__mig_dealloc_reply_port, mig_dealloc_reply_port)
 libc_hidden_def (__mig_dealloc_reply_port)
index 1c869f5cb201c3f4c8741ac5d1b5f644b7ed1161..35ad1e3920691f637cde000f1cf04a599994b6a0 100644 (file)
@@ -45,7 +45,7 @@
 
 #ifndef __ASSEMBLER__
 #define FATAL_PREPARE_INCLUDE <mach/mig_support.h>
-#define FATAL_PREPARE __mig_dealloc_reply_port (MACH_PORT_NULL)
+#define FATAL_PREPARE __mig_dealloc_reply_port (__mig_get_reply_port ())
 #endif
 
 /* sysdeps/mach/MACHINE/sysdep.h should define the following macros.  */