# UNDF: UNDF-2026-000000315 From 0000001 Mon Sep 17 00:00:00 2001 Subject: [PATCH] CWE-407: tomcat-0001 — fix O(n²) ArrayList.contains() in ReplicationValve.registerReplicationSession() ReplicationValve accumulates cross-context DeltaSession objects per request in a ThreadLocal>. Each call to registerReplicationSession() called sessions.contains(session) — O(n) scan — before adding. With many portlet fragments sharing sessions this degrades to O(n²). Fix: replace ArrayList with LinkedHashSet in the ThreadLocal initialiser and all three call sites that set/iterate it (lines 297, 394, 422). Set.add() is idempotent so the contains() guard is removed entirely. CWE: CWE-407 (Inefficient Algorithmic Complexity) Severity: MEDIUM --- .../apache/catalina/ha/tcp/ReplicationValve.java | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/java/org/apache/catalina/ha/tcp/ReplicationValve.java b/java/org/apache/catalina/ha/tcp/ReplicationValve.java index aaaaaaa..bbbbbbb 100644 --- a/java/org/apache/catalina/ha/tcp/ReplicationValve.java +++ b/java/org/apache/catalina/ha/tcp/ReplicationValve.java @@ -17,7 +17,8 @@ package org.apache.catalina.ha.tcp; import java.io.IOException; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.regex.Pattern; @@ -77,7 +78,7 @@ public class ReplicationValve extends ValveBase implements ClusterValve { * Register all cross context sessions inside endAccess. Use a list with * contains check, that the Portlet API can include a lot of fragments from * same or different applications with session changes. - * ThreadLocal> + * ThreadLocal> */ - protected final ThreadLocal> crossContextSessions = new ThreadLocal<>(); + protected final ThreadLocal> crossContextSessions = new ThreadLocal<>(); @@ -262,13 +263,10 @@ public class ReplicationValve extends ValveBase implements ClusterValve { */ public void registerReplicationSession(DeltaSession session) { - List sessions = crossContextSessions.get(); + LinkedHashSet sessions = crossContextSessions.get(); if (sessions != null) { - if (!sessions.contains(session)) { - if (log.isTraceEnabled()) { - log.trace(sm.getString("ReplicationValve.crossContext.registerSession", - session.getIdInternal(), - session.getManager().getContext().getName())); - } - sessions.add(session); + if (log.isTraceEnabled() && sessions.add(session)) { + log.trace(sm.getString("ReplicationValve.crossContext.registerSession", + session.getIdInternal(), + session.getManager().getContext().getName())); + } else { + sessions.add(session); // O(1) — Set deduplicates automatically } } } @@ -293,7 +291,7 @@ public class ReplicationValve extends ValveBase implements ClusterValve { if (isCrossContext) { - crossContextSessions.set(new ArrayList<>()); + crossContextSessions.set(new LinkedHashSet<>()); }