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

rmaucher pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit ab9b5cc7d26ab89692ffbef25aff013a65f20e55
Author: opencode <[email protected]>
AuthorDate: Wed Oct 7 11:24:55 2026 +0200

    Avoid ConcurrentModificationException rendering the status page
    
    The object name lists used to render connector status are
    Collections.synchronizedList instances which handleNotification()
    modifies concurrently when connector MBeans are registered or
    unregistered at runtime. StatusTransformer iterates them with plain
    for-each loops without holding the list monitor, which the
    synchronizedList contract does not cover, so a connector change
    during rendering could fail the whole status page with a
    ConcurrentModificationException wrapped in a ServletException.
    
    Pass snapshots of the three lists, taken while holding each list's
    own monitor, to StatusTransformer.writeConnectorsState() at its
    single call site rather than the live lists.
---
 .../apache/catalina/manager/StatusManagerServlet.java  | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/catalina/manager/StatusManagerServlet.java 
b/java/org/apache/catalina/manager/StatusManagerServlet.java
index 93b8945b88..ae5147a765 100644
--- a/java/org/apache/catalina/manager/StatusManagerServlet.java
+++ b/java/org/apache/catalina/manager/StatusManagerServlet.java
@@ -286,8 +286,12 @@ public class StatusManagerServlet extends HttpServlet 
implements NotificationLis
             args[16] = 
smClient.getString("htmlManagerServlet.connectorStateTableTitleVHost");
             args[17] = 
smClient.getString("htmlManagerServlet.connectorStateTableTitleRequest");
             args[18] = 
smClient.getString("htmlManagerServlet.connectorStateHint");
-            StatusTransformer.writeConnectorsState(writer, mBeanServer, 
threadPools, globalRequestProcessors,
-                    requestProcessors, mode, args);
+            // Take snapshots of the lists. They may be modified concurrently
+            // by handleNotification() when connectors are registered or
+            // unregistered and StatusTransformer iterates them without
+            // holding the lists' monitor.
+            StatusTransformer.writeConnectorsState(writer, mBeanServer, 
copyOf(threadPools),
+                    copyOf(globalRequestProcessors), 
copyOf(requestProcessors), mode, args);
 
             if (request.getPathInfo() != null && 
request.getPathInfo().equals("/all")) {
                 // Note: Retrieving the full status is much slower
@@ -304,6 +308,16 @@ public class StatusManagerServlet extends HttpServlet 
implements NotificationLis
     }
 
 
+    // Takes a snapshot of a list created with Collections.synchronizedList().
+    // The wrapper instance is its own lock, which is also acquired by the
+    // add() and remove() calls in handleNotification().
+    private static <T> List<T> copyOf(List<T> list) {
+        synchronized (list) {
+            return new ArrayList<>(list);
+        }
+    }
+
+
     // ------------------------------------------- NotificationListener Methods
 
     @Override


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to