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]
