From 4e9adae5da95219b85f11309919944bc07c4043d Mon Sep 17 00:00:00 2001
From: Liam <byteslice@airmail.cc>
Date: Sun, 30 Oct 2022 20:58:20 -0400
Subject: [PATCH] kernel: more complete fix for KPort reference counting

---
 src/core/hle/service/sm/sm.cpp            |  7 ++---
 src/core/hle/service/sm/sm_controller.cpp | 33 ++++++++++++++++-------
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index e2b8d8720..cb6c0e96f 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -149,9 +149,10 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
         return port_result.Code();
     }
     auto& port = port_result.Unwrap();
-    SCOPE_EXIT({ port->GetClientPort().Close(); });
-
-    kernel.RegisterServerObject(&port->GetServerPort());
+    SCOPE_EXIT({
+        port->GetClientPort().Close();
+        port->GetServerPort().Close();
+    });
 
     // Create a new session.
     Kernel::KClientSession* session{};
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp
index 273f79568..46a8439d8 100644
--- a/src/core/hle/service/sm/sm_controller.cpp
+++ b/src/core/hle/service/sm/sm_controller.cpp
@@ -28,23 +28,36 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
 void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service, "called");
 
+    auto& process = *ctx.GetThread().GetOwnerProcess();
     auto& parent_session = *ctx.Session()->GetParent();
-    auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort();
     auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager();
+    auto& session_handler = session_manager->SessionHandler();
 
-    // Create a session.
-    Kernel::KClientSession* session{};
-    const Result result = parent_port.CreateSession(std::addressof(session), session_manager);
-    if (result.IsError()) {
-        LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(result);
-    }
+    // FIXME: this is duplicated from the SVC, it should just call it instead
+    // once this is a proper process
+
+    // Reserve a new session from the process resource limit.
+    Kernel::KScopedResourceReservation session_reservation(&process,
+                                                           Kernel::LimitableResource::Sessions);
+    ASSERT(session_reservation.Succeeded());
+
+    // Create the session.
+    Kernel::KSession* session = Kernel::KSession::Create(system.Kernel());
+    ASSERT(session != nullptr);
+
+    // Initialize the session.
+    session->Initialize(nullptr, parent_session.GetName(), session_manager);
+
+    // Commit the session reservation.
+    session_reservation.Commit();
+
+    // Register the session.
+    session_handler.ClientConnected(&session->GetServerSession());
 
     // We succeeded.
     IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
     rb.Push(ResultSuccess);
-    rb.PushMoveObjects(session);
+    rb.PushMoveObjects(session->GetClientSession());
 }
 
 void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {