[libc-commits] [libc] 101f88a - [libc] Fix move destruction double-freeing ports after move to RAII

Joseph Huber via libc-commits libc-commits at lists.llvm.org
Mon Feb 16 15:50:20 PST 2026


Author: Joseph Huber
Date: 2026-02-16T17:49:52-06:00
New Revision: 101f88aa99b83f904d709c96953098faf7f73991

URL: https://github.com/llvm/llvm-project/commit/101f88aa99b83f904d709c96953098faf7f73991
DIFF: https://github.com/llvm/llvm-project/commit/101f88aa99b83f904d709c96953098faf7f73991.diff

LOG: [libc] Fix move destruction double-freeing ports after move to RAII

Summary:
Recently I changed the interface to use RAII to close the ports. This
exposed a problem where the default move constructor was invoked in the
optional wrapping, this caused the destructor to fire twice on the
server, obviously causing havok. This PR changes the move destructor to
be deleted so this never happens again. Now everything is constructed
once  and only references are allowed. The optional class had to be
fixed to properly set in_use so we run the destructor properly as well.

Added: 
    

Modified: 
    libc/shared/rpc.h
    libc/shared/rpc_util.h

Removed: 
    


################################################################################
diff  --git a/libc/shared/rpc.h b/libc/shared/rpc.h
index 9465868f21fce..e13ba1de89c20 100644
--- a/libc/shared/rpc.h
+++ b/libc/shared/rpc.h
@@ -302,8 +302,8 @@ template <bool T> struct Port {
 private:
   RPC_ATTRS Port(const Port &) = delete;
   RPC_ATTRS Port &operator=(const Port &) = delete;
-  RPC_ATTRS Port(Port &&) = default;
-  RPC_ATTRS Port &operator=(Port &&) = default;
+  RPC_ATTRS Port(Port &&) = delete;
+  RPC_ATTRS Port &operator=(Port &&) = delete;
 
   friend struct Client;
   friend struct Server;
@@ -383,7 +383,6 @@ struct Server {
   using Port = rpc::Port<true>;
   RPC_ATTRS rpc::optional<Port> try_open(uint32_t lane_size,
                                          uint32_t start = 0);
-  RPC_ATTRS Port open(uint32_t lane_size);
 
   RPC_ATTRS static constexpr uint64_t allocation_size(uint32_t lane_size,
                                                       uint32_t port_count) {
@@ -611,19 +610,12 @@ Server::try_open(uint32_t lane_size, uint32_t start) {
       continue;
     }
 
-    return Port(process, lane_mask, lane_size, index, out);
+    return rpc::optional<Port>(rpc::in_place, process, lane_mask, lane_size,
+                               index, out);
   }
   return rpc::nullopt;
 }
 
-RPC_ATTRS Server::Port Server::open(uint32_t lane_size) {
-  for (;;) {
-    if (rpc::optional<Server::Port> p = try_open(lane_size))
-      return rpc::move(p.value());
-    sleep_briefly();
-  }
-}
-
 #if !__has_builtin(__scoped_atomic_load_n)
 #undef __scoped_atomic_load_n
 #undef __scoped_atomic_store_n

diff  --git a/libc/shared/rpc_util.h b/libc/shared/rpc_util.h
index 171caff1140f9..9b6368e1b4fca 100644
--- a/libc/shared/rpc_util.h
+++ b/libc/shared/rpc_util.h
@@ -179,7 +179,9 @@ template <typename T> struct optional {
 
     template <typename... Args>
     RPC_ATTRS constexpr explicit OptionalStorage(in_place_t, Args &&...args)
-        : stored_value(forward<Args>(args)...) {}
+        : stored_value(forward<Args>(args)...) {
+      in_use = true;
+    }
 
     RPC_ATTRS constexpr void reset() {
       if (in_use)
@@ -194,16 +196,16 @@ template <typename T> struct optional {
   RPC_ATTRS constexpr optional() = default;
   RPC_ATTRS constexpr optional(nullopt_t) {}
 
-  RPC_ATTRS constexpr optional(const T &t) : storage(in_place, t) {
-    storage.in_use = true;
-  }
+  RPC_ATTRS constexpr optional(const T &t) : storage(in_place, t) {}
   RPC_ATTRS constexpr optional(const optional &) = default;
 
-  RPC_ATTRS constexpr optional(T &&t) : storage(in_place, move(t)) {
-    storage.in_use = true;
-  }
+  RPC_ATTRS constexpr optional(T &&t) : storage(in_place, move(t)) {}
   RPC_ATTRS constexpr optional(optional &&O) = default;
 
+  template <typename... Args>
+  RPC_ATTRS constexpr optional(in_place_t, Args &&...args)
+      : storage(in_place, forward<Args>(args)...) {}
+
   RPC_ATTRS constexpr optional &operator=(T &&t) {
     storage = move(t);
     return *this;


        


More information about the libc-commits mailing list