This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit b51567b21de6317ba8467efcd1af29a5a03a2d6b Author: opencode <[email protected]> AuthorDate: Wed Sep 30 13:27:25 2026 +0200 Synchronize access to the StandardHost childClassLoaders map which is written by context start threads and read by findReloadedContextMemoryLeaks() from Manager/JMX threads, preventing concurrent modification of the underlying WeakHashMap during iteration --- java/org/apache/catalina/core/StandardHost.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/java/org/apache/catalina/core/StandardHost.java b/java/org/apache/catalina/core/StandardHost.java index bc0ca4f1a9..51950cb768 100644 --- a/java/org/apache/catalina/core/StandardHost.java +++ b/java/org/apache/catalina/core/StandardHost.java @@ -170,6 +170,12 @@ public class StandardHost extends ContainerBase implements Host { */ private final Map<ClassLoader,String> childClassLoaders = new WeakHashMap<>(); + /** + * Lock used to synchronise access to {@link #childClassLoaders} which is written when child contexts start and + * read when memory leaks are checked. + */ + private final Object childClassLoadersLock = new Object(); + /** * Any file or directory in {@link #appBase} that this pattern matches will be ignored by the automatic deployment @@ -691,8 +697,10 @@ public class StandardHost extends ContainerBase implements Host { if (event.getType().equals(AFTER_START_EVENT)) { if (event.getSource() instanceof Context) { Context context = ((Context) event.getSource()); - childClassLoaders.put(context.getLoader().getClassLoader(), - context.getServletContext().getContextPath()); + synchronized (childClassLoadersLock) { + childClassLoaders.put(context.getLoader().getClassLoader(), + context.getServletContext().getContextPath()); + } } } } @@ -712,7 +720,12 @@ public class StandardHost extends ContainerBase implements Host { List<String> result = new ArrayList<>(); - for (Map.Entry<ClassLoader,String> entry : childClassLoaders.entrySet()) { + List<Map.Entry<ClassLoader,String>> entries; + synchronized (childClassLoadersLock) { + entries = new ArrayList<>(childClassLoaders.entrySet()); + } + + for (Map.Entry<ClassLoader,String> entry : entries) { ClassLoader cl = entry.getKey(); if (cl instanceof WebappClassLoaderBase) { if (!((WebappClassLoaderBase) cl).getState().isAvailable()) { --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
