On 09/11/2026 13:53, Arturo Bernal via dev wrote:
Thanks for the report.
For TestLargeClientHello the cause is in TomcatBaseTest.LogCapture.
logRecords is a Collections.synchronizedList(), so add() is safe, but
containsText() and hasException() iterate it without locking, which the
synchronizedList Javadoc says the caller has to do. The test polls
containsText() and then calls hasException() while the server threads are
still logging at FINE, so they sometimes overlap.
A test that adds records from one thread through LogCapture.handler while
the test thread calls hasException() and containsText() fails with
ConcurrentModificationException after a few milliseconds with the current
code, and passes with the fix below.
The fix is to wrap the two loops in synchronized (logRecords) { ... }. With
it TestLargeClientHello (5 runs), TestPerWebappJuliIntegration,
TestTldScanner and TestTomcatStandalone pass (Java 17, 11.0.28 tarball). I
could not reproduce the failure inside TestLargeClientHello itself as it is
sporadic.
Thanks for the analysis. This failure has also been fixed in all branched.
Mark
Arturo
On Mon, Nov 9, 2026 at 2:41 PM Rainer Jung <[email protected]> wrote:
Thanks Arturo!
Another sporadic one in org.apache.tomcat.util.net.TestLargeClientHello:
Testcase: testClientHelloLargerThanParseLimit took 4.741 sec
Caused an ERROR
null
java.util.ConcurrentModificationException
at
java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at
org.apache.catalina.startup.TomcatBaseTest$LogCapture.hasException(TomcatBaseTest.java:1005)
at
org.apache.tomcat.util.net
.TestLargeClientHello.testClientHelloLargerThanParseLimit(TestLargeClientHello.java:144)
at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
Am 09.11.26 um 14:08 schrieb Arturo Bernal via dev:
I looked at the three failures with the 11.0.28 source tarball and Java
17.
1. TestAbstractEndpoint (2 errors) The two virtual thread tests need Java
21 and 11.0.x supports Java 17. Adding
Assume.assumeTrue(JreCompat.isJre21Available()), as
TestStandardVirtualThreadExecutor does, skips them on Java 17 and they
still run on Java 21.
2. TestJspCServletContext.testGetResourceWithUriIllegalCharacters It
passes
with a UTF-8 locale and fails with LANG=C (InvalidPathException on
unicode-ü.jsp). An Assume that sun.jnu.encoding can encode the character
skips it in that case.
3. TestUpgrade.testUpgradeInfoUnregisteredWhenConnectionClosed I could
not
reproduce it as it is (8 runs with NIO and 8 with NIO2). I think I found
the cause. In ConnectionHandler.process() the processor is taken from the
socket wrapper on entry and only set back at the end. The UpgradeInfo is
registered earlier, in the processor constructor. If the endpoint closes
the socket in between, which is what stop() does, release(socketWrapper)
finds no processor, recycle() is never called and the UpgradeInfo stays
registered.
To check this I added Thread.sleep(1500) to NoClose.init() in the test.
With that, NIO2 fails every time with the same message and the same line
(TestUpgrade.java:439) and NIO passes.
This change fixes it, on top of setCurrentProcessor() in process():
if (wrapper.isClosed()) {
// The socket was closed while this thread owned the processor
so
// the close could not release it.
release(wrapper);
}
takeCurrentProcessor() is atomic so only one thread can release the
processor. With it the sleep version of the test passes with NIO and
NIO2,
and all the coyote tests pass with NIO and NIO2 (75 classes, 9322
tests).
Not tested on main, only on the 11.0.28 tarball.
Arturo
On Mon, Nov 9, 2026 at 1:24 PM Mark Thomas via dev <
[email protected]>
wrote:
Thanks Rainer. I'll take a look before I tag 11.0.29
Mark
On 09/11/2026 12:08, Rainer Jung wrote:
plus sporadic failures in org.apache.coyote.http11.upgrade.TestUpgrade
(until now only observed in NIO2, but that might be pure coincidence):
Testcase: testUpgradeInfoUnregisteredWhenConnectionClosed took 10.176
sec
FAILED
The UpgradeInfo remained registered after the connection was closed.
expected:<0> but was:<1>
junit.framework.AssertionFailedError: The UpgradeInfo remained
registered after the connection was closed. expected:<0> but was:<1>
at
org.apache.coyote.http11.upgrade.TestUpgrade.testUpgradeInfoUnregisteredWhenConnectionClosed(TestUpgrade.java:439)
at java.base/
jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/
jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/
jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]