Simon,

On 3/21/24 12:39, Simon Niederberger wrote:
Hi Chris

Personally I'd go with

XML_INPUT_FACTORY =
XMLInputFactory.newFactory(XMLInputFactory.class.getName(),
EncodingDetector.class.getClassLoader());

allowing me to place my own JAR in common/lib if I really want to (the
only scenario I can think of is an edge-case where there's a bug in
the JVM XMLInputFactory and no upgrade path is available, so I'd place
my own JAR in common/lib).

I wonder if there really are any use-cases for applications wanting Tomcat to 
specify the XMLInputFactory *to be used for JSP*

That sounds pretty far-fetched. Our use case is simply that we deploy
frequently (several times a day) on a Tomcat 10.1 installation, and
have various reasons for not going down the Docker/container/FAT JAR
path. So, making sure we don't have memory leaks is relevant.

Done and done.

Feel free to put the fix in yourself, or grab 10.1.x from GitHub, or wit for Tomcat 10.1.21 to be released (10.1.20 has already been rolled and the voting will end shortly, so you'll have to wait for the next release).

-chris

On Thu, Mar 21, 2024 at 1:44 PM Christopher Schultz
<ch...@christopherschultz.net> wrote:

Simon,

On 3/20/24 15:36, Simon Niederberger wrote:
What if you create an empty jaxp.properties file and make it available to the 
common ClassLoader (e.g. in lib/empty-jaxp.jar:/jaxp.properties) -- does that 
prevent the problem?
  >
I think that boils down to what I'm already doing with the system
property, getting to the FactoryFinder before it uses
findServiceProvider(). Haven't tried it, but I'm sure it would work.

The difference is that Tomcat can ship it as a part of the distribution,
while we shouldn't really be setting system properties like that. It
might prevent, for example, applications using their own preferred
implementation.

imho, Tomcat's EncodingDetector should init with either

XML_INPUT_FACTORY = XMLInputFactory.newDefaultFactory();

to just always use the JVM XMLInputFactory, or then

XML_INPUT_FACTORY =
XMLInputFactory.newFactory(XMLInputFactory.class.getName(),
EncodingDetector.class.getClassLoader());

to honor it's own classloader (maybe
EncodingDetector.class.getClassLoader() is the wrong approach,
basically something getTomcatCommonClassloader())

Yeah, that's probably better than an empty properties file wrapped in a
JAR file wrapped in an enigma.

We also have the option of using the JreMemoryLeakPreventionListener for
this. There are already some XML-related protections in there, though
this one is not specifically there.

Do you have a preferred technique for fixing this? All of those
suggestions seem equally reasonable. I think I have a slight preference
for passing the JSP compiler's ClassLoader in to the factory method:

    XML_INPUT_FACTORY =
      XMLInputFactory.newFactory(XMLInputFactory.class.getName(),
      EncodingDetector.class.getClassLoader());

If you absolutey need to get your JSP compiler to have a custom
XMLInputFactory, you can copy the JSP compiler into your application and
it will use that ClassLoader instead.

What I just don't get is why there's so little online about others
havingEncodingDetector similar issues. Spring + libs like CXF or
jackson-dataformat-xml are common, both those libs have transitive
dependencies on woodstox-core. Throw in ehcache, also common, and your
webapp won't undeploy if it's the first webapp to load a JSP and thus
clinit EncodingDetector. Maybe the public has just given up on clean
undeploying.

My guess is that most people don't really care too much about clean
shutdowns of their applications. They either bring their applications up
and down along with the whole JVM (either standalone or via Docker,
etc.) or they use an embedded Tomcat where their own application hosts
Tomcat and they start/stop that.

Or they disable/ignore memory-leak detection log messages. *shrug*

I wonder if there really are any use-cases for applications wanting
Tomcat to specify the XMLInputFactory *to be used for JSP*. I suspect not.

-chris

On Wed, Mar 20, 2024 at 7:01 PM Christopher Schultz
<ch...@christopherschultz.net> wrote:

Simon,

On 3/20/24 09:59, Simon Niederberger wrote:
The whole thing is caused by Maven dependencies which pull in
com.fasterxml.woodstox:woodstox-core. The WstxInputFactory has a

@ServiceProvider(XMLInputFactory.class)

annotation, where ServiceProvider is
org.ehcache.spi.service.ServiceProvider. I didn't manage to trace the
key code section, but I do find that the
javax.xml.stream.FactoryFinder then ends up finding WstxInputFactory
as registered service provider. As WstxInputFactory is not on the
common classpath (it's in WEB-INF/lib), I assume it's the webapp
classloader which is used. Below is the stacktrace where
EncodingDetector clinit happens (I defined a
ch.want.funnel.FunnelApp$DelegatingXMLInputFactory to get
stacktraces):

Currently I'm setting

System.setProperty("javax.xml.stream.XMLInputFactory",
"com.sun.xml.internal.stream.XMLInputFactoryImpl");
to get a XMLInputFactory implementation which is on the common
loader's classpath, so the webapp can be undeployed cleanly.

So this works, right?

What if you create an empty jaxp.properties file and make it available
to the common ClassLoader (e.g. in lib/empty-jaxp.jar:/jaxp.properties)
-- does that prevent the problem?

I'm wondering if Tomcat should simply ship with an empty jaxp.properties
file to prevent this kind of thing from happening by default. If someone
wants to bundle an XMLInputFactory into Tomcat's lib/ directory and use
that, they could remove this file.

BTW that's an impressive stack trace. ;)

-chris

java.lang.RuntimeException: Stracktrace for tracking XMLInputFactory creation
           at 
ch.want.funnel.FunnelApp$DelegatingXMLInputFactory.<init>(FunnelApp.java:107)
           at 
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native
Method)
           at 
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
           at 
java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
           at 
java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
           at 
java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
           at 
java.xml/javax.xml.stream.FactoryFinder.newInstance(FactoryFinder.java:190)
           at 
java.xml/javax.xml.stream.FactoryFinder.newInstance(FactoryFinder.java:148)
           at 
java.xml/javax.xml.stream.FactoryFinder.find(FactoryFinder.java:261)
           at 
java.xml/javax.xml.stream.FactoryFinder.find(FactoryFinder.java:223)
           at 
java.xml/javax.xml.stream.XMLInputFactory.newInstance(XMLInputFactory.java:166)
           at 
org.apache.jasper.compiler.EncodingDetector.<clinit>(EncodingDetector.java:38)
           at 
org.apache.jasper.compiler.ParserController.determineSyntaxAndEncoding(ParserController.java:324)
           at 
org.apache.jasper.compiler.ParserController.doParse(ParserController.java:201)
           at 
org.apache.jasper.compiler.ParserController.parseDirectives(ParserController.java:128)
           at 
org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:207)
           at org.apache.jasper.compiler.Compiler.compile(Compiler.java:396)
           at org.apache.jasper.compiler.Compiler.compile(Compiler.java:372)
           at org.apache.jasper.compiler.Compiler.compile(Compiler.java:356)
           at 
org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:603)
           at 
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:396)
           at 
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:380)
           at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:328)
           at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108)
           at 
org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$FilterObservation$SimpleFilterObservation.lambda$wrap$1(ObservationFilterChainDecorator.java:479)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$1(ObservationFilterChainDecorator.java:340)
           at 
org.springframework.security.web.ObservationFilterChainDecorator.lambda$wrapSecured$0(ObservationFilterChainDecorator.java:82)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:128)
           at 
org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126)
           at 
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:91)
           at 
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:227)
           at 
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:221)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:75)
           at 
org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
           at 
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
           at 
org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
           at 
org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195)
           at 
org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
           at 
org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
           at 
org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:225)
           at 
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
           at 
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:642)
           at 
org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:408)
           at 
org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:340)
           at 
org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:277)
           at 
org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequestDispatcher.forward(HeaderWriterFilter.java:170)
           at 
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:171)
           at 
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:314)
           at 
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1431)
           at 
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1167)
           at 
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1106)
           at 
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
           at 
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
           at 
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
           at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
           at 
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
           at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:289)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108)
           at 
org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$FilterObservation$SimpleFilterObservation.lambda$wrap$1(ObservationFilterChainDecorator.java:479)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$1(ObservationFilterChainDecorator.java:340)
           at 
org.springframework.security.web.ObservationFilterChainDecorator.lambda$wrapSecured$0(ObservationFilterChainDecorator.java:82)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:128)
           at 
org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126)
           at 
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131)
           at 
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:227)
           at 
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:221)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
           at 
org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
           at 
org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224)
           at 
org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
           at 
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
           at 
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
           at 
org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
           at 
org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195)
           at 
org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
           at 
org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
           at 
org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:225)
           at 
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
           at 
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:109)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:124)
           at 
org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:99)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:117)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
           at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
           at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
           at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
           at 
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
           at 
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
           at 
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
           at 
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
           at 
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
           at 
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:673)
           at 
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
           at 
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
           at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:431)
           at 
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
           at 
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
           at 
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)
           at 
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
           at 
org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
           at 
org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
           at 
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
           at java.base/java.lang.Thread.run(Thread.java:840)


Mühlegasse 18, 6340 Baar, Switzerland

https://www.want.ch

https://www.funnel.travel





On Tue, Mar 19, 2024 at 12:31 PM Christopher Schultz
<ch...@christopherschultz.net> wrote:

Simon,

On 3/18/24 15:17, Simon Niederberger wrote:
I'm analyzing a memory leak reported by Tomcat, and have narrowed it
down to org.apache.jasper.compiler.EncodingDetector:

private static final XMLInputFactory XML_INPUT_FACTORY;
static {
        XML_INPUT_FACTORY = XMLInputFactory.newInstance();
}

This class is called by webapp code on a GET request

            at 
org.apache.jasper.compiler.EncodingDetector.<clinit>(EncodingDetector.java:38)
            at 
org.apache.jasper.compiler.ParserController.determineSyntaxAndEncoding(ParserController.java:324)
            at 
org.apache.jasper.compiler.ParserController.doParse(ParserController.java:201)
            at 
org.apache.jasper.compiler.ParserController.parseDirectives(ParserController.java:128)
            at 
org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:207)
            ...
            at 
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:396)
            at 
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:380)
            at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:328)
            at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)

The EncodingDetector class, if not yet loaded, will be loaded in the
common classloader, then continue by loading the XMLInputFactory using
the webapp context, and might end up with a XMLInputFactory
implementation from a webapp-provided JAR. If that happens, the webapp
can't undeploy. (In my case, woodstox WstxInputFactory registers
itself as ServiceProvider for XMLInputFactory)

For completeness: javax.xml.stream.FactoryFinder.findServiceProvider()
is called without classloader (cl = null), and has

if (cl == null) {
        //the current thread's context class loader
        serviceLoader = ServiceLoader.load(type);
} else {
        serviceLoader = ServiceLoader.load(type, cl);
}

I can't find anything online about memory leaks from webapp-provided
XMLInputFactory implementations, but this must be fairly common. Is my
understanding correct, or have I mis-configured something? (I'm mainly
wondering whether any XMLInputFactory-implementing JARs belong in
tomcat/lib, but again I'm not finding anything online confirming that)

Tomcat 10.1.19
JVM 17.0.10+7-Ubuntu-120.04.1
Ubuntu 20.04.6 LTS

I'm not sure how many web applications ship with an XMLInputSource, but
they definitely do exist. I'm fairly sure most applications won't set a
system property or ship with a stax.properties/jaxp.properties file to
override the default implementation, but of course if it's possible,
someone will eventually do it.

I'm curious: in your example, how are you declaring your implementation
class, and which implementation are you using?

Are you able to log in EncodingDetector.<clinit> what the value of the
thread's context classloader is? I would expect that it's using the
common classloader, as you say, and that the implementation class would
also be loaded using that same classloader.

-chris

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to