[llvm] [orc-rt] Make the Session attach preconditions a contract (PR #217325)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 19 05:25:32 PDT 2026


https://github.com/lhames created https://github.com/llvm/llvm-project/pull/217325

Session::attach silently dropped the attach if the Session was already attached, or if a detach or shutdown had been requested, leaving the ControllerAccess constructed but never connected or notified and giving the caller no indication. There is no coherent alternative behaviour -- a detach may be arbitrarily far along by then -- so document the precondition and assert it instead.

Also make Session::detach pass nullptr to proceedToDetach from its Start-state branch, asserting that no ControllerAccess is attached, to match Session::shutdown on the same path.

A TODO covers what to do about contract violations in release builds.

>From 4af9678f1de6f88c6ce27d69fb1e89495ea5a961 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Wed, 19 Aug 2026 18:16:03 +1000
Subject: [PATCH] [orc-rt] Make the Session attach preconditions a contract

Session::attach silently dropped the attach if the Session was already
attached, or if a detach or shutdown had been requested, leaving the
ControllerAccess constructed but never connected or notified and giving
the caller no indication. There is no coherent alternative behaviour --
a detach may be arbitrarily far along by then -- so document the
precondition and assert it instead.

Also make Session::detach pass nullptr to proceedToDetach from its
Start-state branch, asserting that no ControllerAccess is attached, to
match Session::shutdown on the same path.

A TODO covers what to do about contract violations in release builds.
---
 orc-rt/include/orc-rt/Session.h | 10 ++++++++++
 orc-rt/lib/executor/Session.cpp | 23 +++++++++++++++++------
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/orc-rt/include/orc-rt/Session.h b/orc-rt/include/orc-rt/Session.h
index 9a8fe68eecfc1..43ffcf8775a34 100644
--- a/orc-rt/include/orc-rt/Session.h
+++ b/orc-rt/include/orc-rt/Session.h
@@ -434,6 +434,13 @@ class Session {
   /// ControllerAccessT is constructed with a reference to this Session as its
   /// first argument, followed by the given args, as required by the
   /// ControllerAccess base constructor.
+  ///
+  /// A Session may be attached at most once, and attach must not be called
+  /// after -- or concurrently with -- detach or shutdown: by the time a detach
+  /// has been requested it may be arbitrarily far along, so there is no point
+  /// at which a newly attached controller could be connected, or its
+  /// disconnection coherently reported. Violating this is a programming error,
+  /// checked by assertion.
   template <typename ControllerAccessT, typename... ArgTs>
   void attach(BootstrapInfo BI, ArgTs &&...Args) {
     doAttach(std::make_shared<ControllerAccessT>(*this,
@@ -455,6 +462,9 @@ class Session {
   ///
   /// ControllerAccessT::Create is passed a reference to this Session as its
   /// first argument, followed by the given args.
+  ///
+  /// The attach itself is subject to the same restrictions as
+  /// attach<ControllerAccessT>; the returned Error reports Create failure only.
   template <typename ControllerAccessT, typename... ArgTs>
   Error tryAttach(BootstrapInfo BI, ArgTs &&...Args) {
     auto CA = ControllerAccessT::Create(*this, std::forward<ArgTs>(Args)...);
diff --git a/orc-rt/lib/executor/Session.cpp b/orc-rt/lib/executor/Session.cpp
index 1a435ad291767..820b5117c17c4 100644
--- a/orc-rt/lib/executor/Session.cpp
+++ b/orc-rt/lib/executor/Session.cpp
@@ -76,10 +76,17 @@ void Session::doAttach(std::shared_ptr<ControllerAccess> CA, BootstrapInfo BI) {
 
   {
     std::scoped_lock<std::mutex> Lock(M);
-    // Controller can only be attached from the start state if no
-    // other operation has been requested.
-    if (CurrentState != State::Start || TargetState != State::None)
-      return;
+    // A controller can only be attached from the start state, with no other
+    // operation requested: a Session is attached at most once, and attach must
+    // not be called after -- or concurrently with -- detach or shutdown. See
+    // the Session::attach contract.
+    //
+    // TODO: Settle on a policy for contract violations in release builds
+    // (probably abort) and apply it here. Without the assertions below a
+    // violating attach proceeds, clobbering TargetState and potentially
+    // regressing CurrentState from Detached back to Attached.
+    assert(CurrentState == State::Start && TargetState == State::None &&
+           "attach raced detach / shutdown, or Session already attached");
     assert(std::atomic_load(&this->CA) == nullptr &&
            "ControllerAccess object already attached?");
     std::atomic_store(&this->CA, CA);
@@ -160,9 +167,13 @@ void Session::detach(OnDetachFn OnDetach) {
       TmpCA = std::atomic_load(&this->CA);
     } else {
       assert(CurrentState == State::Start);
+      // A CA is only ever stored with TargetState raised to Attached, and
+      // TargetState is not lowered back to None until CurrentState reaches
+      // Attached, so reaching the Start state here implies no CA was attached.
+      assert(std::atomic_load(&this->CA) == nullptr &&
+             "Start state, but a ControllerAccess is attached?");
       // No controller was ever attached, so the disconnect trivially succeeds.
-      proceedToDetach(Lock, std::atomic_exchange(&this->CA, {}),
-                      Error::success());
+      proceedToDetach(Lock, nullptr, Error::success());
       return;
     }
   }



More information about the llvm-commits mailing list