This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 6fe39d64b6d05d05a71cd905c9e158cffebaf4c4 Author: opencode <[email protected]> AuthorDate: Mon Oct 19 11:33:38 2026 +0200 Avoid NullPointerException releasing a PageContext when the pool size changed JspFactoryImpl is installed as the JVM-wide default JspFactory while its pool size is set per web application at startup. The per-thread PageContext pool is created by getPageContext only when pooling is enabled at that moment, but releasePageContext dereferenced the thread local pool unconditionally whenever pooling was enabled at release time. A thread that obtained a PageContext while pooling was disabled and released it after the shared pool size was increased (a second web application with pooling enabled started in between) threw a NullPointerException from the release, failing the request. Return the context to the pool only when the current thread actually has one, and make poolSize volatile since it is written by web application start threads and read by request threads without synchronization. Found by code review. --- java/org/apache/jasper/runtime/JspFactoryImpl.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/java/org/apache/jasper/runtime/JspFactoryImpl.java b/java/org/apache/jasper/runtime/JspFactoryImpl.java index 7b61fec7ca..9e6d753c1e 100644 --- a/java/org/apache/jasper/runtime/JspFactoryImpl.java +++ b/java/org/apache/jasper/runtime/JspFactoryImpl.java @@ -44,7 +44,7 @@ public class JspFactoryImpl extends JspFactory { } private final ThreadLocal<PageContextPool> localPool = new ThreadLocal<>(); - private int poolSize = -1; + private volatile int poolSize = -1; @Override public PageContext getPageContext(Servlet servlet, ServletRequest request, ServletResponse response, @@ -118,7 +118,14 @@ public class JspFactoryImpl extends JspFactory { private void internalReleasePageContext(PageContext pc) { pc.release(); if (poolSize > 0 && (pc instanceof PageContextImpl)) { - localPool.get().put(pc); + // The thread local pool is only created by getPageContext() when + // pooling is enabled at that moment. The pool size may be changed + // (by the start of another web application) after this context was + // obtained on this thread, leaving the pool null here. + PageContextPool pool = localPool.get(); + if (pool != null) { + pool.put(pc); + } } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
