Very cool Chris, thanks for the quick reaction!

Simon out


On Fri, Mar 22, 2024 at 1:41 PM Christopher Schultz <
ch...@christopherschultz.net> wrote:

> 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