This is an automated email from the ASF dual-hosted git repository.

bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 571ee72309 Fix lock-order inversion deadlock in Diags::tag_activated 
(#13106)
571ee72309 is described below

commit 571ee72309a6935e83b017e5618ddb788af019df
Author: Brian Neradt <[email protected]>
AuthorDate: Thu Apr 23 18:06:14 2026 -0500

    Fix lock-order inversion deadlock in Diags::tag_activated (#13106)
---
 include/tscore/DiagsTypes.h |  7 ++++---
 src/tscore/Diags.cc         | 42 ++++++++++++++++++++++++------------------
 2 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/include/tscore/DiagsTypes.h b/include/tscore/DiagsTypes.h
index f770e871c4..1b3713160b 100644
--- a/include/tscore/DiagsTypes.h
+++ b/include/tscore/DiagsTypes.h
@@ -32,6 +32,7 @@
 #pragma once
 
 #include <cstdarg>
+#include <memory>
 #include <string>
 #include <string_view>
 #include "tsutil/DbgCtl.h"
@@ -242,9 +243,9 @@ public:
   IpAddr debug_client_ip;
 
 private:
-  const std::string prefix_str;
-  mutable ink_mutex tag_table_lock;    // prevents reconfig/read races
-  Regex            *activated_tags[2]; // 1 table for debug, 1 for action
+  const std::string      prefix_str;
+  mutable ink_mutex      tag_table_lock;    // prevents reconfig/read races
+  std::shared_ptr<Regex> activated_tags[2]; // 1 table for debug, 1 for action
 
   // These are the default logfile permissions
   int diags_logfile_perm  = -1;
diff --git a/src/tscore/Diags.cc b/src/tscore/Diags.cc
index 14a1b3436e..6fe5b79cf8 100644
--- a/src/tscore/Diags.cc
+++ b/src/tscore/Diags.cc
@@ -328,19 +328,26 @@ Diags::print_va(const char *debug_tag, DiagsLevel 
diags_level, const SourceLocat
 bool
 Diags::tag_activated(const char *tag, DiagsTagType mode) const
 {
-  bool activated = false;
-
   if (tag == nullptr) {
-    return (true);
+    return true;
   }
 
-  lock();
-  if (activated_tags[mode]) {
-    activated = activated_tags[mode]->exec(tag, RE_ANCHORED);
+  // Snapshot the regex under the lock, then release the lock before running
+  // Regex::exec().  exec() can lazily construct a thread_local RegexContext
+  // whose destructor registration via __cxa_thread_atexit_impl takes the
+  // dynamic loader lock.  Holding tag_table_lock across exec() therefore
+  // creates a lock-order inversion with dlopen() callers that construct a
+  // DbgCtl during a plugin's static initialization (which takes
+  // tag_table_lock while already holding the dl loader lock).  See the
+  // analogous fix in DbgCtl::_new_reference.
+  std::shared_ptr<Regex> regex;
+  {
+    lock();
+    regex = activated_tags[mode];
+    unlock();
   }
-  unlock();
 
-  return (activated);
+  return regex ? regex->exec(tag, RE_ANCHORED) : false;
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -358,13 +365,15 @@ void
 Diags::activate_taglist(const char *taglist, DiagsTagType mode)
 {
   if (taglist) {
-    lock();
-    if (activated_tags[mode]) {
-      delete activated_tags[mode];
+    // Compile the new regex outside tag_table_lock to avoid holding the lock
+    // across work that may touch thread_local state (see tag_activated).
+    auto new_regex = std::make_shared<Regex>();
+    new_regex->compile(taglist);
+    {
+      lock();
+      activated_tags[mode] = std::move(new_regex);
+      unlock();
     }
-    activated_tags[mode] = new Regex;
-    activated_tags[mode]->compile(taglist);
-    unlock();
   }
   if ((DiagsTagType_Debug == mode) && (this == diags())) {
     DbgCtl::update([&](const char *tag) -> bool { return tag_activated(tag, 
DiagsTagType_Debug); });
@@ -385,10 +394,7 @@ void
 Diags::deactivate_all(DiagsTagType mode)
 {
   lock();
-  if (activated_tags[mode]) {
-    delete activated_tags[mode];
-    activated_tags[mode] = nullptr;
-  }
+  activated_tags[mode].reset();
   unlock();
   if ((DiagsTagType_Debug == mode) && (this == diags())) {
     DbgCtl::update([&](const char *tag) -> bool { return tag_activated(tag, 
DiagsTagType_Debug); });

Reply via email to